github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/tests/vm_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 12:09:50</date> 10 //</624342686521888768> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package tests 29 30 import ( 31 "bytes" 32 "encoding/json" 33 "fmt" 34 "math/big" 35 36 "github.com/ethereum/go-ethereum/common" 37 "github.com/ethereum/go-ethereum/common/hexutil" 38 "github.com/ethereum/go-ethereum/common/math" 39 "github.com/ethereum/go-ethereum/core" 40 "github.com/ethereum/go-ethereum/core/state" 41 "github.com/ethereum/go-ethereum/core/vm" 42 "github.com/ethereum/go-ethereum/crypto" 43 "github.com/ethereum/go-ethereum/ethdb" 44 "github.com/ethereum/go-ethereum/params" 45 ) 46 47 // 48 // 49 type VMTest struct { 50 json vmJSON 51 } 52 53 func (t *VMTest) UnmarshalJSON(data []byte) error { 54 return json.Unmarshal(data, &t.json) 55 } 56 57 type vmJSON struct { 58 Env stEnv `json:"env"` 59 Exec vmExec `json:"exec"` 60 Logs common.UnprefixedHash `json:"logs"` 61 GasRemaining *math.HexOrDecimal64 `json:"gas"` 62 Out hexutil.Bytes `json:"out"` 63 Pre core.GenesisAlloc `json:"pre"` 64 Post core.GenesisAlloc `json:"post"` 65 PostStateRoot common.Hash `json:"postStateRoot"` 66 } 67 68 // 69 70 type vmExec struct { 71 Address common.Address `json:"address" gencodec:"required"` 72 Caller common.Address `json:"caller" gencodec:"required"` 73 Origin common.Address `json:"origin" gencodec:"required"` 74 Code []byte `json:"code" gencodec:"required"` 75 Data []byte `json:"data" gencodec:"required"` 76 Value *big.Int `json:"value" gencodec:"required"` 77 GasLimit uint64 `json:"gas" gencodec:"required"` 78 GasPrice *big.Int `json:"gasPrice" gencodec:"required"` 79 } 80 81 type vmExecMarshaling struct { 82 Address common.UnprefixedAddress 83 Caller common.UnprefixedAddress 84 Origin common.UnprefixedAddress 85 Code hexutil.Bytes 86 Data hexutil.Bytes 87 Value *math.HexOrDecimal256 88 GasLimit math.HexOrDecimal64 89 GasPrice *math.HexOrDecimal256 90 } 91 92 func (t *VMTest) Run(vmconfig vm.Config) error { 93 statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) 94 ret, gasRemaining, err := t.exec(statedb, vmconfig) 95 96 if t.json.GasRemaining == nil { 97 if err == nil { 98 return fmt.Errorf("gas unspecified (indicating an error), but VM returned no error") 99 } 100 if gasRemaining > 0 { 101 return fmt.Errorf("gas unspecified (indicating an error), but VM returned gas remaining > 0") 102 } 103 return nil 104 } 105 // 106 if !bytes.Equal(ret, t.json.Out) { 107 return fmt.Errorf("return data mismatch: got %x, want %x", ret, t.json.Out) 108 } 109 if gasRemaining != uint64(*t.json.GasRemaining) { 110 return fmt.Errorf("remaining gas %v, want %v", gasRemaining, *t.json.GasRemaining) 111 } 112 for addr, account := range t.json.Post { 113 for k, wantV := range account.Storage { 114 if haveV := statedb.GetState(addr, k); haveV != wantV { 115 return fmt.Errorf("wrong storage value at %x:\n got %x\n want %x", k, haveV, wantV) 116 } 117 } 118 } 119 // 120 // 121 // 122 if logs := rlpHash(statedb.Logs()); logs != common.Hash(t.json.Logs) { 123 return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, t.json.Logs) 124 } 125 return nil 126 } 127 128 func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { 129 evm := t.newEVM(statedb, vmconfig) 130 e := t.json.Exec 131 return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, e.Value) 132 } 133 134 func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { 135 initialCall := true 136 canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { 137 if initialCall { 138 initialCall = false 139 return true 140 } 141 return core.CanTransfer(db, address, amount) 142 } 143 transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} 144 context := vm.Context{ 145 CanTransfer: canTransfer, 146 Transfer: transfer, 147 GetHash: vmTestBlockHash, 148 Origin: t.json.Exec.Origin, 149 Coinbase: t.json.Env.Coinbase, 150 BlockNumber: new(big.Int).SetUint64(t.json.Env.Number), 151 Time: new(big.Int).SetUint64(t.json.Env.Timestamp), 152 GasLimit: t.json.Env.GasLimit, 153 Difficulty: t.json.Env.Difficulty, 154 GasPrice: t.json.Exec.GasPrice, 155 } 156 vmconfig.NoRecursion = true 157 return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig) 158 } 159 160 func vmTestBlockHash(n uint64) common.Hash { 161 return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) 162 } 163