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