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 }