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