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