github.com/aswedchain/aswed@v1.0.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 27 "github.com/aswedchain/aswed/common" 28 "github.com/aswedchain/aswed/common/hexutil" 29 "github.com/aswedchain/aswed/common/math" 30 "github.com/aswedchain/aswed/consensus" 31 "github.com/aswedchain/aswed/consensus/ethash" 32 "github.com/aswedchain/aswed/core" 33 "github.com/aswedchain/aswed/core/rawdb" 34 "github.com/aswedchain/aswed/core/state" 35 "github.com/aswedchain/aswed/core/state/snapshot" 36 "github.com/aswedchain/aswed/core/types" 37 "github.com/aswedchain/aswed/core/vm" 38 "github.com/aswedchain/aswed/params" 39 "github.com/aswedchain/aswed/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(snapshotter bool) 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 := rawdb.NewMemoryDatabase() 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 cache := &core.CacheConfig{TrieCleanLimit: 0} 123 if snapshotter { 124 cache.SnapshotLimit = 1 125 cache.SnapshotWait = true 126 } 127 chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil) 128 if err != nil { 129 return err 130 } 131 defer chain.Stop() 132 133 validBlocks, err := t.insertBlocks(chain) 134 if err != nil { 135 return err 136 } 137 cmlast := chain.CurrentBlock().Hash() 138 if common.Hash(t.json.BestBlock) != cmlast { 139 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 140 } 141 newDB, err := chain.State() 142 if err != nil { 143 return err 144 } 145 if err = t.validatePostState(newDB); err != nil { 146 return fmt.Errorf("post state validation failed: %v", err) 147 } 148 // Cross-check the snapshot-to-hash against the trie hash 149 if snapshotter { 150 if err := snapshot.VerifyState(chain.Snapshot(), chain.CurrentBlock().Root()); err != nil { 151 return err 152 } 153 } 154 return t.validateImportedHeaders(chain, validBlocks) 155 } 156 157 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 158 return &core.Genesis{ 159 Config: config, 160 Nonce: t.json.Genesis.Nonce.Uint64(), 161 Timestamp: t.json.Genesis.Timestamp, 162 ParentHash: t.json.Genesis.ParentHash, 163 ExtraData: t.json.Genesis.ExtraData, 164 GasLimit: t.json.Genesis.GasLimit, 165 GasUsed: t.json.Genesis.GasUsed, 166 Difficulty: t.json.Genesis.Difficulty, 167 Mixhash: t.json.Genesis.MixHash, 168 Coinbase: t.json.Genesis.Coinbase, 169 Alloc: t.json.Pre, 170 } 171 } 172 173 /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 174 175 Whether a block is valid or not is a bit subtle, it's defined by presence of 176 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 177 invalid and we must verify that we do not accept it. 178 179 Since some tests mix valid and invalid blocks we need to check this for every block. 180 181 If a block is invalid it does not necessarily fail the test, if it's invalidness is 182 expected we are expected to ignore it and continue processing and then validate the 183 post state. 184 */ 185 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 186 validBlocks := make([]btBlock, 0) 187 // insert the test blocks, which will execute all transactions 188 for _, b := range t.json.Blocks { 189 cb, err := b.decode() 190 if err != nil { 191 if b.BlockHeader == nil { 192 continue // OK - block is supposed to be invalid, continue with next block 193 } else { 194 return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err) 195 } 196 } 197 // RLP decoding worked, try to insert into chain: 198 blocks := types.Blocks{cb} 199 i, err := blockchain.InsertChain(blocks) 200 if err != nil { 201 if b.BlockHeader == nil { 202 continue // OK - block is supposed to be invalid, continue with next block 203 } else { 204 return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err) 205 } 206 } 207 if b.BlockHeader == nil { 208 return nil, fmt.Errorf("block insertion should have failed") 209 } 210 211 // validate RLP decoding by checking all values against test file JSON 212 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 213 return nil, fmt.Errorf("deserialised block header validation failed: %v", err) 214 } 215 validBlocks = append(validBlocks, b) 216 } 217 return validBlocks, nil 218 } 219 220 func validateHeader(h *btHeader, h2 *types.Header) error { 221 if h.Bloom != h2.Bloom { 222 return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom) 223 } 224 if h.Coinbase != h2.Coinbase { 225 return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 226 } 227 if h.MixHash != h2.MixDigest { 228 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 229 } 230 if h.Nonce != h2.Nonce { 231 return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce) 232 } 233 if h.Number.Cmp(h2.Number) != 0 { 234 return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number) 235 } 236 if h.ParentHash != h2.ParentHash { 237 return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 238 } 239 if h.ReceiptTrie != h2.ReceiptHash { 240 return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 241 } 242 if h.TransactionsTrie != h2.TxHash { 243 return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 244 } 245 if h.StateRoot != h2.Root { 246 return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root) 247 } 248 if h.UncleHash != h2.UncleHash { 249 return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 250 } 251 if !bytes.Equal(h.ExtraData, h2.Extra) { 252 return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra) 253 } 254 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 255 return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 256 } 257 if h.GasLimit != h2.GasLimit { 258 return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 259 } 260 if h.GasUsed != h2.GasUsed { 261 return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 262 } 263 if h.Timestamp != h2.Time { 264 return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time) 265 } 266 return nil 267 } 268 269 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 270 // validate post state accounts in test file against what we have in state db 271 for addr, acct := range t.json.Post { 272 // address is indirectly verified by the other fields, as it's the db key 273 code2 := statedb.GetCode(addr) 274 balance2 := statedb.GetBalance(addr) 275 nonce2 := statedb.GetNonce(addr) 276 if !bytes.Equal(code2, acct.Code) { 277 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 278 } 279 if balance2.Cmp(acct.Balance) != 0 { 280 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 281 } 282 if nonce2 != acct.Nonce { 283 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 284 } 285 } 286 return nil 287 } 288 289 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 290 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 291 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 292 for _, b := range validBlocks { 293 bmap[b.BlockHeader.Hash] = b 294 } 295 // iterate over blocks backwards from HEAD and validate imported 296 // headers vs test file. some tests have reorgs, and we import 297 // block-by-block, so we can only validate imported headers after 298 // all blocks have been processed by BlockChain, as they may not 299 // be part of the longest chain until last block is imported. 300 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 301 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 302 return fmt.Errorf("imported block header validation failed: %v", err) 303 } 304 } 305 return nil 306 } 307 308 func (bb *btBlock) decode() (*types.Block, error) { 309 data, err := hexutil.Decode(bb.Rlp) 310 if err != nil { 311 return nil, err 312 } 313 var b types.Block 314 err = rlp.DecodeBytes(data, &b) 315 return &b, err 316 }