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