Skip to content

Commit 87a6bcc

Browse files
PARTIAL sync: coreth PR #963,981,1009: nodeType w/o serialization (#1815)
Signed-off-by: Jonathan Oppenheimer <jonathan.oppenheimer@avalabs.org> Co-authored-by: Ceyhun Onur <ceyhun.onur@avalabs.org>
1 parent c12b018 commit 87a6bcc

File tree

16 files changed

+327
-236
lines changed

16 files changed

+327
-236
lines changed

network/network.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func NewNetwork(
139139
appSender,
140140
registerer,
141141
"p2p",
142-
p2pValidators,
142+
p2pValidators, // p2pValidators implements ConnectionHandler
143143
)
144144
if err != nil {
145145
return nil, fmt.Errorf("failed to initialize p2p network: %w", err)
@@ -492,7 +492,7 @@ func (n *network) SendSyncedAppRequest(ctx context.Context, nodeID ids.NodeID, r
492492
}
493493

494494
func (n *network) NewClient(protocol uint64) *p2p.Client {
495-
return n.sdkNetwork.NewClient(protocol, n.p2pValidators)
495+
return n.sdkNetwork.NewClient(protocol, n.p2pValidators) // p2pValidators implements NodeSampler
496496
}
497497

498498
func (n *network) AddHandler(protocol uint64, handler p2p.Handler) error {

plugin/evm/extension/config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/ava-labs/subnet-evm/plugin/evm/message"
1212
"github.com/ava-labs/subnet-evm/plugin/evm/sync"
13+
"github.com/ava-labs/subnet-evm/sync/handlers"
1314
)
1415

1516
var (
@@ -19,6 +20,17 @@ var (
1920
errNilClock = errors.New("nil clock")
2021
)
2122

23+
// LeafRequestConfig is the configuration to handle leaf requests
24+
// in the network and syncer
25+
type LeafRequestConfig struct {
26+
// LeafType is the type of the leaf node
27+
LeafType message.NodeType
28+
// MetricName is the name of the metric to use for the leaf request
29+
MetricName string
30+
// Handler is the handler to use for the leaf request
31+
Handler handlers.LeafRequestHandler
32+
}
33+
2234
// Config is the configuration for the VM extension
2335
type Config struct {
2436
// SyncSummaryProvider is the sync summary provider to use

plugin/evm/message/handler.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ var _ RequestHandler = NoopRequestHandler{}
1515
// Must have methods in format of handleType(context.Context, ids.NodeID, uint32, request Type) error
1616
// so that the Request object of relevant Type can invoke its respective handle method
1717
// on this struct.
18-
// Also see GossipHandler for implementation style.
1918
type RequestHandler interface {
20-
HandleStateTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest LeafsRequest) ([]byte, error)
19+
HandleLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest LeafsRequest) ([]byte, error)
2120
HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request BlockRequest) ([]byte, error)
2221
HandleCodeRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, codeRequest CodeRequest) ([]byte, error)
2322
}
@@ -33,7 +32,7 @@ type ResponseHandler interface {
3332

3433
type NoopRequestHandler struct{}
3534

36-
func (NoopRequestHandler) HandleStateTrieLeafsRequest(context.Context, ids.NodeID, uint32, LeafsRequest) ([]byte, error) {
35+
func (NoopRequestHandler) HandleLeafsRequest(context.Context, ids.NodeID, uint32, LeafsRequest) ([]byte, error) {
3736
return nil, nil
3837
}
3938

plugin/evm/message/leafs_request.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,38 @@ import (
1313

1414
const MaxCodeHashesPerRequest = 5
1515

16-
var _ Request = LeafsRequest{}
16+
// NodeType outlines the trie that a leaf node belongs to
17+
// handlers.LeafsRequestHandler uses this information to determine
18+
// which trie type to fetch the information from
19+
type NodeType uint8
20+
21+
const (
22+
StateTrieNode = NodeType(1)
23+
StateTrieKeyLength = common.HashLength
24+
)
1725

1826
// LeafsRequest is a request to receive trie leaves at specified Root within Start and End byte range
1927
// Limit outlines maximum number of leaves to returns starting at Start
28+
// NodeType outlines which trie to read from state/atomic.
29+
// NOTE: NodeType is not serialized to avoid breaking changes. We rely on the single used node type (StateTrieNode).
2030
type LeafsRequest struct {
21-
Root common.Hash `serialize:"true"`
22-
Account common.Hash `serialize:"true"`
23-
Start []byte `serialize:"true"`
24-
End []byte `serialize:"true"`
25-
Limit uint16 `serialize:"true"`
31+
Root common.Hash `serialize:"true"`
32+
Account common.Hash `serialize:"true"`
33+
Start []byte `serialize:"true"`
34+
End []byte `serialize:"true"`
35+
Limit uint16 `serialize:"true"`
36+
NodeType NodeType // TODO(JonathanOppenheimer): Not serialized to avoid breaking changes. We rely on the single used node type (StateTrieNode).
2637
}
2738

2839
func (l LeafsRequest) String() string {
2940
return fmt.Sprintf(
30-
"LeafsRequest(Root=%s, Account=%s, Start=%s, End %s, Limit=%d)",
31-
l.Root, l.Account, common.Bytes2Hex(l.Start), common.Bytes2Hex(l.End), l.Limit,
41+
"LeafsRequest(Root=%s, Account=%s, Start=%s, End=%s, Limit=%d, NodeType=%d)",
42+
l.Root, l.Account, common.Bytes2Hex(l.Start), common.Bytes2Hex(l.End), l.Limit, l.NodeType,
3243
)
3344
}
3445

3546
func (l LeafsRequest) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler RequestHandler) ([]byte, error) {
36-
return handler.HandleStateTrieLeafsRequest(ctx, nodeID, requestID, l)
47+
return handler.HandleLeafsRequest(ctx, nodeID, requestID, l)
3748
}
3849

3950
// LeafsResponse is a response to a LeafsRequest

plugin/evm/message/leafs_request_test.go

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
package message
55

66
import (
7-
"bytes"
8-
"context"
97
"encoding/base64"
108
"math/rand"
119
"testing"
1210

13-
"github.com/ava-labs/avalanchego/ids"
1411
"github.com/ava-labs/libevm/common"
15-
"github.com/stretchr/testify/assert"
1612
"github.com/stretchr/testify/require"
1713
)
1814

@@ -52,6 +48,7 @@ func TestMarshalLeafsRequest(t *testing.T) {
5248
require.Equal(t, leafsRequest.Start, l.Start)
5349
require.Equal(t, leafsRequest.End, l.End)
5450
require.Equal(t, leafsRequest.Limit, l.Limit)
51+
require.Equal(t, NodeType(0), l.NodeType) // make sure it is not serialized
5552
}
5653

5754
// TestMarshalLeafsResponse requires that the structure or serialization logic hasn't changed, primarily to
@@ -107,61 +104,53 @@ func TestMarshalLeafsResponse(t *testing.T) {
107104
require.Equal(t, leafsResponse.ProofVals, l.ProofVals)
108105
}
109106

110-
func TestLeafsRequestValidation(t *testing.T) {
111-
mockRequestHandler := &mockHandler{}
112-
113-
tests := map[string]struct {
114-
request LeafsRequest
115-
assertResponse func(t *testing.T)
116-
}{
117-
"node type StateTrieNode": {
118-
request: LeafsRequest{
119-
Root: common.BytesToHash([]byte("some hash goes here")),
120-
Start: bytes.Repeat([]byte{0x00}, common.HashLength),
121-
End: bytes.Repeat([]byte{0xff}, common.HashLength),
122-
Limit: 10,
123-
},
124-
assertResponse: func(t *testing.T) {
125-
assert.True(t, mockRequestHandler.handleStateTrieCalled)
126-
assert.False(t, mockRequestHandler.handleBlockRequestCalled)
127-
assert.False(t, mockRequestHandler.handleCodeRequestCalled)
128-
},
129-
},
130-
}
131-
for name, test := range tests {
132-
t.Run(name, func(t *testing.T) {
133-
_, _ = test.request.Handle(context.Background(), ids.GenerateTestNodeID(), 1, mockRequestHandler)
134-
test.assertResponse(t)
135-
mockRequestHandler.reset()
136-
})
107+
// TestLeafsRequestNodeTypeNotSerialized verifies that NodeType is not serialized
108+
// and does not affect the encoded output. This ensures backward compatibility.
109+
func TestLeafsRequestNodeTypeNotSerialized(t *testing.T) {
110+
// set random seed for deterministic random
111+
rand := rand.New(rand.NewSource(1))
112+
113+
startBytes := make([]byte, common.HashLength)
114+
endBytes := make([]byte, common.HashLength)
115+
116+
_, err := rand.Read(startBytes)
117+
require.NoError(t, err)
118+
119+
_, err = rand.Read(endBytes)
120+
require.NoError(t, err)
121+
122+
// Create request without explicit NodeType (defaults to 0)
123+
leafsRequestDefault := LeafsRequest{
124+
Root: common.BytesToHash([]byte("test root")),
125+
Start: startBytes,
126+
End: endBytes,
127+
Limit: 512,
137128
}
138-
}
139129

140-
var _ RequestHandler = (*mockHandler)(nil)
130+
// Create request with explicit NodeType
131+
leafsRequestWithNodeType := LeafsRequest{
132+
Root: common.BytesToHash([]byte("test root")),
133+
Start: startBytes,
134+
End: endBytes,
135+
Limit: 512,
136+
NodeType: StateTrieNode,
137+
}
141138

142-
type mockHandler struct {
143-
handleStateTrieCalled,
144-
handleBlockRequestCalled,
145-
handleCodeRequestCalled bool
146-
}
139+
bytesDefault, err := Codec.Marshal(Version, leafsRequestDefault)
140+
require.NoError(t, err)
147141

148-
func (m *mockHandler) HandleStateTrieLeafsRequest(context.Context, ids.NodeID, uint32, LeafsRequest) ([]byte, error) {
149-
m.handleStateTrieCalled = true
150-
return nil, nil
151-
}
142+
bytesWithNodeType, err := Codec.Marshal(Version, leafsRequestWithNodeType)
143+
require.NoError(t, err)
152144

153-
func (m *mockHandler) HandleBlockRequest(context.Context, ids.NodeID, uint32, BlockRequest) ([]byte, error) {
154-
m.handleBlockRequestCalled = true
155-
return nil, nil
156-
}
145+
require.Equal(t, bytesDefault, bytesWithNodeType, "NodeType should not affect serialization")
157146

158-
func (m *mockHandler) HandleCodeRequest(context.Context, ids.NodeID, uint32, CodeRequest) ([]byte, error) {
159-
m.handleCodeRequestCalled = true
160-
return nil, nil
161-
}
147+
var unmarshaled LeafsRequest
148+
_, err = Codec.Unmarshal(bytesWithNodeType, &unmarshaled)
149+
require.NoError(t, err)
162150

163-
func (m *mockHandler) reset() {
164-
m.handleStateTrieCalled = false
165-
m.handleBlockRequestCalled = false
166-
m.handleCodeRequestCalled = false
151+
require.Equal(t, NodeType(0), unmarshaled.NodeType, "NodeType should not be serialized")
152+
require.Equal(t, leafsRequestDefault.Root, unmarshaled.Root)
153+
require.Equal(t, leafsRequestDefault.Start, unmarshaled.Start)
154+
require.Equal(t, leafsRequestDefault.End, unmarshaled.End)
155+
require.Equal(t, leafsRequestDefault.Limit, unmarshaled.Limit)
167156
}

plugin/evm/network_handler.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/ava-labs/avalanchego/codec"
1010
"github.com/ava-labs/avalanchego/ids"
1111
"github.com/ava-labs/libevm/ethdb"
12-
"github.com/ava-labs/libevm/metrics"
12+
"github.com/ava-labs/libevm/log"
1313
"github.com/ava-labs/libevm/triedb"
1414

1515
"github.com/ava-labs/subnet-evm/plugin/evm/message"
@@ -20,29 +20,51 @@ import (
2020

2121
var _ message.RequestHandler = (*networkHandler)(nil)
2222

23+
type LeafHandlers map[message.NodeType]syncHandlers.LeafRequestHandler
24+
2325
type networkHandler struct {
24-
leafRequestHandler *syncHandlers.LeafsRequestHandler
26+
leafRequestHandlers LeafHandlers
2527
blockRequestHandler *syncHandlers.BlockRequestHandler
2628
codeRequestHandler *syncHandlers.CodeRequestHandler
2729
}
2830

31+
type LeafRequestTypeConfig struct {
32+
NodeType message.NodeType
33+
NodeKeyLen int
34+
TrieDB *triedb.Database
35+
UseSnapshots bool
36+
MetricName string
37+
}
38+
2939
// newNetworkHandler constructs the handler for serving network requests.
3040
func newNetworkHandler(
3141
provider syncHandlers.SyncDataProvider,
3242
diskDB ethdb.KeyValueReader,
33-
evmTrieDB *triedb.Database,
3443
networkCodec codec.Manager,
35-
) message.RequestHandler {
36-
syncStats := syncStats.NewHandlerStats(metrics.Enabled)
44+
leafRequestHandlers LeafHandlers,
45+
syncStats syncStats.HandlerStats,
46+
) *networkHandler {
3747
return &networkHandler{
38-
leafRequestHandler: syncHandlers.NewLeafsRequestHandler(evmTrieDB, nil, networkCodec, syncStats),
48+
leafRequestHandlers: leafRequestHandlers,
3949
blockRequestHandler: syncHandlers.NewBlockRequestHandler(provider, networkCodec, syncStats),
4050
codeRequestHandler: syncHandlers.NewCodeRequestHandler(diskDB, networkCodec, syncStats),
4151
}
4252
}
4353

44-
func (n networkHandler) HandleStateTrieLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest message.LeafsRequest) ([]byte, error) {
45-
return n.leafRequestHandler.OnLeafsRequest(ctx, nodeID, requestID, leafsRequest)
54+
func (n networkHandler) HandleLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest message.LeafsRequest) ([]byte, error) {
55+
nodeType := leafsRequest.NodeType
56+
// TODO(JonathanOppenheimer):Handle legacy requests where NodeType was not serialized (defaults to 0)
57+
// In this interim period, we treat NodeType 0 as StateTrieNode
58+
if nodeType == 0 {
59+
nodeType = message.StateTrieNode
60+
}
61+
62+
handler, ok := n.leafRequestHandlers[nodeType]
63+
if !ok {
64+
log.Debug("node type is not recognised, dropping request", "nodeID", nodeID, "requestID", requestID, "nodeType", leafsRequest.NodeType)
65+
return nil, nil
66+
}
67+
return handler.OnLeafsRequest(ctx, nodeID, requestID, leafsRequest)
4668
}
4769

4870
func (n networkHandler) HandleBlockRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, blockRequest message.BlockRequest) ([]byte, error) {

0 commit comments

Comments
 (0)