github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/tests/state_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 //</624450122498969600> 11 12 13 package tests 14 15 import ( 16 "encoding/hex" 17 "encoding/json" 18 "fmt" 19 "math/big" 20 "strings" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/common/hexutil" 24 "github.com/ethereum/go-ethereum/common/math" 25 "github.com/ethereum/go-ethereum/core" 26 "github.com/ethereum/go-ethereum/core/state" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/core/vm" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/params" 32 "github.com/ethereum/go-ethereum/rlp" 33 "golang.org/x/crypto/sha3" 34 ) 35 36 //StateTest检查没有块上下文的事务处理。 37 //有关测试格式规范,请参阅https://github.com/ethereum/eips/issues/176。 38 type StateTest struct { 39 json stJSON 40 } 41 42 //StateSubTest选择常规状态测试的特定配置。 43 type StateSubtest struct { 44 Fork string 45 Index int 46 } 47 48 func (t *StateTest) UnmarshalJSON(in []byte) error { 49 return json.Unmarshal(in, &t.json) 50 } 51 52 type stJSON struct { 53 Env stEnv `json:"env"` 54 Pre core.GenesisAlloc `json:"pre"` 55 Tx stTransaction `json:"transaction"` 56 Out hexutil.Bytes `json:"out"` 57 Post map[string][]stPostState `json:"post"` 58 } 59 60 type stPostState struct { 61 Root common.UnprefixedHash `json:"hash"` 62 Logs common.UnprefixedHash `json:"logs"` 63 Indexes struct { 64 Data int `json:"data"` 65 Gas int `json:"gas"` 66 Value int `json:"value"` 67 } 68 } 69 70 //go:生成gencodec-类型stenv-字段覆盖stenvmarshaling-out gen_stenv.go 71 72 type stEnv struct { 73 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 74 Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` 75 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 76 Number uint64 `json:"currentNumber" gencodec:"required"` 77 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 78 } 79 80 type stEnvMarshaling struct { 81 Coinbase common.UnprefixedAddress 82 Difficulty *math.HexOrDecimal256 83 GasLimit math.HexOrDecimal64 84 Number math.HexOrDecimal64 85 Timestamp math.HexOrDecimal64 86 } 87 88 //go:生成gencodec-type sttransaction-field override sttransaction封送处理-out gen_sttransaction.go 89 90 type stTransaction struct { 91 GasPrice *big.Int `json:"gasPrice"` 92 Nonce uint64 `json:"nonce"` 93 To string `json:"to"` 94 Data []string `json:"data"` 95 GasLimit []uint64 `json:"gasLimit"` 96 Value []string `json:"value"` 97 PrivateKey []byte `json:"secretKey"` 98 } 99 100 type stTransactionMarshaling struct { 101 GasPrice *math.HexOrDecimal256 102 Nonce math.HexOrDecimal64 103 GasLimit []math.HexOrDecimal64 104 PrivateKey hexutil.Bytes 105 } 106 107 //子测试返回测试的所有有效子测试。 108 func (t *StateTest) Subtests() []StateSubtest { 109 var sub []StateSubtest 110 for fork, pss := range t.json.Post { 111 for i := range pss { 112 sub = append(sub, StateSubtest{fork, i}) 113 } 114 } 115 return sub 116 } 117 118 //运行执行特定的子测试。 119 func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateDB, error) { 120 config, ok := Forks[subtest.Fork] 121 if !ok { 122 return nil, UnsupportedForkError{subtest.Fork} 123 } 124 block := t.genesis(config).ToBlock(nil) 125 statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) 126 127 post := t.json.Post[subtest.Fork][subtest.Index] 128 msg, err := t.json.Tx.toMessage(post) 129 if err != nil { 130 return nil, err 131 } 132 context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) 133 context.GetHash = vmTestBlockHash 134 evm := vm.NewEVM(context, statedb, config, vmconfig) 135 136 gaspool := new(core.GasPool) 137 gaspool.AddGas(block.GasLimit()) 138 snapshot := statedb.Snapshot() 139 if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { 140 statedb.RevertToSnapshot(snapshot) 141 } 142 //提交块 143 statedb.Commit(config.IsEIP158(block.Number())) 144 //增加0值采矿奖励。这只会使情况有所不同 145 //在哪里? 146 //-Coinbase自杀,或 147 //-只有“坏”事务没有执行。在那些情况下, 148 //CoinBase没有txfee,因此没有创建,因此需要触摸 149 statedb.AddBalance(block.Coinbase(), new(big.Int)) 150 //现在获取状态根 151 root := statedb.IntermediateRoot(config.IsEIP158(block.Number())) 152 //注意:我们需要在两个步骤的过程中完成这项工作,因为第一个提交需要注意。 153 //在自杀事件中,我们需要在有可能自杀后触摸硬币库。 154 if root != common.Hash(post.Root) { 155 return statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) 156 } 157 if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { 158 return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) 159 } 160 return statedb, nil 161 } 162 163 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 164 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 165 } 166 167 func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { 168 sdb := state.NewDatabase(db) 169 statedb, _ := state.New(common.Hash{}, sdb) 170 for addr, a := range accounts { 171 statedb.SetCode(addr, a.Code) 172 statedb.SetNonce(addr, a.Nonce) 173 statedb.SetBalance(addr, a.Balance) 174 for k, v := range a.Storage { 175 statedb.SetState(addr, k, v) 176 } 177 } 178 //提交并重新打开以从干净状态开始。 179 root, _ := statedb.Commit(false) 180 statedb, _ = state.New(root, sdb) 181 return statedb 182 } 183 184 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 185 return &core.Genesis{ 186 Config: config, 187 Coinbase: t.json.Env.Coinbase, 188 Difficulty: t.json.Env.Difficulty, 189 GasLimit: t.json.Env.GasLimit, 190 Number: t.json.Env.Number, 191 Timestamp: t.json.Env.Timestamp, 192 Alloc: t.json.Pre, 193 } 194 } 195 196 func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { 197 //从私钥派生发送者(如果存在)。 198 var from common.Address 199 if len(tx.PrivateKey) > 0 { 200 key, err := crypto.ToECDSA(tx.PrivateKey) 201 if err != nil { 202 return nil, fmt.Errorf("invalid private key: %v", err) 203 } 204 from = crypto.PubkeyToAddress(key.PublicKey) 205 } 206 //分析收件人(如果存在)。 207 var to *common.Address 208 if tx.To != "" { 209 to = new(common.Address) 210 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 211 return nil, fmt.Errorf("invalid to address: %v", err) 212 } 213 } 214 215 //获取特定于此发布状态的值。 216 if ps.Indexes.Data > len(tx.Data) { 217 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 218 } 219 if ps.Indexes.Value > len(tx.Value) { 220 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 221 } 222 if ps.Indexes.Gas > len(tx.GasLimit) { 223 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 224 } 225 dataHex := tx.Data[ps.Indexes.Data] 226 valueHex := tx.Value[ps.Indexes.Value] 227 gasLimit := tx.GasLimit[ps.Indexes.Gas] 228 //值,数据十六进制编码混乱:https://github.com/ethereum/tests/issues/203 229 value := new(big.Int) 230 if valueHex != "0x" { 231 v, ok := math.ParseBig256(valueHex) 232 if !ok { 233 return nil, fmt.Errorf("invalid tx value %q", valueHex) 234 } 235 value = v 236 } 237 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 238 if err != nil { 239 return nil, fmt.Errorf("invalid tx data %q", dataHex) 240 } 241 242 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true) 243 return msg, nil 244 } 245 246 func rlpHash(x interface{}) (h common.Hash) { 247 hw := sha3.NewLegacyKeccak256() 248 rlp.Encode(hw, x) 249 hw.Sum(h[:0]) 250 return h 251 } 252