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