-
Notifications
You must be signed in to change notification settings - Fork 378
feat(handshake): enum protobuf and capabilities #5105
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
base: master
Are you sure you want to change the base?
Conversation
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.
Migrates the golang CI yaml to version 2, given that the project now uses go 1.24.0
| if: github.ref != 'refs/heads/master' | ||
| uses: wagoid/commitlint-github-action@v5 | ||
| - name: GolangCI-Lint | ||
| uses: golangci/golangci-lint-action@v7 |
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.
Bump required here as v2.1.6 of GolangCI-lint is only supported in @7
| - linters: | ||
| - staticcheck | ||
| text: "QF1008:" | ||
| - linters: | ||
| - staticcheck | ||
| text: "QF1001:" | ||
| - linters: | ||
| - staticcheck | ||
| text: "QF1002:" | ||
| - linters: | ||
| - staticcheck | ||
| text: "QF1003:" | ||
| - linters: | ||
| - staticcheck | ||
| text: "QF1006:" |
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.
Disregarded as these are general in nature
|
@mfw78 please fix linting errors for a green CI, ta |
I've bumped to the latest golang linters for CI/CD within this PR, the failing CI/CD currently seems limited to beekeeper settlement tests. |
| ProtocolName = "handshake" | ||
| // ProtocolVersion is the current handshake protocol version. | ||
| ProtocolVersion = "13.0.0" | ||
| ProtocolVersion = "14.0.0" |
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.
You have to increase this once more, ProtocolVersion was already increased in the meanwhile
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.
nice initiative!
| - packaging/** | ||
| branches: | ||
| - '**' | ||
| push: |
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.
unnecessary indentation doubling on each line.
| // F F F | ||
| // | ||
| // F F F F S | ||
| // # F F F F S |
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.
unnecessary change as well as below
| - goheader | ||
| text: go-ethereum Authors | ||
| - linters: | ||
| - goconst |
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.
originally, next to the rules there we comments like "temporally disable...", but this is how temporal solutions work usually : D
| return &stream{Stream: s, metrics: metrics} | ||
| } | ||
|
|
||
| func newStreamWithHeaders(s network.Stream, metrics metrics, ctx context.Context, headler p2p.HeadlerFunc, peerAddress swarm.Address, headers p2p.Headers) (*stream, error) { |
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.
headers parameter is unused and ctx is usually the first parameter
|
|
||
| // Write data to trigger the protocol handler | ||
| if stream != nil { | ||
| _, _ = stream.Write([]byte("test")) |
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.
I would do error check here because it may lead to silent failure.
| return | ||
| // Check if BOTH local and remote peer support trace headers | ||
| // At this point, handshake has completed and capabilities are known | ||
| peerCaps := s.peers.capabilities(overlay) |
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 could be optimized by mapping to the capabilities only once and get traceability flag along with fullnode flag (above this change)
| } | ||
|
|
||
| func TestInfo_CapabilitiesReuse(t *testing.T) { | ||
| // Test that Info struct reuses the protobuf Capabilities object |
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.
does it test the pointer functionality in Go? :D
| } | ||
|
|
||
| func (m *Syn) Marshal() (dAtA []byte, err error) { | ||
| // 438 bytes of a gzipped FileDescriptorProto |
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.
I get different output by running
protoc --gogofaster_out=. --gogofaster_opt=paths=source_relative,Mgzip.proto ./pkg/p2p/libp2p/internal/handshake/pb/handshake.proto
|
|
||
| if s.picker != nil { | ||
| if !s.picker.Pick(p2p.Peer{Address: overlay, FullNode: ack.FullNode}) { | ||
| if !s.picker.Pick(p2p.Peer{Address: overlay, FullNode: ack.Capabilities.FullNode}) { |
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.
Protocol Buffers does not automatically create empty objects for missing fields and it can cause nil pointer dereference here since there is no nil check on Capabilities.
| BzzAddress: remoteBzzAddress, | ||
| FullNode: ack.FullNode, | ||
| BzzAddress: remoteBzzAddress, | ||
| Capabilities: ack.Capabilities, |
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.
same as above
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.
Capabilities
Grouping Capabilities into a dedicated protobuf message is nice and adds clarity to the specific features that a node can provide.
Stream Headers
The Headers feature that is added to the Streams in bee are supposed to be a general purpose headers as string key/value pairs similar to the HTTP headers, as libp2p did not have any way to share metadata upon establishing Streams. Tracing is using Stream Headers to avoid adding tracing field to most of bee protobuf messages. So every mention of the tracing alongside headers in names should be removed.
At the time it was measured that headers did not add any significant overhead to streams. I hope that making Headers optional is influenced by measurements and metrics that support this change.
Unrelated changes
This PR holds some changes that are unrelated to the handshake protocol, and I think that they should be part of other PRs.
| GOBIN ?= $$($(GO) env GOPATH)/bin | ||
| GOLANGCI_LINT ?= $(GOBIN)/golangci-lint | ||
| GOLANGCI_LINT_VERSION ?= v1.64.5 | ||
| GOLANGCI_LINT_VERSION ?= v2.1.6 |
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.
Raising golangci-lint version to 2 involves a larger set of changes in this PR which as a different purpose. I would recommend to create a separate PR for improvimg golangci-lint usage.
|
|
||
| logger.Debug("write root", "hash", rootRef) | ||
| _, err = writer.WriteString(fmt.Sprintf("%s\n", rootRef)) | ||
| _, err = fmt.Fprintf(writer, "%s\n", rootRef) |
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.
While this change can be considered as an improvement, as well as a change a few lines below, it does not relate to the handshake protocol and are not crucial.
| hostFactory func(...libp2p.Option) (host.Host, error) | ||
| HeadersRWTimeout time.Duration | ||
| Registry *prometheus.Registry | ||
| EnableTraceHeaders bool |
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.
EnableTraceHeaders should be named only EnableHeaders as the whole headers functionality is now optional, not only tracing. Tracing is just one of the possible headers. Headers in bee streams have general purpose just as HTTP protocol headers are, just keys and values. It is ok to make them optional, like here, but tracing is just one of the header key/value pair. I do not think that there are any other usages of headers currently.
|
|
||
| // PendingNonceAt returns the nonce we should use, but we will | ||
| // compare this to our pending tx list, therefore the -1. | ||
| var maxNonce uint64 = onchainNonce - 1 |
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.
This file has an unrelated changes to the handshake protocol.
| peerCaps := s.peers.capabilities(overlay) | ||
| localSupportsTrace := s.handshakeService.SupportsTraceHeaders() | ||
| remoteSupportsTrace := peerCaps != nil && peerCaps.TraceHeaders | ||
| bothSupportTrace := localSupportsTrace && remoteSupportsTrace |
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.
Thise value should be called localSupportsHeaders, remoteSupportsTrace, bothSupportHeaders...
| Ack Ack = 2; | ||
| message Capabilities { | ||
| bool full_node = 1; | ||
| bool trace_headers = 2; |
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.
Just as on other places, where I provided some context on the naming for similar flags, this filed should be called supports_headers or something similar, just without tracing, as tracing is just one feature that uses headers feature.
| option go_package = "pb"; | ||
|
|
||
| message Syn { | ||
| message Handshake { |
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.
I am not sure why Handshake message is needed as it only wraps existing messages. Maybe this indirection could be avoided and only to use explicit messages as before as their order is sequential and deterministic in the protocol?
| return found, full, peerID | ||
| } | ||
|
|
||
| func (r *peerRegistry) capabilities(overlay swarm.Address) *pb.Capabilities { |
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.
I think this would be a cleaner solution:
func (r *peerRegistry) capabilities(overlay swarm.Address) *pb.Capabilities {
r.mu.RLock()
defer r.mu.RUnlock()
peerID, exists := r.underlays[overlay.ByteString()]
if !exists {
return nil
}
return r.peerCapabilities[peerID]
}
|
investigated the beekeeper test error and it turned out swap protocol also uses libp2p header exchange. |
Checklist
My change requires a documentation update, and I have done it.Description
This PR revises the
handshakeprotocol such that:Capabilitiesmessage within theAckthat determines if the node is a full node and/or supports tracing headers.Handshakeprotobuf now is aoneofmessage which enforces strict typing of the messages on the wire.libp2p, essentially reducing RTTs / network traffic that is needlessly sending empty headers on every single stream creation exceptHandshake. The functionality is preserved for developers / those wanting to debug the protocol.Open API Spec Version Changes (if applicable)
N/A
Motivation and Context (Optional)
Strict typing and reduction in needless network chatter.
Related Issue (Optional)
Screenshots (if appropriate):
N/A