github.com/ethereum/go-ethereum@v1.16.1/core/txpool/blobpool/blobpool_test.go (about)

     1  // Copyright 2023 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package blobpool
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"crypto/sha256"
    23  	"errors"
    24  	"fmt"
    25  	"math"
    26  	"math/big"
    27  	"os"
    28  	"path/filepath"
    29  	"sync"
    30  	"testing"
    31  
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
    34  	"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
    35  	"github.com/ethereum/go-ethereum/core"
    36  	"github.com/ethereum/go-ethereum/core/state"
    37  	"github.com/ethereum/go-ethereum/core/tracing"
    38  	"github.com/ethereum/go-ethereum/core/txpool"
    39  	"github.com/ethereum/go-ethereum/core/types"
    40  	"github.com/ethereum/go-ethereum/crypto"
    41  	"github.com/ethereum/go-ethereum/crypto/kzg4844"
    42  	"github.com/ethereum/go-ethereum/params"
    43  	"github.com/ethereum/go-ethereum/rlp"
    44  	"github.com/holiman/billy"
    45  	"github.com/holiman/uint256"
    46  )
    47  
    48  var (
    49  	testBlobs       []*kzg4844.Blob
    50  	testBlobCommits []kzg4844.Commitment
    51  	testBlobProofs  []kzg4844.Proof
    52  	testBlobVHashes [][32]byte
    53  )
    54  
    55  const testMaxBlobsPerBlock = 6
    56  
    57  func init() {
    58  	for i := 0; i < 24; i++ {
    59  		testBlob := &kzg4844.Blob{byte(i)}
    60  		testBlobs = append(testBlobs, testBlob)
    61  
    62  		testBlobCommit, _ := kzg4844.BlobToCommitment(testBlob)
    63  		testBlobCommits = append(testBlobCommits, testBlobCommit)
    64  
    65  		testBlobProof, _ := kzg4844.ComputeBlobProof(testBlob, testBlobCommit)
    66  		testBlobProofs = append(testBlobProofs, testBlobProof)
    67  
    68  		testBlobVHash := kzg4844.CalcBlobHashV1(sha256.New(), &testBlobCommit)
    69  		testBlobVHashes = append(testBlobVHashes, testBlobVHash)
    70  	}
    71  }
    72  
    73  // testBlockChain is a mock of the live chain for testing the pool.
    74  type testBlockChain struct {
    75  	config  *params.ChainConfig
    76  	basefee *uint256.Int
    77  	blobfee *uint256.Int
    78  	statedb *state.StateDB
    79  
    80  	blocks map[uint64]*types.Block
    81  }
    82  
    83  func (bc *testBlockChain) Config() *params.ChainConfig {
    84  	return bc.config
    85  }
    86  
    87  func (bc *testBlockChain) CurrentBlock() *types.Header {
    88  	// Yolo, life is too short to invert misc.CalcBaseFee and misc.CalcBlobFee,
    89  	// just binary search it them.
    90  
    91  	// The base fee at 5714 ETH translates into the 21000 base gas higher than
    92  	// mainnet ether existence, use that as a cap for the tests.
    93  	var (
    94  		blockNumber = new(big.Int).Add(bc.config.LondonBlock, big.NewInt(1))
    95  		blockTime   = *bc.config.CancunTime + 1
    96  		gasLimit    = uint64(30_000_000)
    97  	)
    98  	lo := new(big.Int)
    99  	hi := new(big.Int).Mul(big.NewInt(5714), new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
   100  
   101  	for new(big.Int).Add(lo, big.NewInt(1)).Cmp(hi) != 0 {
   102  		mid := new(big.Int).Add(lo, hi)
   103  		mid.Div(mid, big.NewInt(2))
   104  
   105  		if eip1559.CalcBaseFee(bc.config, &types.Header{
   106  			Number:   blockNumber,
   107  			GasLimit: gasLimit,
   108  			GasUsed:  0,
   109  			BaseFee:  mid,
   110  		}).Cmp(bc.basefee.ToBig()) > 0 {
   111  			hi = mid
   112  		} else {
   113  			lo = mid
   114  		}
   115  	}
   116  	baseFee := lo
   117  
   118  	// The excess blob gas at 2^27 translates into a blob fee higher than mainnet
   119  	// ether existence, use that as a cap for the tests.
   120  	lo = new(big.Int)
   121  	hi = new(big.Int).Exp(big.NewInt(2), big.NewInt(27), nil)
   122  
   123  	for new(big.Int).Add(lo, big.NewInt(1)).Cmp(hi) != 0 {
   124  		mid := new(big.Int).Add(lo, hi)
   125  		mid.Div(mid, big.NewInt(2))
   126  
   127  		tmp := mid.Uint64()
   128  		if eip4844.CalcBlobFee(bc.Config(), &types.Header{
   129  			Number:        blockNumber,
   130  			Time:          blockTime,
   131  			ExcessBlobGas: &tmp,
   132  		}).Cmp(bc.blobfee.ToBig()) > 0 {
   133  			hi = mid
   134  		} else {
   135  			lo = mid
   136  		}
   137  	}
   138  	excessBlobGas := lo.Uint64()
   139  
   140  	return &types.Header{
   141  		Number:        blockNumber,
   142  		Time:          blockTime,
   143  		GasLimit:      gasLimit,
   144  		BaseFee:       baseFee,
   145  		ExcessBlobGas: &excessBlobGas,
   146  		Difficulty:    common.Big0,
   147  	}
   148  }
   149  
   150  func (bc *testBlockChain) CurrentFinalBlock() *types.Header {
   151  	return &types.Header{
   152  		Number: big.NewInt(0),
   153  	}
   154  }
   155  
   156  func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
   157  	// This is very yolo for the tests. If the number is the origin block we use
   158  	// to init the pool, return an empty block with the correct starting header.
   159  	//
   160  	// If it is something else, return some baked in mock data.
   161  	if number == bc.config.LondonBlock.Uint64()+1 {
   162  		return types.NewBlockWithHeader(bc.CurrentBlock())
   163  	}
   164  	return bc.blocks[number]
   165  }
   166  
   167  func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
   168  	return bc.statedb, nil
   169  }
   170  
   171  // reserver is a utility struct to sanity check that accounts are
   172  // properly reserved by the blobpool (no duplicate reserves or unreserves).
   173  type reserver struct {
   174  	accounts map[common.Address]struct{}
   175  	lock     sync.RWMutex
   176  }
   177  
   178  func newReserver() txpool.Reserver {
   179  	return &reserver{accounts: make(map[common.Address]struct{})}
   180  }
   181  
   182  func (r *reserver) Hold(addr common.Address) error {
   183  	r.lock.Lock()
   184  	defer r.lock.Unlock()
   185  	if _, exists := r.accounts[addr]; exists {
   186  		panic("already reserved")
   187  	}
   188  	r.accounts[addr] = struct{}{}
   189  	return nil
   190  }
   191  
   192  func (r *reserver) Release(addr common.Address) error {
   193  	r.lock.Lock()
   194  	defer r.lock.Unlock()
   195  	if _, exists := r.accounts[addr]; !exists {
   196  		panic("not reserved")
   197  	}
   198  	delete(r.accounts, addr)
   199  	return nil
   200  }
   201  
   202  func (r *reserver) Has(address common.Address) bool {
   203  	r.lock.RLock()
   204  	defer r.lock.RUnlock()
   205  	_, exists := r.accounts[address]
   206  	return exists
   207  }
   208  
   209  // makeTx is a utility method to construct a random blob transaction and sign it
   210  // with a valid key, only setting the interesting fields from the perspective of
   211  // the blob pool.
   212  func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, key *ecdsa.PrivateKey) *types.Transaction {
   213  	blobtx := makeUnsignedTx(nonce, gasTipCap, gasFeeCap, blobFeeCap)
   214  	return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
   215  }
   216  
   217  // makeMultiBlobTx is a utility method to construct a ramdom blob tx with
   218  // certain number of blobs in its sidecar.
   219  func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction {
   220  	var (
   221  		blobs       []kzg4844.Blob
   222  		blobHashes  []common.Hash
   223  		commitments []kzg4844.Commitment
   224  		proofs      []kzg4844.Proof
   225  	)
   226  	for i := 0; i < blobCount; i++ {
   227  		blobs = append(blobs, *testBlobs[i])
   228  		commitments = append(commitments, testBlobCommits[i])
   229  		proofs = append(proofs, testBlobProofs[i])
   230  		blobHashes = append(blobHashes, testBlobVHashes[i])
   231  	}
   232  	blobtx := &types.BlobTx{
   233  		ChainID:    uint256.MustFromBig(params.MainnetChainConfig.ChainID),
   234  		Nonce:      nonce,
   235  		GasTipCap:  uint256.NewInt(gasTipCap),
   236  		GasFeeCap:  uint256.NewInt(gasFeeCap),
   237  		Gas:        21000,
   238  		BlobFeeCap: uint256.NewInt(blobFeeCap),
   239  		BlobHashes: blobHashes,
   240  		Value:      uint256.NewInt(100),
   241  		Sidecar: &types.BlobTxSidecar{
   242  			Blobs:       blobs,
   243  			Commitments: commitments,
   244  			Proofs:      proofs,
   245  		},
   246  	}
   247  	return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
   248  }
   249  
   250  // makeUnsignedTx is a utility method to construct a random blob transaction
   251  // without signing it.
   252  func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
   253  	return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rnd.Intn(len(testBlobs)))
   254  }
   255  
   256  // makeUnsignedTx is a utility method to construct a random blob transaction
   257  // without signing it.
   258  func makeUnsignedTxWithTestBlob(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobIdx int) *types.BlobTx {
   259  	return &types.BlobTx{
   260  		ChainID:    uint256.MustFromBig(params.MainnetChainConfig.ChainID),
   261  		Nonce:      nonce,
   262  		GasTipCap:  uint256.NewInt(gasTipCap),
   263  		GasFeeCap:  uint256.NewInt(gasFeeCap),
   264  		Gas:        21000,
   265  		BlobFeeCap: uint256.NewInt(blobFeeCap),
   266  		BlobHashes: []common.Hash{testBlobVHashes[blobIdx]},
   267  		Value:      uint256.NewInt(100),
   268  		Sidecar: &types.BlobTxSidecar{
   269  			Blobs:       []kzg4844.Blob{*testBlobs[blobIdx]},
   270  			Commitments: []kzg4844.Commitment{testBlobCommits[blobIdx]},
   271  			Proofs:      []kzg4844.Proof{testBlobProofs[blobIdx]},
   272  		},
   273  	}
   274  }
   275  
   276  // verifyPoolInternals iterates over all the transactions in the pool and checks
   277  // that sort orders, calculated fields, cumulated fields are correct.
   278  func verifyPoolInternals(t *testing.T, pool *BlobPool) {
   279  	// Mark this method as a helper to remove from stack traces
   280  	t.Helper()
   281  
   282  	// Verify that all items in the index are present in the tx lookup and nothing more
   283  	seen := make(map[common.Hash]struct{})
   284  	for addr, txs := range pool.index {
   285  		for _, tx := range txs {
   286  			if _, ok := seen[tx.hash]; ok {
   287  				t.Errorf("duplicate hash #%x in transaction index: address %s, nonce %d", tx.hash, addr, tx.nonce)
   288  			}
   289  			seen[tx.hash] = struct{}{}
   290  		}
   291  	}
   292  	for hash, id := range pool.lookup.txIndex {
   293  		if _, ok := seen[hash]; !ok {
   294  			t.Errorf("tx lookup entry missing from transaction index: hash #%x, id %d", hash, id)
   295  		}
   296  		delete(seen, hash)
   297  	}
   298  	for hash := range seen {
   299  		t.Errorf("indexed transaction hash #%x missing from tx lookup table", hash)
   300  	}
   301  	// Verify that all blobs in the index are present in the blob lookup and nothing more
   302  	blobs := make(map[common.Hash]map[common.Hash]struct{})
   303  	for _, txs := range pool.index {
   304  		for _, tx := range txs {
   305  			for _, vhash := range tx.vhashes {
   306  				if blobs[vhash] == nil {
   307  					blobs[vhash] = make(map[common.Hash]struct{})
   308  				}
   309  				blobs[vhash][tx.hash] = struct{}{}
   310  			}
   311  		}
   312  	}
   313  	for vhash, txs := range pool.lookup.blobIndex {
   314  		for txhash := range txs {
   315  			if _, ok := blobs[vhash][txhash]; !ok {
   316  				t.Errorf("blob lookup entry missing from transaction index: blob hash #%x, tx hash #%x", vhash, txhash)
   317  			}
   318  			delete(blobs[vhash], txhash)
   319  			if len(blobs[vhash]) == 0 {
   320  				delete(blobs, vhash)
   321  			}
   322  		}
   323  	}
   324  	for vhash := range blobs {
   325  		t.Errorf("indexed transaction blob hash #%x missing from blob lookup table", vhash)
   326  	}
   327  	// Verify that transactions are sorted per account and contain no nonce gaps,
   328  	// and that the first nonce is the next expected one based on the state.
   329  	for addr, txs := range pool.index {
   330  		for i := 1; i < len(txs); i++ {
   331  			if txs[i].nonce != txs[i-1].nonce+1 {
   332  				t.Errorf("addr %v, tx %d nonce mismatch: have %d, want %d", addr, i, txs[i].nonce, txs[i-1].nonce+1)
   333  			}
   334  		}
   335  		if txs[0].nonce != pool.state.GetNonce(addr) {
   336  			t.Errorf("addr %v, first tx nonce mismatch: have %d, want %d", addr, txs[0].nonce, pool.state.GetNonce(addr))
   337  		}
   338  	}
   339  	// Verify that calculated evacuation thresholds are correct
   340  	for addr, txs := range pool.index {
   341  		if !txs[0].evictionExecTip.Eq(txs[0].execTipCap) {
   342  			t.Errorf("addr %v, tx %d eviction execution tip mismatch: have %d, want %d", addr, 0, txs[0].evictionExecTip, txs[0].execTipCap)
   343  		}
   344  		if math.Abs(txs[0].evictionExecFeeJumps-txs[0].basefeeJumps) > 0.001 {
   345  			t.Errorf("addr %v, tx %d eviction execution fee jumps mismatch: have %f, want %f", addr, 0, txs[0].evictionExecFeeJumps, txs[0].basefeeJumps)
   346  		}
   347  		if math.Abs(txs[0].evictionBlobFeeJumps-txs[0].blobfeeJumps) > 0.001 {
   348  			t.Errorf("addr %v, tx %d eviction blob fee jumps mismatch: have %f, want %f", addr, 0, txs[0].evictionBlobFeeJumps, txs[0].blobfeeJumps)
   349  		}
   350  		for i := 1; i < len(txs); i++ {
   351  			wantExecTip := txs[i-1].evictionExecTip
   352  			if wantExecTip.Gt(txs[i].execTipCap) {
   353  				wantExecTip = txs[i].execTipCap
   354  			}
   355  			if !txs[i].evictionExecTip.Eq(wantExecTip) {
   356  				t.Errorf("addr %v, tx %d eviction execution tip mismatch: have %d, want %d", addr, i, txs[i].evictionExecTip, wantExecTip)
   357  			}
   358  
   359  			wantExecFeeJumps := txs[i-1].evictionExecFeeJumps
   360  			if wantExecFeeJumps > txs[i].basefeeJumps {
   361  				wantExecFeeJumps = txs[i].basefeeJumps
   362  			}
   363  			if math.Abs(txs[i].evictionExecFeeJumps-wantExecFeeJumps) > 0.001 {
   364  				t.Errorf("addr %v, tx %d eviction execution fee jumps mismatch: have %f, want %f", addr, i, txs[i].evictionExecFeeJumps, wantExecFeeJumps)
   365  			}
   366  
   367  			wantBlobFeeJumps := txs[i-1].evictionBlobFeeJumps
   368  			if wantBlobFeeJumps > txs[i].blobfeeJumps {
   369  				wantBlobFeeJumps = txs[i].blobfeeJumps
   370  			}
   371  			if math.Abs(txs[i].evictionBlobFeeJumps-wantBlobFeeJumps) > 0.001 {
   372  				t.Errorf("addr %v, tx %d eviction blob fee jumps mismatch: have %f, want %f", addr, i, txs[i].evictionBlobFeeJumps, wantBlobFeeJumps)
   373  			}
   374  		}
   375  	}
   376  	// Verify that account balance accumulations are correct
   377  	for addr, txs := range pool.index {
   378  		spent := new(uint256.Int)
   379  		for _, tx := range txs {
   380  			spent.Add(spent, tx.costCap)
   381  		}
   382  		if !pool.spent[addr].Eq(spent) {
   383  			t.Errorf("addr %v expenditure mismatch: have %d, want %d", addr, pool.spent[addr], spent)
   384  		}
   385  	}
   386  	// Verify that pool storage size is correct
   387  	var stored uint64
   388  	for _, txs := range pool.index {
   389  		for _, tx := range txs {
   390  			stored += uint64(tx.storageSize)
   391  		}
   392  	}
   393  	if pool.stored != stored {
   394  		t.Errorf("pool storage mismatch: have %d, want %d", pool.stored, stored)
   395  	}
   396  	// Verify the price heap internals
   397  	verifyHeapInternals(t, pool.evict)
   398  
   399  	// Verify that all the blobs can be retrieved
   400  	verifyBlobRetrievals(t, pool)
   401  }
   402  
   403  // verifyBlobRetrievals attempts to retrieve all testing blobs and checks that
   404  // whatever is in the pool, it can be retrieved correctly.
   405  func verifyBlobRetrievals(t *testing.T, pool *BlobPool) {
   406  	// Collect all the blobs tracked by the pool
   407  	known := make(map[common.Hash]struct{})
   408  	for _, txs := range pool.index {
   409  		for _, tx := range txs {
   410  			for _, vhash := range tx.vhashes {
   411  				known[vhash] = struct{}{}
   412  			}
   413  		}
   414  	}
   415  	// Attempt to retrieve all test blobs
   416  	hashes := make([]common.Hash, len(testBlobVHashes))
   417  	for i := range testBlobVHashes {
   418  		copy(hashes[i][:], testBlobVHashes[i][:])
   419  	}
   420  	sidecars := pool.GetBlobs(hashes)
   421  	var blobs []*kzg4844.Blob
   422  	var proofs []*kzg4844.Proof
   423  	for idx, sidecar := range sidecars {
   424  		if sidecar == nil {
   425  			blobs = append(blobs, nil)
   426  			proofs = append(proofs, nil)
   427  			continue
   428  		}
   429  		blobHashes := sidecar.BlobHashes()
   430  		for i, hash := range blobHashes {
   431  			if hash == hashes[idx] {
   432  				blobs = append(blobs, &sidecar.Blobs[i])
   433  				proofs = append(proofs, &sidecar.Proofs[i])
   434  			}
   435  		}
   436  	}
   437  	// Cross validate what we received vs what we wanted
   438  	if len(blobs) != len(hashes) || len(proofs) != len(hashes) {
   439  		t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want %d", len(blobs), len(proofs), len(hashes))
   440  		return
   441  	}
   442  	for i, hash := range hashes {
   443  		// If an item is missing, but shouldn't, error
   444  		if blobs[i] == nil || proofs[i] == nil {
   445  			if _, ok := known[hash]; ok {
   446  				t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash)
   447  			}
   448  			continue
   449  		}
   450  		// Item retrieved, make sure it matches the expectation
   451  		if *blobs[i] != *testBlobs[i] || *proofs[i] != testBlobProofs[i] {
   452  			t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash)
   453  			continue
   454  		}
   455  		delete(known, hash)
   456  	}
   457  	for hash := range known {
   458  		t.Errorf("indexed blob #%x missing from retrieval", hash)
   459  	}
   460  }
   461  
   462  // Tests that transactions can be loaded from disk on startup and that they are
   463  // correctly discarded if invalid.
   464  //
   465  //   - 1. A transaction that cannot be decoded must be dropped
   466  //   - 2. A transaction that cannot be recovered (bad signature) must be dropped
   467  //   - 3. All transactions after a nonce gap must be dropped
   468  //   - 4. All transactions after an already included nonce must be dropped
   469  //   - 5. All transactions after an underpriced one (including it) must be dropped
   470  //   - 6. All transactions after an overdrafting sequence must be dropped
   471  //   - 7. All transactions exceeding the per-account limit must be dropped
   472  //
   473  // Furthermore, some strange corner-cases can also occur after a crash, as Billy's
   474  // simplicity also allows it to resurrect past deleted entities:
   475  //
   476  //   - 8. Fully duplicate transactions (matching hash) must be dropped
   477  //   - 9. Duplicate nonces from the same account must be dropped
   478  func TestOpenDrops(t *testing.T) {
   479  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
   480  
   481  	// Create a temporary folder for the persistent backend
   482  	storage := t.TempDir()
   483  
   484  	os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
   485  	store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
   486  
   487  	// Insert a malformed transaction to verify that decoding errors (or format
   488  	// changes) are handled gracefully (case 1)
   489  	malformed, _ := store.Put([]byte("this is a badly encoded transaction"))
   490  
   491  	// Insert a transaction with a bad signature to verify that stale junk after
   492  	// potential hard-forks can get evicted (case 2)
   493  	tx := types.NewTx(&types.BlobTx{
   494  		ChainID:    uint256.MustFromBig(params.MainnetChainConfig.ChainID),
   495  		GasTipCap:  new(uint256.Int),
   496  		GasFeeCap:  new(uint256.Int),
   497  		Gas:        0,
   498  		Value:      new(uint256.Int),
   499  		Data:       nil,
   500  		BlobFeeCap: new(uint256.Int),
   501  		V:          new(uint256.Int),
   502  		R:          new(uint256.Int),
   503  		S:          new(uint256.Int),
   504  	})
   505  	blob, _ := rlp.EncodeToBytes(tx)
   506  	badsig, _ := store.Put(blob)
   507  
   508  	// Insert a sequence of transactions with a nonce gap in between to verify
   509  	// that anything gapped will get evicted (case 3).
   510  	var (
   511  		gapper, _ = crypto.GenerateKey()
   512  
   513  		valids = make(map[uint64]struct{})
   514  		gapped = make(map[uint64]struct{})
   515  	)
   516  	for _, nonce := range []uint64{0, 1, 3, 4, 6, 7} { // first gap at #2, another at #5
   517  		tx := makeTx(nonce, 1, 1, 1, gapper)
   518  		blob, _ := rlp.EncodeToBytes(tx)
   519  
   520  		id, _ := store.Put(blob)
   521  		if nonce < 2 {
   522  			valids[id] = struct{}{}
   523  		} else {
   524  			gapped[id] = struct{}{}
   525  		}
   526  	}
   527  	// Insert a sequence of transactions with a gapped starting nonce to verify
   528  	// that the entire set will get dropped (case 3).
   529  	var (
   530  		dangler, _ = crypto.GenerateKey()
   531  		dangling   = make(map[uint64]struct{})
   532  	)
   533  	for _, nonce := range []uint64{1, 2, 3} { // first gap at #0, all set dangling
   534  		tx := makeTx(nonce, 1, 1, 1, dangler)
   535  		blob, _ := rlp.EncodeToBytes(tx)
   536  
   537  		id, _ := store.Put(blob)
   538  		dangling[id] = struct{}{}
   539  	}
   540  	// Insert a sequence of transactions with already passed nonces to veirfy
   541  	// that the entire set will get dropped (case 4).
   542  	var (
   543  		filler, _ = crypto.GenerateKey()
   544  		filled    = make(map[uint64]struct{})
   545  	)
   546  	for _, nonce := range []uint64{0, 1, 2} { // account nonce at 3, all set filled
   547  		tx := makeTx(nonce, 1, 1, 1, filler)
   548  		blob, _ := rlp.EncodeToBytes(tx)
   549  
   550  		id, _ := store.Put(blob)
   551  		filled[id] = struct{}{}
   552  	}
   553  	// Insert a sequence of transactions with partially passed nonces to verify
   554  	// that the included part of the set will get dropped (case 4).
   555  	var (
   556  		overlapper, _ = crypto.GenerateKey()
   557  		overlapped    = make(map[uint64]struct{})
   558  	)
   559  	for _, nonce := range []uint64{0, 1, 2, 3} { // account nonce at 2, half filled
   560  		tx := makeTx(nonce, 1, 1, 1, overlapper)
   561  		blob, _ := rlp.EncodeToBytes(tx)
   562  
   563  		id, _ := store.Put(blob)
   564  		if nonce >= 2 {
   565  			valids[id] = struct{}{}
   566  		} else {
   567  			overlapped[id] = struct{}{}
   568  		}
   569  	}
   570  	// Insert a sequence of transactions with an underpriced first to verify that
   571  	// the entire set will get dropped (case 5).
   572  	var (
   573  		underpayer, _ = crypto.GenerateKey()
   574  		underpaid     = make(map[uint64]struct{})
   575  	)
   576  	for i := 0; i < 5; i++ { // make #0 underpriced
   577  		var tx *types.Transaction
   578  		if i == 0 {
   579  			tx = makeTx(uint64(i), 0, 0, 0, underpayer)
   580  		} else {
   581  			tx = makeTx(uint64(i), 1, 1, 1, underpayer)
   582  		}
   583  		blob, _ := rlp.EncodeToBytes(tx)
   584  
   585  		id, _ := store.Put(blob)
   586  		underpaid[id] = struct{}{}
   587  	}
   588  
   589  	// Insert a sequence of transactions with an underpriced in between to verify
   590  	// that it and anything newly gapped will get evicted (case 5).
   591  	var (
   592  		outpricer, _ = crypto.GenerateKey()
   593  		outpriced    = make(map[uint64]struct{})
   594  	)
   595  	for i := 0; i < 5; i++ { // make #2 underpriced
   596  		var tx *types.Transaction
   597  		if i == 2 {
   598  			tx = makeTx(uint64(i), 0, 0, 0, outpricer)
   599  		} else {
   600  			tx = makeTx(uint64(i), 1, 1, 1, outpricer)
   601  		}
   602  		blob, _ := rlp.EncodeToBytes(tx)
   603  
   604  		id, _ := store.Put(blob)
   605  		if i < 2 {
   606  			valids[id] = struct{}{}
   607  		} else {
   608  			outpriced[id] = struct{}{}
   609  		}
   610  	}
   611  	// Insert a sequence of transactions fully overdrafted to verify that the
   612  	// entire set will get invalidated (case 6).
   613  	var (
   614  		exceeder, _ = crypto.GenerateKey()
   615  		exceeded    = make(map[uint64]struct{})
   616  	)
   617  	for _, nonce := range []uint64{0, 1, 2} { // nonce 0 overdrafts the account
   618  		var tx *types.Transaction
   619  		if nonce == 0 {
   620  			tx = makeTx(nonce, 1, 100, 1, exceeder)
   621  		} else {
   622  			tx = makeTx(nonce, 1, 1, 1, exceeder)
   623  		}
   624  		blob, _ := rlp.EncodeToBytes(tx)
   625  
   626  		id, _ := store.Put(blob)
   627  		exceeded[id] = struct{}{}
   628  	}
   629  	// Insert a sequence of transactions partially overdrafted to verify that part
   630  	// of the set will get invalidated (case 6).
   631  	var (
   632  		overdrafter, _ = crypto.GenerateKey()
   633  		overdrafted    = make(map[uint64]struct{})
   634  	)
   635  	for _, nonce := range []uint64{0, 1, 2} { // nonce 1 overdrafts the account
   636  		var tx *types.Transaction
   637  		if nonce == 1 {
   638  			tx = makeTx(nonce, 1, 100, 1, overdrafter)
   639  		} else {
   640  			tx = makeTx(nonce, 1, 1, 1, overdrafter)
   641  		}
   642  		blob, _ := rlp.EncodeToBytes(tx)
   643  
   644  		id, _ := store.Put(blob)
   645  		if nonce < 1 {
   646  			valids[id] = struct{}{}
   647  		} else {
   648  			overdrafted[id] = struct{}{}
   649  		}
   650  	}
   651  	// Insert a sequence of transactions overflowing the account cap to verify
   652  	// that part of the set will get invalidated (case 7).
   653  	var (
   654  		overcapper, _ = crypto.GenerateKey()
   655  		overcapped    = make(map[uint64]struct{})
   656  	)
   657  	for nonce := uint64(0); nonce < maxTxsPerAccount+3; nonce++ {
   658  		blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, 1, 1, overcapper))
   659  
   660  		id, _ := store.Put(blob)
   661  		if nonce < maxTxsPerAccount {
   662  			valids[id] = struct{}{}
   663  		} else {
   664  			overcapped[id] = struct{}{}
   665  		}
   666  	}
   667  	// Insert a batch of duplicated transactions to verify that only one of each
   668  	// version will remain (case 8).
   669  	var (
   670  		duplicater, _ = crypto.GenerateKey()
   671  		duplicated    = make(map[uint64]struct{})
   672  	)
   673  	for _, nonce := range []uint64{0, 1, 2} {
   674  		blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, 1, 1, duplicater))
   675  
   676  		for i := 0; i < int(nonce)+1; i++ {
   677  			id, _ := store.Put(blob)
   678  			if i == 0 {
   679  				valids[id] = struct{}{}
   680  			} else {
   681  				duplicated[id] = struct{}{}
   682  			}
   683  		}
   684  	}
   685  	// Insert a batch of duplicated nonces to verify that only one of each will
   686  	// remain (case 9).
   687  	var (
   688  		repeater, _ = crypto.GenerateKey()
   689  		repeated    = make(map[uint64]struct{})
   690  	)
   691  	for _, nonce := range []uint64{0, 1, 2} {
   692  		for i := 0; i < int(nonce)+1; i++ {
   693  			blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, uint64(i)+1 /* unique hashes */, 1, repeater))
   694  
   695  			id, _ := store.Put(blob)
   696  			if i == 0 {
   697  				valids[id] = struct{}{}
   698  			} else {
   699  				repeated[id] = struct{}{}
   700  			}
   701  		}
   702  	}
   703  	store.Close()
   704  
   705  	// Create a blob pool out of the pre-seeded data
   706  	statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
   707  	statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   708  	statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   709  	statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   710  	statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3, tracing.NonceChangeUnspecified)
   711  	statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   712  	statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2, tracing.NonceChangeUnspecified)
   713  	statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   714  	statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   715  	statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   716  	statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   717  	statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified)
   718  	statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   719  	statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
   720  	statedb.Commit(0, true, false)
   721  
   722  	chain := &testBlockChain{
   723  		config:  params.MainnetChainConfig,
   724  		basefee: uint256.NewInt(params.InitialBaseFee),
   725  		blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice),
   726  		statedb: statedb,
   727  	}
   728  	pool := New(Config{Datadir: storage}, chain, nil)
   729  	if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
   730  		t.Fatalf("failed to create blob pool: %v", err)
   731  	}
   732  	defer pool.Close()
   733  
   734  	// Verify that the malformed (case 1), badly signed (case 2) and gapped (case
   735  	// 3) txs have been deleted from the pool
   736  	alive := make(map[uint64]struct{})
   737  	for _, txs := range pool.index {
   738  		for _, tx := range txs {
   739  			switch tx.id {
   740  			case malformed:
   741  				t.Errorf("malformed RLP transaction remained in storage")
   742  			case badsig:
   743  				t.Errorf("invalidly signed transaction remained in storage")
   744  			default:
   745  				if _, ok := dangling[tx.id]; ok {
   746  					t.Errorf("dangling transaction remained in storage: %d", tx.id)
   747  				} else if _, ok := filled[tx.id]; ok {
   748  					t.Errorf("filled transaction remained in storage: %d", tx.id)
   749  				} else if _, ok := overlapped[tx.id]; ok {
   750  					t.Errorf("overlapped transaction remained in storage: %d", tx.id)
   751  				} else if _, ok := gapped[tx.id]; ok {
   752  					t.Errorf("gapped transaction remained in storage: %d", tx.id)
   753  				} else if _, ok := underpaid[tx.id]; ok {
   754  					t.Errorf("underpaid transaction remained in storage: %d", tx.id)
   755  				} else if _, ok := outpriced[tx.id]; ok {
   756  					t.Errorf("outpriced transaction remained in storage: %d", tx.id)
   757  				} else if _, ok := exceeded[tx.id]; ok {
   758  					t.Errorf("fully overdrafted transaction remained in storage: %d", tx.id)
   759  				} else if _, ok := overdrafted[tx.id]; ok {
   760  					t.Errorf("partially overdrafted transaction remained in storage: %d", tx.id)
   761  				} else if _, ok := overcapped[tx.id]; ok {
   762  					t.Errorf("overcapped transaction remained in storage: %d", tx.id)
   763  				} else if _, ok := duplicated[tx.id]; ok {
   764  					t.Errorf("duplicated transaction remained in storage: %d", tx.id)
   765  				} else if _, ok := repeated[tx.id]; ok {
   766  					t.Errorf("repeated nonce transaction remained in storage: %d", tx.id)
   767  				} else {
   768  					alive[tx.id] = struct{}{}
   769  				}
   770  			}
   771  		}
   772  	}
   773  	// Verify that the rest of the transactions remained alive
   774  	if len(alive) != len(valids) {
   775  		t.Errorf("valid transaction count mismatch: have %d, want %d", len(alive), len(valids))
   776  	}
   777  	for id := range alive {
   778  		if _, ok := valids[id]; !ok {
   779  			t.Errorf("extra transaction %d", id)
   780  		}
   781  	}
   782  	for id := range valids {
   783  		if _, ok := alive[id]; !ok {
   784  			t.Errorf("missing transaction %d", id)
   785  		}
   786  	}
   787  	// Verify all the calculated pool internals. Interestingly, this is **not**
   788  	// a duplication of the above checks, this actually validates the verifier
   789  	// using the above already hard coded checks.
   790  	//
   791  	// Do not remove this, nor alter the above to be generic.
   792  	verifyPoolInternals(t, pool)
   793  }
   794  
   795  // Tests that transactions loaded from disk are indexed correctly.
   796  //
   797  //   - 1. Transactions must be grouped by sender, sorted by nonce
   798  //   - 2. Eviction thresholds are calculated correctly for the sequences
   799  //   - 3. Balance usage of an account is totals across all transactions
   800  func TestOpenIndex(t *testing.T) {
   801  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
   802  
   803  	// Create a temporary folder for the persistent backend
   804  	storage := t.TempDir()
   805  
   806  	os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
   807  	store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
   808  
   809  	// Insert a sequence of transactions with varying price points to check that
   810  	// the cumulative minimum will be maintained.
   811  	var (
   812  		key, _ = crypto.GenerateKey()
   813  		addr   = crypto.PubkeyToAddress(key.PublicKey)
   814  
   815  		txExecTipCaps = []uint64{10, 25, 5, 7, 1, 100}
   816  		txExecFeeCaps = []uint64{100, 90, 200, 10, 80, 300}
   817  		txBlobFeeCaps = []uint64{55, 66, 77, 33, 22, 11}
   818  
   819  		//basefeeJumps = []float64{39.098, 38.204, 44.983, 19.549, 37.204, 48.426} // log 1.125 (exec fee cap)
   820  		//blobfeeJumps = []float64{34.023, 35.570, 36.879, 29.686, 26.243, 20.358} // log 1.125 (blob fee cap)
   821  
   822  		evictExecTipCaps  = []uint64{10, 10, 5, 5, 1, 1}
   823  		evictExecFeeJumps = []float64{39.098, 38.204, 38.204, 19.549, 19.549, 19.549} //  min(log 1.125 (exec fee cap))
   824  		evictBlobFeeJumps = []float64{34.023, 34.023, 34.023, 29.686, 26.243, 20.358} // min(log 1.125 (blob fee cap))
   825  
   826  		totalSpent = uint256.NewInt(21000*(100+90+200+10+80+300) + blobSize*(55+66+77+33+22+11) + 100*6) // 21000 gas x price + 128KB x blobprice + value
   827  	)
   828  	for _, i := range []int{5, 3, 4, 2, 0, 1} { // Randomize the tx insertion order to force sorting on load
   829  		tx := makeTx(uint64(i), txExecTipCaps[i], txExecFeeCaps[i], txBlobFeeCaps[i], key)
   830  		blob, _ := rlp.EncodeToBytes(tx)
   831  		store.Put(blob)
   832  	}
   833  	store.Close()
   834  
   835  	// Create a blob pool out of the pre-seeded data
   836  	statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
   837  	statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
   838  	statedb.Commit(0, true, false)
   839  
   840  	chain := &testBlockChain{
   841  		config:  params.MainnetChainConfig,
   842  		basefee: uint256.NewInt(params.InitialBaseFee),
   843  		blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice),
   844  		statedb: statedb,
   845  	}
   846  	pool := New(Config{Datadir: storage}, chain, nil)
   847  	if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
   848  		t.Fatalf("failed to create blob pool: %v", err)
   849  	}
   850  	defer pool.Close()
   851  
   852  	// Verify that the transactions have been sorted by nonce (case 1)
   853  	for i := 0; i < len(pool.index[addr]); i++ {
   854  		if pool.index[addr][i].nonce != uint64(i) {
   855  			t.Errorf("tx %d nonce mismatch: have %d, want %d", i, pool.index[addr][i].nonce, uint64(i))
   856  		}
   857  	}
   858  	// Verify that the cumulative fee minimums have been correctly calculated (case 2)
   859  	for i, cap := range evictExecTipCaps {
   860  		if !pool.index[addr][i].evictionExecTip.Eq(uint256.NewInt(cap)) {
   861  			t.Errorf("eviction tip cap %d mismatch: have %d, want %d", i, pool.index[addr][i].evictionExecTip, cap)
   862  		}
   863  	}
   864  	for i, jumps := range evictExecFeeJumps {
   865  		if math.Abs(pool.index[addr][i].evictionExecFeeJumps-jumps) > 0.001 {
   866  			t.Errorf("eviction fee cap jumps %d mismatch: have %f, want %f", i, pool.index[addr][i].evictionExecFeeJumps, jumps)
   867  		}
   868  	}
   869  	for i, jumps := range evictBlobFeeJumps {
   870  		if math.Abs(pool.index[addr][i].evictionBlobFeeJumps-jumps) > 0.001 {
   871  			t.Errorf("eviction blob fee cap jumps %d mismatch: have %f, want %f", i, pool.index[addr][i].evictionBlobFeeJumps, jumps)
   872  		}
   873  	}
   874  	// Verify that the balance usage has been correctly calculated (case 3)
   875  	if !pool.spent[addr].Eq(totalSpent) {
   876  		t.Errorf("expenditure mismatch: have %d, want %d", pool.spent[addr], totalSpent)
   877  	}
   878  	// Verify all the calculated pool internals. Interestingly, this is **not**
   879  	// a duplication of the above checks, this actually validates the verifier
   880  	// using the above already hard coded checks.
   881  	//
   882  	// Do not remove this, nor alter the above to be generic.
   883  	verifyPoolInternals(t, pool)
   884  }
   885  
   886  // Tests that after indexing all the loaded transactions from disk, a price heap
   887  // is correctly constructed based on the head basefee and blobfee.
   888  func TestOpenHeap(t *testing.T) {
   889  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
   890  
   891  	// Create a temporary folder for the persistent backend
   892  	storage := t.TempDir()
   893  
   894  	os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
   895  	store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
   896  
   897  	// Insert a few transactions from a few accounts. To remove randomness from
   898  	// the heap initialization, use a deterministic account/tx/priority ordering.
   899  	var (
   900  		key1, _ = crypto.GenerateKey()
   901  		key2, _ = crypto.GenerateKey()
   902  		key3, _ = crypto.GenerateKey()
   903  
   904  		addr1 = crypto.PubkeyToAddress(key1.PublicKey)
   905  		addr2 = crypto.PubkeyToAddress(key2.PublicKey)
   906  		addr3 = crypto.PubkeyToAddress(key3.PublicKey)
   907  	)
   908  	if bytes.Compare(addr1[:], addr2[:]) > 0 {
   909  		key1, addr1, key2, addr2 = key2, addr2, key1, addr1
   910  	}
   911  	if bytes.Compare(addr1[:], addr3[:]) > 0 {
   912  		key1, addr1, key3, addr3 = key3, addr3, key1, addr1
   913  	}
   914  	if bytes.Compare(addr2[:], addr3[:]) > 0 {
   915  		key2, addr2, key3, addr3 = key3, addr3, key2, addr2
   916  	}
   917  	var (
   918  		tx1 = makeTx(0, 1, 1000, 90, key1)
   919  		tx2 = makeTx(0, 1, 800, 70, key2)
   920  		tx3 = makeTx(0, 1, 1500, 110, key3)
   921  
   922  		blob1, _ = rlp.EncodeToBytes(tx1)
   923  		blob2, _ = rlp.EncodeToBytes(tx2)
   924  		blob3, _ = rlp.EncodeToBytes(tx3)
   925  
   926  		heapOrder = []common.Address{addr2, addr1, addr3}
   927  		heapIndex = map[common.Address]int{addr2: 0, addr1: 1, addr3: 2}
   928  	)
   929  	store.Put(blob1)
   930  	store.Put(blob2)
   931  	store.Put(blob3)
   932  	store.Close()
   933  
   934  	// Create a blob pool out of the pre-seeded data
   935  	statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
   936  	statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
   937  	statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
   938  	statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
   939  	statedb.Commit(0, true, false)
   940  
   941  	chain := &testBlockChain{
   942  		config:  params.MainnetChainConfig,
   943  		basefee: uint256.NewInt(1050),
   944  		blobfee: uint256.NewInt(105),
   945  		statedb: statedb,
   946  	}
   947  	pool := New(Config{Datadir: storage}, chain, nil)
   948  	if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
   949  		t.Fatalf("failed to create blob pool: %v", err)
   950  	}
   951  	defer pool.Close()
   952  
   953  	// Verify that the heap's internal state matches the expectations
   954  	for i, addr := range pool.evict.addrs {
   955  		if addr != heapOrder[i] {
   956  			t.Errorf("slot %d mismatch: have %v, want %v", i, addr, heapOrder[i])
   957  		}
   958  	}
   959  	for addr, i := range pool.evict.index {
   960  		if i != heapIndex[addr] {
   961  			t.Errorf("index for %v mismatch: have %d, want %d", addr, i, heapIndex[addr])
   962  		}
   963  	}
   964  	// Verify all the calculated pool internals. Interestingly, this is **not**
   965  	// a duplication of the above checks, this actually validates the verifier
   966  	// using the above already hard coded checks.
   967  	//
   968  	// Do not remove this, nor alter the above to be generic.
   969  	verifyPoolInternals(t, pool)
   970  }
   971  
   972  // Tests that after the pool's previous state is loaded back, any transactions
   973  // over the new storage cap will get dropped.
   974  func TestOpenCap(t *testing.T) {
   975  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
   976  
   977  	// Create a temporary folder for the persistent backend
   978  	storage := t.TempDir()
   979  
   980  	os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
   981  	store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
   982  
   983  	// Insert a few transactions from a few accounts
   984  	var (
   985  		key1, _ = crypto.GenerateKey()
   986  		key2, _ = crypto.GenerateKey()
   987  		key3, _ = crypto.GenerateKey()
   988  
   989  		addr1 = crypto.PubkeyToAddress(key1.PublicKey)
   990  		addr2 = crypto.PubkeyToAddress(key2.PublicKey)
   991  		addr3 = crypto.PubkeyToAddress(key3.PublicKey)
   992  
   993  		tx1 = makeTx(0, 1, 1000, 100, key1)
   994  		tx2 = makeTx(0, 1, 800, 70, key2)
   995  		tx3 = makeTx(0, 1, 1500, 110, key3)
   996  
   997  		blob1, _ = rlp.EncodeToBytes(tx1)
   998  		blob2, _ = rlp.EncodeToBytes(tx2)
   999  		blob3, _ = rlp.EncodeToBytes(tx3)
  1000  
  1001  		keep = []common.Address{addr1, addr3}
  1002  		drop = []common.Address{addr2}
  1003  		size = uint64(2 * (txAvgSize + blobSize))
  1004  	)
  1005  	store.Put(blob1)
  1006  	store.Put(blob2)
  1007  	store.Put(blob3)
  1008  	store.Close()
  1009  
  1010  	// Verify pool capping twice: first by reducing the data cap, then restarting
  1011  	// with a high cap to ensure everything was persisted previously
  1012  	for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
  1013  		// Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction
  1014  		statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
  1015  		statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1016  		statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1017  		statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1018  		statedb.Commit(0, true, false)
  1019  
  1020  		chain := &testBlockChain{
  1021  			config:  params.MainnetChainConfig,
  1022  			basefee: uint256.NewInt(1050),
  1023  			blobfee: uint256.NewInt(105),
  1024  			statedb: statedb,
  1025  		}
  1026  		pool := New(Config{Datadir: storage, Datacap: datacap}, chain, nil)
  1027  		if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
  1028  			t.Fatalf("failed to create blob pool: %v", err)
  1029  		}
  1030  		// Verify that enough transactions have been dropped to get the pool's size
  1031  		// under the requested limit
  1032  		if len(pool.index) != len(keep) {
  1033  			t.Errorf("tracked account count mismatch: have %d, want %d", len(pool.index), len(keep))
  1034  		}
  1035  		for _, addr := range keep {
  1036  			if _, ok := pool.index[addr]; !ok {
  1037  				t.Errorf("expected account %v missing from pool", addr)
  1038  			}
  1039  		}
  1040  		for _, addr := range drop {
  1041  			if _, ok := pool.index[addr]; ok {
  1042  				t.Errorf("unexpected account %v present in pool", addr)
  1043  			}
  1044  		}
  1045  		if pool.stored != size {
  1046  			t.Errorf("pool stored size mismatch: have %v, want %v", pool.stored, size)
  1047  		}
  1048  		// Verify all the calculated pool internals. Interestingly, this is **not**
  1049  		// a duplication of the above checks, this actually validates the verifier
  1050  		// using the above already hard coded checks.
  1051  		//
  1052  		// Do not remove this, nor alter the above to be generic.
  1053  		verifyPoolInternals(t, pool)
  1054  
  1055  		pool.Close()
  1056  	}
  1057  }
  1058  
  1059  // TestChangingSlotterSize attempts to mimic a scenario where the max blob count
  1060  // of the pool is increased. This would happen during a client release where a
  1061  // new fork is added with a max blob count higher than the previous fork. We
  1062  // want to make sure transactions a persisted between those runs.
  1063  func TestChangingSlotterSize(t *testing.T) {
  1064  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
  1065  
  1066  	// Create a temporary folder for the persistent backend
  1067  	storage := t.TempDir()
  1068  
  1069  	os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
  1070  	store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil)
  1071  
  1072  	// Create transactions from a few accounts.
  1073  	var (
  1074  		key1, _ = crypto.GenerateKey()
  1075  		key2, _ = crypto.GenerateKey()
  1076  		key3, _ = crypto.GenerateKey()
  1077  
  1078  		addr1 = crypto.PubkeyToAddress(key1.PublicKey)
  1079  		addr2 = crypto.PubkeyToAddress(key2.PublicKey)
  1080  		addr3 = crypto.PubkeyToAddress(key3.PublicKey)
  1081  
  1082  		tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1)
  1083  		tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2)
  1084  		tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3)
  1085  
  1086  		blob1, _ = rlp.EncodeToBytes(tx1)
  1087  		blob2, _ = rlp.EncodeToBytes(tx2)
  1088  	)
  1089  
  1090  	// Write the two safely sized txs to store. note: although the store is
  1091  	// configured for a blob count of 6, it can also support around ~1mb of call
  1092  	// data - all this to say that we aren't using the the absolute largest shelf
  1093  	// available.
  1094  	store.Put(blob1)
  1095  	store.Put(blob2)
  1096  	store.Close()
  1097  
  1098  	// Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24.
  1099  	for _, maxBlobs := range []int{6, 24} {
  1100  		statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
  1101  		statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1102  		statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1103  		statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1104  		statedb.Commit(0, true, false)
  1105  
  1106  		// Make custom chain config where the max blob count changes based on the loop variable.
  1107  		cancunTime := uint64(0)
  1108  		config := &params.ChainConfig{
  1109  			ChainID:     big.NewInt(1),
  1110  			LondonBlock: big.NewInt(0),
  1111  			BerlinBlock: big.NewInt(0),
  1112  			CancunTime:  &cancunTime,
  1113  			BlobScheduleConfig: &params.BlobScheduleConfig{
  1114  				Cancun: &params.BlobConfig{
  1115  					Target:         maxBlobs / 2,
  1116  					Max:            maxBlobs,
  1117  					UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction,
  1118  				},
  1119  			},
  1120  		}
  1121  		chain := &testBlockChain{
  1122  			config:  config,
  1123  			basefee: uint256.NewInt(1050),
  1124  			blobfee: uint256.NewInt(105),
  1125  			statedb: statedb,
  1126  		}
  1127  		pool := New(Config{Datadir: storage}, chain, nil)
  1128  		if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
  1129  			t.Fatalf("failed to create blob pool: %v", err)
  1130  		}
  1131  
  1132  		// Try to add the big blob tx. In the initial iteration it should overflow
  1133  		// the pool. On the subsequent iteration it should be accepted.
  1134  		errs := pool.Add([]*types.Transaction{tx3}, true)
  1135  		if _, ok := pool.index[addr3]; ok && maxBlobs == 6 {
  1136  			t.Errorf("expected insert of oversized blob tx to fail: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
  1137  		} else if !ok && maxBlobs == 10 {
  1138  			t.Errorf("expected insert of oversized blob tx to succeed: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
  1139  		}
  1140  
  1141  		// Verify the regular two txs are always available.
  1142  		if got := pool.Get(tx1.Hash()); got == nil {
  1143  			t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1)
  1144  		}
  1145  		if got := pool.Get(tx2.Hash()); got == nil {
  1146  			t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2)
  1147  		}
  1148  
  1149  		// Verify all the calculated pool internals. Interestingly, this is **not**
  1150  		// a duplication of the above checks, this actually validates the verifier
  1151  		// using the above already hard coded checks.
  1152  		//
  1153  		// Do not remove this, nor alter the above to be generic.
  1154  		verifyPoolInternals(t, pool)
  1155  
  1156  		pool.Close()
  1157  	}
  1158  }
  1159  
  1160  // TestBlobCountLimit tests the blobpool enforced limits on the max blob count.
  1161  func TestBlobCountLimit(t *testing.T) {
  1162  	var (
  1163  		key1, _ = crypto.GenerateKey()
  1164  		key2, _ = crypto.GenerateKey()
  1165  
  1166  		addr1 = crypto.PubkeyToAddress(key1.PublicKey)
  1167  		addr2 = crypto.PubkeyToAddress(key2.PublicKey)
  1168  	)
  1169  
  1170  	statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
  1171  	statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1172  	statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1173  	statedb.Commit(0, true, false)
  1174  
  1175  	// Make Prague-enabled custom chain config.
  1176  	cancunTime := uint64(0)
  1177  	pragueTime := uint64(0)
  1178  	config := &params.ChainConfig{
  1179  		ChainID:     big.NewInt(1),
  1180  		LondonBlock: big.NewInt(0),
  1181  		BerlinBlock: big.NewInt(0),
  1182  		CancunTime:  &cancunTime,
  1183  		PragueTime:  &pragueTime,
  1184  		BlobScheduleConfig: &params.BlobScheduleConfig{
  1185  			Cancun: params.DefaultCancunBlobConfig,
  1186  			Prague: params.DefaultPragueBlobConfig,
  1187  		},
  1188  	}
  1189  	chain := &testBlockChain{
  1190  		config:  config,
  1191  		basefee: uint256.NewInt(1050),
  1192  		blobfee: uint256.NewInt(105),
  1193  		statedb: statedb,
  1194  	}
  1195  	pool := New(Config{Datadir: t.TempDir()}, chain, nil)
  1196  	if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
  1197  		t.Fatalf("failed to create blob pool: %v", err)
  1198  	}
  1199  
  1200  	// Attempt to add transactions.
  1201  	var (
  1202  		tx1 = makeMultiBlobTx(0, 1, 1000, 100, 7, key1)
  1203  		tx2 = makeMultiBlobTx(0, 1, 800, 70, 8, key2)
  1204  	)
  1205  	errs := pool.Add([]*types.Transaction{tx1, tx2}, true)
  1206  
  1207  	// Check that first succeeds second fails.
  1208  	if errs[0] != nil {
  1209  		t.Fatalf("expected tx with 7 blobs to succeed")
  1210  	}
  1211  	if !errors.Is(errs[1], txpool.ErrTxBlobLimitExceeded) {
  1212  		t.Fatalf("expected tx with 8 blobs to fail, got: %v", errs[1])
  1213  	}
  1214  
  1215  	verifyPoolInternals(t, pool)
  1216  	pool.Close()
  1217  }
  1218  
  1219  // Tests that adding transaction will correctly store it in the persistent store
  1220  // and update all the indices.
  1221  //
  1222  // Note, this tests mostly checks the pool transaction shuffling logic or things
  1223  // specific to the blob pool. It does not do an exhaustive transaction validity
  1224  // check.
  1225  func TestAdd(t *testing.T) {
  1226  	//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
  1227  
  1228  	// seed is a helper tuple to seed an initial state db and pool
  1229  	type seed struct {
  1230  		balance uint64
  1231  		nonce   uint64
  1232  		txs     []*types.BlobTx
  1233  	}
  1234  	// addtx is a helper sender/tx tuple to represent a new tx addition
  1235  	type addtx struct {
  1236  		from string
  1237  		tx   *types.BlobTx
  1238  		err  error
  1239  	}
  1240  
  1241  	tests := []struct {
  1242  		seeds map[string]seed
  1243  		adds  []addtx
  1244  		block []addtx
  1245  	}{
  1246  		// Transactions from new accounts should be accepted if their initial
  1247  		// nonce matches the expected one from the statedb. Higher or lower must
  1248  		// be rejected.
  1249  		{
  1250  			seeds: map[string]seed{
  1251  				"alice":  {balance: 21100 + blobSize},
  1252  				"bob":    {balance: 21100 + blobSize, nonce: 1},
  1253  				"claire": {balance: 21100 + blobSize},
  1254  				"dave":   {balance: 21100 + blobSize, nonce: 1},
  1255  			},
  1256  			adds: []addtx{
  1257  				{ // New account, no previous txs: accept nonce 0
  1258  					from: "alice",
  1259  					tx:   makeUnsignedTx(0, 1, 1, 1),
  1260  					err:  nil,
  1261  				},
  1262  				{ // Old account, 1 tx in chain, 0 pending: accept nonce 1
  1263  					from: "bob",
  1264  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1265  					err:  nil,
  1266  				},
  1267  				{ // New account, no previous txs: reject nonce 1
  1268  					from: "claire",
  1269  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1270  					err:  core.ErrNonceTooHigh,
  1271  				},
  1272  				{ // Old account, 1 tx in chain, 0 pending: reject nonce 0
  1273  					from: "dave",
  1274  					tx:   makeUnsignedTx(0, 1, 1, 1),
  1275  					err:  core.ErrNonceTooLow,
  1276  				},
  1277  				{ // Old account, 1 tx in chain, 0 pending: reject nonce 2
  1278  					from: "dave",
  1279  					tx:   makeUnsignedTx(2, 1, 1, 1),
  1280  					err:  core.ErrNonceTooHigh,
  1281  				},
  1282  			},
  1283  		},
  1284  		// Transactions from already pooled accounts should only be accepted if
  1285  		// the nonces are contiguous (ignore prices for now, will check later)
  1286  		{
  1287  			seeds: map[string]seed{
  1288  				"alice": {
  1289  					balance: 1000000,
  1290  					txs: []*types.BlobTx{
  1291  						makeUnsignedTxWithTestBlob(0, 1, 1, 1, 0),
  1292  					},
  1293  				},
  1294  				"bob": {
  1295  					balance: 1000000,
  1296  					nonce:   1,
  1297  					txs: []*types.BlobTx{
  1298  						makeUnsignedTxWithTestBlob(1, 1, 1, 1, 1),
  1299  					},
  1300  				},
  1301  			},
  1302  			adds: []addtx{
  1303  				{ // New account, 1 tx pending: reject duplicate nonce 0
  1304  					from: "alice",
  1305  					tx:   makeUnsignedTxWithTestBlob(0, 1, 1, 1, 0),
  1306  					err:  txpool.ErrAlreadyKnown,
  1307  				},
  1308  				{ // New account, 1 tx pending: reject replacement nonce 0 (ignore price for now)
  1309  					from: "alice",
  1310  					tx:   makeUnsignedTx(0, 1, 1, 2),
  1311  					err:  txpool.ErrReplaceUnderpriced,
  1312  				},
  1313  				{ // New account, 1 tx pending: accept nonce 1
  1314  					from: "alice",
  1315  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1316  					err:  nil,
  1317  				},
  1318  				{ // New account, 2 txs pending: reject nonce 3
  1319  					from: "alice",
  1320  					tx:   makeUnsignedTx(3, 1, 1, 1),
  1321  					err:  core.ErrNonceTooHigh,
  1322  				},
  1323  				{ // New account, 2 txs pending: accept nonce 2
  1324  					from: "alice",
  1325  					tx:   makeUnsignedTx(2, 1, 1, 1),
  1326  					err:  nil,
  1327  				},
  1328  				{ // New account, 3 txs pending: accept nonce 3 now
  1329  					from: "alice",
  1330  					tx:   makeUnsignedTx(3, 1, 1, 1),
  1331  					err:  nil,
  1332  				},
  1333  				{ // Old account, 1 tx in chain, 1 tx pending: reject duplicate nonce 1
  1334  					from: "bob",
  1335  					tx:   makeUnsignedTxWithTestBlob(1, 1, 1, 1, 1),
  1336  					err:  txpool.ErrAlreadyKnown,
  1337  				},
  1338  				{ // Old account, 1 tx in chain, 1 tx pending: accept nonce 2 (ignore price for now)
  1339  					from: "bob",
  1340  					tx:   makeUnsignedTx(2, 1, 1, 1),
  1341  					err:  nil,
  1342  				},
  1343  			},
  1344  		},
  1345  		// Transactions should only be accepted into the pool if the cumulative
  1346  		// expenditure doesn't overflow the account balance
  1347  		{
  1348  			seeds: map[string]seed{
  1349  				"alice": {balance: 63299 + 3*blobSize}, // 3 tx - 1 wei
  1350  			},
  1351  			adds: []addtx{
  1352  				{ // New account, no previous txs: accept nonce 0 with 21100 wei spend
  1353  					from: "alice",
  1354  					tx:   makeUnsignedTx(0, 1, 1, 1),
  1355  					err:  nil,
  1356  				},
  1357  				{ // New account, 1 pooled tx with 21100 wei spent: accept nonce 1 with 21100 wei spend
  1358  					from: "alice",
  1359  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1360  					err:  nil,
  1361  				},
  1362  				{ // New account, 2 pooled tx with 42200 wei spent: reject nonce 2 with 21100 wei spend (1 wei overflow)
  1363  					from: "alice",
  1364  					tx:   makeUnsignedTx(2, 1, 1, 1),
  1365  					err:  core.ErrInsufficientFunds,
  1366  				},
  1367  			},
  1368  		},
  1369  		// Transactions should only be accepted into the pool if the total count
  1370  		// from the same account doesn't overflow the pool limits
  1371  		{
  1372  			seeds: map[string]seed{
  1373  				"alice": {balance: 10000000},
  1374  			},
  1375  			adds: []addtx{
  1376  				{ // New account, no previous txs, 16 slots left: accept nonce 0
  1377  					from: "alice",
  1378  					tx:   makeUnsignedTx(0, 1, 1, 1),
  1379  					err:  nil,
  1380  				},
  1381  				{ // New account, 1 pooled tx, 15 slots left: accept nonce 1
  1382  					from: "alice",
  1383  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1384  					err:  nil,
  1385  				},
  1386  				{ // New account, 2 pooled tx, 14 slots left: accept nonce 2
  1387  					from: "alice",
  1388  					tx:   makeUnsignedTx(2, 1, 1, 1),
  1389  					err:  nil,
  1390  				},
  1391  				{ // New account, 3 pooled tx, 13 slots left: accept nonce 3
  1392  					from: "alice",
  1393  					tx:   makeUnsignedTx(3, 1, 1, 1),
  1394  					err:  nil,
  1395  				},
  1396  				{ // New account, 4 pooled tx, 12 slots left: accept nonce 4
  1397  					from: "alice",
  1398  					tx:   makeUnsignedTx(4, 1, 1, 1),
  1399  					err:  nil,
  1400  				},
  1401  				{ // New account, 5 pooled tx, 11 slots left: accept nonce 5
  1402  					from: "alice",
  1403  					tx:   makeUnsignedTx(5, 1, 1, 1),
  1404  					err:  nil,
  1405  				},
  1406  				{ // New account, 6 pooled tx, 10 slots left: accept nonce 6
  1407  					from: "alice",
  1408  					tx:   makeUnsignedTx(6, 1, 1, 1),
  1409  					err:  nil,
  1410  				},
  1411  				{ // New account, 7 pooled tx, 9 slots left: accept nonce 7
  1412  					from: "alice",
  1413  					tx:   makeUnsignedTx(7, 1, 1, 1),
  1414  					err:  nil,
  1415  				},
  1416  				{ // New account, 8 pooled tx, 8 slots left: accept nonce 8
  1417  					from: "alice",
  1418  					tx:   makeUnsignedTx(8, 1, 1, 1),
  1419  					err:  nil,
  1420  				},
  1421  				{ // New account, 9 pooled tx, 7 slots left: accept nonce 9
  1422  					from: "alice",
  1423  					tx:   makeUnsignedTx(9, 1, 1, 1),
  1424  					err:  nil,
  1425  				},
  1426  				{ // New account, 10 pooled tx, 6 slots left: accept nonce 10
  1427  					from: "alice",
  1428  					tx:   makeUnsignedTx(10, 1, 1, 1),
  1429  					err:  nil,
  1430  				},
  1431  				{ // New account, 11 pooled tx, 5 slots left: accept nonce 11
  1432  					from: "alice",
  1433  					tx:   makeUnsignedTx(11, 1, 1, 1),
  1434  					err:  nil,
  1435  				},
  1436  				{ // New account, 12 pooled tx, 4 slots left: accept nonce 12
  1437  					from: "alice",
  1438  					tx:   makeUnsignedTx(12, 1, 1, 1),
  1439  					err:  nil,
  1440  				},
  1441  				{ // New account, 13 pooled tx, 3 slots left: accept nonce 13
  1442  					from: "alice",
  1443  					tx:   makeUnsignedTx(13, 1, 1, 1),
  1444  					err:  nil,
  1445  				},
  1446  				{ // New account, 14 pooled tx, 2 slots left: accept nonce 14
  1447  					from: "alice",
  1448  					tx:   makeUnsignedTx(14, 1, 1, 1),
  1449  					err:  nil,
  1450  				},
  1451  				{ // New account, 15 pooled tx, 1 slots left: accept nonce 15
  1452  					from: "alice",
  1453  					tx:   makeUnsignedTx(15, 1, 1, 1),
  1454  					err:  nil,
  1455  				},
  1456  				{ // New account, 16 pooled tx, 0 slots left: accept nonce 15 replacement
  1457  					from: "alice",
  1458  					tx:   makeUnsignedTx(15, 10, 10, 10),
  1459  					err:  nil,
  1460  				},
  1461  				{ // New account, 16 pooled tx, 0 slots left: reject nonce 16 with overcap
  1462  					from: "alice",
  1463  					tx:   makeUnsignedTx(16, 1, 1, 1),
  1464  					err:  txpool.ErrAccountLimitExceeded,
  1465  				},
  1466  			},
  1467  		},
  1468  		// Previously existing transactions should be allowed to be replaced iff
  1469  		// the new cumulative expenditure can be covered by the account and the
  1470  		// prices are bumped all around (no percentage check here).
  1471  		{
  1472  			seeds: map[string]seed{
  1473  				"alice": {balance: 2*100 + 5*21000 + 3*blobSize},
  1474  			},
  1475  			adds: []addtx{
  1476  				{ // New account, no previous txs: reject nonce 0 with 341172 wei spend
  1477  					from: "alice",
  1478  					tx:   makeUnsignedTx(0, 1, 20, 1),
  1479  					err:  core.ErrInsufficientFunds,
  1480  				},
  1481  				{ // New account, no previous txs: accept nonce 0 with 173172 wei spend
  1482  					from: "alice",
  1483  					tx:   makeUnsignedTx(0, 1, 2, 1),
  1484  					err:  nil,
  1485  				},
  1486  				{ // New account, 1 pooled tx with 173172 wei spent: accept nonce 1 with 152172 wei spend
  1487  					from: "alice",
  1488  					tx:   makeUnsignedTx(1, 1, 1, 1),
  1489  					err:  nil,
  1490  				},
  1491  				{ // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with 599684 wei spend (173072 extra) (would overflow balance at nonce 1)
  1492  					from: "alice",
  1493  					tx:   makeUnsignedTx(0, 2, 5, 2),
  1494  					err:  core.ErrInsufficientFunds,
  1495  				},
  1496  				{ // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-gastip-bump
  1497  					from: "alice",
  1498  					tx:   makeUnsignedTx(0, 1, 3, 2),
  1499  					err:  txpool.ErrReplaceUnderpriced,
  1500  				},
  1501  				{ // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-gascap-bump
  1502  					from: "alice",
  1503  					tx:   makeUnsignedTx(0, 2, 2, 2),
  1504  					err:  txpool.ErrReplaceUnderpriced,
  1505  				},
  1506  				{ // New account, 2 pooled tx with 325344 wei spent: reject nonce 0 with no-blobcap-bump
  1507  					from: "alice",
  1508  					tx:   makeUnsignedTx(0, 2, 4, 1),
  1509  					err:  txpool.ErrReplaceUnderpriced,
  1510  				},
  1511  				{ // New account, 2 pooled tx with 325344 wei spent: accept nonce 0 with 84100 wei spend (42000 extra)
  1512  					from: "alice",
  1513  					tx:   makeUnsignedTx(0, 2, 4, 2),
  1514  					err:  nil,
  1515  				},
  1516  			},
  1517  		},
  1518  		// Previously existing transactions should be allowed to be replaced iff
  1519  		// the new prices are bumped by a sufficient amount.
  1520  		{
  1521  			seeds: map[string]seed{
  1522  				"alice": {balance: 100 + 8*21000 + 4*blobSize},
  1523  			},
  1524  			adds: []addtx{
  1525  				{ // New account, no previous txs: accept nonce 0
  1526  					from: "alice",
  1527  					tx:   makeUnsignedTx(0, 2, 4, 2),
  1528  					err:  nil,
  1529  				},
  1530  				{ // New account, 1 pooled tx: reject nonce 0 with low-gastip-bump
  1531  					from: "alice",
  1532  					tx:   makeUnsignedTx(0, 3, 8, 4),
  1533  					err:  txpool.ErrReplaceUnderpriced,
  1534  				},
  1535  				{ // New account, 1 pooled tx: reject nonce 0 with low-gascap-bump
  1536  					from: "alice",
  1537  					tx:   makeUnsignedTx(0, 4, 6, 4),
  1538  					err:  txpool.ErrReplaceUnderpriced,
  1539  				},
  1540  				{ // New account, 1 pooled tx: reject nonce 0 with low-blobcap-bump
  1541  					from: "alice",
  1542  					tx:   makeUnsignedTx(0, 4, 8, 3),
  1543  					err:  txpool.ErrReplaceUnderpriced,
  1544  				},
  1545  				{ // New account, 1 pooled tx: accept nonce 0 with all-bumps
  1546  					from: "alice",
  1547  					tx:   makeUnsignedTx(0, 4, 8, 4),
  1548  					err:  nil,
  1549  				},
  1550  			},
  1551  		},
  1552  		// Blob transactions that don't meet the min blob gas price should be rejected
  1553  		{
  1554  			seeds: map[string]seed{
  1555  				"alice": {balance: 10000000},
  1556  			},
  1557  			adds: []addtx{
  1558  				{ // New account, no previous txs, nonce 0, but blob fee cap too low
  1559  					from: "alice",
  1560  					tx:   makeUnsignedTx(0, 1, 1, 0),
  1561  					err:  txpool.ErrTxGasPriceTooLow,
  1562  				},
  1563  				{ // Same as above but blob fee cap equals minimum, should be accepted
  1564  					from: "alice",
  1565  					tx:   makeUnsignedTx(0, 1, 1, params.BlobTxMinBlobGasprice),
  1566  					err:  nil,
  1567  				},
  1568  			},
  1569  		},
  1570  		// Tests issue #30518 where a refactor broke internal state invariants,
  1571  		// causing included transactions not to be properly accounted and thus
  1572  		// account states going our of sync with the chain.
  1573  		{
  1574  			seeds: map[string]seed{
  1575  				"alice": {
  1576  					balance: 1000000,
  1577  					txs: []*types.BlobTx{
  1578  						makeUnsignedTx(0, 1, 1, 1),
  1579  					},
  1580  				},
  1581  			},
  1582  			block: []addtx{
  1583  				{
  1584  					from: "alice",
  1585  					tx:   makeUnsignedTx(0, 1, 1, 1),
  1586  				},
  1587  			},
  1588  		},
  1589  	}
  1590  	for i, tt := range tests {
  1591  		// Create a temporary folder for the persistent backend
  1592  		storage := filepath.Join(t.TempDir(), fmt.Sprintf("test-%d", i))
  1593  
  1594  		os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
  1595  		store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
  1596  
  1597  		// Insert the seed transactions for the pool startup
  1598  		var (
  1599  			keys  = make(map[string]*ecdsa.PrivateKey)
  1600  			addrs = make(map[string]common.Address)
  1601  		)
  1602  		statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
  1603  		for acc, seed := range tt.seeds {
  1604  			// Generate a new random key/address for the seed account
  1605  			keys[acc], _ = crypto.GenerateKey()
  1606  			addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
  1607  
  1608  			// Seed the state database with this account
  1609  			statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified)
  1610  			statedb.SetNonce(addrs[acc], seed.nonce, tracing.NonceChangeUnspecified)
  1611  
  1612  			// Sign the seed transactions and store them in the data store
  1613  			for _, tx := range seed.txs {
  1614  				signed := types.MustSignNewTx(keys[acc], types.LatestSigner(params.MainnetChainConfig), tx)
  1615  				blob, _ := rlp.EncodeToBytes(signed)
  1616  				store.Put(blob)
  1617  			}
  1618  		}
  1619  		statedb.Commit(0, true, false)
  1620  		store.Close()
  1621  
  1622  		// Create a blob pool out of the pre-seeded dats
  1623  		chain := &testBlockChain{
  1624  			config:  params.MainnetChainConfig,
  1625  			basefee: uint256.NewInt(1050),
  1626  			blobfee: uint256.NewInt(105),
  1627  			statedb: statedb,
  1628  		}
  1629  		pool := New(Config{Datadir: storage}, chain, nil)
  1630  		if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
  1631  			t.Fatalf("test %d: failed to create blob pool: %v", i, err)
  1632  		}
  1633  		verifyPoolInternals(t, pool)
  1634  
  1635  		// Add each transaction one by one, verifying the pool internals in between
  1636  		for j, add := range tt.adds {
  1637  			signed, _ := types.SignNewTx(keys[add.from], types.LatestSigner(params.MainnetChainConfig), add.tx)
  1638  			if err := pool.add(signed); !errors.Is(err, add.err) {
  1639  				t.Errorf("test %d, tx %d: adding transaction error mismatch: have %v, want %v", i, j, err, add.err)
  1640  			}
  1641  			if add.err == nil {
  1642  				size, exist := pool.lookup.sizeOfTx(signed.Hash())
  1643  				if !exist {
  1644  					t.Errorf("test %d, tx %d: failed to lookup transaction's size", i, j)
  1645  				}
  1646  				if size != signed.Size() {
  1647  					t.Errorf("test %d, tx %d: transaction's size mismatches: have %v, want %v",
  1648  						i, j, size, signed.Size())
  1649  				}
  1650  			}
  1651  			verifyPoolInternals(t, pool)
  1652  		}
  1653  		verifyPoolInternals(t, pool)
  1654  
  1655  		// If the test contains a chain head event, run that and gain verify the internals
  1656  		if tt.block != nil {
  1657  			// Fake a header for the new set of transactions
  1658  			header := &types.Header{
  1659  				Number:     big.NewInt(int64(chain.CurrentBlock().Number.Uint64() + 1)),
  1660  				Difficulty: common.Big0,
  1661  				BaseFee:    chain.CurrentBlock().BaseFee, // invalid, but nothing checks it, yolo
  1662  			}
  1663  			// Inject the fake block into the chain
  1664  			txs := make([]*types.Transaction, len(tt.block))
  1665  			for j, inc := range tt.block {
  1666  				txs[j] = types.MustSignNewTx(keys[inc.from], types.LatestSigner(params.MainnetChainConfig), inc.tx)
  1667  			}
  1668  			chain.blocks = map[uint64]*types.Block{
  1669  				header.Number.Uint64(): types.NewBlockWithHeader(header).WithBody(types.Body{
  1670  					Transactions: txs,
  1671  				}),
  1672  			}
  1673  			// Apply the nonce updates to the state db
  1674  			for _, tx := range txs {
  1675  				sender, _ := types.Sender(types.LatestSigner(params.MainnetChainConfig), tx)
  1676  				chain.statedb.SetNonce(sender, tx.Nonce()+1, tracing.NonceChangeUnspecified)
  1677  			}
  1678  			pool.Reset(chain.CurrentBlock(), header)
  1679  			verifyPoolInternals(t, pool)
  1680  		}
  1681  		// Close down the test
  1682  		pool.Close()
  1683  	}
  1684  }
  1685  
  1686  // fakeBilly is a billy.Database implementation which just drops data on the floor.
  1687  type fakeBilly struct {
  1688  	billy.Database
  1689  	count uint64
  1690  }
  1691  
  1692  func (f *fakeBilly) Put(data []byte) (uint64, error) {
  1693  	f.count++
  1694  	return f.count, nil
  1695  }
  1696  
  1697  var _ billy.Database = (*fakeBilly)(nil)
  1698  
  1699  // Benchmarks the time it takes to assemble the lazy pending transaction list
  1700  // from the pool contents.
  1701  func BenchmarkPoolPending100Mb(b *testing.B) { benchmarkPoolPending(b, 100_000_000) }
  1702  func BenchmarkPoolPending1GB(b *testing.B)   { benchmarkPoolPending(b, 1_000_000_000) }
  1703  func BenchmarkPoolPending10GB(b *testing.B) {
  1704  	if testing.Short() {
  1705  		b.Skip("Skipping in short-mode")
  1706  	}
  1707  	benchmarkPoolPending(b, 10_000_000_000)
  1708  }
  1709  
  1710  func benchmarkPoolPending(b *testing.B, datacap uint64) {
  1711  	// Calculate the maximum number of transaction that would fit into the pool
  1712  	// and generate a set of random accounts to seed them with.
  1713  	capacity := datacap / params.BlobTxBlobGasPerBlob
  1714  
  1715  	var (
  1716  		basefee    = uint64(1050)
  1717  		blobfee    = uint64(105)
  1718  		signer     = types.LatestSigner(params.MainnetChainConfig)
  1719  		statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
  1720  		chain      = &testBlockChain{
  1721  			config:  params.MainnetChainConfig,
  1722  			basefee: uint256.NewInt(basefee),
  1723  			blobfee: uint256.NewInt(blobfee),
  1724  			statedb: statedb,
  1725  		}
  1726  		pool = New(Config{Datadir: ""}, chain, nil)
  1727  	)
  1728  
  1729  	if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
  1730  		b.Fatalf("failed to create blob pool: %v", err)
  1731  	}
  1732  	// Make the pool not use disk (just drop everything). This test never reads
  1733  	// back the data, it just iterates over the pool in-memory items
  1734  	pool.store = &fakeBilly{pool.store, 0}
  1735  	// Avoid validation - verifying all blob proofs take significant time
  1736  	// when the capacity is large. The purpose of this bench is to measure assembling
  1737  	// the lazies, not the kzg verifications.
  1738  	pool.txValidationFn = func(tx *types.Transaction, head *types.Header, signer types.Signer, opts *txpool.ValidationOptions) error {
  1739  		return nil // accept all
  1740  	}
  1741  	// Fill the pool up with one random transaction from each account with the
  1742  	// same price and everything to maximize the worst case scenario
  1743  	for i := 0; i < int(capacity); i++ {
  1744  		blobtx := makeUnsignedTx(0, 10, basefee+10, blobfee)
  1745  		blobtx.R = uint256.NewInt(1)
  1746  		blobtx.S = uint256.NewInt(uint64(100 + i))
  1747  		blobtx.V = uint256.NewInt(0)
  1748  		tx := types.NewTx(blobtx)
  1749  		addr, err := types.Sender(signer, tx)
  1750  		if err != nil {
  1751  			b.Fatal(err)
  1752  		}
  1753  		statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
  1754  		pool.add(tx)
  1755  	}
  1756  	statedb.Commit(0, true, false)
  1757  	defer pool.Close()
  1758  
  1759  	// Benchmark assembling the pending
  1760  	b.ResetTimer()
  1761  	b.ReportAllocs()
  1762  
  1763  	for i := 0; i < b.N; i++ {
  1764  		p := pool.Pending(txpool.PendingFilter{
  1765  			MinTip:  uint256.NewInt(1),
  1766  			BaseFee: chain.basefee,
  1767  			BlobFee: chain.blobfee,
  1768  		})
  1769  		if len(p) != int(capacity) {
  1770  			b.Fatalf("have %d want %d", len(p), capacity)
  1771  		}
  1772  	}
  1773  }