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