github.com/ethereum/go-ethereum@v1.16.1/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 stdmath "math" 26 "math/big" 27 "os" 28 "reflect" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/common/hexutil" 32 "github.com/ethereum/go-ethereum/common/math" 33 "github.com/ethereum/go-ethereum/consensus/beacon" 34 "github.com/ethereum/go-ethereum/consensus/ethash" 35 "github.com/ethereum/go-ethereum/core" 36 "github.com/ethereum/go-ethereum/core/rawdb" 37 "github.com/ethereum/go-ethereum/core/state" 38 "github.com/ethereum/go-ethereum/core/tracing" 39 "github.com/ethereum/go-ethereum/core/types" 40 "github.com/ethereum/go-ethereum/core/vm" 41 "github.com/ethereum/go-ethereum/log" 42 "github.com/ethereum/go-ethereum/params" 43 "github.com/ethereum/go-ethereum/rlp" 44 "github.com/ethereum/go-ethereum/triedb" 45 "github.com/ethereum/go-ethereum/triedb/hashdb" 46 "github.com/ethereum/go-ethereum/triedb/pathdb" 47 ) 48 49 // A BlockTest checks handling of entire blocks. 50 type BlockTest struct { 51 json btJSON 52 } 53 54 // UnmarshalJSON implements json.Unmarshaler interface. 55 func (t *BlockTest) UnmarshalJSON(in []byte) error { 56 return json.Unmarshal(in, &t.json) 57 } 58 59 type btJSON struct { 60 Blocks []btBlock `json:"blocks"` 61 Genesis btHeader `json:"genesisBlockHeader"` 62 Pre types.GenesisAlloc `json:"pre"` 63 Post types.GenesisAlloc `json:"postState"` 64 BestBlock common.UnprefixedHash `json:"lastblockhash"` 65 Network string `json:"network"` 66 SealEngine string `json:"sealEngine"` 67 } 68 69 type btBlock struct { 70 BlockHeader *btHeader 71 ExpectException string 72 Rlp string 73 UncleHeaders []*btHeader 74 } 75 76 //go:generate go run github.com/fjl/gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go 77 78 type btHeader struct { 79 Bloom types.Bloom 80 Coinbase common.Address 81 MixHash common.Hash 82 Nonce types.BlockNonce 83 Number *big.Int 84 Hash common.Hash 85 ParentHash common.Hash 86 ReceiptTrie common.Hash 87 StateRoot common.Hash 88 TransactionsTrie common.Hash 89 UncleHash common.Hash 90 ExtraData []byte 91 Difficulty *big.Int 92 GasLimit uint64 93 GasUsed uint64 94 Timestamp uint64 95 BaseFeePerGas *big.Int 96 WithdrawalsRoot *common.Hash 97 BlobGasUsed *uint64 98 ExcessBlobGas *uint64 99 ParentBeaconBlockRoot *common.Hash 100 } 101 102 type btHeaderMarshaling struct { 103 ExtraData hexutil.Bytes 104 Number *math.HexOrDecimal256 105 Difficulty *math.HexOrDecimal256 106 GasLimit math.HexOrDecimal64 107 GasUsed math.HexOrDecimal64 108 Timestamp math.HexOrDecimal64 109 BaseFeePerGas *math.HexOrDecimal256 110 BlobGasUsed *math.HexOrDecimal64 111 ExcessBlobGas *math.HexOrDecimal64 112 } 113 114 func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { 115 config, ok := Forks[t.json.Network] 116 if !ok { 117 return UnsupportedForkError{t.json.Network} 118 } 119 // import pre accounts & construct test genesis block & state root 120 var ( 121 db = rawdb.NewMemoryDatabase() 122 tconf = &triedb.Config{ 123 Preimages: true, 124 } 125 ) 126 if scheme == rawdb.PathScheme { 127 tconf.PathDB = pathdb.Defaults 128 } else { 129 tconf.HashDB = hashdb.Defaults 130 } 131 // Commit genesis state 132 gspec := t.genesis(config) 133 134 // if ttd is not specified, set an arbitrary huge value 135 if gspec.Config.TerminalTotalDifficulty == nil { 136 gspec.Config.TerminalTotalDifficulty = big.NewInt(stdmath.MaxInt64) 137 } 138 triedb := triedb.NewDatabase(db, tconf) 139 gblock, err := gspec.Commit(db, triedb) 140 if err != nil { 141 return err 142 } 143 triedb.Close() // close the db to prevent memory leak 144 145 if gblock.Hash() != t.json.Genesis.Hash { 146 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 147 } 148 if gblock.Root() != t.json.Genesis.StateRoot { 149 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 150 } 151 // Wrap the original engine within the beacon-engine 152 engine := beacon.New(ethash.NewFaker()) 153 154 options := &core.BlockChainConfig{ 155 TrieCleanLimit: 0, 156 StateScheme: scheme, 157 Preimages: true, 158 TxLookupLimit: -1, // disable tx indexing 159 VmConfig: vm.Config{ 160 Tracer: tracer, 161 StatelessSelfValidation: witness, 162 }, 163 } 164 if snapshotter { 165 options.SnapshotLimit = 1 166 options.SnapshotWait = true 167 } 168 chain, err := core.NewBlockChain(db, gspec, engine, options) 169 if err != nil { 170 return err 171 } 172 defer chain.Stop() 173 174 validBlocks, err := t.insertBlocks(chain) 175 if err != nil { 176 return err 177 } 178 // Import succeeded: regardless of whether the _test_ succeeds or not, schedule 179 // the post-check to run 180 if postCheck != nil { 181 defer postCheck(result, chain) 182 } 183 cmlast := chain.CurrentBlock().Hash() 184 if common.Hash(t.json.BestBlock) != cmlast { 185 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 186 } 187 newDB, err := chain.State() 188 if err != nil { 189 return err 190 } 191 if err = t.validatePostState(newDB); err != nil { 192 return fmt.Errorf("post state validation failed: %v", err) 193 } 194 // Cross-check the snapshot-to-hash against the trie hash 195 if snapshotter { 196 if chain.Snapshots() != nil { 197 if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil { 198 return err 199 } 200 } 201 } 202 return t.validateImportedHeaders(chain, validBlocks) 203 } 204 205 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 206 return &core.Genesis{ 207 Config: config, 208 Nonce: t.json.Genesis.Nonce.Uint64(), 209 Timestamp: t.json.Genesis.Timestamp, 210 ParentHash: t.json.Genesis.ParentHash, 211 ExtraData: t.json.Genesis.ExtraData, 212 GasLimit: t.json.Genesis.GasLimit, 213 GasUsed: t.json.Genesis.GasUsed, 214 Difficulty: t.json.Genesis.Difficulty, 215 Mixhash: t.json.Genesis.MixHash, 216 Coinbase: t.json.Genesis.Coinbase, 217 Alloc: t.json.Pre, 218 BaseFee: t.json.Genesis.BaseFeePerGas, 219 BlobGasUsed: t.json.Genesis.BlobGasUsed, 220 ExcessBlobGas: t.json.Genesis.ExcessBlobGas, 221 } 222 } 223 224 /* 225 See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 226 227 Whether a block is valid or not is a bit subtle, it's defined by presence of 228 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 229 invalid and we must verify that we do not accept it. 230 231 Since some tests mix valid and invalid blocks we need to check this for every block. 232 233 If a block is invalid it does not necessarily fail the test, if it's invalidness is 234 expected we are expected to ignore it and continue processing and then validate the 235 post state. 236 */ 237 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 238 validBlocks := make([]btBlock, 0) 239 // insert the test blocks, which will execute all transactions 240 for bi, b := range t.json.Blocks { 241 cb, err := b.decode() 242 if err != nil { 243 if b.BlockHeader == nil { 244 log.Info("Block decoding failed", "index", bi, "err", err) 245 continue // OK - block is supposed to be invalid, continue with next block 246 } else { 247 return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err) 248 } 249 } 250 // RLP decoding worked, try to insert into chain: 251 blocks := types.Blocks{cb} 252 i, err := blockchain.InsertChain(blocks) 253 if err != nil { 254 if b.BlockHeader == nil { 255 continue // OK - block is supposed to be invalid, continue with next block 256 } else { 257 return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err) 258 } 259 } 260 if b.BlockHeader == nil { 261 if data, err := json.MarshalIndent(cb.Header(), "", " "); err == nil { 262 fmt.Fprintf(os.Stderr, "block (index %d) insertion should have failed due to: %v:\n%v\n", 263 bi, b.ExpectException, string(data)) 264 } 265 return nil, fmt.Errorf("block (index %d) insertion should have failed due to: %v", 266 bi, b.ExpectException) 267 } 268 269 // validate RLP decoding by checking all values against test file JSON 270 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 271 return nil, fmt.Errorf("deserialised block header validation failed: %v", err) 272 } 273 validBlocks = append(validBlocks, b) 274 } 275 return validBlocks, nil 276 } 277 278 func validateHeader(h *btHeader, h2 *types.Header) error { 279 if h.Bloom != h2.Bloom { 280 return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom) 281 } 282 if h.Coinbase != h2.Coinbase { 283 return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 284 } 285 if h.MixHash != h2.MixDigest { 286 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 287 } 288 if h.Nonce != h2.Nonce { 289 return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce) 290 } 291 if h.Number.Cmp(h2.Number) != 0 { 292 return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number) 293 } 294 if h.ParentHash != h2.ParentHash { 295 return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 296 } 297 if h.ReceiptTrie != h2.ReceiptHash { 298 return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 299 } 300 if h.TransactionsTrie != h2.TxHash { 301 return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 302 } 303 if h.StateRoot != h2.Root { 304 return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root) 305 } 306 if h.UncleHash != h2.UncleHash { 307 return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 308 } 309 if !bytes.Equal(h.ExtraData, h2.Extra) { 310 return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra) 311 } 312 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 313 return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 314 } 315 if h.GasLimit != h2.GasLimit { 316 return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 317 } 318 if h.GasUsed != h2.GasUsed { 319 return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 320 } 321 if h.Timestamp != h2.Time { 322 return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time) 323 } 324 if !reflect.DeepEqual(h.BaseFeePerGas, h2.BaseFee) { 325 return fmt.Errorf("baseFeePerGas: want: %v have: %v", h.BaseFeePerGas, h2.BaseFee) 326 } 327 if !reflect.DeepEqual(h.WithdrawalsRoot, h2.WithdrawalsHash) { 328 return fmt.Errorf("withdrawalsRoot: want: %v have: %v", h.WithdrawalsRoot, h2.WithdrawalsHash) 329 } 330 if !reflect.DeepEqual(h.BlobGasUsed, h2.BlobGasUsed) { 331 return fmt.Errorf("blobGasUsed: want: %v have: %v", h.BlobGasUsed, h2.BlobGasUsed) 332 } 333 if !reflect.DeepEqual(h.ExcessBlobGas, h2.ExcessBlobGas) { 334 return fmt.Errorf("excessBlobGas: want: %v have: %v", h.ExcessBlobGas, h2.ExcessBlobGas) 335 } 336 if !reflect.DeepEqual(h.ParentBeaconBlockRoot, h2.ParentBeaconRoot) { 337 return fmt.Errorf("parentBeaconBlockRoot: want: %v have: %v", h.ParentBeaconBlockRoot, h2.ParentBeaconRoot) 338 } 339 return nil 340 } 341 342 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 343 // validate post state accounts in test file against what we have in state db 344 for addr, acct := range t.json.Post { 345 // address is indirectly verified by the other fields, as it's the db key 346 code2 := statedb.GetCode(addr) 347 balance2 := statedb.GetBalance(addr).ToBig() 348 nonce2 := statedb.GetNonce(addr) 349 if !bytes.Equal(code2, acct.Code) { 350 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 351 } 352 if balance2.Cmp(acct.Balance) != 0 { 353 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 354 } 355 if nonce2 != acct.Nonce { 356 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 357 } 358 for k, v := range acct.Storage { 359 v2 := statedb.GetState(addr, k) 360 if v2 != v { 361 return fmt.Errorf("account storage mismatch for addr: %s, slot: %x, want: %x, have: %x", addr, k, v, v2) 362 } 363 } 364 } 365 return nil 366 } 367 368 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 369 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 370 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 371 for _, b := range validBlocks { 372 bmap[b.BlockHeader.Hash] = b 373 } 374 // iterate over blocks backwards from HEAD and validate imported 375 // headers vs test file. some tests have reorgs, and we import 376 // block-by-block, so we can only validate imported headers after 377 // all blocks have been processed by BlockChain, as they may not 378 // be part of the longest chain until last block is imported. 379 for b := cm.CurrentBlock(); b != nil && b.Number.Uint64() != 0; b = cm.GetBlockByHash(b.ParentHash).Header() { 380 if err := validateHeader(bmap[b.Hash()].BlockHeader, b); err != nil { 381 return fmt.Errorf("imported block header validation failed: %v", err) 382 } 383 } 384 return nil 385 } 386 387 func (bb *btBlock) decode() (*types.Block, error) { 388 data, err := hexutil.Decode(bb.Rlp) 389 if err != nil { 390 return nil, err 391 } 392 var b types.Block 393 err = rlp.DecodeBytes(data, &b) 394 return &b, err 395 }