github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:45</date> 10 //</624450121920155648> 11 12 13 //包测试实现了以太坊JSON测试的执行。 14 package tests 15 16 import ( 17 "bytes" 18 "encoding/hex" 19 "encoding/json" 20 "fmt" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/common/hexutil" 25 "github.com/ethereum/go-ethereum/common/math" 26 "github.com/ethereum/go-ethereum/consensus" 27 "github.com/ethereum/go-ethereum/consensus/ethash" 28 "github.com/ethereum/go-ethereum/core" 29 "github.com/ethereum/go-ethereum/core/state" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/params" 34 "github.com/ethereum/go-ethereum/rlp" 35 ) 36 37 //块测试检查整个块的处理。 38 type BlockTest struct { 39 json btJSON 40 } 41 42 //unmashaljson实现json.unmasheler接口。 43 func (t *BlockTest) UnmarshalJSON(in []byte) error { 44 return json.Unmarshal(in, &t.json) 45 } 46 47 type btJSON struct { 48 Blocks []btBlock `json:"blocks"` 49 Genesis btHeader `json:"genesisBlockHeader"` 50 Pre core.GenesisAlloc `json:"pre"` 51 Post core.GenesisAlloc `json:"postState"` 52 BestBlock common.UnprefixedHash `json:"lastblockhash"` 53 Network string `json:"network"` 54 SealEngine string `json:"sealEngine"` 55 } 56 57 type btBlock struct { 58 BlockHeader *btHeader 59 Rlp string 60 UncleHeaders []*btHeader 61 } 62 63 //go:生成gencodec-type btheader-field override btheadermarshaling-out gen_btheader.go 64 65 type btHeader struct { 66 Bloom types.Bloom 67 Coinbase common.Address 68 MixHash common.Hash 69 Nonce types.BlockNonce 70 Number *big.Int 71 Hash common.Hash 72 ParentHash common.Hash 73 ReceiptTrie common.Hash 74 StateRoot common.Hash 75 TransactionsTrie common.Hash 76 UncleHash common.Hash 77 ExtraData []byte 78 Difficulty *big.Int 79 GasLimit uint64 80 GasUsed uint64 81 Timestamp *big.Int 82 } 83 84 type btHeaderMarshaling struct { 85 ExtraData hexutil.Bytes 86 Number *math.HexOrDecimal256 87 Difficulty *math.HexOrDecimal256 88 GasLimit math.HexOrDecimal64 89 GasUsed math.HexOrDecimal64 90 Timestamp *math.HexOrDecimal256 91 } 92 93 func (t *BlockTest) Run() error { 94 config, ok := Forks[t.json.Network] 95 if !ok { 96 return UnsupportedForkError{t.json.Network} 97 } 98 99 //导入预帐户并构建测试Genesis块和状态根 100 db := ethdb.NewMemDatabase() 101 gblock, err := t.genesis(config).Commit(db) 102 if err != nil { 103 return err 104 } 105 if gblock.Hash() != t.json.Genesis.Hash { 106 return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) 107 } 108 if gblock.Root() != t.json.Genesis.StateRoot { 109 return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) 110 } 111 var engine consensus.Engine 112 if t.json.SealEngine == "NoProof" { 113 engine = ethash.NewFaker() 114 } else { 115 engine = ethash.NewShared() 116 } 117 chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil) 118 if err != nil { 119 return err 120 } 121 defer chain.Stop() 122 123 validBlocks, err := t.insertBlocks(chain) 124 if err != nil { 125 return err 126 } 127 cmlast := chain.CurrentBlock().Hash() 128 if common.Hash(t.json.BestBlock) != cmlast { 129 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 130 } 131 newDB, err := chain.State() 132 if err != nil { 133 return err 134 } 135 if err = t.validatePostState(newDB); err != nil { 136 return fmt.Errorf("post state validation failed: %v", err) 137 } 138 return t.validateImportedHeaders(chain, validBlocks) 139 } 140 141 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 142 return &core.Genesis{ 143 Config: config, 144 Nonce: t.json.Genesis.Nonce.Uint64(), 145 Timestamp: t.json.Genesis.Timestamp.Uint64(), 146 ParentHash: t.json.Genesis.ParentHash, 147 ExtraData: t.json.Genesis.ExtraData, 148 GasLimit: t.json.Genesis.GasLimit, 149 GasUsed: t.json.Genesis.GasUsed, 150 Difficulty: t.json.Genesis.Difficulty, 151 Mixhash: t.json.Genesis.MixHash, 152 Coinbase: t.json.Genesis.Coinbase, 153 Alloc: t.json.Pre, 154 } 155 } 156 157 /*参见https://github.com/ethereum/tests/wiki/blockback-tests-ii 158 159 一个块是否有效有点微妙,它是通过存在 160 BlockHeader、Transactions和UncleHeaders字段。如果他们不见了,这个街区就是 161 无效,我们必须确认我们不接受它。 162 163 由于一些测试混合了有效和无效的块,我们需要为每个块检查这一点。 164 165 如果一个块是无效的,它不一定会通过测试,如果它的无效性是 166 期望我们忽略它并继续处理,然后验证 167 后状态。 168 **/ 169 170 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 171 validBlocks := make([]btBlock, 0) 172 //插入将执行所有事务的测试块 173 for _, b := range t.json.Blocks { 174 cb, err := b.decode() 175 if err != nil { 176 if b.BlockHeader == nil { 177 continue //好-块应该无效,继续下一个块 178 } else { 179 return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err) 180 } 181 } 182 //RLP解码成功,尝试插入链: 183 blocks := types.Blocks{cb} 184 i, err := blockchain.InsertChain(blocks) 185 if err != nil { 186 if b.BlockHeader == nil { 187 continue //好-块应该无效,继续下一个块 188 } else { 189 return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err) 190 } 191 } 192 if b.BlockHeader == nil { 193 return nil, fmt.Errorf("Block insertion should have failed") 194 } 195 196 //通过检查测试文件json的所有值来验证rlp解码 197 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 198 return nil, fmt.Errorf("Deserialised block header validation failed: %v", err) 199 } 200 validBlocks = append(validBlocks, b) 201 } 202 return validBlocks, nil 203 } 204 205 func validateHeader(h *btHeader, h2 *types.Header) error { 206 if h.Bloom != h2.Bloom { 207 return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom) 208 } 209 if h.Coinbase != h2.Coinbase { 210 return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 211 } 212 if h.MixHash != h2.MixDigest { 213 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 214 } 215 if h.Nonce != h2.Nonce { 216 return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce) 217 } 218 if h.Number.Cmp(h2.Number) != 0 { 219 return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number) 220 } 221 if h.ParentHash != h2.ParentHash { 222 return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 223 } 224 if h.ReceiptTrie != h2.ReceiptHash { 225 return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 226 } 227 if h.TransactionsTrie != h2.TxHash { 228 return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 229 } 230 if h.StateRoot != h2.Root { 231 return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root) 232 } 233 if h.UncleHash != h2.UncleHash { 234 return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 235 } 236 if !bytes.Equal(h.ExtraData, h2.Extra) { 237 return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra) 238 } 239 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 240 return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 241 } 242 if h.GasLimit != h2.GasLimit { 243 return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 244 } 245 if h.GasUsed != h2.GasUsed { 246 return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 247 } 248 if h.Timestamp.Cmp(h2.Time) != 0 { 249 return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) 250 } 251 return nil 252 } 253 254 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 255 //根据状态数据库中的内容验证测试文件中的状态后帐户 256 for addr, acct := range t.json.Post { 257 //地址由其他字段间接验证,因为它是db键 258 code2 := statedb.GetCode(addr) 259 balance2 := statedb.GetBalance(addr) 260 nonce2 := statedb.GetNonce(addr) 261 if !bytes.Equal(code2, acct.Code) { 262 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 263 } 264 if balance2.Cmp(acct.Balance) != 0 { 265 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 266 } 267 if nonce2 != acct.Nonce { 268 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 269 } 270 } 271 return nil 272 } 273 274 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 275 //通过哈希验证块头时获取常量查找(某些测试有许多块) 276 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 277 for _, b := range validBlocks { 278 bmap[b.BlockHeader.Hash] = b 279 } 280 //从头部向后迭代块并验证导入的 281 //头与测试文件。有些测试有REORG,我们导入 282 //逐块,因此我们只能在 283 //所有块都已由区块链处理,因为它们可能不是 284 //成为最长链的一部分,直到导入最后一个块。 285 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 286 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 287 return fmt.Errorf("Imported block header validation failed: %v", err) 288 } 289 } 290 return nil 291 } 292 293 func (bb *btBlock) decode() (*types.Block, error) { 294 data, err := hexutil.Decode(bb.Rlp) 295 if err != nil { 296 return nil, err 297 } 298 var b types.Block 299 err = rlp.DecodeBytes(data, &b) 300 return &b, err 301 } 302