github.com/core-coin/go-core/v2@v2.1.9/core/state_processor_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "math/big" 21 "testing" 22 23 "golang.org/x/crypto/sha3" 24 25 "github.com/core-coin/go-core/v2/consensus/cryptore" 26 27 "github.com/core-coin/go-core/v2/common" 28 "github.com/core-coin/go-core/v2/consensus" 29 "github.com/core-coin/go-core/v2/core/rawdb" 30 "github.com/core-coin/go-core/v2/core/types" 31 "github.com/core-coin/go-core/v2/core/vm" 32 "github.com/core-coin/go-core/v2/crypto" 33 "github.com/core-coin/go-core/v2/params" 34 "github.com/core-coin/go-core/v2/trie" 35 ) 36 37 // TestStateProcessorErrors tests the output from the 'core' errors 38 // as defined in core/error.go. These errors are generated when the 39 // blockchain imports bad blocks, meaning blocks which have valid headers but 40 // contain invalid transactions 41 func TestStateProcessorErrors(t *testing.T) { 42 var ( 43 signer = types.NewNucleusSigner(big.NewInt(1)) 44 testKey, _ = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313") 45 db = rawdb.NewMemoryDatabase() 46 gspec = &Genesis{ 47 Config: params.MainnetChainConfig, 48 } 49 genesis = gspec.MustCommit(db) 50 blockchain, err = NewBlockChain(db, nil, gspec.Config, cryptore.NewFaker(), vm.Config{}, nil, nil) 51 ) 52 if err != nil { 53 t.Error(err) 54 } 55 defer blockchain.Stop() 56 var makeTx = func(nonce uint64, to common.Address, amount *big.Int, energyLimit uint64, energyPrice *big.Int, data []byte) *types.Transaction { 57 tx, err := types.SignTx(types.NewTransaction(nonce, to, amount, energyLimit, energyPrice, data), signer, testKey) 58 if err != nil { 59 t.Error(err) 60 } 61 return tx 62 } 63 for i, tt := range []struct { 64 txs []*types.Transaction 65 want string 66 }{ 67 { 68 txs: []*types.Transaction{ 69 makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 70 makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 71 }, 72 want: "could not apply tx 1 [0xf8bc550eaed9cdbdee2897934410fbff78ba05f3cfa3d1cbc53ade58d6f91eea]: nonce too low: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e, tx: 0 state: 1", 73 }, 74 { 75 txs: []*types.Transaction{ 76 makeTx(100, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 77 }, 78 want: "could not apply tx 0 [0xb0390f103112930b5f3105c7b4cf6f36ed5586d77654e28b97fa848c0dd1fde3]: nonce too high: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e, tx: 100 state: 0", 79 }, 80 { 81 txs: []*types.Transaction{ 82 makeTx(0, common.Address{}, big.NewInt(0), 21000000, nil, nil), 83 }, 84 want: "could not apply tx 0 [0x5b7c1c6a4531a327422151ab1fc7e62e67ae13456357bdf2ed14a6388bf4c23a]: energy limit reached", 85 }, 86 { 87 txs: []*types.Transaction{ 88 makeTx(0, common.Address{}, big.NewInt(1), params.TxEnergy, nil, nil), 89 }, 90 want: "could not apply tx 0 [0x9eca1a545fea71373e72f0cfc881047b6c4b191160ba9e7a50fdf6775c228557]: insufficient funds for transfer: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e", 91 }, 92 { 93 txs: []*types.Transaction{ 94 makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, big.NewInt(0xffffff), nil), 95 }, 96 want: "could not apply tx 0 [0x67c36b9e6c20ee836cbf7cd0f91ef407902cb33b2cb0529cb6ae5bf7c54fb7a4]: insufficient funds for energy * price + value: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e have 0 want 352321515000", 97 }, 98 { 99 txs: []*types.Transaction{ 100 makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 101 makeTx(1, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 102 makeTx(2, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil), 103 makeTx(3, common.Address{}, big.NewInt(0), params.TxEnergy-1000, big.NewInt(0), nil), 104 }, 105 want: "could not apply tx 3 [0x3590cc281751dce7f99b3cc2a32f74367353236004c9b0491aa05a37500e52fe]: intrinsic energy too low: have 20000, want 21000", 106 }, 107 // The last 'core' error is ErrEnergyUintOverflow: "energy uint64 overflow", but in order to 108 // trigger that one, we'd have to allocate a _huge_ chunk of data, such that the 109 // multiplication len(data) +energy_per_byte overflows uint64. Not testable at the moment 110 } { 111 block := GenerateBadBlock(genesis, cryptore.NewFaker(), tt.txs) 112 _, err := blockchain.InsertChain(types.Blocks{block}) 113 if err == nil { 114 t.Fatal("block imported without errors") 115 } 116 if have, want := err.Error(), tt.want; have != want { 117 t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) 118 } 119 } 120 } 121 122 // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be 123 // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently 124 // valid to be considered for import: 125 // - valid pow (fake), ancestry, difficulty, energylimit etc 126 func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions) *types.Block { 127 header := &types.Header{ 128 ParentHash: parent.Hash(), 129 Coinbase: parent.Coinbase(), 130 Difficulty: engine.CalcDifficulty(&fakeChainReader{params.MainnetChainConfig}, parent.Time()+10, &types.Header{ 131 Number: parent.Number(), 132 Time: parent.Time(), 133 Difficulty: parent.Difficulty(), 134 UncleHash: parent.UncleHash(), 135 }), 136 EnergyLimit: CalcEnergyLimit(parent, parent.EnergyLimit(), parent.EnergyLimit()), 137 Number: new(big.Int).Add(parent.Number(), common.Big1), 138 Time: parent.Time() + 10, 139 UncleHash: types.EmptyUncleHash, 140 } 141 var receipts []*types.Receipt 142 143 // The post-state result doesn't need to be correct (this is a bad block), but we do need something there 144 // Preferably something unique. So let's use a combo of blocknum + txhash 145 hasher := sha3.New256() 146 hasher.Write(header.Number.Bytes()) 147 var cumulativeEnergy uint64 148 for _, tx := range txs { 149 txh := tx.Hash() 150 hasher.Write(txh[:]) 151 receipt := types.NewReceipt(nil, false, cumulativeEnergy+tx.Energy()) 152 receipt.TxHash = tx.Hash() 153 receipt.EnergyUsed = tx.Energy() 154 receipts = append(receipts, receipt) 155 cumulativeEnergy += tx.Energy() 156 } 157 header.Root = common.BytesToHash(hasher.Sum(nil)) 158 // Assemble and return the final block for sealing 159 return types.NewBlock(header, txs, nil, receipts, new(trie.Trie)) 160 }