github.com/ledgerwatch/erigon-lib@v1.0.0/txpool/pool_test.go (about)

     1  /*
     2     Copyright 2021 The 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  	"bytes"
    21  	"context"
    22  
    23  	// "crypto/rand"
    24  	"fmt"
    25  	"math"
    26  	"math/big"
    27  	"testing"
    28  
    29  	gokzg4844 "github.com/crate-crypto/go-kzg-4844"
    30  	"github.com/holiman/uint256"
    31  	"github.com/ledgerwatch/log/v3"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  
    35  	"github.com/ledgerwatch/erigon-lib/common"
    36  	"github.com/ledgerwatch/erigon-lib/common/fixedgas"
    37  	"github.com/ledgerwatch/erigon-lib/common/hexutility"
    38  	"github.com/ledgerwatch/erigon-lib/common/u256"
    39  	"github.com/ledgerwatch/erigon-lib/crypto/kzg"
    40  	"github.com/ledgerwatch/erigon-lib/gointerfaces"
    41  	"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
    42  	"github.com/ledgerwatch/erigon-lib/kv"
    43  	"github.com/ledgerwatch/erigon-lib/kv/kvcache"
    44  	"github.com/ledgerwatch/erigon-lib/kv/memdb"
    45  	"github.com/ledgerwatch/erigon-lib/txpool/txpoolcfg"
    46  	"github.com/ledgerwatch/erigon-lib/types"
    47  )
    48  
    49  func TestNonceFromAddress(t *testing.T) {
    50  	assert, require := assert.New(t), require.New(t)
    51  	ch := make(chan types.Announcements, 100)
    52  	db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
    53  
    54  	cfg := txpoolcfg.DefaultConfig
    55  	sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
    56  	pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, log.New())
    57  	assert.NoError(err)
    58  	require.True(pool != nil)
    59  	ctx := context.Background()
    60  	var stateVersionID uint64 = 0
    61  	pendingBaseFee := uint64(200000)
    62  	// start blocks from 0, set empty hash - then kvcache will also work on this
    63  	h1 := gointerfaces.ConvertHashToH256([32]byte{})
    64  	change := &remote.StateChangeBatch{
    65  		StateVersionId:      stateVersionID,
    66  		PendingBlockBaseFee: pendingBaseFee,
    67  		BlockGasLimit:       1000000,
    68  		ChangeBatch: []*remote.StateChange{
    69  			{BlockHeight: 0, BlockHash: h1},
    70  		},
    71  	}
    72  	var addr [20]byte
    73  	addr[0] = 1
    74  	v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether)))
    75  	types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v)
    76  	change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{
    77  		Action:  remote.Action_UPSERT,
    78  		Address: gointerfaces.ConvertAddressToH160(addr),
    79  		Data:    v,
    80  	})
    81  	tx, err := db.BeginRw(ctx)
    82  	require.NoError(err)
    83  	defer tx.Rollback()
    84  	err = pool.OnNewBlock(ctx, change, types.TxSlots{}, types.TxSlots{}, tx)
    85  	assert.NoError(err)
    86  
    87  	{
    88  		var txSlots types.TxSlots
    89  		txSlot1 := &types.TxSlot{
    90  			Tip:    *uint256.NewInt(300000),
    91  			FeeCap: *uint256.NewInt(300000),
    92  			Gas:    100000,
    93  			Nonce:  3,
    94  		}
    95  		txSlot1.IDHash[0] = 1
    96  		txSlots.Append(txSlot1, addr[:], true)
    97  
    98  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
    99  		assert.NoError(err)
   100  		for _, reason := range reasons {
   101  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   102  		}
   103  	}
   104  
   105  	{
   106  		txSlots := types.TxSlots{}
   107  		txSlot2 := &types.TxSlot{
   108  			Tip:    *uint256.NewInt(300000),
   109  			FeeCap: *uint256.NewInt(300000),
   110  			Gas:    100000,
   111  			Nonce:  4,
   112  		}
   113  		txSlot2.IDHash[0] = 2
   114  		txSlot3 := &types.TxSlot{
   115  			Tip:    *uint256.NewInt(300000),
   116  			FeeCap: *uint256.NewInt(300000),
   117  			Gas:    100000,
   118  			Nonce:  6,
   119  		}
   120  		txSlot3.IDHash[0] = 3
   121  		txSlots.Append(txSlot2, addr[:], true)
   122  		txSlots.Append(txSlot3, addr[:], true)
   123  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   124  		assert.NoError(err)
   125  		for _, reason := range reasons {
   126  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   127  		}
   128  		nonce, ok := pool.NonceFromAddress(addr)
   129  		assert.True(ok)
   130  		assert.Equal(uint64(6), nonce)
   131  	}
   132  	// test too expensive tx
   133  	{
   134  		var txSlots types.TxSlots
   135  		txSlot1 := &types.TxSlot{
   136  			Tip:    *uint256.NewInt(300000),
   137  			FeeCap: *uint256.NewInt(9 * common.Ether),
   138  			Gas:    100000,
   139  			Nonce:  3,
   140  		}
   141  		txSlot1.IDHash[0] = 4
   142  		txSlots.Append(txSlot1, addr[:], true)
   143  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   144  		assert.NoError(err)
   145  		for _, reason := range reasons {
   146  			assert.Equal(txpoolcfg.InsufficientFunds, reason, reason.String())
   147  		}
   148  	}
   149  
   150  	// test too low nonce
   151  	{
   152  		var txSlots types.TxSlots
   153  		txSlot1 := &types.TxSlot{
   154  			Tip:    *uint256.NewInt(300000),
   155  			FeeCap: *uint256.NewInt(300000),
   156  			Gas:    100000,
   157  			Nonce:  1,
   158  		}
   159  		txSlot1.IDHash[0] = 5
   160  		txSlots.Append(txSlot1, addr[:], true)
   161  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   162  		assert.NoError(err)
   163  		for _, reason := range reasons {
   164  			assert.Equal(txpoolcfg.NonceTooLow, reason, reason.String())
   165  		}
   166  	}
   167  }
   168  
   169  func TestReplaceWithHigherFee(t *testing.T) {
   170  	assert, require := assert.New(t), require.New(t)
   171  	ch := make(chan types.Announcements, 100)
   172  	db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
   173  
   174  	cfg := txpoolcfg.DefaultConfig
   175  	sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
   176  	pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, log.New())
   177  	assert.NoError(err)
   178  	require.True(pool != nil)
   179  	ctx := context.Background()
   180  	var stateVersionID uint64 = 0
   181  	pendingBaseFee := uint64(200000)
   182  	// start blocks from 0, set empty hash - then kvcache will also work on this
   183  	h1 := gointerfaces.ConvertHashToH256([32]byte{})
   184  	change := &remote.StateChangeBatch{
   185  		StateVersionId:      stateVersionID,
   186  		PendingBlockBaseFee: pendingBaseFee,
   187  		BlockGasLimit:       1000000,
   188  		ChangeBatch: []*remote.StateChange{
   189  			{BlockHeight: 0, BlockHash: h1},
   190  		},
   191  	}
   192  	var addr [20]byte
   193  	addr[0] = 1
   194  	v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether)))
   195  	types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v)
   196  	change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{
   197  		Action:  remote.Action_UPSERT,
   198  		Address: gointerfaces.ConvertAddressToH160(addr),
   199  		Data:    v,
   200  	})
   201  	tx, err := db.BeginRw(ctx)
   202  	require.NoError(err)
   203  	defer tx.Rollback()
   204  	err = pool.OnNewBlock(ctx, change, types.TxSlots{}, types.TxSlots{}, tx)
   205  	assert.NoError(err)
   206  
   207  	{
   208  		var txSlots types.TxSlots
   209  		txSlot := &types.TxSlot{
   210  			Tip:    *uint256.NewInt(300000),
   211  			FeeCap: *uint256.NewInt(300000),
   212  			Gas:    100000,
   213  			Nonce:  3,
   214  		}
   215  		txSlot.IDHash[0] = 1
   216  		txSlots.Append(txSlot, addr[:], true)
   217  
   218  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   219  		assert.NoError(err)
   220  		for _, reason := range reasons {
   221  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   222  		}
   223  	}
   224  	// Bumped only feeCap, transaction not accepted
   225  	{
   226  		txSlots := types.TxSlots{}
   227  		txSlot := &types.TxSlot{
   228  			Tip:    *uint256.NewInt(300000),
   229  			FeeCap: *uint256.NewInt(3000000),
   230  			Gas:    100000,
   231  			Nonce:  3,
   232  		}
   233  		txSlot.IDHash[0] = 2
   234  		txSlots.Append(txSlot, addr[:], true)
   235  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   236  		assert.NoError(err)
   237  		for _, reason := range reasons {
   238  			assert.Equal(txpoolcfg.NotReplaced, reason, reason.String())
   239  		}
   240  		nonce, ok := pool.NonceFromAddress(addr)
   241  		assert.True(ok)
   242  		assert.Equal(uint64(3), nonce)
   243  	}
   244  	// Bumped only tip, transaction not accepted
   245  	{
   246  		txSlots := types.TxSlots{}
   247  		txSlot := &types.TxSlot{
   248  			Tip:    *uint256.NewInt(3000000),
   249  			FeeCap: *uint256.NewInt(300000),
   250  			Gas:    100000,
   251  			Nonce:  3,
   252  		}
   253  		txSlot.IDHash[0] = 3
   254  		txSlots.Append(txSlot, addr[:], true)
   255  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   256  		assert.NoError(err)
   257  		for _, reason := range reasons {
   258  			assert.Equal(txpoolcfg.NotReplaced, reason, reason.String())
   259  		}
   260  		nonce, ok := pool.NonceFromAddress(addr)
   261  		assert.True(ok)
   262  		assert.Equal(uint64(3), nonce)
   263  	}
   264  	// Bumped both tip and feeCap by 10%, tx accepted
   265  	{
   266  		txSlots := types.TxSlots{}
   267  		txSlot := &types.TxSlot{
   268  			Tip:    *uint256.NewInt(330000),
   269  			FeeCap: *uint256.NewInt(330000),
   270  			Gas:    100000,
   271  			Nonce:  3,
   272  		}
   273  		txSlot.IDHash[0] = 4
   274  		txSlots.Append(txSlot, addr[:], true)
   275  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   276  		assert.NoError(err)
   277  		for _, reason := range reasons {
   278  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   279  		}
   280  		nonce, ok := pool.NonceFromAddress(addr)
   281  		assert.True(ok)
   282  		assert.Equal(uint64(3), nonce)
   283  	}
   284  }
   285  
   286  func TestReverseNonces(t *testing.T) {
   287  	assert, require := assert.New(t), require.New(t)
   288  	ch := make(chan types.Announcements, 100)
   289  	db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
   290  
   291  	cfg := txpoolcfg.DefaultConfig
   292  	sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
   293  	pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, log.New())
   294  	assert.NoError(err)
   295  	require.True(pool != nil)
   296  	ctx := context.Background()
   297  	var stateVersionID uint64 = 0
   298  	pendingBaseFee := uint64(1_000_000)
   299  	// start blocks from 0, set empty hash - then kvcache will also work on this
   300  	h1 := gointerfaces.ConvertHashToH256([32]byte{})
   301  	change := &remote.StateChangeBatch{
   302  		StateVersionId:      stateVersionID,
   303  		PendingBlockBaseFee: pendingBaseFee,
   304  		BlockGasLimit:       1000000,
   305  		ChangeBatch: []*remote.StateChange{
   306  			{BlockHeight: 0, BlockHash: h1},
   307  		},
   308  	}
   309  	var addr [20]byte
   310  	addr[0] = 1
   311  	v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether)))
   312  	types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v)
   313  	change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{
   314  		Action:  remote.Action_UPSERT,
   315  		Address: gointerfaces.ConvertAddressToH160(addr),
   316  		Data:    v,
   317  	})
   318  	tx, err := db.BeginRw(ctx)
   319  	require.NoError(err)
   320  	defer tx.Rollback()
   321  	err = pool.OnNewBlock(ctx, change, types.TxSlots{}, types.TxSlots{}, tx)
   322  	assert.NoError(err)
   323  	// 1. Send high fee transaction with nonce gap
   324  	{
   325  		var txSlots types.TxSlots
   326  		txSlot := &types.TxSlot{
   327  			Tip:    *uint256.NewInt(500_000),
   328  			FeeCap: *uint256.NewInt(3_000_000),
   329  			Gas:    100000,
   330  			Nonce:  3,
   331  		}
   332  		txSlot.IDHash[0] = 1
   333  		txSlots.Append(txSlot, addr[:], true)
   334  
   335  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   336  		assert.NoError(err)
   337  		for _, reason := range reasons {
   338  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   339  		}
   340  	}
   341  	fmt.Printf("AFTER TX 1\n")
   342  	select {
   343  	case annoucements := <-ch:
   344  		for i := 0; i < annoucements.Len(); i++ {
   345  			_, _, hash := annoucements.At(i)
   346  			fmt.Printf("propagated hash %x\n", hash)
   347  		}
   348  	default:
   349  
   350  	}
   351  	// 2. Send low fee (below base fee) transaction without nonce gap
   352  	{
   353  		var txSlots types.TxSlots
   354  		txSlot := &types.TxSlot{
   355  			Tip:    *uint256.NewInt(500_000),
   356  			FeeCap: *uint256.NewInt(500_000),
   357  			Gas:    100000,
   358  			Nonce:  2,
   359  		}
   360  		txSlot.IDHash[0] = 2
   361  		txSlots.Append(txSlot, addr[:], true)
   362  
   363  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   364  		assert.NoError(err)
   365  		for _, reason := range reasons {
   366  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   367  		}
   368  	}
   369  	fmt.Printf("AFTER TX 2\n")
   370  	select {
   371  	case annoucements := <-ch:
   372  		for i := 0; i < annoucements.Len(); i++ {
   373  			_, _, hash := annoucements.At(i)
   374  			fmt.Printf("propagated hash %x\n", hash)
   375  		}
   376  	default:
   377  
   378  	}
   379  
   380  	{
   381  		var txSlots types.TxSlots
   382  		txSlot := &types.TxSlot{
   383  			Tip:    *uint256.NewInt(600_000),
   384  			FeeCap: *uint256.NewInt(3_000_000),
   385  			Gas:    100000,
   386  			Nonce:  2,
   387  		}
   388  		txSlot.IDHash[0] = 3
   389  		txSlots.Append(txSlot, addr[:], true)
   390  
   391  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   392  		assert.NoError(err)
   393  		for _, reason := range reasons {
   394  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   395  		}
   396  	}
   397  	fmt.Printf("AFTER TX 3\n")
   398  	select {
   399  	case annoucements := <-ch:
   400  		for i := 0; i < annoucements.Len(); i++ {
   401  			_, _, hash := annoucements.At(i)
   402  			fmt.Printf("propagated hash %x\n", hash)
   403  		}
   404  	default:
   405  
   406  	}
   407  }
   408  
   409  // When local transaction is send to the pool, but it cannot replace existing transaction,
   410  // the existing transaction gets "poked" and is getting re-broadcasted
   411  // this is a workaround for cases when transactions are getting stuck for strange reasons
   412  // even though logs show they are broadcast
   413  func TestTxPoke(t *testing.T) {
   414  	assert, require := assert.New(t), require.New(t)
   415  	ch := make(chan types.Announcements, 100)
   416  	db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
   417  
   418  	cfg := txpoolcfg.DefaultConfig
   419  	sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
   420  	pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, log.New())
   421  	assert.NoError(err)
   422  	require.True(pool != nil)
   423  	ctx := context.Background()
   424  	var stateVersionID uint64 = 0
   425  	pendingBaseFee := uint64(200000)
   426  	// start blocks from 0, set empty hash - then kvcache will also work on this
   427  	h1 := gointerfaces.ConvertHashToH256([32]byte{})
   428  	change := &remote.StateChangeBatch{
   429  		StateVersionId:      stateVersionID,
   430  		PendingBlockBaseFee: pendingBaseFee,
   431  		BlockGasLimit:       1000000,
   432  		ChangeBatch: []*remote.StateChange{
   433  			{BlockHeight: 0, BlockHash: h1},
   434  		},
   435  	}
   436  	var addr [20]byte
   437  	addr[0] = 1
   438  	v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether)))
   439  	types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v)
   440  	change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{
   441  		Action:  remote.Action_UPSERT,
   442  		Address: gointerfaces.ConvertAddressToH160(addr),
   443  		Data:    v,
   444  	})
   445  	tx, err := db.BeginRw(ctx)
   446  	require.NoError(err)
   447  	defer tx.Rollback()
   448  	err = pool.OnNewBlock(ctx, change, types.TxSlots{}, types.TxSlots{}, tx)
   449  	assert.NoError(err)
   450  
   451  	var idHash types.Hashes
   452  	{
   453  		var txSlots types.TxSlots
   454  		txSlot := &types.TxSlot{
   455  			Tip:    *uint256.NewInt(300000),
   456  			FeeCap: *uint256.NewInt(300000),
   457  			Gas:    100000,
   458  			Nonce:  2,
   459  		}
   460  		txSlot.IDHash[0] = 1
   461  		idHash = append(idHash, txSlot.IDHash[:]...)
   462  		txSlots.Append(txSlot, addr[:], true)
   463  
   464  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   465  		assert.NoError(err)
   466  		for _, reason := range reasons {
   467  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   468  		}
   469  	}
   470  	var promoted types.Announcements
   471  	select {
   472  	case promoted = <-ch:
   473  		if !bytes.Equal(idHash, promoted.DedupHashes()) {
   474  			t.Errorf("expected promoted %x, got %x", idHash, promoted)
   475  		}
   476  	default:
   477  		t.Errorf("expected promotion")
   478  	}
   479  	// Send the same transaction, not accepted
   480  	{
   481  		txSlots := types.TxSlots{}
   482  		txSlot := &types.TxSlot{
   483  			Tip:    *uint256.NewInt(300000),
   484  			FeeCap: *uint256.NewInt(300000),
   485  			Gas:    100000,
   486  			Nonce:  2,
   487  		}
   488  		txSlot.IDHash[0] = 1
   489  		txSlots.Append(txSlot, addr[:], true)
   490  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   491  		assert.NoError(err)
   492  		for _, reason := range reasons {
   493  			assert.Equal(txpoolcfg.DuplicateHash, reason, reason.String())
   494  		}
   495  		nonce, ok := pool.NonceFromAddress(addr)
   496  		assert.True(ok)
   497  		assert.Equal(uint64(2), nonce)
   498  	}
   499  	// Even though transaction not replaced, it gets poked
   500  	select {
   501  	case promoted = <-ch:
   502  		if !bytes.Equal(idHash, promoted.Hashes()) {
   503  			t.Errorf("expected promoted %x, got %x", idHash, promoted)
   504  		}
   505  	default:
   506  		t.Errorf("expected promotion")
   507  	}
   508  	// Send different transaction, but only with tip bumped
   509  	{
   510  		txSlots := types.TxSlots{}
   511  		txSlot := &types.TxSlot{
   512  			Tip:    *uint256.NewInt(3000000),
   513  			FeeCap: *uint256.NewInt(300000),
   514  			Gas:    100000,
   515  			Nonce:  2,
   516  		}
   517  		txSlot.IDHash[0] = 2
   518  		txSlots.Append(txSlot, addr[:], true)
   519  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   520  		assert.NoError(err)
   521  		for _, reason := range reasons {
   522  			assert.Equal(txpoolcfg.NotReplaced, reason, reason.String())
   523  		}
   524  		nonce, ok := pool.NonceFromAddress(addr)
   525  		assert.True(ok)
   526  		assert.Equal(uint64(2), nonce)
   527  	}
   528  	// Even though transaction not replaced, it gets poked
   529  	select {
   530  	case promoted = <-ch:
   531  		if !bytes.Equal(idHash, promoted.Hashes()) {
   532  			t.Errorf("expected promoted %x, got %x", idHash, promoted)
   533  		}
   534  	default:
   535  		t.Errorf("expected promotion")
   536  	}
   537  
   538  	// Send the same transaction, but as remote
   539  	{
   540  		txSlots := types.TxSlots{}
   541  		txSlot := &types.TxSlot{
   542  			Tip:    *uint256.NewInt(300000),
   543  			FeeCap: *uint256.NewInt(300000),
   544  			Gas:    100000,
   545  			Nonce:  2,
   546  		}
   547  		txSlot.IDHash[0] = 1
   548  		txSlots.Append(txSlot, addr[:], true)
   549  		pool.AddRemoteTxs(ctx, txSlots)
   550  		nonce, ok := pool.NonceFromAddress(addr)
   551  		assert.True(ok)
   552  		assert.Equal(uint64(2), nonce)
   553  	}
   554  	// Remote transactions do not cause pokes
   555  	select {
   556  	case <-ch:
   557  		t.Errorf("remote transactions should not cause re-broadcast")
   558  	default:
   559  	}
   560  	// Send different transaction, but only with tip bumped, as a remote
   561  	{
   562  		txSlots := types.TxSlots{}
   563  		txSlot := &types.TxSlot{
   564  			Tip:    *uint256.NewInt(3000000),
   565  			FeeCap: *uint256.NewInt(3000000),
   566  			Gas:    100000,
   567  			Nonce:  2,
   568  		}
   569  		txSlot.IDHash[0] = 2
   570  		txSlots.Append(txSlot, addr[:], true)
   571  		pool.AddRemoteTxs(ctx, txSlots)
   572  		nonce, ok := pool.NonceFromAddress(addr)
   573  		assert.True(ok)
   574  		assert.Equal(uint64(2), nonce)
   575  	}
   576  	// Remote transactions do not cause pokes
   577  	select {
   578  	case <-ch:
   579  		t.Errorf("remote transactions should not cause re-broadcast")
   580  	default:
   581  	}
   582  }
   583  
   584  func TestShanghaiIntrinsicGas(t *testing.T) {
   585  	cases := map[string]struct {
   586  		expected       uint64
   587  		dataLen        uint64
   588  		dataNonZeroLen uint64
   589  		creation       bool
   590  		isShanghai     bool
   591  	}{
   592  		"simple no data": {
   593  			expected:       21000,
   594  			dataLen:        0,
   595  			dataNonZeroLen: 0,
   596  			creation:       false,
   597  			isShanghai:     false,
   598  		},
   599  		"simple with data": {
   600  			expected:       21512,
   601  			dataLen:        32,
   602  			dataNonZeroLen: 32,
   603  			creation:       false,
   604  			isShanghai:     false,
   605  		},
   606  		"creation with data no shanghai": {
   607  			expected:       53512,
   608  			dataLen:        32,
   609  			dataNonZeroLen: 32,
   610  			creation:       true,
   611  			isShanghai:     false,
   612  		},
   613  		"creation with single word and shanghai": {
   614  			expected:       53514, // additional gas for single word
   615  			dataLen:        32,
   616  			dataNonZeroLen: 32,
   617  			creation:       true,
   618  			isShanghai:     true,
   619  		},
   620  		"creation between word 1 and 2 and shanghai": {
   621  			expected:       53532, // additional gas for going into 2nd word although not filling it
   622  			dataLen:        33,
   623  			dataNonZeroLen: 33,
   624  			creation:       true,
   625  			isShanghai:     true,
   626  		},
   627  	}
   628  
   629  	for name, c := range cases {
   630  		t.Run(name, func(t *testing.T) {
   631  			gas, reason := txpoolcfg.CalcIntrinsicGas(c.dataLen, c.dataNonZeroLen, nil, c.creation, true, true, c.isShanghai)
   632  			if reason != txpoolcfg.Success {
   633  				t.Errorf("expected success but got reason %v", reason)
   634  			}
   635  			if gas != c.expected {
   636  				t.Errorf("expected %v but got %v", c.expected, gas)
   637  			}
   638  		})
   639  	}
   640  }
   641  
   642  func TestShanghaiValidateTx(t *testing.T) {
   643  	asrt := assert.New(t)
   644  	tests := map[string]struct {
   645  		expected   txpoolcfg.DiscardReason
   646  		dataLen    int
   647  		isShanghai bool
   648  	}{
   649  		"no shanghai": {
   650  			expected:   txpoolcfg.Success,
   651  			dataLen:    32,
   652  			isShanghai: false,
   653  		},
   654  		"shanghai within bounds": {
   655  			expected:   txpoolcfg.Success,
   656  			dataLen:    32,
   657  			isShanghai: true,
   658  		},
   659  		"shanghai exactly on bound": {
   660  			expected:   txpoolcfg.Success,
   661  			dataLen:    fixedgas.MaxInitCodeSize,
   662  			isShanghai: true,
   663  		},
   664  		"shanghai one over bound": {
   665  			expected:   txpoolcfg.InitCodeTooLarge,
   666  			dataLen:    fixedgas.MaxInitCodeSize + 1,
   667  			isShanghai: true,
   668  		},
   669  	}
   670  
   671  	logger := log.New()
   672  
   673  	for name, test := range tests {
   674  		t.Run(name, func(t *testing.T) {
   675  			ch := make(chan types.Announcements, 100)
   676  			_, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
   677  			cfg := txpoolcfg.DefaultConfig
   678  
   679  			var shanghaiTime *big.Int
   680  			if test.isShanghai {
   681  				shanghaiTime = big.NewInt(0)
   682  			}
   683  
   684  			cache := &kvcache.DummyCache{}
   685  			pool, err := New(ch, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* cancunTime */, logger)
   686  			asrt.NoError(err)
   687  			ctx := context.Background()
   688  			tx, err := coreDB.BeginRw(ctx)
   689  			defer tx.Rollback()
   690  			asrt.NoError(err)
   691  
   692  			sndr := sender{nonce: 0, balance: *uint256.NewInt(math.MaxUint64)}
   693  			sndrBytes := make([]byte, types.EncodeSenderLengthForStorage(sndr.nonce, sndr.balance))
   694  			types.EncodeSender(sndr.nonce, sndr.balance, sndrBytes)
   695  			err = tx.Put(kv.PlainState, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, sndrBytes)
   696  			asrt.NoError(err)
   697  
   698  			txn := &types.TxSlot{
   699  				DataLen:  test.dataLen,
   700  				FeeCap:   *uint256.NewInt(21000),
   701  				Gas:      500000,
   702  				SenderID: 0,
   703  				Creation: true,
   704  			}
   705  
   706  			txns := types.TxSlots{
   707  				Txs:     append([]*types.TxSlot{}, txn),
   708  				Senders: types.Addresses{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   709  			}
   710  			err = pool.senders.registerNewSenders(&txns, logger)
   711  			asrt.NoError(err)
   712  			view, err := cache.View(ctx, tx)
   713  			asrt.NoError(err)
   714  
   715  			reason := pool.validateTx(txn, false, view)
   716  
   717  			if reason != test.expected {
   718  				t.Errorf("expected %v, got %v", test.expected, reason)
   719  			}
   720  		})
   721  	}
   722  }
   723  
   724  // Blob gas price bump + other requirements to replace existing txns in the pool
   725  func TestBlobTxReplacement(t *testing.T) {
   726  	assert, require := assert.New(t), require.New(t)
   727  	ch := make(chan types.Announcements, 5)
   728  	db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t)
   729  	cfg := txpoolcfg.DefaultConfig
   730  	sendersCache := kvcache.New(kvcache.DefaultCoherentConfig)
   731  	pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, common.Big0, log.New())
   732  	assert.NoError(err)
   733  	require.True(pool != nil)
   734  	ctx := context.Background()
   735  	var stateVersionID uint64 = 0
   736  
   737  	h1 := gointerfaces.ConvertHashToH256([32]byte{})
   738  	change := &remote.StateChangeBatch{
   739  		StateVersionId:       stateVersionID,
   740  		PendingBlockBaseFee:  200_000,
   741  		BlockGasLimit:        1000000,
   742  		PendingBlobFeePerGas: 100_000,
   743  		ChangeBatch: []*remote.StateChange{
   744  			{BlockHeight: 0, BlockHash: h1},
   745  		},
   746  	}
   747  	var addr [20]byte
   748  	addr[0] = 1
   749  
   750  	// Add 1 eth to the user account, as a part of change
   751  	v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether)))
   752  	types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v)
   753  
   754  	change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{
   755  		Action:  remote.Action_UPSERT,
   756  		Address: gointerfaces.ConvertAddressToH160(addr),
   757  		Data:    v,
   758  	})
   759  	tx, err := db.BeginRw(ctx)
   760  	require.NoError(err)
   761  	defer tx.Rollback()
   762  	err = pool.OnNewBlock(ctx, change, types.TxSlots{}, types.TxSlots{}, tx)
   763  	assert.NoError(err)
   764  
   765  	tip, feeCap, blobFeeCap := uint256.NewInt(100_000), uint256.NewInt(200_000), uint256.NewInt(200_000)
   766  
   767  	//add a blob txn to the pool
   768  	{
   769  		txSlots := types.TxSlots{}
   770  		blobTxn := makeBlobTx()
   771  
   772  		blobTxn.IDHash[0] = 0x00
   773  		blobTxn.Nonce = 0x2
   774  		txSlots.Append(&blobTxn, addr[:], true)
   775  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   776  		assert.NoError(err)
   777  		t.Logf("Reasons %v", reasons)
   778  		for _, reason := range reasons {
   779  			assert.Equal(txpoolcfg.Success, reason, reason.String())
   780  		}
   781  	}
   782  
   783  	{
   784  		// try to replace it with 5% extra blob gas, 2x higher tx fee - should fail
   785  		txSlots := types.TxSlots{}
   786  		blobTxn := makeBlobTx()
   787  		blobTxn.Nonce = 0x2
   788  		blobTxn.FeeCap.Mul(uint256.NewInt(2), feeCap)
   789  		blobTxn.Tip.Mul(uint256.NewInt(2), tip)
   790  		//increase blobFeeCap by 10% - no good
   791  		blobTxn.BlobFeeCap.Add(blobFeeCap, uint256.NewInt(1).Div(blobFeeCap, uint256.NewInt(10)))
   792  		blobTxn.IDHash[0] = 0x01
   793  		txSlots.Append(&blobTxn, addr[:], true)
   794  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   795  		assert.NoError(err)
   796  		t.Logf("Reasons %v", reasons)
   797  		for _, reason := range reasons {
   798  			assert.Equal(txpoolcfg.ReplaceUnderpriced, reason, reason.String())
   799  		}
   800  	}
   801  
   802  	{
   803  		txSlots := types.TxSlots{}
   804  		//try to replace it with a regular txn - should fail
   805  		regularTx := types.TxSlot{
   806  			DataLen:    32,
   807  			FeeCap:     *uint256.NewInt(1).Mul(uint256.NewInt(10), feeCap), //10x the previous
   808  			Tip:        *uint256.NewInt(1).Mul(uint256.NewInt(10), tip),
   809  			BlobFeeCap: *uint256.NewInt(1).Mul(uint256.NewInt(10), blobFeeCap),
   810  			Gas:        500000,
   811  			SenderID:   0,
   812  			Creation:   true,
   813  			Nonce:      0x2,
   814  		}
   815  		regularTx.IDHash[0] = 0x02
   816  		txSlots.Append(&regularTx, addr[:], true)
   817  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   818  		assert.NoError(err)
   819  		t.Logf("Reasons %v", reasons)
   820  		for _, reason := range reasons {
   821  			assert.Equal(txpoolcfg.BlobTxReplace, reason, reason.String())
   822  		}
   823  	}
   824  
   825  	// Try to replace it with required price bump (configured in pool.cfg.BlobPriceBump for blob txns) to all transaction fields - should be successful only if all are bumped
   826  	{
   827  		blobTxn := makeBlobTx()
   828  		origTip := blobTxn.Tip
   829  		origFee := blobTxn.FeeCap
   830  		blobTxn.Nonce = 0x2
   831  		blobTxn.IDHash[0] = 0x03
   832  		txSlots := types.TxSlots{}
   833  		txSlots.Append(&blobTxn, addr[:], true)
   834  
   835  		// Get the config of the pool for BlobPriceBump and bump prices
   836  		requiredPriceBump := pool.cfg.BlobPriceBump
   837  
   838  		// Bump the tip only
   839  		blobTxn.Tip.MulDivOverflow(tip, uint256.NewInt(requiredPriceBump+100), uint256.NewInt(100))
   840  		reasons, err := pool.AddLocalTxs(ctx, txSlots, tx)
   841  		assert.NoError(err)
   842  		assert.Equal(txpoolcfg.ReplaceUnderpriced, reasons[0], reasons[0].String())
   843  
   844  		// Bump the fee + tip
   845  		blobTxn.FeeCap.MulDivOverflow(feeCap, uint256.NewInt(requiredPriceBump+100), uint256.NewInt(100))
   846  		reasons, err = pool.AddLocalTxs(ctx, txSlots, tx)
   847  		assert.NoError(err)
   848  		assert.Equal(txpoolcfg.ReplaceUnderpriced, reasons[0], reasons[0].String())
   849  
   850  		// Bump only Feecap
   851  		blobTxn.Tip = origTip
   852  		reasons, err = pool.AddLocalTxs(ctx, txSlots, tx)
   853  		assert.NoError(err)
   854  		assert.Equal(txpoolcfg.ReplaceUnderpriced, reasons[0], reasons[0].String())
   855  
   856  		// Bump fee cap + blobFee cap
   857  		blobTxn.BlobFeeCap.MulDivOverflow(blobFeeCap, uint256.NewInt(requiredPriceBump+100), uint256.NewInt(100))
   858  		reasons, err = pool.AddLocalTxs(ctx, txSlots, tx)
   859  		assert.NoError(err)
   860  		assert.Equal(txpoolcfg.NotReplaced, reasons[0], reasons[0].String())
   861  
   862  		// Bump only blobFee cap
   863  		blobTxn.FeeCap = origFee
   864  		reasons, err = pool.AddLocalTxs(ctx, txSlots, tx)
   865  		assert.NoError(err)
   866  		assert.Equal(txpoolcfg.NotReplaced, reasons[0], reasons[0].String())
   867  
   868  		// Bump all prices
   869  		blobTxn.Tip.MulDivOverflow(tip, uint256.NewInt(requiredPriceBump+100), uint256.NewInt(100))
   870  		blobTxn.FeeCap.MulDivOverflow(feeCap, uint256.NewInt(requiredPriceBump+100), uint256.NewInt(100))
   871  		reasons, err = pool.AddLocalTxs(ctx, txSlots, tx)
   872  		assert.NoError(err)
   873  		assert.Equal(txpoolcfg.Success, reasons[0], reasons[0].String())
   874  	}
   875  }
   876  
   877  // Todo, make the tx more realistic with good values
   878  func makeBlobTx() types.TxSlot {
   879  	// Some arbitrary hardcoded example
   880  	bodyRlpHex := "f9012705078502540be4008506fc23ac008357b58494811a752c8cd697e3cb27" +
   881  		"279c330ed1ada745a8d7808204f7f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697b" +
   882  		"aef842a00000000000000000000000000000000000000000000000000000000000000003a000" +
   883  		"00000000000000000000000000000000000000000000000000000000000007d694bb9bc244d7" +
   884  		"98123fde783fcc1c72d3bb8c189413c07bf842a0c6bdd1de713471bd6cfa62dd8b5a5b42969e" +
   885  		"d09e26212d3377f3f8426d8ec210a08aaeccaf3873d07cef005aca28c39f8a9f8bdb1ec8d79f" +
   886  		"fc25afc0a4fa2ab73601a036b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc09035" +
   887  		"90c16b02b0a05edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094"
   888  	bodyRlp := hexutility.MustDecodeHex(bodyRlpHex)
   889  
   890  	blobsRlpPrefix := hexutility.MustDecodeHex("fa040008")
   891  	blobRlpPrefix := hexutility.MustDecodeHex("ba020000")
   892  
   893  	var blob0, blob1 = gokzg4844.Blob{}, gokzg4844.Blob{}
   894  	copy(blob0[:], hexutility.MustDecodeHex(validBlob1))
   895  	copy(blob1[:], hexutility.MustDecodeHex(validBlob2))
   896  
   897  	var err error
   898  	proofsRlpPrefix := hexutility.MustDecodeHex("f862")
   899  	commitment0, _ := kzg.Ctx().BlobToKZGCommitment(blob0, 0)
   900  	commitment1, _ := kzg.Ctx().BlobToKZGCommitment(blob1, 0)
   901  
   902  	proof0, err := kzg.Ctx().ComputeBlobKZGProof(blob0, commitment0, 0)
   903  	if err != nil {
   904  		fmt.Println("error", err)
   905  	}
   906  	proof1, err := kzg.Ctx().ComputeBlobKZGProof(blob1, commitment1, 0)
   907  	if err != nil {
   908  		fmt.Println("error", err)
   909  	}
   910  
   911  	wrapperRlp := hexutility.MustDecodeHex("03fa0401fe")
   912  	wrapperRlp = append(wrapperRlp, bodyRlp...)
   913  	wrapperRlp = append(wrapperRlp, blobsRlpPrefix...)
   914  	wrapperRlp = append(wrapperRlp, blobRlpPrefix...)
   915  	wrapperRlp = append(wrapperRlp, blob0[:]...)
   916  	wrapperRlp = append(wrapperRlp, blobRlpPrefix...)
   917  	wrapperRlp = append(wrapperRlp, blob1[:]...)
   918  	wrapperRlp = append(wrapperRlp, proofsRlpPrefix...)
   919  	wrapperRlp = append(wrapperRlp, 0xb0)
   920  	wrapperRlp = append(wrapperRlp, commitment0[:]...)
   921  	wrapperRlp = append(wrapperRlp, 0xb0)
   922  	wrapperRlp = append(wrapperRlp, commitment1[:]...)
   923  	wrapperRlp = append(wrapperRlp, proofsRlpPrefix...)
   924  	wrapperRlp = append(wrapperRlp, 0xb0)
   925  	wrapperRlp = append(wrapperRlp, proof0[:]...)
   926  	wrapperRlp = append(wrapperRlp, 0xb0)
   927  	wrapperRlp = append(wrapperRlp, proof1[:]...)
   928  
   929  	tip, feeCap, blobFeeCap := uint256.NewInt(100_000), uint256.NewInt(200_000), uint256.NewInt(200_000)
   930  
   931  	blobTx := types.TxSlot{}
   932  	tctx := types.NewTxParseContext(*uint256.NewInt(5))
   933  	tctx.WithSender(false)
   934  	tctx.ParseTransaction(wrapperRlp, 0, &blobTx, nil, false, true, nil)
   935  	blobTx.BlobHashes = make([]common.Hash, 2)
   936  	blobTx.BlobHashes[0] = common.Hash(kzg.KZGToVersionedHash(commitment0))
   937  	blobTx.BlobHashes[1] = common.Hash(kzg.KZGToVersionedHash(commitment1))
   938  
   939  	blobTx.Tip = *tip
   940  	blobTx.FeeCap = *feeCap
   941  	blobTx.BlobFeeCap = *blobFeeCap
   942  	return blobTx
   943  }