github.com/ledgerwatch/erigon-lib@v1.0.0/txpool/fetch_test.go (about) 1 /* 2 Copyright 2021 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package txpool 18 19 import ( 20 "context" 21 "encoding/hex" 22 "fmt" 23 "io" 24 "sync" 25 "testing" 26 27 "github.com/ledgerwatch/erigon-lib/common/u256" 28 "github.com/ledgerwatch/erigon-lib/direct" 29 "github.com/ledgerwatch/erigon-lib/gointerfaces" 30 "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" 31 "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" 32 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" 33 "github.com/ledgerwatch/erigon-lib/kv/memdb" 34 types3 "github.com/ledgerwatch/erigon-lib/types" 35 "github.com/ledgerwatch/log/v3" 36 "github.com/stretchr/testify/assert" 37 "github.com/stretchr/testify/require" 38 "google.golang.org/grpc" 39 ) 40 41 func TestFetch(t *testing.T) { 42 ctx, cancel := context.WithCancel(context.Background()) 43 defer cancel() 44 45 m := NewMockSentry(ctx) 46 sentryClient := direct.NewSentryClientDirect(direct.ETH66, m) 47 pool := &PoolMock{} 48 49 fetch := NewFetch(ctx, []direct.SentryClient{sentryClient}, pool, &remote.KVClientMock{}, nil, nil, *u256.N1, log.New()) 50 var wg sync.WaitGroup 51 fetch.SetWaitGroup(&wg) 52 m.StreamWg.Add(2) 53 fetch.ConnectSentries() 54 m.StreamWg.Wait() 55 // Send one transaction id 56 wg.Add(1) 57 errs := m.Send(&sentry.InboundMessage{ 58 Id: sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_66, 59 Data: decodeHex("e1a0595e27a835cd79729ff1eeacec3120eeb6ed1464a04ec727aaca734ead961328"), 60 PeerId: peerID, 61 }) 62 for i, err := range errs { 63 if err != nil { 64 t.Errorf("sending new pool tx hashes 66 (%d): %v", i, err) 65 } 66 } 67 wg.Wait() 68 69 } 70 71 func TestSendTxPropagate(t *testing.T) { 72 ctx, cancelFn := context.WithCancel(context.Background()) 73 defer cancelFn() 74 t.Run("few remote byHash", func(t *testing.T) { 75 m := NewMockSentry(ctx) 76 send := NewSend(ctx, []direct.SentryClient{direct.NewSentryClientDirect(direct.ETH68, m)}, nil, log.New()) 77 send.BroadcastPooledTxs(testRlps(2)) 78 send.AnnouncePooledTxs([]byte{0, 1}, []uint32{10, 15}, toHashes(1, 42)) 79 80 calls1 := m.SendMessageToRandomPeersCalls() 81 require.Equal(t, 1, len(calls1)) 82 calls2 := m.SendMessageToAllCalls() 83 require.Equal(t, 1, len(calls2)) 84 first := calls1[0].SendMessageToRandomPeersRequest.Data 85 assert.Equal(t, sentry.MessageId_TRANSACTIONS_66, first.Id) 86 assert.Equal(t, 3, len(first.Data)) 87 second := calls2[0].OutboundMessageData 88 assert.Equal(t, sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_68, second.Id) 89 assert.Equal(t, 76, len(second.Data)) 90 }) 91 t.Run("much remote byHash", func(t *testing.T) { 92 m := NewMockSentry(ctx) 93 send := NewSend(ctx, []direct.SentryClient{direct.NewSentryClientDirect(direct.ETH68, m)}, nil, log.New()) 94 list := make(types3.Hashes, p2pTxPacketLimit*3) 95 for i := 0; i < len(list); i += 32 { 96 b := []byte(fmt.Sprintf("%x", i)) 97 copy(list[i:i+32], b) 98 } 99 send.BroadcastPooledTxs(testRlps(len(list) / 32)) 100 send.AnnouncePooledTxs([]byte{0, 1, 2}, []uint32{10, 12, 14}, list) 101 calls1 := m.SendMessageToRandomPeersCalls() 102 require.Equal(t, 1, len(calls1)) 103 calls2 := m.SendMessageToAllCalls() 104 require.Equal(t, 1, len(calls2)) 105 call1 := calls1[0].SendMessageToRandomPeersRequest.Data 106 require.Equal(t, sentry.MessageId_TRANSACTIONS_66, call1.Id) 107 require.True(t, len(call1.Data) > 0) 108 for i := 0; i < 1; i++ { 109 call2 := calls2[i].OutboundMessageData 110 require.Equal(t, sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_68, call2.Id) 111 require.True(t, len(call2.Data) > 0) 112 } 113 }) 114 t.Run("few local byHash", func(t *testing.T) { 115 m := NewMockSentry(ctx) 116 m.SendMessageToAllFunc = func(contextMoqParam context.Context, outboundMessageData *sentry.OutboundMessageData) (*sentry.SentPeers, error) { 117 return &sentry.SentPeers{Peers: make([]*types.H512, 5)}, nil 118 } 119 send := NewSend(ctx, []direct.SentryClient{direct.NewSentryClientDirect(direct.ETH68, m)}, nil, log.New()) 120 send.BroadcastPooledTxs(testRlps(2)) 121 send.AnnouncePooledTxs([]byte{0, 1}, []uint32{10, 15}, toHashes(1, 42)) 122 123 calls := m.SendMessageToAllCalls() 124 require.Equal(t, 1, len(calls)) 125 first := calls[0].OutboundMessageData 126 assert.Equal(t, sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_68, first.Id) 127 assert.Equal(t, 76, len(first.Data)) 128 }) 129 t.Run("sync with new peer", func(t *testing.T) { 130 m := NewMockSentry(ctx) 131 132 m.SendMessageToAllFunc = func(contextMoqParam context.Context, outboundMessageData *sentry.OutboundMessageData) (*sentry.SentPeers, error) { 133 return &sentry.SentPeers{Peers: make([]*types.H512, 5)}, nil 134 } 135 send := NewSend(ctx, []direct.SentryClient{direct.NewSentryClientDirect(direct.ETH68, m)}, nil, log.New()) 136 expectPeers := toPeerIDs(1, 2, 42) 137 send.PropagatePooledTxsToPeersList(expectPeers, []byte{0, 1}, []uint32{10, 15}, toHashes(1, 42)) 138 139 calls := m.SendMessageByIdCalls() 140 require.Equal(t, 3, len(calls)) 141 for i, call := range calls { 142 req := call.SendMessageByIdRequest 143 assert.Equal(t, expectPeers[i], types3.PeerID(req.PeerId)) 144 assert.Equal(t, sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_68, req.Data.Id) 145 assert.True(t, len(req.Data.Data) > 0) 146 } 147 }) 148 } 149 150 func decodeHex(in string) []byte { 151 payload, err := hex.DecodeString(in) 152 if err != nil { 153 panic(err) 154 } 155 return payload 156 } 157 func TestOnNewBlock(t *testing.T) { 158 ctx, cancel := context.WithCancel(context.Background()) 159 defer cancel() 160 coreDB, db := memdb.NewTestDB(t), memdb.NewTestDB(t) 161 162 i := 0 163 stream := &remote.KV_StateChangesClientMock{ 164 RecvFunc: func() (*remote.StateChangeBatch, error) { 165 if i > 0 { 166 return nil, io.EOF 167 } 168 i++ 169 return &remote.StateChangeBatch{ 170 StateVersionId: 1, 171 ChangeBatch: []*remote.StateChange{ 172 {Txs: [][]byte{decodeHex(types3.TxParseMainnetTests[0].PayloadStr), decodeHex(types3.TxParseMainnetTests[1].PayloadStr), decodeHex(types3.TxParseMainnetTests[2].PayloadStr)}, BlockHeight: 1, BlockHash: gointerfaces.ConvertHashToH256([32]byte{})}, 173 }, 174 }, nil 175 }, 176 } 177 stateChanges := &remote.KVClientMock{ 178 StateChangesFunc: func(ctx context.Context, in *remote.StateChangeRequest, opts ...grpc.CallOption) (remote.KV_StateChangesClient, error) { 179 return stream, nil 180 }, 181 } 182 pool := &PoolMock{} 183 fetch := NewFetch(ctx, nil, pool, stateChanges, coreDB, db, *u256.N1, log.New()) 184 err := fetch.handleStateChanges(ctx, stateChanges) 185 assert.ErrorIs(t, io.EOF, err) 186 assert.Equal(t, 1, len(pool.OnNewBlockCalls())) 187 assert.Equal(t, 3, len(pool.OnNewBlockCalls()[0].MinedTxs.Txs)) 188 }