diff --git a/database/merkle/firewood/syncer/syncer.go b/database/merkle/firewood/syncer/syncer.go index c8d499c0455a..534e8eac0839 100644 --- a/database/merkle/firewood/syncer/syncer.go +++ b/database/merkle/firewood/syncer/syncer.go @@ -34,6 +34,7 @@ type Config struct { SimultaneousWorkLimit int Log logging.Logger StateSyncNodes []ids.NodeID + PeerTracker *p2p.PeerTracker Registerer prometheus.Registerer } @@ -61,11 +62,12 @@ func newWithDB(config Config, db sync.DB[*RangeProof, struct{}], targetRoot ids. sync.Config[*RangeProof, struct{}]{ RangeProofMarshaler: rangeProofMarshaler{}, ChangeProofMarshaler: changeProofMarshaler{}, - EmptyRoot: ids.ID(types.EmptyRootHash), ProofClient: proofClient, + TargetRoot: targetRoot, + EmptyRoot: ids.ID(types.EmptyRootHash), + PeerTracker: config.PeerTracker, SimultaneousWorkLimit: config.SimultaneousWorkLimit, Log: config.Log, - TargetRoot: targetRoot, StateSyncNodes: config.StateSyncNodes, }, config.Registerer, diff --git a/database/merkle/sync/BUILD.bazel b/database/merkle/sync/BUILD.bazel index 0c883fcad747..8f5750718e69 100644 --- a/database/merkle/sync/BUILD.bazel +++ b/database/merkle/sync/BUILD.bazel @@ -49,6 +49,7 @@ go_test( "//snow/engine/common", "//utils/logging", "//utils/maybe", + "//utils/set", "@com_github_prometheus_client_golang//prometheus", "@com_github_stretchr_testify//assert", "@com_github_stretchr_testify//require", diff --git a/database/merkle/sync/sync_test.go b/database/merkle/sync/sync_test.go index f177c82e10ee..123f6d027547 100644 --- a/database/merkle/sync/sync_test.go +++ b/database/merkle/sync/sync_test.go @@ -22,6 +22,7 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/maybe" + "github.com/ava-labs/avalanchego/utils/set" pb "github.com/ava-labs/avalanchego/proto/pb/sync" ) @@ -318,6 +319,121 @@ func Test_Sync_BusyContextCancellation(t *testing.T) { require.ErrorIs(t, err, context.Canceled) } +// Test_Sync_WithPeerTracker ensures that the peer tracker is used for sampling if provided. +func Test_Sync_WithPeerTracker(t *testing.T) { + targetRoot := ids.GenerateTestID() + clientDB := &db{id: ids.Empty} + + var observedNodeID ids.NodeID + response := marshalRangeProofResponse(t, &proofDouble{newRoot: targetRoot}) + handler := p2p.TestHandler{ + AppRequestF: func(_ context.Context, nodeID ids.NodeID, _ time.Time, _ []byte) ([]byte, *common.AppError) { + observedNodeID = nodeID + return response, nil + }, + } + + knownNodeID := ids.GenerateTestNodeID() + pt, err := p2p.NewPeerTracker(logging.NoLog{}, "", prometheus.NewRegistry(), set.Set[ids.NodeID]{}, nil) + require.NoError(t, err) + pt.Connected(knownNodeID, nil) + + syncer, err := NewSyncer( + clientDB, + Config[*proofDouble, *proofDouble]{ + TargetRoot: targetRoot, + RangeProofMarshaler: marshaler{}, + ChangeProofMarshaler: marshaler{}, + ProofClient: p2ptest.NewSelfClient(t, t.Context(), knownNodeID, handler), + PeerTracker: pt, + Log: logging.NoLog{}, + SimultaneousWorkLimit: 1, + }, + prometheus.NewRegistry(), + ) + require.NoError(t, err) + require.NoErrorf(t, syncer.Sync(t.Context()), "%T.Sync()", syncer) + require.Equal(t, knownNodeID, observedNodeID, "peer tracker must drive node selection") +} + +func Test_Sync_NoPeersAvailable(t *testing.T) { + targetRoot := ids.GenerateTestID() + clientDB := &db{id: ids.Empty} + + pt, err := p2p.NewPeerTracker(logging.NoLog{}, "", prometheus.NewRegistry(), set.Set[ids.NodeID]{}, nil) + require.NoError(t, err) + + syncer, err := NewSyncer( + clientDB, + Config[*proofDouble, *proofDouble]{ + TargetRoot: targetRoot, + RangeProofMarshaler: marshaler{}, + ChangeProofMarshaler: marshaler{}, + ProofClient: p2ptest.NewSelfClient(t, t.Context(), ids.EmptyNodeID, p2p.TestHandler{}), + PeerTracker: pt, + Log: logging.NoLog{}, + SimultaneousWorkLimit: 1, + }, + prometheus.NewRegistry(), + ) + require.NoError(t, err) + err = syncer.Sync(t.Context()) + require.ErrorIs(t, err, errNoPeersAvailable) +} + +// Test_Sync_NodeIDs ensures that specific nodeIDs are used for state syncing. +func Test_Sync_NodeIDs(t *testing.T) { + targetRoot := ids.GenerateTestID() + clientDB := &db{id: ids.Empty} + + const numRequests = 10 + response := marshalRangeProofResponse(t, &proofDouble{newRoot: ids.Empty}) + finalResponse := marshalRangeProofResponse(t, &proofDouble{newRoot: targetRoot}) + count := 0 + expectedHandler := p2p.TestHandler{ + AppRequestF: func(context.Context, ids.NodeID, time.Time, []byte) ([]byte, *common.AppError) { + count++ + if count >= numRequests { + return finalResponse, nil + } + return response, nil + }, + } + unexpectedHandler := p2p.TestHandler{ + AppRequestF: func(context.Context, ids.NodeID, time.Time, []byte) ([]byte, *common.AppError) { + assert.Fail(t, "unexpected AppRequest to node") + return nil, nil + }, + } + + expectedNodeID := ids.GenerateTestNodeID() + unexpectedNodeID := ids.GenerateTestNodeID() + syncer, err := NewSyncer( + clientDB, + Config[*proofDouble, *proofDouble]{ + TargetRoot: targetRoot, + RangeProofMarshaler: marshaler{}, + ChangeProofMarshaler: marshaler{}, + ProofClient: p2ptest.NewClientWithPeers( + t, + t.Context(), + ids.EmptyNodeID, + p2p.TestHandler{}, + map[ids.NodeID]p2p.Handler{ + expectedNodeID: expectedHandler, + unexpectedNodeID: unexpectedHandler, + }, + ), + StateSyncNodes: []ids.NodeID{expectedNodeID}, + Log: logging.NoLog{}, + SimultaneousWorkLimit: 1, + }, + prometheus.NewRegistry(), + ) + require.NoError(t, err) + require.NoErrorf(t, syncer.Sync(t.Context()), "%T.Sync()", syncer) +} + func Test_Midpoint(t *testing.T) { require := require.New(t) diff --git a/database/merkle/sync/syncer.go b/database/merkle/sync/syncer.go index a2c15f21cc62..d5498d82a169 100644 --- a/database/merkle/sync/syncer.go +++ b/database/merkle/sync/syncer.go @@ -51,6 +51,7 @@ var ( errInvalidChangeProof = errors.New("failed to verify change proof") errTooManyBytes = errors.New("response contains more than requested bytes") errUnexpectedResponseType = errors.New("unexpected response type") + errNoPeersAvailable = errors.New("no peers available") ) type priority byte @@ -144,14 +145,18 @@ type Syncer[R any, C any] struct { // TODO remove non-config values out of this struct type Config[R any, C any] struct { - RangeProofMarshaler Marshaler[R] - ChangeProofMarshaler Marshaler[C] - ProofClient *p2p.Client + // Required fields: + RangeProofMarshaler Marshaler[R] + ChangeProofMarshaler Marshaler[C] + ProofClient *p2p.Client + TargetRoot ids.ID + EmptyRoot ids.ID // defaults to [ids.Empty] if not set + + // Optional SimultaneousWorkLimit int Log logging.Logger - TargetRoot ids.ID - EmptyRoot ids.ID StateSyncNodes []ids.NodeID + PeerTracker *p2p.PeerTracker } func NewSyncer[R any, C any]( @@ -418,15 +423,16 @@ func (s *Syncer[_, _]) requestChangeProof(ctx context.Context, work *workItem) { return } - onResponse := func(ctx context.Context, _ ids.NodeID, responseBytes []byte, err error) { + onResponse := func(ctx context.Context, _ ids.NodeID, responseBytes []byte, appErr error) bool { defer s.finishWorkItem() - if err := s.handleChangeProofResponse(ctx, targetRootID, work, changeReq, responseBytes, err); err != nil { + if err := s.handleChangeProofResponse(ctx, targetRootID, work, changeReq, responseBytes, appErr); err != nil { // TODO log responses s.config.Log.Debug("dropping response", zap.Error(err), zap.Stringer("request", request)) s.retryWork(work) - return + return false } + return true } if err := s.sendRequest(ctx, s.config.ProofClient, requestBytes, onResponse); err != nil { @@ -473,15 +479,16 @@ func (s *Syncer[_, _]) requestRangeProof(ctx context.Context, work *workItem) { return } - onResponse := func(ctx context.Context, _ ids.NodeID, responseBytes []byte, appErr error) { + onResponse := func(ctx context.Context, _ ids.NodeID, responseBytes []byte, appErr error) bool { defer s.finishWorkItem() if err := s.handleRangeProofResponse(ctx, targetRootID, work, rangeReq, responseBytes, appErr); err != nil { // TODO log responses s.config.Log.Debug("dropping response", zap.Error(err), zap.Stringer("request", request)) s.retryWork(work) - return + return false } + return true } if err := s.sendRequest(ctx, s.config.ProofClient, requestBytes, onResponse); err != nil { @@ -493,22 +500,53 @@ func (s *Syncer[_, _]) requestRangeProof(ctx context.Context, work *workItem) { s.metrics.RequestMade() } +type appResponseCallbackWithResult func(ctx context.Context, nodeID ids.NodeID, responseBytes []byte, err error) bool + +// toAppResponseCallback wraps the callback, discarding the bool return value. +func (c appResponseCallbackWithResult) toAppResponseCallback() p2p.AppResponseCallback { + return func(ctx context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { + _ = c(ctx, nodeID, responseBytes, err) + } +} + func (s *Syncer[_, _]) sendRequest( ctx context.Context, client *p2p.Client, requestBytes []byte, - onResponse p2p.AppResponseCallback, + onResponse appResponseCallbackWithResult, ) error { - if len(s.config.StateSyncNodes) == 0 { - return client.AppRequestAny(ctx, requestBytes, onResponse) + switch { + case len(s.config.StateSyncNodes) > 0: + nodeIdx := atomic.AddUint32(&s.stateSyncNodeIdx, 1) + nodeID := s.config.StateSyncNodes[nodeIdx%uint32(len(s.config.StateSyncNodes))] + return client.AppRequest(ctx, set.Of(nodeID), requestBytes, onResponse.toAppResponseCallback()) + case s.config.PeerTracker != nil: + // TODO(alarso16): This logic should be pushed to the [p2p.Client] implementation. + return sendRequestWithPeerTracker(ctx, client, s.config.PeerTracker, requestBytes, onResponse) + default: + // Default to built-in selection from the [p2p.NodeSampler]. + return client.AppRequestAny(ctx, requestBytes, onResponse.toAppResponseCallback()) } +} - // Get the next nodeID to query using the [nodeIdx] offset. - // If we're out of nodes, loop back to 0. - // We do this try to query a different node each time if possible. - nodeIdx := atomic.AddUint32(&s.stateSyncNodeIdx, 1) - nodeID := s.config.StateSyncNodes[nodeIdx%uint32(len(s.config.StateSyncNodes))] - return client.AppRequest(ctx, set.Of(nodeID), requestBytes, onResponse) +func sendRequestWithPeerTracker(ctx context.Context, c *p2p.Client, pt *p2p.PeerTracker, requestBytes []byte, onResponse appResponseCallbackWithResult) error { + nodeID, ok := pt.SelectPeer() + if !ok { + return errNoPeersAvailable + } + pt.RegisterRequest(nodeID) + start := time.Now() + return c.AppRequest(ctx, set.Of(nodeID), requestBytes, func(ctx context.Context, nodeID ids.NodeID, responseBytes []byte, appErr error) { + timeToRespond := time.Since(start) + if success := onResponse(ctx, nodeID, responseBytes, appErr); !success { + pt.RegisterFailure(nodeID) + return + } + + const epsilon = 1e-9 // avoid division by zero + bandwidth := float64(len(responseBytes)) / float64(timeToRespond.Seconds()+epsilon) + pt.RegisterResponse(nodeID, bandwidth) + }) } func (s *Syncer[_, _]) retryWork(work *workItem) { @@ -745,8 +783,13 @@ func (s *Syncer[_, _]) setError(err error) { s.errLock.Lock() defer s.errLock.Unlock() + if s.fatalError != nil { + return + } + s.config.Log.Error("sync errored", zap.Error(err)) s.fatalError = err + // Call in goroutine because we might be holding [s.workLock] go func() { s.workLock.Lock() diff --git a/graft/coreth/network/network.go b/graft/coreth/network/network.go index 5c2ff6946c08..3d958a17c89e 100644 --- a/graft/coreth/network/network.go +++ b/graft/coreth/network/network.go @@ -58,12 +58,7 @@ type SyncedNetworkClient interface { // Returns response bytes, and ErrRequestFailed if the request should be retried. SendSyncedAppRequest(ctx context.Context, nodeID ids.NodeID, request []byte) ([]byte, error) - // RegisterResponse records a successful response from nodeID with the - // observed bandwidth (response bytes divided by request time). - RegisterResponse(nodeID ids.NodeID, bandwidth float64) - - // RegisterFailure records a failed response from nodeID. - RegisterFailure(nodeID ids.NodeID) + PeerTracker() *p2p.PeerTracker } type Network interface { @@ -168,6 +163,11 @@ func NewNetwork( }, nil } +// PeerTracker returns the bandwidth-tracked peer list for use during state sync. +func (n *network) PeerTracker() *p2p.PeerTracker { + return n.peers +} + // Sample returns a random sample of connected peers. // `limit` is ignored, and one peer will be returned. // The peer returned may not be a validator - to sample validators, @@ -484,14 +484,6 @@ func (n *network) Size() uint32 { return uint32(n.peers.Size()) } -func (n *network) RegisterResponse(nodeID ids.NodeID, bandwidth float64) { - n.peers.RegisterResponse(nodeID, bandwidth) -} - -func (n *network) RegisterFailure(nodeID ids.NodeID) { - n.peers.RegisterFailure(nodeID) -} - // SendSyncedAppRequestAny synchronously sends request to an arbitrary peer. // Returns response bytes, the ID of the chosen peer, and ErrRequestFailed if // the request should be retried. diff --git a/graft/evm/go.mod b/graft/evm/go.mod index 3b1ee3de5c1e..ec3746cf90bc 100644 --- a/graft/evm/go.mod +++ b/graft/evm/go.mod @@ -14,6 +14,7 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.4 + github.com/prometheus/client_golang v1.23.0 github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 golang.org/x/crypto v0.49.0 @@ -65,7 +66,6 @@ require ( github.com/onsi/gomega v1.36.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.23.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect diff --git a/graft/evm/sync/client/BUILD.bazel b/graft/evm/sync/client/BUILD.bazel index e1b723cc8001..53b7ec6a0348 100644 --- a/graft/evm/sync/client/BUILD.bazel +++ b/graft/evm/sync/client/BUILD.bazel @@ -17,6 +17,8 @@ go_library( "//graft/evm/sync/handlers", "//ids", "//network/p2p", + "//utils/logging", + "//utils/set", "@com_github_ava_labs_libevm//common", "@com_github_ava_labs_libevm//core/rawdb", "@com_github_ava_labs_libevm//core/types", @@ -26,6 +28,7 @@ go_library( "@com_github_ava_labs_libevm//params", "@com_github_ava_labs_libevm//rlp", "@com_github_ava_labs_libevm//trie", + "@com_github_prometheus_client_golang//prometheus", ], ) diff --git a/graft/evm/sync/client/client.go b/graft/evm/sync/client/client.go index 058d411576f4..c67d3544a812 100644 --- a/graft/evm/sync/client/client.go +++ b/graft/evm/sync/client/client.go @@ -62,12 +62,7 @@ type Network interface { // Returns response bytes, and ErrRequestFailed if the request should be retried. SendSyncedAppRequest(ctx context.Context, nodeID ids.NodeID, request []byte) ([]byte, error) - // RegisterResponse records a successful response from nodeID with the - // observed bandwidth. Used to prioritize more responsive peers. - RegisterResponse(nodeID ids.NodeID, bandwidth float64) - - // RegisterFailure records a failed response from nodeID. - RegisterFailure(nodeID ids.NodeID) + PeerTracker() *p2p.PeerTracker // P2PNetwork returns the unabstracted [p2p.Network]. P2PNetwork() *p2p.Network @@ -87,8 +82,7 @@ type Client interface { // GetCode synchronously retrieves code associated with the given hashes GetCode(ctx context.Context, hashes []common.Hash) ([][]byte, error) - // AddClient creates a separate client on the underlying [p2p.Network]. - AddClient(handlerID uint64) *p2p.Client + Network() Network // StateSyncNodes returns the list of nodes provided via config. StateSyncNodes() []ids.NodeID @@ -107,6 +101,7 @@ type client struct { stateSyncNodeIdx uint32 stats stats.ClientSyncerStats blockParser EthBlockParser + pt *p2p.PeerTracker } type Config struct { @@ -128,11 +123,12 @@ func New(config *Config) *client { stats: config.Stats, stateSyncNodes: config.StateSyncNodeIDs, blockParser: config.BlockParser, + pt: config.Network.PeerTracker(), } } -func (c *client) AddClient(handlerID uint64) *p2p.Client { - return c.network.P2PNetwork().NewClient(handlerID, c.network) +func (c *client) Network() Network { + return c.network } func (c *client) StateSyncNodes() []ids.NodeID { @@ -365,6 +361,7 @@ func (c *client) get(ctx context.Context, request message.Request, parseFn parse response, err = c.network.SendSyncedAppRequest(ctx, nodeID, requestBytes) } metric.UpdateRequestLatency(time.Since(start)) + c.pt.RegisterRequest(nodeID) if err != nil { logCtx := make([]any, 0, 8) @@ -374,7 +371,7 @@ func (c *client) get(ctx context.Context, request message.Request, parseFn parse logCtx = append(logCtx, "attempt", attempt, "request", request, "err", err) log.Debug("request failed, retrying", logCtx...) metric.IncFailed() - c.network.RegisterFailure(nodeID) + c.pt.RegisterFailure(nodeID) time.Sleep(failedRequestSleepInterval) continue } else { @@ -382,14 +379,14 @@ func (c *client) get(ctx context.Context, request message.Request, parseFn parse if err != nil { lastErr = err log.Debug("could not validate response, retrying", "nodeID", nodeID, "attempt", attempt, "request", request, "err", err) - c.network.RegisterFailure(nodeID) + c.pt.RegisterFailure(nodeID) metric.IncFailed() metric.IncInvalidResponse() continue } bandwidth := float64(len(response)) / (time.Since(start).Seconds() + epsilon) - c.network.RegisterResponse(nodeID, bandwidth) + c.pt.RegisterResponse(nodeID, bandwidth) metric.IncSucceeded() metric.IncReceived(int64(numElements)) return responseIntf, nil diff --git a/graft/evm/sync/client/test_client.go b/graft/evm/sync/client/test_client.go index b455e40d64e5..1a8aec8e4357 100644 --- a/graft/evm/sync/client/test_client.go +++ b/graft/evm/sync/client/test_client.go @@ -16,7 +16,6 @@ import ( "github.com/ava-labs/avalanchego/graft/evm/message" "github.com/ava-labs/avalanchego/graft/evm/sync/handlers" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/p2p" ) var ( @@ -57,14 +56,14 @@ func NewTestClient( } } -func (*TestClient) AddClient(uint64) *p2p.Client { - panic("AddClient is not supported in TestClient") -} - func (*TestClient) StateSyncNodes() []ids.NodeID { return nil } +func (*TestClient) Network() Network { + panic("Network is not supported in TestClient") +} + func (ml *TestClient) GetLeafs(ctx context.Context, request message.LeafsRequest) (message.LeafsResponse, error) { response, err := ml.leafsHandler.OnLeafsRequest(ctx, ids.GenerateTestNodeID(), 1, request) if err != nil { diff --git a/graft/evm/sync/client/test_network.go b/graft/evm/sync/client/test_network.go index db338bc6fcd2..f98a32e80f8f 100644 --- a/graft/evm/sync/client/test_network.go +++ b/graft/evm/sync/client/test_network.go @@ -7,8 +7,12 @@ import ( "context" "errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/network/p2p" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/set" ) var _ Network = (*testNetwork)(nil) @@ -22,6 +26,20 @@ type testNetwork struct { callback func() // callback is called prior to processing each test call requestErr []error nodesRequested []ids.NodeID + + peerTracker *p2p.PeerTracker +} + +// PeerTracker returns a new empty peer tracker. +func (t *testNetwork) PeerTracker() *p2p.PeerTracker { + if t.peerTracker == nil { + pt, err := p2p.NewPeerTracker(logging.NoLog{}, "", prometheus.NewRegistry(), set.Set[ids.NodeID]{}, nil) + if err != nil { + panic(err) + } + t.peerTracker = pt + } + return t.peerTracker } func (*testNetwork) P2PNetwork() *p2p.Network { @@ -88,7 +106,3 @@ func (t *testNetwork) testResponses(callback func(), responses ...[]byte) { t.callback = callback t.numCalls = 0 } - -func (*testNetwork) RegisterResponse(ids.NodeID, float64) {} - -func (*testNetwork) RegisterFailure(ids.NodeID) {} diff --git a/graft/evm/sync/engine/client.go b/graft/evm/sync/engine/client.go index 64c70e85a519..16d539b31a28 100644 --- a/graft/evm/sync/engine/client.go +++ b/graft/evm/sync/engine/client.go @@ -411,16 +411,18 @@ func (c *client) newSyncerRegistry(summary message.Syncable) (*SyncerRegistry, e if err != nil { return nil, fmt.Errorf("failed to create firewood syncer metrics registerer: %w", err) } + network := c.config.Client.Network() stateSyncer, err = evmstate.NewFirewoodSyncer( syncer.Config{ Log: c.config.SnowCtx.Log, Registerer: registerer, StateSyncNodes: c.config.Client.StateSyncNodes(), + PeerTracker: network.PeerTracker(), }, tdb.Firewood, summary.GetBlockRoot(), codeQueue, - c.config.Client.AddClient(p2p.FirewoodProofHandlerID), + network.P2PNetwork().NewClient(p2p.FirewoodProofHandlerID, network), ) if err != nil { return nil, fmt.Errorf("failed to create firewood syncer: %w", err) diff --git a/graft/subnet-evm/network/network.go b/graft/subnet-evm/network/network.go index 715e365e42b3..b7833591fde4 100644 --- a/graft/subnet-evm/network/network.go +++ b/graft/subnet-evm/network/network.go @@ -58,12 +58,7 @@ type SyncedNetworkClient interface { // Returns response bytes, and ErrRequestFailed if the request should be retried. SendSyncedAppRequest(ctx context.Context, nodeID ids.NodeID, request []byte) ([]byte, error) - // RegisterResponse records a successful response from nodeID with the - // observed bandwidth (response bytes divided by request time). - RegisterResponse(nodeID ids.NodeID, bandwidth float64) - - // RegisterFailure records a failed response from nodeID. - RegisterFailure(nodeID ids.NodeID) + PeerTracker() *p2p.PeerTracker } type Network interface { @@ -168,6 +163,11 @@ func NewNetwork( }, nil } +// PeerTracker returns the bandwidth-tracked peer list for use during state sync. +func (n *network) PeerTracker() *p2p.PeerTracker { + return n.peers +} + // Sample returns a random sample of connected peers. // `limit` is ignored, and one peer will be returned. // The peer returned may not be a validator - to sample validators, @@ -484,14 +484,6 @@ func (n *network) Size() uint32 { return uint32(n.peers.Size()) } -func (n *network) RegisterResponse(nodeID ids.NodeID, bandwidth float64) { - n.peers.RegisterResponse(nodeID, bandwidth) -} - -func (n *network) RegisterFailure(nodeID ids.NodeID) { - n.peers.RegisterFailure(nodeID) -} - // SendSyncedAppRequestAny synchronously sends request to an arbitrary peer. // Returns response bytes, the ID of the chosen peer, and ErrRequestFailed if // the request should be retried.