github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/tests/state_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 package tests 26 27 import ( 28 "encoding/hex" 29 "encoding/json" 30 "fmt" 31 "math/big" 32 "strings" 33 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/common/hexutil" 36 "github.com/ethereum/go-ethereum/common/math" 37 "github.com/ethereum/go-ethereum/core" 38 "github.com/ethereum/go-ethereum/core/state" 39 "github.com/ethereum/go-ethereum/core/types" 40 "github.com/ethereum/go-ethereum/core/vm" 41 "github.com/ethereum/go-ethereum/crypto" 42 "github.com/ethereum/go-ethereum/crypto/sha3" 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 // 50 type StateTest struct { 51 json stJSON 52 } 53 54 // 55 type StateSubtest struct { 56 Fork string 57 Index int 58 } 59 60 func (t *StateTest) UnmarshalJSON(in []byte) error { 61 return json.Unmarshal(in, &t.json) 62 } 63 64 type stJSON struct { 65 Env stEnv `json:"env"` 66 Pre core.GenesisAlloc `json:"pre"` 67 Tx stTransaction `json:"transaction"` 68 Out hexutil.Bytes `json:"out"` 69 Post map[string][]stPostState `json:"post"` 70 } 71 72 type stPostState struct { 73 Root common.UnprefixedHash `json:"hash"` 74 Logs common.UnprefixedHash `json:"logs"` 75 Indexes struct { 76 Data int `json:"data"` 77 Gas int `json:"gas"` 78 Value int `json:"value"` 79 } 80 } 81 82 // 83 84 type stEnv struct { 85 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 86 Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` 87 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 88 Number uint64 `json:"currentNumber" gencodec:"required"` 89 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 90 } 91 92 type stEnvMarshaling struct { 93 Coinbase common.UnprefixedAddress 94 Difficulty *math.HexOrDecimal256 95 GasLimit math.HexOrDecimal64 96 Number math.HexOrDecimal64 97 Timestamp math.HexOrDecimal64 98 } 99 100 // 101 102 type stTransaction struct { 103 GasPrice *big.Int `json:"gasPrice"` 104 Nonce uint64 `json:"nonce"` 105 To string `json:"to"` 106 Data []string `json:"data"` 107 GasLimit []uint64 `json:"gasLimit"` 108 Value []string `json:"value"` 109 PrivateKey []byte `json:"secretKey"` 110 } 111 112 type stTransactionMarshaling struct { 113 GasPrice *math.HexOrDecimal256 114 Nonce math.HexOrDecimal64 115 GasLimit []math.HexOrDecimal64 116 PrivateKey hexutil.Bytes 117 } 118 119 // 120 func (t *StateTest) Subtests() []StateSubtest { 121 var sub []StateSubtest 122 for fork, pss := range t.json.Post { 123 for i := range pss { 124 sub = append(sub, StateSubtest{fork, i}) 125 } 126 } 127 return sub 128 } 129 130 // 131 func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateDB, error) { 132 config, ok := Forks[subtest.Fork] 133 if !ok { 134 return nil, UnsupportedForkError{subtest.Fork} 135 } 136 block := t.genesis(config).ToBlock(nil) 137 statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) 138 139 post := t.json.Post[subtest.Fork][subtest.Index] 140 msg, err := t.json.Tx.toMessage(post) 141 if err != nil { 142 return nil, err 143 } 144 context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) 145 context.GetHash = vmTestBlockHash 146 evm := vm.NewEVM(context, statedb, config, vmconfig) 147 148 gaspool := new(core.GasPool) 149 gaspool.AddGas(block.GasLimit()) 150 snapshot := statedb.Snapshot() 151 if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { 152 statedb.RevertToSnapshot(snapshot) 153 } 154 if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { 155 return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) 156 } 157 root, _ := statedb.Commit(config.IsEIP158(block.Number())) 158 if root != common.Hash(post.Root) { 159 return statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) 160 } 161 return statedb, nil 162 } 163 164 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 165 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 166 } 167 168 func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { 169 sdb := state.NewDatabase(db) 170 statedb, _ := state.New(common.Hash{}, sdb) 171 for addr, a := range accounts { 172 statedb.SetCode(addr, a.Code) 173 statedb.SetNonce(addr, a.Nonce) 174 statedb.SetBalance(addr, a.Balance) 175 for k, v := range a.Storage { 176 statedb.SetState(addr, k, v) 177 } 178 } 179 // 180 root, _ := statedb.Commit(false) 181 statedb, _ = state.New(root, sdb) 182 return statedb 183 } 184 185 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 186 return &core.Genesis{ 187 Config: config, 188 Coinbase: t.json.Env.Coinbase, 189 Difficulty: t.json.Env.Difficulty, 190 GasLimit: t.json.Env.GasLimit, 191 Number: t.json.Env.Number, 192 Timestamp: t.json.Env.Timestamp, 193 Alloc: t.json.Pre, 194 } 195 } 196 197 func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { 198 // 199 var from common.Address 200 if len(tx.PrivateKey) > 0 { 201 key, err := crypto.ToECDSA(tx.PrivateKey) 202 if err != nil { 203 return nil, fmt.Errorf("invalid private key: %v", err) 204 } 205 from = crypto.PubkeyToAddress(key.PublicKey) 206 } 207 // 208 var to *common.Address 209 if tx.To != "" { 210 to = new(common.Address) 211 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 212 return nil, fmt.Errorf("invalid to address: %v", err) 213 } 214 } 215 216 // 217 if ps.Indexes.Data > len(tx.Data) { 218 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 219 } 220 if ps.Indexes.Value > len(tx.Value) { 221 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 222 } 223 if ps.Indexes.Gas > len(tx.GasLimit) { 224 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 225 } 226 dataHex := tx.Data[ps.Indexes.Data] 227 valueHex := tx.Value[ps.Indexes.Value] 228 gasLimit := tx.GasLimit[ps.Indexes.Gas] 229 // 230 value := new(big.Int) 231 if valueHex != "0x" { 232 v, ok := math.ParseBig256(valueHex) 233 if !ok { 234 return nil, fmt.Errorf("invalid tx value %q", valueHex) 235 } 236 value = v 237 } 238 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 239 if err != nil { 240 return nil, fmt.Errorf("invalid tx data %q", dataHex) 241 } 242 243 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true) 244 return msg, nil 245 } 246 247 func rlpHash(x interface{}) (h common.Hash) { 248 hw := sha3.NewKeccak256() 249 rlp.Encode(hw, x) 250 hw.Sum(h[:0]) 251 return h 252 }