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