Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

protocols, retrieval: swap-enabled messages implement Price #1771

Merged
merged 4 commits into from
Sep 19, 2019

Conversation

holisticode
Copy link
Contributor

This PR changes the way a message type is marked as accounted (enabled for swap accounting).

So far, the protocol would be queried with the message type, and then the protocol was responsible to return if a message was enabled for swap accounting or not.

This change simplifies this by just requiring accounted message types to implement the protocols.Price interface. The accounting module in p2p/protocols then just tries a type case to Price; if it succeeds, it will continue by accounting the price, if it fails it returns assuming the message needs no accounting.

This removes the need for reflection on the protocol's current Price implementation and catches bugs where an accounted message type would fail if it is a value type and not a pointer, as happened in the first retrieval iteration.

We should force to use pointers as message types on every protocol

Copy link
Member

@janos janos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the approach and I did not think that it would require so few changes. But, tests are failing mostly because NewAccounting constructor needs to be updated.

@holisticode
Copy link
Contributor Author

holisticode commented Sep 17, 2019

Yesssss so sorry I only had tested the swap package....
I am updating the p2p/protocols package with all tests and simulations now :)

Copy link
Member

@janos janos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. :) This approach is better than using reflections and maps with types, for me.

Copy link
Contributor

@mortelli mortelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know this is still a draft, but i was curious enough to take a look and frankly, i think this is a great change.

i just have one question: how do you think this will fare against the idea of eventually getting message prices through an oracle?

p2p/protocols/accounting.go Outdated Show resolved Hide resolved
p2p/protocols/accounting.go Outdated Show resolved Hide resolved
p2p/protocols/accounting.go Outdated Show resolved Hide resolved
@holisticode
Copy link
Contributor Author

@mortelli getting the price through oracles is not affected in any way different than the current code.

It was accessed via a constant in swap/prices.go, and it is now the same way.
The redesign of accessing message prices via oracle needs to take care of this.

I can imagine a service on swap which contains all prices, and the Price method of each message type could be querying that service for the price, just as it is asking the constant now.

@holisticode holisticode marked this pull request as ready for review September 18, 2019 16:10
Copy link
Member

@zelig zelig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great change. looking at the code maybe best time to add constructors to price:

SenderPays(1)
ReceiverPays(1).PerByte()

Copy link
Contributor

@Eknir Eknir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good refactor!

I made one comment which will make your code to make use of go's typing system and effectively transform a run-time error into a compile-time error.

Apart from that, it would be good to make a comment for both the Chunkdelivery struct, as well as the RetrieveRequest struct implement the PricedMessage interface.

@@ -122,17 +119,18 @@ func SetupAccountingMetrics(reportInterval time.Duration, path string) *Accounti
}

// Send takes a peer, a size and a msg and
// - calculates the cost for the local node sending a msg of size to peer using the Prices interface
// - calculates the cost for the local node sending a msg of size to peer querying the message for its price
// - credits/debits local node using balance interface
func (ah *Accounting) Send(peer *Peer, size uint32, msg interface{}) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this function can only succeed by passing a PricedMessage, we can make it a compile-time error if no priced-message is passed instead of a run-time error when we replace msg interface{} with msg PricedMessage.

I just tried this locally and got an error

network/retrieval/retrieve.go:115:15: cannot use protocols.NewAccounting(balance) (type *protocols.Accounting) as type protocols.Hook in assignment:
	*protocols.Accounting does not implement protocols.Hook (wrong type for Send method)
		have Send(*protocols.Peer, uint32, protocols.PricedMessage) error
		want Send(*protocols.Peer, uint32, interface {}) error

which is resolvable by updating the Hook interface (p2p/protocols/protocol.go).

Additionally, this will make the body of the function also more concise.

Same holds for the Receive implementation in p2p/protocols.go/accounting.go:139 => change the function to accept only a PricedMessage type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep in mind that both of the Send and Receive functions return error variables.

when you pass a message which does not implement the PricedMessage interface, the code returns nil. this means success—there is no price, therefore no accounting to be done, therefore no error at this level.

in other words, we should go ahead and process the protocol message if it's not a priced one.

what's more: by only accepting priced messages, we would be blocking every other message from that protocol from being processed. if the protocol has an accounting hook set, it will call Send and Receive for all its messages, and all should be able to be processed whether they are priced or not.

i would like to know more about this error you are getting, can you give more information?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Eknir, if you do this, you need to implement Price for every message of the protocol.
Plus Send and Receive are generic protocol level hooks with generic type signature, accounting is just one such hook (since no other exists, this argument is somewhat weak, but nontheless in line with the design.)

Copy link
Contributor

@Eknir Eknir Sep 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mortelli and @victor . I was somewhat misled because I had the idea that both of these functions were not intended to be called by a message which does not need accounting. If that is not the case, my argument obviously does not hold.

I dived a bit more in the code and I see that indeed, the accounting.Send() function is called with many different message types (p2p/protocol/protocol.go) and that is because of this is needed that the function can be called also by messages for which no price is defined.

@mortelli , the error I am getting is because I changed the type of msg in the Send function, but I did not change it in the protocols.Hook (p2p/protocols/protocols.go:117) definition.
This makes Accounting (p2p/protocols/accounting.go) to not anymore implement the Hook interface, leading to the error.

@Eknir Eknir self-requested a review September 19, 2019 08:27
Copy link
Contributor

@Eknir Eknir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider my comment with regards to letting the Send and the Receive functions accept a PricedMessage type instead of the empty interface type.

@Eknir Eknir self-requested a review September 19, 2019 12:48
Copy link
Contributor

@Eknir Eknir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@holisticode
Copy link
Contributor Author

@zelig #1785

@skylenet skylenet added this to the 0.5.0 milestone Sep 20, 2019
chadsr added a commit to chadsr/swarm that referenced this pull request Sep 23, 2019
* 'master' of github.com:ethersphere/swarm: (32 commits)
  network/stream: refactor cursors tests (ethersphere#1786)
  network: Add capabilities if peer from store does not have it (ethersphere#1791)
  Swap logger (ethersphere#1754)
  network: Add capability filtered depth calculation (ethersphere#1787)
  travis: remove go1.12 job (ethersphere#1784)
  cmd/swarm: correct bzznetworkid flag description (ethersphere#1761)
  network, pss: Capability in pss (ethersphere#1764)
  network/stream: handle nil peer in TestNodesExchangeCorrectBinIndexes (ethersphere#1779)
  protocols, retrieval: swap-enabled messages implement Price (ethersphere#1771)
  cmd/swarm-smoke: fix waitToPushSynced connection closing (ethersphere#1781)
  cmd/swarm: simplify testCluster.StartNewNodes (ethersphere#1777)
  build: increase golangci-lint deadline (ethersphere#1778)
  docker: ignore build/bin when copying files (ethersphere#1780)
  swap: fix and rename Peer.getLastSentCumulativePayout (ethersphere#1769)
  network/stream: more resilient TestNodesCorrectBinsDynamic (ethersphere#1776)
  network: Add Capabilities to Kademlia database (ethersphere#1713)
  network: add own address to KademliaInfo (ethersphere#1775)
  pss: Refactor. Step 2. Refactor forward cache (ethersphere#1742)
  all: configurable payment/disconnect thresholds (ethersphere#1729)
  network/stream/v2: more resilient TestNodesExchangeCorrectBinIndexes (ethersphere#1760)
  ...
@mortelli mortelli deleted the incentives-msg-price branch November 14, 2019 18:52
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants