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  }