github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/tests/block_test_util.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package tests implements execution of Ebakus 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/ebakus/go-ebakus/common" 28 "github.com/ebakus/go-ebakus/common/hexutil" 29 "github.com/ebakus/go-ebakus/common/math" 30 "github.com/ebakus/go-ebakus/consensus" 31 "github.com/ebakus/go-ebakus/consensus/ethash" 32 "github.com/ebakus/go-ebakus/core" 33 "github.com/ebakus/go-ebakus/core/rawdb" 34 "github.com/ebakus/go-ebakus/core/state" 35 "github.com/ebakus/go-ebakus/core/types" 36 "github.com/ebakus/go-ebakus/core/vm" 37 "github.com/ebakus/go-ebakus/params" 38 "github.com/ebakus/go-ebakus/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 Number *big.Int 73 Hash common.Hash 74 ParentHash common.Hash 75 ReceiptTrie common.Hash 76 StateRoot common.Hash 77 TransactionsTrie common.Hash 78 UncleHash common.Hash 79 ExtraData []byte 80 Difficulty *big.Int 81 GasLimit uint64 82 GasUsed uint64 83 Timestamp uint64 84 } 85 86 type btHeaderMarshaling struct { 87 ExtraData hexutil.Bytes 88 Number *math.HexOrDecimal256 89 Difficulty *math.HexOrDecimal256 90 GasLimit math.HexOrDecimal64 91 GasUsed math.HexOrDecimal64 92 Timestamp math.HexOrDecimal64 93 } 94 95 func (t *BlockTest) Run() error { 96 config, ok := Forks[t.json.Network] 97 if !ok { 98 return UnsupportedForkError{t.json.Network} 99 } 100 101 // import pre accounts & construct test genesis block & state root 102 db := rawdb.NewMemoryDatabase() 103 gblock, err := t.genesis(config).Commit(db) 104 if err != nil { 105 return err 106 } 107 if gblock.Hash() != t.json.Genesis.Hash { 108 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 109 } 110 if gblock.Root() != t.json.Genesis.StateRoot { 111 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 112 } 113 var engine consensus.Engine 114 if t.json.SealEngine == "NoProof" { 115 engine = ethash.NewFaker() 116 } else { 117 engine = ethash.NewShared() 118 } 119 chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil) 120 if err != nil { 121 return err 122 } 123 defer chain.Stop() 124 125 validBlocks, err := t.insertBlocks(chain) 126 if err != nil { 127 return err 128 } 129 cmlast := chain.CurrentBlock().Hash() 130 if common.Hash(t.json.BestBlock) != cmlast { 131 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 132 } 133 newDB, err := chain.State() 134 if err != nil { 135 return err 136 } 137 if err = t.validatePostState(newDB); err != nil { 138 return fmt.Errorf("post state validation failed: %v", err) 139 } 140 return t.validateImportedHeaders(chain, validBlocks) 141 } 142 143 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 144 return &core.Genesis{ 145 Config: config, 146 Timestamp: t.json.Genesis.Timestamp, 147 ParentHash: t.json.Genesis.ParentHash, 148 ExtraData: t.json.Genesis.ExtraData, 149 GasLimit: t.json.Genesis.GasLimit, 150 GasUsed: t.json.Genesis.GasUsed, 151 Difficulty: t.json.Genesis.Difficulty, 152 Coinbase: t.json.Genesis.Coinbase, 153 Alloc: t.json.Pre, 154 } 155 } 156 157 /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 158 159 Whether a block is valid or not is a bit subtle, it's defined by presence of 160 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 161 invalid and we must verify that we do not accept it. 162 163 Since some tests mix valid and invalid blocks we need to check this for every block. 164 165 If a block is invalid it does not necessarily fail the test, if it's invalidness is 166 expected we are expected to ignore it and continue processing and then validate the 167 post state. 168 */ 169 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 170 validBlocks := make([]btBlock, 0) 171 // insert the test blocks, which will execute all transactions 172 for _, b := range t.json.Blocks { 173 cb, err := b.decode() 174 if err != nil { 175 if b.BlockHeader == nil { 176 continue // OK - block is supposed to be invalid, continue with next block 177 } else { 178 return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err) 179 } 180 } 181 // RLP decoding worked, try to insert into chain: 182 blocks := types.Blocks{cb} 183 i, err := blockchain.InsertChain(blocks) 184 if err != nil { 185 if b.BlockHeader == nil { 186 continue // OK - block is supposed to be invalid, continue with next block 187 } else { 188 return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err) 189 } 190 } 191 if b.BlockHeader == nil { 192 return nil, fmt.Errorf("Block insertion should have failed") 193 } 194 195 // validate RLP decoding by checking all values against test file JSON 196 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 197 return nil, fmt.Errorf("Deserialised block header validation failed: %v", err) 198 } 199 validBlocks = append(validBlocks, b) 200 } 201 return validBlocks, nil 202 } 203 204 func validateHeader(h *btHeader, h2 *types.Header) error { 205 if h.Bloom != h2.Bloom { 206 return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom) 207 } 208 if h.Coinbase != h2.Coinbase { 209 return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 210 } 211 if h.Number.Cmp(h2.Number) != 0 { 212 return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number) 213 } 214 if h.ParentHash != h2.ParentHash { 215 return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 216 } 217 if h.ReceiptTrie != h2.ReceiptHash { 218 return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 219 } 220 if h.TransactionsTrie != h2.TxHash { 221 return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 222 } 223 if h.StateRoot != h2.Root { 224 return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root) 225 } 226 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 227 return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 228 } 229 if h.GasLimit != h2.GasLimit { 230 return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 231 } 232 if h.GasUsed != h2.GasUsed { 233 return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 234 } 235 if h.Timestamp != h2.Time { 236 return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) 237 } 238 return nil 239 } 240 241 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 242 // validate post state accounts in test file against what we have in state db 243 for addr, acct := range t.json.Post { 244 // address is indirectly verified by the other fields, as it's the db key 245 code2 := statedb.GetCode(addr) 246 balance2 := statedb.GetBalance(addr) 247 nonce2 := statedb.GetNonce(addr) 248 if !bytes.Equal(code2, acct.Code) { 249 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 250 } 251 if balance2.Cmp(acct.Balance) != 0 { 252 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 253 } 254 if nonce2 != acct.Nonce { 255 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 256 } 257 } 258 return nil 259 } 260 261 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 262 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 263 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 264 for _, b := range validBlocks { 265 bmap[b.BlockHeader.Hash] = b 266 } 267 // iterate over blocks backwards from HEAD and validate imported 268 // headers vs test file. some tests have reorgs, and we import 269 // block-by-block, so we can only validate imported headers after 270 // all blocks have been processed by BlockChain, as they may not 271 // be part of the longest chain until last block is imported. 272 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 273 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 274 return fmt.Errorf("Imported block header validation failed: %v", err) 275 } 276 } 277 return nil 278 } 279 280 func (bb *btBlock) decode() (*types.Block, error) { 281 data, err := hexutil.Decode(bb.Rlp) 282 if err != nil { 283 return nil, err 284 } 285 var b types.Block 286 err = rlp.DecodeBytes(data, &b) 287 return &b, err 288 }