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