github.com/ubiq/go-ubiq/v6@v6.0.0/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/ubiq/go-ubiq/v6/common" 25 "github.com/ubiq/go-ubiq/v6/common/math" 26 "github.com/ubiq/go-ubiq/v6/consensus" 27 "github.com/ubiq/go-ubiq/v6/consensus/misc" 28 "github.com/ubiq/go-ubiq/v6/consensus/ubqhash" 29 "github.com/ubiq/go-ubiq/v6/core/rawdb" 30 "github.com/ubiq/go-ubiq/v6/core/types" 31 "github.com/ubiq/go-ubiq/v6/core/vm" 32 "github.com/ubiq/go-ubiq/v6/crypto" 33 "github.com/ubiq/go-ubiq/v6/params" 34 "github.com/ubiq/go-ubiq/v6/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 BerlinBlock: big.NewInt(0), 55 LondonBlock: big.NewInt(0), 56 Ubqhash: new(params.UbqhashConfig), 57 } 58 signer = types.LatestSigner(config) 59 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 60 key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020") 61 ) 62 var makeTx = func(key *ecdsa.PrivateKey, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction { 63 tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, key) 64 return tx 65 } 66 var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction { 67 tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ 68 Nonce: nonce, 69 GasTipCap: gasTipCap, 70 GasFeeCap: gasFeeCap, 71 Gas: gasLimit, 72 To: &to, 73 Value: big.NewInt(0), 74 }), signer, key1) 75 return tx 76 } 77 { // Tests against a 'recent' chain definition 78 var ( 79 db = rawdb.NewMemoryDatabase() 80 gspec = &Genesis{ 81 Config: config, 82 Alloc: GenesisAlloc{ 83 common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ 84 Balance: big.NewInt(2000000000000000000), // 2 ether 85 Nonce: 0, 86 }, 87 common.HexToAddress("0xfd0810DD14796680f72adf1a371963d0745BCc64"): GenesisAccount{ 88 Balance: big.NewInt(1000000000000000000), // 1 ether 89 Nonce: math.MaxUint64, 90 }, 91 }, 92 } 93 genesis = gspec.MustCommit(db) 94 blockchain, _ = NewBlockChain(db, nil, gspec.Config, ubqhash.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(70000000000), nil), 107 makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(70000000000), nil), 108 }, 109 want: "could not apply tx 1 [0x035a4d54498b8faecac7ead306be8d5c641d81150da56d4ca0011820c9d0e732]: 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(70000000000), nil), 126 }, 127 want: "could not apply tx 0 [0x71f496a82fafcb2e3cab0e27796b10984702fd00ea7ad648af22397cb05652a8]: gas limit reached", 128 }, 129 { // ErrInsufficientFundsForTransfer 130 txs: []*types.Transaction{ 131 makeTx(key1, 0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(800000000000000), nil), 132 }, 133 want: "could not apply tx 0 [0x95c504430523b9af2e3765f7a79b5a77275dd329a1f79d7251121b286a80c667]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 17800000000000000000", 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 2000000000000000000 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(70000000000), nil), 148 }, 149 want: "could not apply tx 0 [0x0d0ca7d886da6c28ac094d3c2d2d0783b3753c9b92fcd2987c8d21b87fceb69f]: 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(70000000000), nil), 154 }, 155 want: "could not apply tx 0 [0x71f496a82fafcb2e3cab0e27796b10984702fd00ea7ad648af22397cb05652a8]: 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: 70000000000", 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(500000000000000)), 189 }, 190 want: "could not apply tx 0 [0x3e4bc338670810e7edcd7570dce67ee4e4ac9e38fcea6febc51f89d9bd7fe4ec]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 10500000000000000000", 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 2000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000", 197 }, 198 } { 199 block := GenerateBadBlock(genesis, ubqhash.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 }, 226 Alloc: GenesisAlloc{ 227 common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ 228 Balance: big.NewInt(1000000000000000000), // 1 ether 229 Nonce: 0, 230 }, 231 }, 232 } 233 genesis = gspec.MustCommit(db) 234 blockchain, _ = NewBlockChain(db, nil, gspec.Config, ubqhash.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(genesis, ubqhash.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 genesis = gspec.MustCommit(db) 274 blockchain, _ = NewBlockChain(db, nil, gspec.Config, ubqhash.NewFaker(), vm.Config{}, nil, nil) 275 ) 276 defer blockchain.Stop() 277 for i, tt := range []struct { 278 txs []*types.Transaction 279 want string 280 }{ 281 { // ErrSenderNoEOA 282 txs: []*types.Transaction{ 283 mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), 284 }, 285 want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1", 286 }, 287 } { 288 block := GenerateBadBlock(genesis, ubqhash.NewFaker(), tt.txs, gspec.Config) 289 _, err := blockchain.InsertChain(types.Blocks{block}) 290 if err == nil { 291 t.Fatal("block imported without errors") 292 } 293 if have, want := err.Error(), tt.want; have != want { 294 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 295 } 296 } 297 } 298 } 299 300 // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be 301 // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently 302 // valid to be considered for import: 303 // - valid pow (fake), ancestry, difficulty, gaslimit etc 304 func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { 305 header := &types.Header{ 306 ParentHash: parent.Hash(), 307 Coinbase: parent.Coinbase(), 308 Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ 309 Number: parent.Number(), 310 Time: parent.Time(), 311 Difficulty: parent.Difficulty(), 312 UncleHash: parent.UncleHash(), 313 }), 314 GasLimit: parent.GasLimit(), 315 Number: new(big.Int).Add(parent.Number(), common.Big1), 316 Time: parent.Time() + 10, 317 UncleHash: types.EmptyUncleHash, 318 } 319 if config.IsLondon(header.Number) { 320 header.BaseFee = misc.CalcBaseFee(config, parent.Header()) 321 } 322 var receipts []*types.Receipt 323 // The post-state result doesn't need to be correct (this is a bad block), but we do need something there 324 // Preferably something unique. So let's use a combo of blocknum + txhash 325 hasher := sha3.NewLegacyKeccak256() 326 hasher.Write(header.Number.Bytes()) 327 var cumulativeGas uint64 328 for _, tx := range txs { 329 txh := tx.Hash() 330 hasher.Write(txh[:]) 331 receipt := types.NewReceipt(nil, false, cumulativeGas+tx.Gas()) 332 receipt.TxHash = tx.Hash() 333 receipt.GasUsed = tx.Gas() 334 receipts = append(receipts, receipt) 335 cumulativeGas += tx.Gas() 336 } 337 header.Root = common.BytesToHash(hasher.Sum(nil)) 338 // Assemble and return the final block for sealing 339 return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) 340 }