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