github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/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 INT Chain 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/intfoundation/intchain/common" 28 "github.com/intfoundation/intchain/common/hexutil" 29 "github.com/intfoundation/intchain/common/math" 30 "github.com/intfoundation/intchain/core" 31 "github.com/intfoundation/intchain/core/rawdb" 32 "github.com/intfoundation/intchain/core/state" 33 "github.com/intfoundation/intchain/core/types" 34 "github.com/intfoundation/intchain/core/vm" 35 "github.com/intfoundation/intchain/params" 36 "github.com/intfoundation/intchain/rlp" 37 ) 38 39 // A BlockTest checks handling of entire blocks. 40 type BlockTest struct { 41 json btJSON 42 } 43 44 func (t *BlockTest) UnmarshalJSON(in []byte) error { 45 return json.Unmarshal(in, &t.json) 46 } 47 48 type btJSON struct { 49 Blocks []btBlock `json:"blocks"` 50 Genesis btHeader `json:"genesisBlockHeader"` 51 Pre core.GenesisAlloc `json:"pre"` 52 Post core.GenesisAlloc `json:"postState"` 53 BestBlock common.UnprefixedHash `json:"lastblockhash"` 54 Network string `json:"network"` 55 } 56 57 type btBlock struct { 58 BlockHeader *btHeader 59 Rlp string 60 UncleHeaders []*btHeader 61 } 62 63 //go:generate 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 // import pre accounts & construct test genesis block & state root 100 db := rawdb.NewMemoryDatabase() 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\n", 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 112 chain, err := core.NewBlockChain(db, nil, config, nil, vm.Config{}, nil) 113 if err != nil { 114 return err 115 } 116 defer chain.Stop() 117 118 validBlocks, err := t.insertBlocks(chain) 119 if err != nil { 120 return err 121 } 122 cmlast := chain.CurrentBlock().Hash() 123 if common.Hash(t.json.BestBlock) != cmlast { 124 return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast) 125 } 126 newDB, err := chain.State() 127 if err != nil { 128 return err 129 } 130 if err = t.validatePostState(newDB); err != nil { 131 return fmt.Errorf("post state validation failed: %v", err) 132 } 133 return t.validateImportedHeaders(chain, validBlocks) 134 } 135 136 func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { 137 return &core.Genesis{ 138 Config: config, 139 Nonce: t.json.Genesis.Nonce.Uint64(), 140 Timestamp: t.json.Genesis.Timestamp.Uint64(), 141 ParentHash: t.json.Genesis.ParentHash, 142 ExtraData: t.json.Genesis.ExtraData, 143 GasLimit: t.json.Genesis.GasLimit, 144 GasUsed: t.json.Genesis.GasUsed, 145 Difficulty: t.json.Genesis.Difficulty, 146 Mixhash: t.json.Genesis.MixHash, 147 Coinbase: t.json.Genesis.Coinbase, 148 Alloc: t.json.Pre, 149 } 150 } 151 152 /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II 153 154 Whether a block is valid or not is a bit subtle, it's defined by presence of 155 blockHeader, transactions and uncleHeaders fields. If they are missing, the block is 156 invalid and we must verify that we do not accept it. 157 158 Since some tests mix valid and invalid blocks we need to check this for every block. 159 160 If a block is invalid it does not necessarily fail the test, if it's invalidness is 161 expected we are expected to ignore it and continue processing and then validate the 162 post state. 163 */ 164 func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { 165 validBlocks := make([]btBlock, 0) 166 // insert the test blocks, which will execute all transactions 167 for _, b := range t.json.Blocks { 168 cb, err := b.decode() 169 if err != nil { 170 if b.BlockHeader == nil { 171 continue // OK - block is supposed to be invalid, continue with next block 172 } else { 173 return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err) 174 } 175 } 176 // RLP decoding worked, try to insert into chain: 177 blocks := types.Blocks{cb} 178 i, err := blockchain.InsertChain(blocks) 179 if err != nil { 180 if b.BlockHeader == nil { 181 continue // OK - block is supposed to be invalid, continue with next block 182 } else { 183 return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err) 184 } 185 } 186 if b.BlockHeader == nil { 187 return nil, fmt.Errorf("Block insertion should have failed") 188 } 189 190 // validate RLP decoding by checking all values against test file JSON 191 if err = validateHeader(b.BlockHeader, cb.Header()); err != nil { 192 return nil, fmt.Errorf("Deserialised block header validation failed: %v", err) 193 } 194 validBlocks = append(validBlocks, b) 195 } 196 return validBlocks, nil 197 } 198 199 func validateHeader(h *btHeader, h2 *types.Header) error { 200 if h.Bloom != h2.Bloom { 201 return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom) 202 } 203 if h.Coinbase != h2.Coinbase { 204 return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase) 205 } 206 if h.MixHash != h2.MixDigest { 207 return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest) 208 } 209 if h.Nonce != h2.Nonce { 210 return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce) 211 } 212 if h.Number.Cmp(h2.Number) != 0 { 213 return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number) 214 } 215 if h.ParentHash != h2.ParentHash { 216 return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash) 217 } 218 if h.ReceiptTrie != h2.ReceiptHash { 219 return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash) 220 } 221 if h.TransactionsTrie != h2.TxHash { 222 return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash) 223 } 224 if h.StateRoot != h2.Root { 225 return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root) 226 } 227 if h.UncleHash != h2.UncleHash { 228 return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash) 229 } 230 if !bytes.Equal(h.ExtraData, h2.Extra) { 231 return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra) 232 } 233 if h.Difficulty.Cmp(h2.Difficulty) != 0 { 234 return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) 235 } 236 if h.GasLimit != h2.GasLimit { 237 return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) 238 } 239 if h.GasUsed != h2.GasUsed { 240 return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) 241 } 242 if h.Timestamp.Cmp(h2.Time) != 0 { 243 return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) 244 } 245 return nil 246 } 247 248 func (t *BlockTest) validatePostState(statedb *state.StateDB) error { 249 // validate post state accounts in test file against what we have in state db 250 for addr, acct := range t.json.Post { 251 // address is indirectly verified by the other fields, as it's the db key 252 code2 := statedb.GetCode(addr) 253 balance2 := statedb.GetBalance(addr) 254 nonce2 := statedb.GetNonce(addr) 255 if !bytes.Equal(code2, acct.Code) { 256 return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2)) 257 } 258 if balance2.Cmp(acct.Balance) != 0 { 259 return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2) 260 } 261 if nonce2 != acct.Nonce { 262 return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2) 263 } 264 } 265 return nil 266 } 267 268 func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error { 269 // to get constant lookup when verifying block headers by hash (some tests have many blocks) 270 bmap := make(map[common.Hash]btBlock, len(t.json.Blocks)) 271 for _, b := range validBlocks { 272 bmap[b.BlockHeader.Hash] = b 273 } 274 // iterate over blocks backwards from HEAD and validate imported 275 // headers vs test file. some tests have reorgs, and we import 276 // block-by-block, so we can only validate imported headers after 277 // all blocks have been processed by BlockChain, as they may not 278 // be part of the longest chain until last block is imported. 279 for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { 280 if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { 281 return fmt.Errorf("Imported block header validation failed: %v", err) 282 } 283 } 284 return nil 285 } 286 287 func (bb *btBlock) decode() (*types.Block, error) { 288 data, err := hexutil.Decode(bb.Rlp) 289 if err != nil { 290 return nil, err 291 } 292 var b types.Block 293 err = rlp.DecodeBytes(data, &b) 294 return &b, err 295 }