github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state_processor_test.go (about) 1 // (c) 2019-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2020 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package core 28 29 import ( 30 "math/big" 31 "testing" 32 33 "github.com/MetalBlockchain/subnet-evm/consensus" 34 "github.com/MetalBlockchain/subnet-evm/consensus/dummy" 35 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 36 "github.com/MetalBlockchain/subnet-evm/core/types" 37 "github.com/MetalBlockchain/subnet-evm/core/vm" 38 "github.com/MetalBlockchain/subnet-evm/params" 39 "github.com/MetalBlockchain/subnet-evm/precompile" 40 "github.com/MetalBlockchain/subnet-evm/trie" 41 "github.com/ethereum/go-ethereum/common" 42 "github.com/ethereum/go-ethereum/crypto" 43 "golang.org/x/crypto/sha3" 44 ) 45 46 var ( 47 config = params.TestChainConfig 48 signer = types.LatestSigner(config) 49 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 50 ) 51 52 func makeTx(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction { 53 tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey) 54 return tx 55 } 56 57 func mkDynamicTx(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction { 58 tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ 59 Nonce: nonce, 60 GasTipCap: gasTipCap, 61 GasFeeCap: gasFeeCap, 62 Gas: gasLimit, 63 To: &to, 64 Value: big.NewInt(0), 65 }), signer, testKey) 66 return tx 67 } 68 69 // TestStateProcessorErrors tests the output from the 'core' errors 70 // as defined in core/error.go. These errors are generated when the 71 // blockchain imports bad blocks, meaning blocks which have valid headers but 72 // contain invalid transactions 73 func TestStateProcessorErrors(t *testing.T) { 74 config.FeeConfig.MinBaseFee = params.TestMaxBaseFee 75 { // Tests against a 'recent' chain definition 76 var ( 77 db = rawdb.NewMemoryDatabase() 78 gspec = &Genesis{ 79 Config: config, 80 Alloc: GenesisAlloc{ 81 common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ 82 Balance: big.NewInt(2000000000000000000), // 2 ether 83 Nonce: 0, 84 }, 85 }, 86 GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(), 87 } 88 genesis = gspec.MustCommit(db) 89 blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{}) 90 ) 91 defer blockchain.Stop() 92 bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) 93 tooBigNumber := new(big.Int).Set(bigNumber) 94 tooBigNumber.Add(tooBigNumber, common.Big1) 95 for i, tt := range []struct { 96 txs []*types.Transaction 97 want string 98 }{ 99 { // ErrNonceTooLow 100 txs: []*types.Transaction{ 101 makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil), 102 makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil), 103 }, 104 want: "could not apply tx 1 [0x734d821c990099c6ae42d78072aadd3931c35328cf03ef4cf5b2a4ac9c398522]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1", 105 }, 106 { // ErrNonceTooHigh 107 txs: []*types.Transaction{ 108 makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil), 109 }, 110 want: "could not apply tx 0 [0x0df36254cfbef8ed6961b38fc68aecc777177166144c8a56bc8919e23a559bf4]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0", 111 }, 112 { // ErrGasLimitReached 113 txs: []*types.Transaction{ 114 makeTx(0, common.Address{}, big.NewInt(0), 8000001, big.NewInt(225000000000), nil), 115 }, 116 want: "could not apply tx 0 [0xfbe38b817aaa760c2766b56c019fcdba506560a28fd41c69ae96bdaa4569e317]: gas limit reached", 117 }, 118 { // ErrInsufficientFundsForTransfer 119 txs: []*types.Transaction{ 120 makeTx(0, common.Address{}, big.NewInt(2000000000000000000), params.TxGas, big.NewInt(225000000000), nil), 121 }, 122 want: "could not apply tx 0 [0xae1601ef55b676ebb824ee7e16a0d14af725b7f9cf5ec79e21f14833c26b5b35]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2004725000000000000", 123 }, 124 { // ErrInsufficientFunds 125 txs: []*types.Transaction{ 126 makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil), 127 }, 128 want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 18900000000000000000000", 129 }, 130 // ErrGasUintOverflow 131 // One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow", 132 // In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the 133 // multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment 134 { // ErrIntrinsicGas 135 txs: []*types.Transaction{ 136 makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(225000000000), nil), 137 }, 138 want: "could not apply tx 0 [0x2fc3e3b5cc26917d413e26983fe189475f47d4f0757e32aaa5561fcb9c9dc432]: intrinsic gas too low: have 20000, want 21000", 139 }, 140 { // ErrGasLimitReached 141 txs: []*types.Transaction{ 142 makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*381, big.NewInt(225000000000), nil), 143 }, 144 want: "could not apply tx 0 [0x9ee548e001369418ae53aaa11b5d823f081cc7fa9c9a7ee71a978ae17a2aece0]: gas limit reached", 145 }, 146 { // ErrFeeCapTooLow 147 txs: []*types.Transaction{ 148 mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)), 149 }, 150 want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 225000000000", 151 }, 152 { // ErrTipVeryHigh 153 txs: []*types.Transaction{ 154 mkDynamicTx(0, common.Address{}, params.TxGas, tooBigNumber, big.NewInt(1)), 155 }, 156 want: "could not apply tx 0 [0x15b8391b9981f266b32f3ab7da564bbeb3d6c21628364ea9b32a21139f89f712]: max priority fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas bit length: 257", 157 }, 158 { // ErrFeeCapVeryHigh 159 txs: []*types.Transaction{ 160 mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), tooBigNumber), 161 }, 162 want: "could not apply tx 0 [0x48bc299b83fdb345c57478f239e89814bb3063eb4e4b49f3b6057a69255c16bd]: max fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas bit length: 257", 163 }, 164 { // ErrTipAboveFeeCap 165 txs: []*types.Transaction{ 166 mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(2), big.NewInt(1)), 167 }, 168 want: "could not apply tx 0 [0xf987a31ff0c71895780a7612f965a0c8b056deb54e020bb44fa478092f14c9b4]: max priority fee per gas higher than max fee per gas: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas: 2, maxFeePerGas: 1", 169 }, 170 { // ErrInsufficientFunds 171 // Available balance: 1000000000000000000 172 // Effective cost: 18375000021000 173 // FeeCap * gas: 1050000000000000000 174 // This test is designed to have the effective cost be covered by the balance, but 175 // the extended requirement on FeeCap*gas < balance to fail 176 txs: []*types.Transaction{ 177 mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(100000000000000)), 178 }, 179 want: "could not apply tx 0 [0x3388378ed60640e75d2edf728d5528a305f599997abc4f23ec46b351b6197499]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2100000000000000000", 180 }, 181 { // Another ErrInsufficientFunds, this one to ensure that feecap/tip of max u256 is allowed 182 txs: []*types.Transaction{ 183 mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber), 184 }, 185 want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000", 186 }, 187 } { 188 block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config) 189 _, err := blockchain.InsertChain(types.Blocks{block}) 190 if err == nil { 191 t.Fatal("block imported without errors") 192 } 193 if have, want := err.Error(), tt.want; have != want { 194 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 195 } 196 } 197 } 198 199 // ErrTxTypeNotSupported, For this, we need an older chain 200 { 201 var ( 202 db = rawdb.NewMemoryDatabase() 203 gspec = &Genesis{ 204 Config: ¶ms.ChainConfig{ 205 ChainID: big.NewInt(1), 206 FeeConfig: params.DefaultFeeConfig, 207 HomesteadBlock: big.NewInt(0), 208 EIP150Block: big.NewInt(0), 209 EIP150Hash: common.Hash{}, 210 EIP155Block: big.NewInt(0), 211 EIP158Block: big.NewInt(0), 212 ByzantiumBlock: big.NewInt(0), 213 ConstantinopleBlock: big.NewInt(0), 214 PetersburgBlock: big.NewInt(0), 215 IstanbulBlock: big.NewInt(0), 216 MuirGlacierBlock: big.NewInt(0), 217 }, 218 Alloc: GenesisAlloc{ 219 common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ 220 Balance: big.NewInt(1000000000000000000), // 1 ether 221 Nonce: 0, 222 }, 223 }, 224 GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(), 225 } 226 genesis = gspec.MustCommit(db) 227 blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{}) 228 ) 229 defer blockchain.Stop() 230 for i, tt := range []struct { 231 txs []*types.Transaction 232 want string 233 }{ 234 { // ErrTxTypeNotSupported 235 txs: []*types.Transaction{ 236 mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), 237 }, 238 want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: transaction type not supported", 239 }, 240 } { 241 block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config) 242 _, err := blockchain.InsertChain(types.Blocks{block}) 243 if err == nil { 244 t.Fatal("block imported without errors") 245 } 246 if have, want := err.Error(), tt.want; have != want { 247 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 248 } 249 } 250 } 251 252 // ErrSenderNoEOA, for this we need the sender to have contract code 253 { 254 var ( 255 db = rawdb.NewMemoryDatabase() 256 gspec = &Genesis{ 257 Config: config, 258 Alloc: GenesisAlloc{ 259 common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ 260 Balance: big.NewInt(1000000000000000000), // 1 ether 261 Nonce: 0, 262 Code: common.FromHex("0xB0B0FACE"), 263 }, 264 }, 265 GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(), 266 } 267 genesis = gspec.MustCommit(db) 268 blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{}) 269 ) 270 defer blockchain.Stop() 271 for i, tt := range []struct { 272 txs []*types.Transaction 273 want string 274 }{ 275 { // ErrSenderNoEOA 276 txs: []*types.Transaction{ 277 mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), 278 }, 279 want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1", 280 }, 281 } { 282 block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config) 283 _, err := blockchain.InsertChain(types.Blocks{block}) 284 if err == nil { 285 t.Fatal("block imported without errors") 286 } 287 if have, want := err.Error(), tt.want; have != want { 288 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 289 } 290 } 291 } 292 } 293 294 // TestBadTxAllowListBlock tests the output generated when the 295 // blockchain imports a bad block with a transaction from a 296 // non-whitelisted TX Allow List address. 297 func TestBadTxAllowListBlock(t *testing.T) { 298 var ( 299 db = rawdb.NewMemoryDatabase() 300 testAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") 301 302 config = ¶ms.ChainConfig{ 303 ChainID: big.NewInt(1), 304 FeeConfig: params.DefaultFeeConfig, 305 HomesteadBlock: big.NewInt(0), 306 EIP150Block: big.NewInt(0), 307 EIP150Hash: common.Hash{}, 308 EIP155Block: big.NewInt(0), 309 EIP158Block: big.NewInt(0), 310 ByzantiumBlock: big.NewInt(0), 311 ConstantinopleBlock: big.NewInt(0), 312 PetersburgBlock: big.NewInt(0), 313 IstanbulBlock: big.NewInt(0), 314 MuirGlacierBlock: big.NewInt(0), 315 NetworkUpgrades: params.NetworkUpgrades{ 316 SubnetEVMTimestamp: big.NewInt(0), 317 }, 318 PrecompileUpgrade: params.PrecompileUpgrade{ 319 TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(0), nil, nil), 320 }, 321 } 322 signer = types.LatestSigner(config) 323 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 324 325 gspec = &Genesis{ 326 Config: config, 327 Alloc: GenesisAlloc{ 328 testAddr: GenesisAccount{ 329 Balance: big.NewInt(1000000000000000000), // 1 ether 330 Nonce: 0, 331 }, 332 }, 333 334 GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(), 335 } 336 genesis = gspec.MustCommit(db) 337 blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{}) 338 ) 339 340 mkDynamicTx := func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction { 341 tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ 342 Nonce: nonce, 343 GasTipCap: gasTipCap, 344 GasFeeCap: gasFeeCap, 345 Gas: gasLimit, 346 To: &to, 347 Value: big.NewInt(0), 348 }), signer, testKey) 349 return tx 350 } 351 352 defer blockchain.Stop() 353 for i, tt := range []struct { 354 txs []*types.Transaction 355 want string 356 }{ 357 { // Nonwhitelisted address 358 txs: []*types.Transaction{ 359 mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(225000000000)), 360 }, 361 want: "could not apply tx 0 [0xc5725e8baac950b2925dd4fea446ccddead1cc0affdae18b31a7d910629d9225]: cannot issue transaction from non-allow listed address: 0x71562b71999873DB5b286dF957af199Ec94617F7", 362 }, 363 } { 364 block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config) 365 _, err := blockchain.InsertChain(types.Blocks{block}) 366 if err == nil { 367 t.Fatal("block imported without errors") 368 } 369 if have, want := err.Error(), tt.want; have != want { 370 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 371 } 372 } 373 } 374 375 // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be 376 // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently 377 // valid to be considered for import: 378 // - valid pow (fake), ancestry, difficulty, gaslimit etc 379 func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { 380 header := &types.Header{ 381 ParentHash: parent.Hash(), 382 Coinbase: parent.Coinbase(), 383 Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ 384 Number: parent.Number(), 385 Time: parent.Time(), 386 Difficulty: parent.Difficulty(), 387 UncleHash: parent.UncleHash(), 388 }), 389 GasLimit: parent.GasLimit(), 390 Number: new(big.Int).Add(parent.Number(), common.Big1), 391 Time: parent.Time() + 10, 392 UncleHash: types.EmptyUncleHash, 393 } 394 395 if config.IsSubnetEVM(new(big.Int).SetUint64(header.Time)) { 396 header.Extra, header.BaseFee, _ = dummy.CalcBaseFee(config, config.FeeConfig, parent.Header(), header.Time) 397 header.BlockGasCost = big.NewInt(0) 398 } 399 var receipts []*types.Receipt 400 // The post-state result doesn't need to be correct (this is a bad block), but we do need something there 401 // Preferably something unique. So let's use a combo of blocknum + txhash 402 hasher := sha3.NewLegacyKeccak256() 403 hasher.Write(header.Number.Bytes()) 404 var cumulativeGas uint64 405 for _, tx := range txs { 406 txh := tx.Hash() 407 hasher.Write(txh[:]) 408 receipt := types.NewReceipt(nil, false, cumulativeGas+tx.Gas()) 409 receipt.TxHash = tx.Hash() 410 receipt.GasUsed = tx.Gas() 411 receipts = append(receipts, receipt) 412 cumulativeGas += tx.Gas() 413 } 414 header.Root = common.BytesToHash(hasher.Sum(nil)) 415 // Assemble and return the final block for sealing 416 return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) 417 }