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