gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/tests/block_test_util.go (about) 1 // Copyright 2015 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 tests implements execution of Ethereum JSON tests. 18 package tests 19 20 import ( 21 "bytes" 22 "encoding/hex" 23 "encoding/json" 24 "fmt" 25 "math/big" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/common/math" 30 "github.com/ethereum/go-ethereum/consensus" 31 "github.com/ethereum/go-ethereum/consensus/ethash" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/rawdb" 34 "github.com/ethereum/go-ethereum/core/state" 35 "github.com/ethereum/go-ethereum/core/state/snapshot" 36 "github.com/ethereum/go-ethereum/core/types" 37 "github.com/ethereum/go-ethereum/core/vm" 38 "github.com/ethereum/go-ethereum/params" 39 "github.com/ethereum/go-ethereum/rlp" 40 ) 41 42 // A BlockTest checks handling of entire blocks. 43 type BlockTest struct { 44 json btJSON 45 } 46 47 // UnmarshalJSON implements json.Unmarshaler interface. 48 func (t *BlockTest) UnmarshalJSON(in []byte) error { 49 return json.Unmarshal(in, &t.json) 50 } 51 52 type btJSON struct { 53 Blocks []btBlock `json:"blocks"` 54 Genesis btHeader `json:"genesisBlockHeader"` 55 Pre core.GenesisAlloc `json:"pre"` 56 Post core.GenesisAlloc `json:"postState"` 57 BestBlock common.UnprefixedHash `json:"lastblockhash"` 58 Network string `json:"network"` 59 SealEngine string `json:"sealEngine"` 60 } 61 62 type btBlock struct { 63 BlockHeader *btHeader 64 Rlp string 65 UncleHeaders []*btHeader 66 } 67 68 //go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go 69 70 type btHeader struct { 71 Bloom types.Bloom 72 Coinbase common.Address 73 MixHash common.Hash 74 Nonce types.BlockNonce 75 Number *big.Int 76 Hash common.Hash 77 ParentHash common.Hash 78 ReceiptTrie common.Hash 79 StateRoot common.Hash 80 TransactionsTrie common.Hash 81 UncleHash common.Hash 82 ExtraData []byte 83 Difficulty *big.Int 84 GasLimit uint64 85 GasUsed uint64 86 Timestamp uint64 87 } 88 89 type btHeaderMarshaling struct { 90 ExtraData hexutil.Bytes 91 Number *math.HexOrDecimal256 92 Difficulty *math.HexOrDecimal256 93 GasLimit math.HexOrDecimal64 94 GasUsed math.HexOrDecimal64 95 Timestamp math.HexOrDecimal64 96 } 97 98 func (t *BlockTest) Run(snapshotter bool) error { 99 config, ok := Forks[t.json.Network] 100 if !ok { 101 return UnsupportedForkError{t.json.Network} 102 } 103 104 // import pre accounts & construct test genesis block & state root 105 db := rawdb.NewMemoryDatabase() 106 gblock, err := t.genesis(config).Commit(db) 107 if err != nil { 108 return err 109 } 110 if gblock.Hash() != t.json.Genesis.Hash { 111 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 112 } 113 if gblock.Root() != t.json.Genesis.StateRoot { 114 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 115 } 116 var engine consensus.Engine 117 if t.json.SealEngine == "NoProof" { 118 engine = ethash.NewFaker() 119 } else { 120 engine = ethash.NewShared() 121 } 122 cache := &core.CacheConfig{TrieCleanLimit: 0} 123 if snapshotter { 124 cache.SnapshotLimit = 1 125 cache.SnapshotWait = true 126 } 127 chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil) 128 if err != nil { 129 return err 130 } 131 defer chain.Stop() 132 133 validBlocks, err := t.insertBlocks(chain) 134 if err != nil { 135 return err 136 } 137 cmlast := chain.CurrentBlock().Hash() 138 if common.Hash(t.json.BestBlock) != cmlast { 139 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 140 } 141 newDB, err := chain.State() 142 if err != nil { 143 return err 144 } 145 if err = t.validatePostState(newDB); err != nil { 146 return fmt.Errorf("post state validation failed: %v", err) 147 } 148 // Cross-check the snapshot-to-hash against the trie hash 149 if snapshotter { 150 snapTree := chain.Snapshot() 151 root := chain.CurrentBlock().Root() 152 it, err := snapTree.AccountIterator(root, common.Hash{}) 153 if err != nil { 154 return fmt.Errorf("Could not create iterator for root %x: %v", root, err) 155 } 156 generatedRoot := snapshot.GenerateTrieRoot(it) 157 if generatedRoot != root { 158 return fmt.Errorf("Snapshot corruption, got %d exp %d", generatedRoot, root) 159 } 160 } 161 return t.validateImportedHeaders(chain, validBlocks) 162 } 163 164 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 165 return &core.Genesis{ 166 Config: config, 167 Nonce: t.json.Genesis.Nonce.Uint64(), 168 Timestamp: t.json.Genesis.Timestamp, 169 ParentHash: t.json.Genesis.ParentHash, 170 ExtraData: t.json.Genesis.ExtraData, 171 GasLimit: t.json.Genesis.GasLimit, 172 GasUsed: t.json.Genesis.GasUsed, 173 Difficulty: t.json.Genesis.Difficulty, 174 Mixhash: t.json.Genesis.MixHash, 175 Coinbase: t.json.Genesis.Coinbase, 176 Alloc: t.json.Pre, 177 } 178 } 179 180 /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 181 182 Whether a block is valid or not is a bit subtle, it's defined by presence of 183 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 184 invalid and we must verify that we do not accept it. 185 186 Since some tests mix valid and invalid blocks we need to check this for every block. 187 188 If a block is invalid it does not necessarily fail the test, if it's invalidness is 189 expected we are expected to ignore it and continue processing and then validate the 190 post state. 191 */ 192 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 193 validBlocks := make([]btBlock, 0) 194 // insert the test blocks, which will execute all transactions 195 for _, b := range t.json.Blocks { 196 cb, err := b.decode() 197 if err != nil { 198 if b.BlockHeader == nil { 199 continue // OK - block is supposed to be invalid, continue with next block 200 } else { 201 return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err) 202 } 203 } 204 // RLP decoding worked, try to insert into chain: 205 blocks := types.Blocks{cb} 206 i, err := blockchain.InsertChain(blocks) 207 if err != nil { 208 if b.BlockHeader == nil { 209 continue // OK - block is supposed to be invalid, continue with next block 210 } else { 211 return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err) 212 } 213 } 214 if b.BlockHeader == nil { 215 return nil, fmt.Errorf("block insertion should have failed") 216 } 217 218 // validate RLP decoding by checking all values against test file JSON 219 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 220 return nil, fmt.Errorf("deserialised block header validation failed: %v", err) 221 } 222 validBlocks = append(validBlocks, b) 223 } 224 return validBlocks, nil 225 } 226 227 func validateHeader(h *btHeader, h2 *types.Header) error { 228 if h.Bloom != h2.Bloom { 229 return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom) 230 } 231 if h.Coinbase != h2.Coinbase { 232 return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 233 } 234 if h.MixHash != h2.MixDigest { 235 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 236 } 237 if h.Nonce != h2.Nonce { 238 return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce) 239 } 240 if h.Number.Cmp(h2.Number) != 0 { 241 return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number) 242 } 243 if h.ParentHash != h2.ParentHash { 244 return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 245 } 246 if h.ReceiptTrie != h2.ReceiptHash { 247 return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 248 } 249 if h.TransactionsTrie != h2.TxHash { 250 return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 251 } 252 if h.StateRoot != h2.Root { 253 return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root) 254 } 255 if h.UncleHash != h2.UncleHash { 256 return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 257 } 258 if !bytes.Equal(h.ExtraData, h2.Extra) { 259 return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra) 260 } 261 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 262 return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 263 } 264 if h.GasLimit != h2.GasLimit { 265 return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 266 } 267 if h.GasUsed != h2.GasUsed { 268 return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 269 } 270 if h.Timestamp != h2.Time { 271 return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time) 272 } 273 return nil 274 } 275 276 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 277 // validate post state accounts in test file against what we have in state db 278 for addr, acct := range t.json.Post { 279 // address is indirectly verified by the other fields, as it's the db key 280 code2 := statedb.GetCode(addr) 281 balance2 := statedb.GetBalance(addr) 282 nonce2 := statedb.GetNonce(addr) 283 if !bytes.Equal(code2, acct.Code) { 284 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 285 } 286 if balance2.Cmp(acct.Balance) != 0 { 287 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 288 } 289 if nonce2 != acct.Nonce { 290 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 291 } 292 } 293 return nil 294 } 295 296 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 297 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 298 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 299 for _, b := range validBlocks { 300 bmap[b.BlockHeader.Hash] = b 301 } 302 // iterate over blocks backwards from HEAD and validate imported 303 // headers vs test file. some tests have reorgs, and we import 304 // block-by-block, so we can only validate imported headers after 305 // all blocks have been processed by BlockChain, as they may not 306 // be part of the longest chain until last block is imported. 307 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 308 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 309 return fmt.Errorf("imported block header validation failed: %v", err) 310 } 311 } 312 return nil 313 } 314 315 func (bb *btBlock) decode() (*types.Block, error) { 316 data, err := hexutil.Decode(bb.Rlp) 317 if err != nil { 318 return nil, err 319 } 320 var b types.Block 321 err = rlp.DecodeBytes(data, &b) 322 return &b, err 323 }