github.com/codingfuture/orig-energi3@v0.8.4/tests/block_test_util.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the Energi Core library. 4 // 5 // The Energi Core library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The Energi Core library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 17 18 // Package tests implements execution of Ethereum JSON tests. 19 package tests 20 21 import ( 22 "bytes" 23 "encoding/hex" 24 "encoding/json" 25 "fmt" 26 "math/big" 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/state" 35 "github.com/ethereum/go-ethereum/core/types" 36 "github.com/ethereum/go-ethereum/core/vm" 37 "github.com/ethereum/go-ethereum/ethdb" 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 Rlp string 65 UncleHeaders []*btHeader 66 } 67 68 //go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go 69 70 type btHeader struct { 71 Bloom types.Bloom 72 Coinbase common.Address 73 MixHash common.Hash 74 Nonce types.BlockNonce 75 Number *big.Int 76 Hash common.Hash 77 ParentHash common.Hash 78 ReceiptTrie common.Hash 79 StateRoot common.Hash 80 TransactionsTrie common.Hash 81 UncleHash common.Hash 82 ExtraData []byte 83 Difficulty *big.Int 84 GasLimit uint64 85 GasUsed uint64 86 Timestamp uint64 87 } 88 89 type btHeaderMarshaling struct { 90 ExtraData hexutil.Bytes 91 Number *math.HexOrDecimal256 92 Difficulty *math.HexOrDecimal256 93 GasLimit math.HexOrDecimal64 94 GasUsed math.HexOrDecimal64 95 Timestamp math.HexOrDecimal64 96 } 97 98 func (t *BlockTest) Run() error { 99 config, ok := Forks[t.json.Network] 100 if !ok { 101 return UnsupportedForkError{t.json.Network} 102 } 103 104 // import pre accounts & construct test genesis block & state root 105 db := ethdb.NewMemDatabase() 106 gblock, err := t.genesis(config).Commit(db) 107 if err != nil { 108 return err 109 } 110 if gblock.Hash() != t.json.Genesis.Hash { 111 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 112 } 113 if gblock.Root() != t.json.Genesis.StateRoot { 114 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 115 } 116 var engine consensus.Engine 117 if t.json.SealEngine == "NoProof" { 118 engine = ethash.NewFaker() 119 } else { 120 engine = ethash.NewShared() 121 } 122 chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil) 123 if err != nil { 124 return err 125 } 126 defer chain.Stop() 127 128 validBlocks, err := t.insertBlocks(chain) 129 if err != nil { 130 return err 131 } 132 cmlast := chain.CurrentBlock().Hash() 133 if common.Hash(t.json.BestBlock) != cmlast { 134 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 135 } 136 newDB, err := chain.State() 137 if err != nil { 138 return err 139 } 140 if err = t.validatePostState(newDB); err != nil { 141 return fmt.Errorf("post state validation failed: %v", err) 142 } 143 return t.validateImportedHeaders(chain, validBlocks) 144 } 145 146 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 147 return &core.Genesis{ 148 Config: config, 149 Nonce: t.json.Genesis.Nonce.Uint64(), 150 Timestamp: t.json.Genesis.Timestamp, 151 ParentHash: t.json.Genesis.ParentHash, 152 ExtraData: t.json.Genesis.ExtraData, 153 GasLimit: t.json.Genesis.GasLimit, 154 GasUsed: t.json.Genesis.GasUsed, 155 Difficulty: t.json.Genesis.Difficulty, 156 Mixhash: t.json.Genesis.MixHash, 157 Coinbase: t.json.Genesis.Coinbase, 158 Alloc: t.json.Pre, 159 } 160 } 161 162 /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 163 164 Whether a block is valid or not is a bit subtle, it's defined by presence of 165 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 166 invalid and we must verify that we do not accept it. 167 168 Since some tests mix valid and invalid blocks we need to check this for every block. 169 170 If a block is invalid it does not necessarily fail the test, if it's invalidness is 171 expected we are expected to ignore it and continue processing and then validate the 172 post state. 173 */ 174 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 175 validBlocks := make([]btBlock, 0) 176 // insert the test blocks, which will execute all transactions 177 for _, b := range t.json.Blocks { 178 cb, err := b.decode() 179 if err != nil { 180 if b.BlockHeader == nil { 181 continue // OK - block is supposed to be invalid, continue with next block 182 } else { 183 return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err) 184 } 185 } 186 // RLP decoding worked, try to insert into chain: 187 blocks := types.Blocks{cb} 188 i, err := blockchain.InsertChain(blocks) 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 #%v insertion into chain failed: %v", blocks[i].Number(), err) 194 } 195 } 196 if b.BlockHeader == nil { 197 return nil, fmt.Errorf("Block insertion should have failed") 198 } 199 200 // validate RLP decoding by checking all values against test file JSON 201 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 202 return nil, fmt.Errorf("Deserialised block header validation failed: %v", err) 203 } 204 validBlocks = append(validBlocks, b) 205 } 206 return validBlocks, nil 207 } 208 209 func validateHeader(h *btHeader, h2 *types.Header) error { 210 if h.Bloom != h2.Bloom { 211 return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom) 212 } 213 if h.Coinbase != h2.Coinbase { 214 return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 215 } 216 if h.MixHash != h2.MixDigest { 217 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 218 } 219 if h.Nonce != h2.Nonce { 220 return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce) 221 } 222 if h.Number.Cmp(h2.Number) != 0 { 223 return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number) 224 } 225 if h.ParentHash != h2.ParentHash { 226 return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 227 } 228 if h.ReceiptTrie != h2.ReceiptHash { 229 return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 230 } 231 if h.TransactionsTrie != h2.TxHash { 232 return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 233 } 234 if h.StateRoot != h2.Root { 235 return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root) 236 } 237 if h.UncleHash != h2.UncleHash { 238 return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 239 } 240 if !bytes.Equal(h.ExtraData, h2.Extra) { 241 return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra) 242 } 243 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 244 return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 245 } 246 if h.GasLimit != h2.GasLimit { 247 return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 248 } 249 if h.GasUsed != h2.GasUsed { 250 return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 251 } 252 if h.Timestamp != h2.Time { 253 return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) 254 } 255 return nil 256 } 257 258 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 259 // validate post state accounts in test file against what we have in state db 260 for addr, acct := range t.json.Post { 261 // address is indirectly verified by the other fields, as it's the db key 262 code2 := statedb.GetCode(addr) 263 balance2 := statedb.GetBalance(addr) 264 nonce2 := statedb.GetNonce(addr) 265 if !bytes.Equal(code2, acct.Code) { 266 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 267 } 268 if balance2.Cmp(acct.Balance) != 0 { 269 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 270 } 271 if nonce2 != acct.Nonce { 272 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 273 } 274 } 275 return nil 276 } 277 278 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 279 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 280 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 281 for _, b := range validBlocks { 282 bmap[b.BlockHeader.Hash] = b 283 } 284 // iterate over blocks backwards from HEAD and validate imported 285 // headers vs test file. some tests have reorgs, and we import 286 // block-by-block, so we can only validate imported headers after 287 // all blocks have been processed by BlockChain, as they may not 288 // be part of the longest chain until last block is imported. 289 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 290 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 291 return fmt.Errorf("Imported block header validation failed: %v", err) 292 } 293 } 294 return nil 295 } 296 297 func (bb *btBlock) decode() (*types.Block, error) { 298 data, err := hexutil.Decode(bb.Rlp) 299 if err != nil { 300 return nil, err 301 } 302 var b types.Block 303 err = rlp.DecodeBytes(data, &b) 304 return &b, err 305 }