Files
node/x/sync/client_test.go
T

159 lines
3.9 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//go:build skip
package sync
import (
"context"
"sync"
"testing"
"time"
"github.com/luxfi/metric"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"github.com/luxfi/consensus/core"
"github.com/luxfi/ids"
"github.com/luxfi/node/trace"
"github.com/luxfi/node/x/merkledb"
"github.com/luxfi/p2p"
"github.com/luxfi/node/trace"
)
var _ p2p.Handler = (*flakyHandler)(nil)
func newDefaultDBConfig() merkledb.Config {
return merkledb.Config{
IntermediateWriteBatchSize: 100,
HistoryLength: defaultRequestKeyLimit,
ValueNodeCacheSize: defaultRequestKeyLimit,
IntermediateWriteBufferSize: defaultRequestKeyLimit,
IntermediateNodeCacheSize: defaultRequestKeyLimit,
Reg: metric.NewNoOp().Registry(),
Tracer: trace.Noop,
BranchFactor: merkledb.BranchFactor16,
}
}
func newFlakyRangeProofHandler(
t *testing.T,
db merkledb.MerkleDB,
modifyResponse func(response *merkledb.RangeProof),
) p2p.Handler {
handler := NewGetRangeProofHandler(db)
c := counter{m: 2}
return &p2p.TestHandler{
RequestF: func(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *common.Error) {
responseBytes, appErr := handler.Request(ctx, nodeID, deadline, requestBytes)
if appErr != nil {
return nil, appErr
}
response := &pb.RangeProof{}
require.NoError(t, proto.Unmarshal(responseBytes, response))
proof := &merkledb.RangeProof{}
require.NoError(t, proof.UnmarshalProto(response))
// Half of requests are modified
if c.Inc() == 0 {
modifyResponse(proof)
}
responseBytes, err := proto.Marshal(proof.ToProto())
if err != nil {
return nil, &common.Error{Code: 123, Message: err.Error()}
}
return responseBytes, nil
},
}
}
func newFlakyChangeProofHandler(
t *testing.T,
db merkledb.MerkleDB,
modifyResponse func(response *merkledb.ChangeProof),
) p2p.Handler {
handler := NewGetChangeProofHandler(db)
c := counter{m: 2}
return &p2p.TestHandler{
RequestF: func(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *common.Error) {
var err error
responseBytes, appErr := handler.Request(ctx, nodeID, deadline, requestBytes)
if appErr != nil {
return nil, appErr
}
response := &pb.SyncGetChangeProofResponse{}
require.NoError(t, proto.Unmarshal(responseBytes, response))
changeProof := response.Response.(*pb.SyncGetChangeProofResponse_ChangeProof)
proof := &merkledb.ChangeProof{}
require.NoError(t, proof.UnmarshalProto(changeProof.ChangeProof))
// Half of requests are modified
if c.Inc() == 0 {
modifyResponse(proof)
}
responseBytes, err = proto.Marshal(&pb.SyncGetChangeProofResponse{
Response: &pb.SyncGetChangeProofResponse_ChangeProof{
ChangeProof: proof.ToProto(),
},
})
if err != nil {
return nil, &common.Error{Code: 123, Message: err.Error()}
}
return responseBytes, nil
},
}
}
type flakyHandler struct {
p2p.Handler
c *counter
}
func (f *flakyHandler) Request(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *common.Error) {
if f.c.Inc() == 0 {
return nil, &common.Error{Code: 123, Message: "flake error"}
}
return f.Handler.Request(ctx, nodeID, deadline, requestBytes)
}
type counter struct {
i int
m int
lock sync.Mutex
}
func (c *counter) Inc() int {
c.lock.Lock()
defer c.lock.Unlock()
tmp := c.i
result := tmp % c.m
c.i++
return result
}
type waitingHandler struct {
p2p.NoOpHandler
handler p2p.Handler
updatedRootChan chan struct{}
}
func (w *waitingHandler) Request(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *common.Error) {
<-w.updatedRootChan
return w.handler.Request(ctx, nodeID, deadline, requestBytes)
}