github.com/dim4egster/coreth@v0.10.2/plugin/evm/mempool_atomic_gossiping_test.go (about)

     1  // (c) 2019-2021, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package evm
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/dim4egster/coreth/params"
    10  
    11  	"github.com/dim4egster/qmallgo/ids"
    12  	"github.com/dim4egster/qmallgo/utils/crypto"
    13  	"github.com/dim4egster/qmallgo/vms/components/avax"
    14  	"github.com/dim4egster/qmallgo/vms/components/chain"
    15  	"github.com/dim4egster/qmallgo/vms/secp256k1fx"
    16  
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  // shows that a locally generated AtomicTx can be added to mempool and then
    21  // removed by inclusion in a block
    22  func TestMempoolAddLocallyCreateAtomicTx(t *testing.T) {
    23  	for _, name := range []string{"import", "export"} {
    24  		t.Run(name, func(t *testing.T) {
    25  			assert := assert.New(t)
    26  
    27  			// we use AP3 genesis here to not trip any block fees
    28  			issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase3, "", "")
    29  			defer func() {
    30  				err := vm.Shutdown()
    31  				assert.NoError(err)
    32  			}()
    33  			mempool := vm.mempool
    34  
    35  			// generate a valid and conflicting tx
    36  			var (
    37  				tx, conflictingTx *Tx
    38  			)
    39  			if name == "import" {
    40  				importTxs := createImportTxOptions(t, vm, sharedMemory)
    41  				tx, conflictingTx = importTxs[0], importTxs[1]
    42  			} else {
    43  				exportTxs := createExportTxOptions(t, vm, issuer, sharedMemory)
    44  				tx, conflictingTx = exportTxs[0], exportTxs[1]
    45  			}
    46  			txID := tx.ID()
    47  			conflictingTxID := conflictingTx.ID()
    48  
    49  			// add a tx to the mempool
    50  			err := vm.issueTx(tx, true /*=local*/)
    51  			assert.NoError(err)
    52  			has := mempool.has(txID)
    53  			assert.True(has, "valid tx not recorded into mempool")
    54  
    55  			// try to add a conflicting tx
    56  			err = vm.issueTx(conflictingTx, true /*=local*/)
    57  			assert.ErrorIs(err, errConflictingAtomicTx)
    58  			has = mempool.has(conflictingTxID)
    59  			assert.False(has, "conflicting tx in mempool")
    60  
    61  			<-issuer
    62  
    63  			has = mempool.has(txID)
    64  			assert.True(has, "valid tx not recorded into mempool")
    65  
    66  			// Show that BuildBlock generates a block containing [txID] and that it is
    67  			// still present in the mempool.
    68  			blk, err := vm.BuildBlock()
    69  			assert.NoError(err, "could not build block out of mempool")
    70  
    71  			evmBlk, ok := blk.(*chain.BlockWrapper).Block.(*Block)
    72  			assert.True(ok, "unknown block type")
    73  
    74  			assert.Equal(txID, evmBlk.atomicTxs[0].ID(), "block does not include expected transaction")
    75  
    76  			has = mempool.has(txID)
    77  			assert.True(has, "tx should stay in mempool until block is accepted")
    78  
    79  			err = blk.Verify()
    80  			assert.NoError(err)
    81  
    82  			err = blk.Accept()
    83  			assert.NoError(err)
    84  
    85  			has = mempool.has(txID)
    86  			assert.False(has, "tx shouldn't be in mempool after block is accepted")
    87  		})
    88  	}
    89  }
    90  
    91  // a valid tx shouldn't be added to the mempool if this would exceed the
    92  // mempool's max size
    93  func TestMempoolMaxMempoolSizeHandling(t *testing.T) {
    94  	assert := assert.New(t)
    95  
    96  	_, vm, _, sharedMemory, _ := GenesisVM(t, true, "", "", "")
    97  	defer func() {
    98  		err := vm.Shutdown()
    99  		assert.NoError(err)
   100  	}()
   101  	mempool := vm.mempool
   102  
   103  	// create candidate tx (we will drop before validation)
   104  	tx := createImportTxOptions(t, vm, sharedMemory)[0]
   105  
   106  	// shortcut to simulated almost filled mempool
   107  	mempool.maxSize = 0
   108  
   109  	assert.ErrorIs(mempool.AddTx(tx), errTooManyAtomicTx)
   110  	assert.False(mempool.has(tx.ID()))
   111  
   112  	// shortcut to simulated empty mempool
   113  	mempool.maxSize = defaultMempoolSize
   114  
   115  	assert.NoError(mempool.AddTx(tx))
   116  	assert.True(mempool.has(tx.ID()))
   117  }
   118  
   119  func createImportTx(t *testing.T, vm *VM, txID ids.ID, feeAmount uint64) *Tx {
   120  	var importAmount uint64 = 10000000
   121  	importTx := &UnsignedImportTx{
   122  		NetworkID:    testNetworkID,
   123  		BlockchainID: testCChainID,
   124  		SourceChain:  testXChainID,
   125  		ImportedInputs: []*avax.TransferableInput{
   126  			{
   127  				UTXOID: avax.UTXOID{
   128  					TxID:        txID,
   129  					OutputIndex: uint32(0),
   130  				},
   131  				Asset: avax.Asset{ID: testAvaxAssetID},
   132  				In: &secp256k1fx.TransferInput{
   133  					Amt: importAmount,
   134  					Input: secp256k1fx.Input{
   135  						SigIndices: []uint32{0},
   136  					},
   137  				},
   138  			},
   139  			{
   140  				UTXOID: avax.UTXOID{
   141  					TxID:        txID,
   142  					OutputIndex: uint32(1),
   143  				},
   144  				Asset: avax.Asset{ID: testAvaxAssetID},
   145  				In: &secp256k1fx.TransferInput{
   146  					Amt: importAmount,
   147  					Input: secp256k1fx.Input{
   148  						SigIndices: []uint32{0},
   149  					},
   150  				},
   151  			},
   152  		},
   153  		Outs: []EVMOutput{
   154  			{
   155  				Address: testEthAddrs[0],
   156  				Amount:  importAmount - feeAmount,
   157  				AssetID: testAvaxAssetID,
   158  			},
   159  			{
   160  				Address: testEthAddrs[1],
   161  				Amount:  importAmount,
   162  				AssetID: testAvaxAssetID,
   163  			},
   164  		},
   165  	}
   166  
   167  	// Sort the inputs and outputs to ensure the transaction is canonical
   168  	avax.SortTransferableInputs(importTx.ImportedInputs)
   169  	SortEVMOutputs(importTx.Outs)
   170  
   171  	tx := &Tx{UnsignedAtomicTx: importTx}
   172  	// Sign with the correct key
   173  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	return tx
   178  }
   179  
   180  // mempool will drop transaction with the lowest fee
   181  func TestMempoolPriorityDrop(t *testing.T) {
   182  	assert := assert.New(t)
   183  
   184  	// we use AP3 genesis here to not trip any block fees
   185  	_, vm, _, _, _ := GenesisVM(t, true, genesisJSONApricotPhase3, "", "")
   186  	defer func() {
   187  		err := vm.Shutdown()
   188  		assert.NoError(err)
   189  	}()
   190  	mempool := vm.mempool
   191  	mempool.maxSize = 1
   192  
   193  	tx1 := createImportTx(t, vm, ids.ID{1}, params.AvalancheAtomicTxFee)
   194  	assert.NoError(mempool.AddTx(tx1))
   195  	assert.True(mempool.has(tx1.ID()))
   196  	tx2 := createImportTx(t, vm, ids.ID{2}, params.AvalancheAtomicTxFee)
   197  	assert.ErrorIs(mempool.AddTx(tx2), errInsufficientAtomicTxFee)
   198  	assert.True(mempool.has(tx1.ID()))
   199  	assert.False(mempool.has(tx2.ID()))
   200  	tx3 := createImportTx(t, vm, ids.ID{3}, 2*params.AvalancheAtomicTxFee)
   201  	assert.NoError(mempool.AddTx(tx3))
   202  	assert.False(mempool.has(tx1.ID()))
   203  	assert.False(mempool.has(tx2.ID()))
   204  	assert.True(mempool.has(tx3.ID()))
   205  }