github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/tests/block_test_util.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:50</date> 10 //</624342685112602624> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 package tests 30 31 import ( 32 "bytes" 33 "encoding/hex" 34 "encoding/json" 35 "fmt" 36 "math/big" 37 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/common/hexutil" 40 "github.com/ethereum/go-ethereum/common/math" 41 "github.com/ethereum/go-ethereum/consensus/ethash" 42 "github.com/ethereum/go-ethereum/core" 43 "github.com/ethereum/go-ethereum/core/state" 44 "github.com/ethereum/go-ethereum/core/types" 45 "github.com/ethereum/go-ethereum/core/vm" 46 "github.com/ethereum/go-ethereum/ethdb" 47 "github.com/ethereum/go-ethereum/params" 48 "github.com/ethereum/go-ethereum/rlp" 49 ) 50 51 // 52 type BlockTest struct { 53 json btJSON 54 } 55 56 // 57 func (t *BlockTest) UnmarshalJSON(in []byte) error { 58 return json.Unmarshal(in, &t.json) 59 } 60 61 type btJSON struct { 62 Blocks []btBlock `json:"blocks"` 63 Genesis btHeader `json:"genesisBlockHeader"` 64 Pre core.GenesisAlloc `json:"pre"` 65 Post core.GenesisAlloc `json:"postState"` 66 BestBlock common.UnprefixedHash `json:"lastblockhash"` 67 Network string `json:"network"` 68 } 69 70 type btBlock struct { 71 BlockHeader *btHeader 72 Rlp string 73 UncleHeaders []*btHeader 74 } 75 76 // 77 78 type btHeader struct { 79 Bloom types.Bloom 80 Coinbase common.Address 81 MixHash common.Hash 82 Nonce types.BlockNonce 83 Number *big.Int 84 Hash common.Hash 85 ParentHash common.Hash 86 ReceiptTrie common.Hash 87 StateRoot common.Hash 88 TransactionsTrie common.Hash 89 UncleHash common.Hash 90 ExtraData []byte 91 Difficulty *big.Int 92 GasLimit uint64 93 GasUsed uint64 94 Timestamp *big.Int 95 } 96 97 type btHeaderMarshaling struct { 98 ExtraData hexutil.Bytes 99 Number *math.HexOrDecimal256 100 Difficulty *math.HexOrDecimal256 101 GasLimit math.HexOrDecimal64 102 GasUsed math.HexOrDecimal64 103 Timestamp *math.HexOrDecimal256 104 } 105 106 func (t *BlockTest) Run() error { 107 config, ok := Forks[t.json.Network] 108 if !ok { 109 return UnsupportedForkError{t.json.Network} 110 } 111 112 // 113 db := ethdb.NewMemDatabase() 114 gblock, err := t.genesis(config).Commit(db) 115 if err != nil { 116 return err 117 } 118 if gblock.Hash() != t.json.Genesis.Hash { 119 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 120 } 121 if gblock.Root() != t.json.Genesis.StateRoot { 122 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 123 } 124 125 chain, err := core.NewBlockChain(db, nil, config, ethash.NewShared(), vm.Config{}) 126 if err != nil { 127 return err 128 } 129 defer chain.Stop() 130 131 validBlocks, err := t.insertBlocks(chain) 132 if err != nil { 133 return err 134 } 135 cmlast := chain.CurrentBlock().Hash() 136 if common.Hash(t.json.BestBlock) != cmlast { 137 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 138 } 139 newDB, err := chain.State() 140 if err != nil { 141 return err 142 } 143 if err = t.validatePostState(newDB); err != nil { 144 return fmt.Errorf("post state validation failed: %v", err) 145 } 146 return t.validateImportedHeaders(chain, validBlocks) 147 } 148 149 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 150 return &core.Genesis{ 151 Config: config, 152 Nonce: t.json.Genesis.Nonce.Uint64(), 153 Timestamp: t.json.Genesis.Timestamp.Uint64(), 154 ParentHash: t.json.Genesis.ParentHash, 155 ExtraData: t.json.Genesis.ExtraData, 156 GasLimit: t.json.Genesis.GasLimit, 157 GasUsed: t.json.Genesis.GasUsed, 158 Difficulty: t.json.Genesis.Difficulty, 159 Mixhash: t.json.Genesis.MixHash, 160 Coinbase: t.json.Genesis.Coinbase, 161 Alloc: t.json.Pre, 162 } 163 } 164 165 /* 166 167 168 169 170 171 172 173 174 175 176 */ 177 178 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 179 validBlocks := make([]btBlock, 0) 180 // 181 for _, b := range t.json.Blocks { 182 cb, err := b.decode() 183 if err != nil { 184 if b.BlockHeader == nil { 185 continue // 186 } else { 187 return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err) 188 } 189 } 190 // 191 blocks := types.Blocks{cb} 192 i, err := blockchain.InsertChain(blocks) 193 if err != nil { 194 if b.BlockHeader == nil { 195 continue // 196 } else { 197 return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err) 198 } 199 } 200 if b.BlockHeader == nil { 201 return nil, fmt.Errorf("Block insertion should have failed") 202 } 203 204 // 205 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 206 return nil, fmt.Errorf("Deserialised block header validation failed: %v", err) 207 } 208 validBlocks = append(validBlocks, b) 209 } 210 return validBlocks, nil 211 } 212 213 func validateHeader(h *btHeader, h2 *types.Header) error { 214 if h.Bloom != h2.Bloom { 215 return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom) 216 } 217 if h.Coinbase != h2.Coinbase { 218 return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 219 } 220 if h.MixHash != h2.MixDigest { 221 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 222 } 223 if h.Nonce != h2.Nonce { 224 return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce) 225 } 226 if h.Number.Cmp(h2.Number) != 0 { 227 return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number) 228 } 229 if h.ParentHash != h2.ParentHash { 230 return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 231 } 232 if h.ReceiptTrie != h2.ReceiptHash { 233 return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 234 } 235 if h.TransactionsTrie != h2.TxHash { 236 return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 237 } 238 if h.StateRoot != h2.Root { 239 return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root) 240 } 241 if h.UncleHash != h2.UncleHash { 242 return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 243 } 244 if !bytes.Equal(h.ExtraData, h2.Extra) { 245 return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra) 246 } 247 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 248 return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 249 } 250 if h.GasLimit != h2.GasLimit { 251 return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 252 } 253 if h.GasUsed != h2.GasUsed { 254 return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 255 } 256 if h.Timestamp.Cmp(h2.Time) != 0 { 257 return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) 258 } 259 return nil 260 } 261 262 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 263 // 264 for addr, acct := range t.json.Post { 265 // 266 code2 := statedb.GetCode(addr) 267 balance2 := statedb.GetBalance(addr) 268 nonce2 := statedb.GetNonce(addr) 269 if !bytes.Equal(code2, acct.Code) { 270 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 271 } 272 if balance2.Cmp(acct.Balance) != 0 { 273 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 274 } 275 if nonce2 != acct.Nonce { 276 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 277 } 278 } 279 return nil 280 } 281 282 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 283 // 284 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 285 for _, b := range validBlocks { 286 bmap[b.BlockHeader.Hash] = b 287 } 288 // 289 // 290 // 291 // 292 // 293 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 294 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 295 return fmt.Errorf("Imported block header validation failed: %v", err) 296 } 297 } 298 return nil 299 } 300 301 func (bb *btBlock) decode() (*types.Block, error) { 302 data, err := hexutil.Decode(bb.Rlp) 303 if err != nil { 304 return nil, err 305 } 306 var b types.Block 307 err = rlp.DecodeBytes(data, &b) 308 return &b, err 309 } 310