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