github.com/klaytn/klaytn@v1.12.1/tests/vm_test_util.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from tests/vm_test_util.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package tests 22 23 import ( 24 "bytes" 25 "encoding/json" 26 "fmt" 27 "math/big" 28 29 "github.com/klaytn/klaytn/blockchain" 30 "github.com/klaytn/klaytn/blockchain/state" 31 "github.com/klaytn/klaytn/blockchain/vm" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/common/hexutil" 34 "github.com/klaytn/klaytn/common/math" 35 "github.com/klaytn/klaytn/crypto" 36 "github.com/klaytn/klaytn/params" 37 "github.com/klaytn/klaytn/storage/database" 38 ) 39 40 // VMTest checks EVM execution without block or transaction context. 41 // See https://github.com/ethereum/tests/wiki/VM-Tests for the test format specification. 42 type VMTest struct { 43 json vmJSON 44 } 45 46 func (t *VMTest) UnmarshalJSON(data []byte) error { 47 return json.Unmarshal(data, &t.json) 48 } 49 50 type vmJSON struct { 51 Env stEnv `json:"env"` 52 Exec vmExec `json:"exec"` 53 Logs common.UnprefixedHash `json:"logs"` 54 GasRemaining *math.HexOrDecimal64 `json:"gas"` 55 Out hexutil.Bytes `json:"out"` 56 Pre blockchain.GenesisAlloc `json:"pre"` 57 Post blockchain.GenesisAlloc `json:"post"` 58 PostStateRoot common.Hash `json:"postStateRoot"` 59 } 60 61 //go:generate gencodec -type vmExec -field-override vmExecMarshaling -out gen_vmexec.go 62 63 type vmExec struct { 64 Address common.Address `json:"address" gencodec:"required"` 65 Caller common.Address `json:"caller" gencodec:"required"` 66 Origin common.Address `json:"origin" gencodec:"required"` 67 Code []byte `json:"code" gencodec:"required"` 68 Data []byte `json:"data" gencodec:"required"` 69 Value *big.Int `json:"value" gencodec:"required"` 70 GasLimit uint64 `json:"gas" gencodec:"required"` 71 GasPrice *big.Int `json:"gasPrice" gencodec:"required"` 72 } 73 74 type vmExecMarshaling struct { 75 Address common.UnprefixedAddress 76 Caller common.UnprefixedAddress 77 Origin common.UnprefixedAddress 78 Code hexutil.Bytes 79 Data hexutil.Bytes 80 Value *math.HexOrDecimal256 81 GasLimit math.HexOrDecimal64 82 GasPrice *math.HexOrDecimal256 83 } 84 85 func (t *VMTest) Run(vmconfig vm.Config) error { 86 memDBManager := database.NewMemoryDBManager() 87 statedb := MakePreState(memDBManager, t.json.Pre) 88 ret, gasRemaining, err := t.exec(statedb, vmconfig) 89 90 if t.json.GasRemaining == nil { 91 if err == nil { 92 return fmt.Errorf("gas unspecified (indicating an error), but VM returned no error") 93 } 94 if gasRemaining > 0 { 95 return fmt.Errorf("gas unspecified (indicating an error), but VM returned gas remaining > 0") 96 } 97 return nil 98 } 99 // Test declares gas, expecting outputs to match. 100 if !bytes.Equal(ret, t.json.Out) { 101 return fmt.Errorf("return data mismatch: got %x, want %x", ret, t.json.Out) 102 } 103 if gasRemaining != uint64(*t.json.GasRemaining) { 104 return fmt.Errorf("remaining gas %v, want %v", gasRemaining, *t.json.GasRemaining) 105 } 106 for addr, account := range t.json.Post { 107 for k, wantV := range account.Storage { 108 if haveV := statedb.GetState(addr, k); haveV != wantV { 109 return fmt.Errorf("wrong storage value at %x:\n got %x\n want %x", k, haveV, wantV) 110 } 111 } 112 } 113 // if root := statedb.IntermediateRoot(false); root != t.json.PostStateRoot { 114 // return fmt.Errorf("post state root mismatch, got %x, want %x", root, t.json.PostStateRoot) 115 // } 116 if logs := rlpHash(statedb.Logs()); logs != common.Hash(t.json.Logs) { 117 return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, t.json.Logs) 118 } 119 return nil 120 } 121 122 func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { 123 /////////////////////////////////////////////////////// 124 // OpcodeComputationCostLimit: The below code is commented and will be usd for debugging purposes. 125 //start := time.Now() 126 //defer func() { 127 // elapsed := time.Since(start) 128 // fmt.Println("[VMTest.exec] EVM execution done", "elapsed", elapsed) 129 //}() 130 /////////////////////////////////////////////////////// 131 evm := t.newEVM(statedb, vmconfig) 132 e := t.json.Exec 133 return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, e.Value) 134 } 135 136 func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { 137 initialCall := true 138 canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { 139 if initialCall { 140 initialCall = false 141 return true 142 } 143 return blockchain.CanTransfer(db, address, amount) 144 } 145 transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} 146 txContext := vm.TxContext{ 147 Origin: t.json.Exec.Origin, 148 GasPrice: t.json.Exec.GasPrice, 149 } 150 blockContext := vm.BlockContext{ 151 CanTransfer: canTransfer, 152 Transfer: transfer, 153 GetHash: vmTestBlockHash, 154 Coinbase: t.json.Env.Coinbase, 155 BlockNumber: new(big.Int).SetUint64(t.json.Env.Number), 156 Time: new(big.Int).SetUint64(t.json.Env.Timestamp), 157 GasLimit: t.json.Env.GasLimit, 158 BlockScore: t.json.Env.BlockScore, 159 } 160 vmconfig.NoRecursion = true 161 return vm.NewEVM(blockContext, txContext, statedb, params.CypressChainConfig, &vmconfig) 162 } 163 164 func vmTestBlockHash(n uint64) common.Hash { 165 return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) 166 }