-
Notifications
You must be signed in to change notification settings - Fork 20.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
eth: implement eth66 #22241
eth: implement eth66 #22241
Conversation
Alternatively, if we handle it 65/66 separation in the layer above, it would look something like this: // SendBlockHeaders sends a batch of block headers to the remote peer.
func (p *Peer) SendBlockHeaders(headers []*types.Header) error {
return p2p.Send(p.rw, BlockHeadersMsg, BlockHeadersPacket(headers))
}
// SendBlockHeaders66 sends a batch of block headers to the remote peer.
func (p *Peer) SendBlockHeaders66(requestId uint64, headers []*types.Header) error {
return p2p.Send(p.rw, BlockHeadersMsg, requestId,
BlockHeadersPacket66{id, BlockHeadersPacket(headers)})
} That's maybe the most straight-forward implementation of them all, but it's not very subtle |
I think this way of doing it is the 'cleanest': d6b1989 |
This PR is more or less 'done'. As in, as far as I know, everything is implemented (as opposed to "this is working perfectly and is safe to merge"). As such, it would be good with a review, to check if the general approach is ok, or if we should approach it some other way. I'm going to try syncing some local instances over eth66 with eachother, and see how it goes. @carver you don't happen to have any eth66 implementations ready, do you? |
One geth goerli node is now serving another locally on my laptop, speaking |
Tested now with two peers which are both in sync. One connected to the 'live' network, the other with |
This PR looks really clean and nice! |
func TestCheckpointEnforcement64Full(t *testing.T) { testCheckpointEnforcement(t, 64, FullSync) } | ||
func TestCheckpointEnforcement64Fast(t *testing.T) { testCheckpointEnforcement(t, 64, FastSync) } | ||
func TestCheckpointEnforcement64Full(t *testing.T) { testCheckpointEnforcement(t, 64, FullSync) } | ||
func TestCheckpointEnforcement64Fast(t *testing.T) { testCheckpointEnforcement(t, 64, FastSync) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit confusing to me. The eth65
only adds the transaction retrievals, it did nothing at the syncing level. Shouldn't we also test the lightSync
on eth64?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, probably. I didn't add any new-old tests, just new-new tests
With the latest fix, I am now able to
So now it appears to function correctly. |
case msg.Code == StatusMsg: | ||
// Status messages should never arrive after the handshake | ||
return fmt.Errorf("%w: uncontrolled status message", errExtraStatusMsg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for reviewer: This explicit error has been removed, and now this case would just fall through and error as an unhandled message
Erm, no, it should be stable independent if it's broadcast or announced blocks. All peers receive either one or the other, but they do receive enough information to never hiccup. |
eth/protocols/eth/protocol.go
Outdated
type BlockBodiesPacket66 struct { | ||
RequestId uint64 | ||
BlockBodiesPacket | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either move this up right under BlockBodiesPacket to keep the sequence. Or alternatively pls flip this with the RLP version so that we have the same ordering as the legacy versions,
eth/protocols/eth/protocol.go
Outdated
@@ -190,9 +202,32 @@ func (request *NewBlockPacket) sanityCheck() error { | |||
// GetBlockBodiesPacket represents a block body query. | |||
type GetBlockBodiesPacket []common.Hash | |||
|
|||
// GetBlockBodiesPacket represents a block body query over ETH-66. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit throughout, it's not ETH-66
, it's eth/66
. Please fix it.
Indeed, while adding testcases, I found that the |
47a8b1c
to
e12632d
Compare
eth/protocols/eth/peer.go
Outdated
for _, hash := range hashes { | ||
p.knownTxs.Add(hash) | ||
} | ||
return p2p.Send(p.rw, PooledTransactionsMsg, PooledTransactionsRLPPacket66{id, txs}) // Not packed into PooledTransactionsPacket to avoid RLP decoding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please expand the struct fields throughout. It's bad style to use unnamed field initialization, it's even forbidden on AppEngine for example.
eth/protocols/eth/handlers.go
Outdated
return peer.ReplyBlockBodiesRLP(query.RequestId, response) | ||
} | ||
|
||
func answerGetBlockBodiesQuery(backend Backend, query GetBlockBodiesPacket, peer *Peer) BlockBodiesRLPPacket { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use *GetBlockBodiesPacket as a paramter, there's no need to copy the struct. Same for the return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah apologies, the output is a slice, so there's no copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the input is a slice too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, []common.Hash
in, []rlp.RawValue
out
eth/protocols/eth/handlers.go
Outdated
return peer.ReplyNodeData(query.RequestId, response) | ||
} | ||
|
||
func answerGetNodeDataQuery(backend Backend, query GetNodeDataPacket, peer *Peer) NodeDataPacket { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use *GetNodeDataPacket as input, *NodeDataPacket as output
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah apologies, the output is a slice, so there's no copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the input is a slice too?
Fixed, rebased |
9dd6850
to
b14d63d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
This PR implements support for
eth66
(https://eips.ethereum.org/EIPS/eip-2481) , in the sense that we advertise it and handle it on the protocol level. This PR does not actually make use of it in any way, internally.The way it's implemented, is that instead of a giant switch, the eth handler splits it up into a map of handlers.
So, e.g the
eth65
handler map hasBlockHeadersMsg: handleBlockHeaders,
, andeth66
maps the same message type tohandleGetBlockHeaders66
instead.The two methods are very simliar, and the actual query-resolving has been moved to a function they both share
The big difference, aside from parsing as
GetBlockHeadersPacket66
instead ofGetBlockHeadersPacket
, is that theeth66
handler callspeer.ReplyBlockHeaders
instead ofpeer.SendBlockHeaders(response)
.The
ReplyXXX( id,...)
wraps the message with the givenrequest id
.All new messages are wrapped from the
eth65/64
message types, e.g.In this implementation, the
Backend
is not aware of request ids. For exampe, when dealing with the response containing receipts -- theeth65
handler decodes it, and shoves to the backend:And the new handler does the same thing -- decodes into the wrapped type, and then passes the 'original' unwrapped message to the backend:
When we deal with outgoing requests, however, we need to handle the distinction in the
Peer
itself. Example when we request bodies: