mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-05 10:32:19 +00:00
df0699a12b
This adds a simulator object with implements the SentryServer api but takes objects from a pre-existing snapshot file. If the snapshot is not available locally it will download and index the .seg file for the header range being asked for. It is created as follows: ```go sim, err := simulator.NewSentry(ctx, "mumbai", dataDir, 1, logger) ``` Where the arguments are: * ctx - a callable context where cancel will close the simulator torrent and file connections (it also has a Close method) * chain - the name of the chain to take the snapshots from * datadir - a directory potentially containing snapshot .seg files. If not files exist in this directory they will be downloaded * num peers - the number of peers the simulator should create * logger - the loger to log actions to It can be attached to a client as follows: ```go simClient := direct.NewSentryClientDirect(66, sim) ``` At the moment only very basic functionality is implemented: * get headers will return headers by range or hash (hash assumes a pre-downloaded .seg as it needs an index * the header replay semantics need to be confirmed * eth 65 and 66(+) messaging is supported * For details see: `simulator_test.go More advanced peer behavior (e.g. header rewriting) can be added Bodies/Transactions handling can be added
204 lines
4.4 KiB
Go
204 lines
4.4 KiB
Go
//go:build integration
|
|
|
|
package simulator_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/direct"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/sentry"
|
|
sentry_if "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry"
|
|
"github.com/ledgerwatch/erigon/eth/protocols/eth"
|
|
"github.com/ledgerwatch/erigon/p2p/sentry/simulator"
|
|
"github.com/ledgerwatch/erigon/rlp"
|
|
"github.com/ledgerwatch/log/v3"
|
|
)
|
|
|
|
func TestSimulatorStart(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
logger := log.New()
|
|
logger.SetHandler(log.StdoutHandler)
|
|
dataDir := t.TempDir()
|
|
|
|
sim, err := simulator.NewSentry(ctx, "mumbai", dataDir, 1, logger)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
simClient := direct.NewSentryClientDirect(66, sim)
|
|
|
|
peerCount, err := simClient.PeerCount(ctx, &sentry.PeerCountRequest{})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if peerCount.Count != 1 {
|
|
t.Fatal("Invalid response count: expected:", 1, "got:", peerCount.Count)
|
|
}
|
|
|
|
receiver, err := simClient.Messages(ctx, &sentry.MessagesRequest{
|
|
Ids: []sentry.MessageId{sentry.MessageId_BLOCK_HEADERS_66},
|
|
})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
getHeaders66 := ð.GetBlockHeadersPacket66{
|
|
RequestId: 1,
|
|
GetBlockHeadersPacket: ð.GetBlockHeadersPacket{
|
|
Origin: eth.HashOrNumber{Number: 10},
|
|
Amount: 10,
|
|
},
|
|
}
|
|
|
|
var data bytes.Buffer
|
|
|
|
err = rlp.Encode(&data, getHeaders66)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
peers, err := simClient.SendMessageToAll(ctx, &sentry.OutboundMessageData{
|
|
Id: sentry_if.MessageId_GET_BLOCK_HEADERS_66,
|
|
Data: data.Bytes(),
|
|
})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(peers.Peers) != int(peerCount.Count) {
|
|
t.Fatal("Unexpected peer count expected:", peerCount.Count, len(peers.Peers))
|
|
}
|
|
|
|
message, err := receiver.Recv()
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if message.Id != sentry_if.MessageId_BLOCK_HEADERS_66 {
|
|
t.Fatal("unexpected message id expected:", sentry_if.MessageId_BLOCK_HEADERS_66, "got:", message.Id)
|
|
}
|
|
|
|
var expectedPeer bool
|
|
|
|
for _, peer := range peers.Peers {
|
|
if message.PeerId.String() == peer.String() {
|
|
expectedPeer = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !expectedPeer {
|
|
t.Fatal("message received from unexpected peer:", message.PeerId)
|
|
}
|
|
|
|
packet := ð.BlockHeadersPacket66{}
|
|
|
|
if err := rlp.DecodeBytes(message.Data, packet); err != nil {
|
|
t.Fatal("failed to decode packet:", err)
|
|
}
|
|
|
|
if len(packet.BlockHeadersPacket) != 10 {
|
|
t.Fatal("unexpected header count: expected:", 10, "got:", len(packet.BlockHeadersPacket))
|
|
}
|
|
|
|
blockNum := uint64(10)
|
|
|
|
for _, header := range packet.BlockHeadersPacket {
|
|
if header.Number.Uint64() != blockNum {
|
|
t.Fatal("unexpected block number: expected:", blockNum, "got:", header.Number)
|
|
}
|
|
|
|
blockNum++
|
|
}
|
|
|
|
simClient65 := direct.NewSentryClientDirect(65, sim)
|
|
|
|
getHeaders65 := ð.GetBlockHeadersPacket{
|
|
Origin: eth.HashOrNumber{Number: 100},
|
|
Amount: 50,
|
|
}
|
|
|
|
data.Reset()
|
|
|
|
err = rlp.Encode(&data, getHeaders65)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
peers65, err := simClient65.SendMessageById(ctx, &sentry_if.SendMessageByIdRequest{
|
|
Data: &sentry.OutboundMessageData{
|
|
Id: sentry_if.MessageId_GET_BLOCK_HEADERS_65,
|
|
Data: data.Bytes(),
|
|
},
|
|
PeerId: peers.Peers[0],
|
|
})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(peers65.Peers) != 1 {
|
|
t.Fatal("message sent to unexpected number of peers:", len(peers65.Peers))
|
|
}
|
|
|
|
if peers65.Peers[0].String() != peers.Peers[0].String() {
|
|
t.Fatal("message sent to unexpected number of peers", peers65.Peers[0])
|
|
}
|
|
|
|
receiver65, err := simClient65.Messages(ctx, &sentry.MessagesRequest{
|
|
Ids: []sentry.MessageId{sentry.MessageId_BLOCK_HEADERS_65},
|
|
})
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
message, err = receiver65.Recv()
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if message.Id != sentry_if.MessageId_BLOCK_HEADERS_65 {
|
|
t.Fatal("unexpected message id expected:", sentry_if.MessageId_BLOCK_HEADERS_65, "got:", message.Id)
|
|
}
|
|
|
|
if message.PeerId.String() != peers.Peers[0].String() {
|
|
t.Fatal("message received from unexpected peer:", message.PeerId)
|
|
}
|
|
|
|
packet65 := eth.BlockHeadersPacket{}
|
|
|
|
if err := rlp.DecodeBytes(message.Data, &packet65); err != nil {
|
|
t.Fatal("failed to decode packet:", err)
|
|
}
|
|
|
|
if len(packet65) != 50 {
|
|
t.Fatal("unexpected header count: expected:", 50, "got:", len(packet.BlockHeadersPacket))
|
|
}
|
|
|
|
blockNum = uint64(100)
|
|
|
|
for _, header := range packet65 {
|
|
if header.Number.Uint64() != blockNum {
|
|
t.Fatal("unexpected block number: expected:", blockNum, "got:", header.Number)
|
|
}
|
|
|
|
blockNum++
|
|
}
|
|
}
|