github.com/immesys/bw2bc@v1.1.0/core/execution.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "math/big" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/core/state" 24 "github.com/ethereum/go-ethereum/core/vm" 25 "github.com/ethereum/go-ethereum/crypto" 26 "github.com/ethereum/go-ethereum/params" 27 ) 28 29 // Execution is the execution environment for the given call or create action. 30 type Execution struct { 31 env vm.Environment 32 address *common.Address 33 input []byte 34 evm vm.VirtualMachine 35 36 Gas, price, value *big.Int 37 } 38 39 // NewExecution returns a new execution environment that handles all calling 40 // and creation logic defined by the YP. 41 func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution { 42 exe := &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value} 43 exe.evm = vm.NewVm(env) 44 return exe 45 } 46 47 // Call executes within the given context 48 func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) { 49 // Retrieve the executing code 50 code := self.env.State().GetCode(codeAddr) 51 52 return self.exec(&codeAddr, code, caller) 53 } 54 55 // Create creates a new contract and runs the initialisation procedure of the 56 // contract. This returns the returned code for the contract and is stored 57 // elsewhere. 58 func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) { 59 // Input must be nil for create 60 code := self.input 61 self.input = nil 62 ret, err = self.exec(nil, code, caller) 63 // Here we get an error if we run into maximum stack depth, 64 // See: https://github.com/ethereum/yellowpaper/pull/131 65 // and YP definitions for CREATE instruction 66 if err != nil { 67 return nil, err, nil 68 } 69 account = self.env.State().GetStateObject(*self.address) 70 return 71 } 72 73 // exec executes the given code and executes within the contextAddr context. 74 func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) { 75 env := self.env 76 evm := self.evm 77 // Depth check execution. Fail if we're trying to execute above the 78 // limit. 79 if env.Depth() > int(params.CallCreateDepth.Int64()) { 80 caller.ReturnGas(self.Gas, self.price) 81 82 return nil, vm.DepthError 83 } 84 85 if !env.CanTransfer(env.State().GetStateObject(caller.Address()), self.value) { 86 caller.ReturnGas(self.Gas, self.price) 87 88 return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", self.value, env.State().GetBalance(caller.Address())) 89 } 90 91 var createAccount bool 92 if self.address == nil { 93 // Generate a new address 94 nonce := env.State().GetNonce(caller.Address()) 95 env.State().SetNonce(caller.Address(), nonce+1) 96 97 addr := crypto.CreateAddress(caller.Address(), nonce) 98 99 self.address = &addr 100 createAccount = true 101 } 102 snapshot := env.State().Copy() 103 104 var ( 105 from = env.State().GetStateObject(caller.Address()) 106 to *state.StateObject 107 ) 108 if createAccount { 109 to = env.State().CreateAccount(*self.address) 110 } else { 111 to = env.State().GetOrNewStateObject(*self.address) 112 } 113 vm.Transfer(from, to, self.value) 114 115 context := vm.NewContext(caller, to, self.value, self.Gas, self.price) 116 context.SetCallCode(contextAddr, code) 117 118 ret, err = evm.Run(context, self.input) 119 if err != nil { 120 env.State().Set(snapshot) 121 } 122 123 return 124 }