diff options
Diffstat (limited to 'core/vm/evm')
-rw-r--r-- | core/vm/evm/evm.go | 81 | ||||
-rw-r--r-- | core/vm/evm/instructions.go | 17 | ||||
-rw-r--r-- | core/vm/evm/interpreter.go | 9 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime_example_test.go | 6 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime_test.go | 48 |
5 files changed, 120 insertions, 41 deletions
diff --git a/core/vm/evm/evm.go b/core/vm/evm/evm.go index 28fe24574..e1c8c02ed 100644 --- a/core/vm/evm/evm.go +++ b/core/vm/evm/evm.go @@ -31,6 +31,57 @@ import ( // deployed contract addresses (relevant after the account abstraction). var emptyCodeHash = crypto.Keccak256Hash(nil) +func init() { + vm.Register(vm.EVM, &EVMImplement{}) +} + +type EVMImplement struct{} + +func (evmImpl *EVMImplement) Create(caller vm.ContractRef, code []byte, gas uint64, + value *big.Int, interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + i := interpreter.(*EVMInterpreter) + return i.evm.Create(caller, code, gas, value) +} + +func (evmImpl *EVMImplement) Create2(caller vm.ContractRef, code []byte, gas uint64, + endowment *big.Int, salt *big.Int, + interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + + i := interpreter.(*EVMInterpreter) + return i.evm.Create2(caller, code, gas, endowment, salt) +} + +func (evmImpl *EVMImplement) Call(caller vm.ContractRef, addr common.Address, + input []byte, gas uint64, value *big.Int, + interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { + i := interpreter.(*EVMInterpreter) + return i.evm.Call(caller, addr, input, gas, value) + +} +func (evmImpl *EVMImplement) CallCode(caller vm.ContractRef, addr common.Address, + input []byte, gas uint64, value *big.Int, + interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { + + i := interpreter.(*EVMInterpreter) + return i.evm.CallCode(caller, addr, input, gas, value) +} + +func (evmImpl *EVMImplement) DelegateCall(caller vm.ContractRef, addr common.Address, + input []byte, gas uint64, + interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { + + i := interpreter.(*EVMInterpreter) + return i.evm.DelegateCall(caller, addr, input, gas) +} + +func (evmImpl *EVMImplement) StaticCall(caller vm.ContractRef, addr common.Address, + input []byte, gas uint64, + interpreter vm.Interpreter) (ret []byte, leftovergas uint64, err error) { + + i := interpreter.(*EVMInterpreter) + return i.evm.StaticCall(caller, addr, input, gas) +} + // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. func run(evm *EVM, contract *vm.Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { @@ -187,8 +238,12 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := vm.NewContract(caller, to, value, gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - + code := evm.StateDB.GetCode(addr) + if len(code) > 0 && code[0] == vm.EVM && vm.MULTIVM { + code = code[1:] + } + codeAndHash := vm.CodeAndHash{Code: code} + contract.SetCodeOptionalHash(&addr, &codeAndHash) // Even if the account has no code, we need to continue because it might be a precompile start := time.Now() @@ -243,7 +298,12 @@ func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byt // EVM. The contract is a scoped environment for this execution context // only. contract := vm.NewContract(caller, to, value, gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + code := evm.StateDB.GetCode(addr) + if len(code) > 0 && vm.MULTIVM { + code = code[1:] + } + codeAndHash := vm.CodeAndHash{Code: code} + contract.SetCodeOptionalHash(&addr, &codeAndHash) ret, err = run(evm, contract, input, false) if err != nil { @@ -276,7 +336,12 @@ func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input [ // Initialise a new contract and make initialise the delegate values contract := vm.NewContract(caller, to, nil, gas).AsDelegate() - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + code := evm.StateDB.GetCode(addr) + if len(code) > 0 && vm.MULTIVM { + code = code[1:] + } + codeAndHash := vm.CodeAndHash{Code: code} + contract.SetCodeOptionalHash(&addr, &codeAndHash) ret, err = run(evm, contract, input, false) if err != nil { @@ -309,7 +374,12 @@ func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []b // EVM. The contract is a scoped environment for this execution context // only. contract := vm.NewContract(caller, to, new(big.Int), gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + code := evm.StateDB.GetCode(addr) + if len(code) > 0 && vm.MULTIVM { + code = code[1:] + } + codeAndHash := vm.CodeAndHash{Code: code} + contract.SetCodeOptionalHash(&addr, &codeAndHash) // We do an AddBalance of zero here, just in order to trigger a touch. // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, @@ -370,7 +440,6 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.Code, gas, value) } start := time.Now() - ret, err := run(evm, contract, nil, false) // check whether the max code size has been exceeded diff --git a/core/vm/evm/instructions.go b/core/vm/evm/instructions.go index 10ff75b69..ce95d2446 100644 --- a/core/vm/evm/instructions.go +++ b/core/vm/evm/instructions.go @@ -491,8 +491,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Cont memOffset = stack.Pop() dataOffset = stack.Pop() length = stack.Pop() - - end = interpreter.intPool.Get().Add(dataOffset, length) + end = interpreter.intPool.Get().Add(dataOffset, length) ) defer interpreter.intPool.Put(memOffset, dataOffset, length, end) @@ -725,12 +724,12 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) + // size.Add(size, big1) if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockNumber) { gas -= gas / 64 } - contract.UseGas(gas) - res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value) + res, addr, returnGas, suberr := vm.Create(contract, input, gas, value, interpreter) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must @@ -763,7 +762,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, m // Apply EIP150 gas -= gas / 64 contract.UseGas(gas) - res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) + res, addr, returnGas, suberr := vm.Create2(contract, input, gas, endowment, salt, interpreter) // Push item on the stack based on the returned error. if suberr != nil { stack.Push(interpreter.intPool.GetZero()) @@ -793,7 +792,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) + ret, returnGas, err := vm.Call(contract, toAddr, args, gas, value, interpreter) if err != nil { stack.Push(interpreter.intPool.GetZero()) } else { @@ -822,7 +821,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) + ret, returnGas, err := vm.CallCode(contract, toAddr, args, gas, value, interpreter) if err != nil { stack.Push(interpreter.intPool.GetZero()) } else { @@ -847,7 +846,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contra // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) + ret, returnGas, err := vm.DelegateCall(contract, toAddr, args, gas, interpreter) if err != nil { stack.Push(interpreter.intPool.GetZero()) } else { @@ -872,7 +871,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) + ret, returnGas, err := vm.StaticCall(contract, toAddr, args, gas, interpreter) if err != nil { stack.Push(interpreter.intPool.GetZero()) } else { diff --git a/core/vm/evm/interpreter.go b/core/vm/evm/interpreter.go index 867e72ee1..9ed647c00 100644 --- a/core/vm/evm/interpreter.go +++ b/core/vm/evm/interpreter.go @@ -172,7 +172,6 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool if len(contract.Code) == 0 { return nil, nil } - var ( op OpCode // current opcode mem = vm.NewMemory() // bound memory @@ -188,7 +187,6 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool logged bool // deferred Tracer should ignore already logged steps ) contract.Input = input - // Reclaim the stack as an int pool when the execution stops defer func() { in.intPool.Put(stack.Data...) @@ -251,6 +249,7 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool if err != nil || !contract.UseGas(cost) { return nil, vm.ErrOutOfGas } + if memorySize > 0 { mem.Resize(memorySize) } @@ -284,6 +283,7 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool pc++ } } + return nil, nil } @@ -292,3 +292,8 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool func (in *EVMInterpreter) CanRun(code []byte) bool { return true } + +// StateDB return StateDB stored in evm +func (in *EVMInterpreter) StateDB() vm.StateDB { + return in.evm.StateDB +} diff --git a/core/vm/evm/runtime/runtime_example_test.go b/core/vm/evm/runtime/runtime_example_test.go index c6050a771..dd50bc373 100644 --- a/core/vm/evm/runtime/runtime_example_test.go +++ b/core/vm/evm/runtime/runtime_example_test.go @@ -21,14 +21,16 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/vm/evm/runtime" + "github.com/dexon-foundation/dexon/core/vm/tools" ) func ExampleExecute() { - ret, _, err := runtime.Execute(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00"), nil, nil) + code := tools.PatchBinary(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00")) + ret, _, err := runtime.Execute(code, nil, nil) if err != nil { fmt.Println(err) } fmt.Println(ret) // Output: - // [96 96 96 64 82 96 8 86 91 0] + // [0 96 96 96 64 82 96 8 86 91 0] } diff --git a/core/vm/evm/runtime/runtime_test.go b/core/vm/evm/runtime/runtime_test.go index 43b8da325..762f3601d 100644 --- a/core/vm/evm/runtime/runtime_test.go +++ b/core/vm/evm/runtime/runtime_test.go @@ -24,7 +24,9 @@ import ( "github.com/dexon-foundation/dexon/accounts/abi" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm/tools" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) @@ -65,24 +67,25 @@ func TestEVM(t *testing.T) { }() Execute([]byte{ - byte(vm.DIFFICULTY), - byte(vm.TIMESTAMP), - byte(vm.GASLIMIT), - byte(vm.PUSH1), - byte(vm.ORIGIN), - byte(vm.BLOCKHASH), - byte(vm.COINBASE), + byte(evm.DIFFICULTY), + byte(evm.TIMESTAMP), + byte(evm.GASLIMIT), + byte(evm.PUSH1), + byte(evm.ORIGIN), + byte(evm.BLOCKHASH), + byte(evm.COINBASE), }, nil, nil) } func TestExecute(t *testing.T) { ret, _, err := Execute([]byte{ - byte(vm.PUSH1), 10, - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - byte(vm.PUSH1), 32, - byte(vm.PUSH1), 0, - byte(vm.RETURN), + byte(vm.EVM), + byte(evm.PUSH1), 10, + byte(evm.PUSH1), 0, + byte(evm.MSTORE), + byte(evm.PUSH1), 32, + byte(evm.PUSH1), 0, + byte(evm.RETURN), }, nil, nil) if err != nil { t.Fatal("didn't expect error", err) @@ -98,12 +101,13 @@ func TestCall(t *testing.T) { state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ - byte(vm.PUSH1), 10, - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - byte(vm.PUSH1), 32, - byte(vm.PUSH1), 0, - byte(vm.RETURN), + byte(vm.EVM), + byte(evm.PUSH1), 10, + byte(evm.PUSH1), 0, + byte(evm.MSTORE), + byte(evm.PUSH1), 32, + byte(evm.PUSH1), 0, + byte(evm.RETURN), }) ret, _, err := Call(address, nil, &Config{State: state}) @@ -121,7 +125,7 @@ func BenchmarkCall(b *testing.B) { var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` var code = common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") - + code = tools.PatchBinary(code) abi, err := abi.JSON(strings.NewReader(definition)) if err != nil { b.Fatal(err) @@ -177,7 +181,7 @@ func benchmarkEVM_Create(bench *testing.B, code string) { EIP155Block: new(big.Int), EIP158Block: new(big.Int), }, - EVMConfig: vm.Config{}, + EVMConfig: evm.Config{}, } // Warm up the intpools and stuff bench.ResetTimer() |