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