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