diff options
author | obscuren <geffobscura@gmail.com> | 2014-12-04 00:06:54 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-12-04 00:06:54 +0800 |
commit | 99853ac3ce57807deb4822dd324186e1d2ee0821 (patch) | |
tree | 4c7dc0c8fa1f83d1081f429fa3175b03c9011101 /chain | |
parent | 82405501872385b240012070bad2f0eda643d423 (diff) | |
download | dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar.gz dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar.bz2 dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar.lz dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar.xz dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.tar.zst dexon-99853ac3ce57807deb4822dd324186e1d2ee0821.zip |
Moved execution from vm to chain.
This moves call and create to the specified environments. Vms are no
longer re-used. Vm uses environment's Call(Code) and Create in order to
execute new contracts or transfer value between accounts.
State transition now uses the same mechanism described above.
Diffstat (limited to 'chain')
-rw-r--r-- | chain/execution.go | 80 | ||||
-rw-r--r-- | chain/state_transition.go | 117 | ||||
-rw-r--r-- | chain/vm_env.go | 23 |
3 files changed, 112 insertions, 108 deletions
diff --git a/chain/execution.go b/chain/execution.go new file mode 100644 index 000000000..932ffa868 --- /dev/null +++ b/chain/execution.go @@ -0,0 +1,80 @@ +package chain + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/vm" +) + +type Execution struct { + vm vm.VirtualMachine + address, input []byte + Gas, price, value *big.Int + object *state.StateObject + SkipTransfer bool +} + +func NewExecution(vm vm.VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { + return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value} +} + +func (self *Execution) Addr() []byte { + return self.address +} + +func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, error) { + // Retrieve the executing code + code := self.vm.Env().State().GetCode(codeAddr) + + return self.exec(code, codeAddr, caller) +} + +func (self *Execution) exec(code, caddr []byte, caller vm.ClosureRef) (ret []byte, err error) { + env := self.vm.Env() + + chainlogger.Debugf("pre state %x\n", env.State().Root()) + snapshot := env.State().Copy() + defer func() { + if vm.IsDepthErr(err) || vm.IsOOGErr(err) { + env.State().Set(snapshot) + } + chainlogger.Debugf("post state %x\n", env.State().Root()) + }() + + from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address) + // Skipping transfer is used on testing for the initial call + if !self.SkipTransfer { + err = env.Transfer(from, to, self.value) + } + + if err != nil { + caller.ReturnGas(self.Gas, self.price) + + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) + } else { + self.object = to + // Pre-compiled contracts (address.go) 1, 2 & 3. + naddr := ethutil.BigD(caddr).Uint64() + if p := vm.Precompiled[naddr]; p != nil { + if self.Gas.Cmp(p.Gas) >= 0 { + ret = p.Call(self.input) + self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) + self.vm.Endl() + } + } else { + ret, err = self.vm.Run(to, caller, code, self.value, self.Gas, self.price, self.input) + } + } + + return +} + +func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject) { + ret, err = self.exec(self.input, nil, caller) + account = self.vm.Env().State().GetStateObject(self.address) + + return +} diff --git a/chain/state_transition.go b/chain/state_transition.go index 8f7b55cd4..b2ba4f22a 100644 --- a/chain/state_transition.go +++ b/chain/state_transition.go @@ -169,120 +169,21 @@ func (self *StateTransition) TransitionState() (err error) { return } - if sender.Balance().Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) - } - - var snapshot *state.State - // If the receiver is nil it's a contract (\0*32). + var ret []byte + vmenv := NewEnv(self.state, self.tx, self.block) + var ref vm.ClosureRef if tx.CreatesContract() { - // Subtract the (irreversible) amount from the senders account - sender.SubAmount(self.value) + self.rec = MakeContract(tx, self.state) - snapshot = self.state.Copy() - - // Create a new state object for the contract - receiver = MakeContract(tx, self.state) - self.rec = receiver - if receiver == nil { - return fmt.Errorf("Unable to create contract") - } - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.value) + ret, err, ref = vmenv.Create(sender, receiver.Address(), self.tx.Data, self.gas, self.gasPrice, self.value) + ref.SetCode(ret) } else { - receiver = self.Receiver() - - // Subtract the amount from the senders account - sender.SubAmount(self.value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.value) - - snapshot = self.state.Copy() + ret, err = vmenv.Call(self.Sender(), self.Receiver().Address(), self.tx.Data, self.gas, self.gasPrice, self.value) } - - msg := self.state.Manifest().AddMessage(&state.Message{ - To: receiver.Address(), From: sender.Address(), - Input: self.tx.Data, - Origin: sender.Address(), - Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, - Value: self.value, - }) - - // Process the init code and create 'valid' contract - if types.IsContractAddr(self.receiver) { - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - self.data = nil - - code, evmerr := self.Eval(msg, receiver.Init(), receiver) - if evmerr != nil { - self.state.Set(snapshot) - - statelogger.Debugf("Error during init execution %v", evmerr) - } - - receiver.Code = code - msg.Output = code - } else { - if len(receiver.Code) > 0 { - ret, evmerr := self.Eval(msg, receiver.Code, receiver) - if evmerr != nil { - self.state.Set(snapshot) - - statelogger.Debugf("Error during code execution %v", evmerr) - } - - msg.Output = ret - } + if err != nil { + statelogger.Debugln(err) } - /* - * XXX The following _should_ replace the above transaction - * execution (also for regular calls. Will replace / test next - * phase - */ - /* - // Execute transaction - if tx.CreatesContract() { - self.rec = MakeContract(tx, self.state) - } - - address := self.Receiver().Address() - evm := vm.New(NewEnv(state, self.tx, self.block), vm.DebugVmTy) - exe := NewExecution(evm, address, self.tx.Data, self.gas, self.gas.Price, self.tx.Value) - ret, err := msg.Exec(address, self.Sender()) - if err != nil { - statelogger.Debugln(err) - } else { - if tx.CreatesContract() { - self.Receiver().Code = ret - } - msg.Output = ret - } - */ - - // Add default LOG. Default = big(sender.addr) + 1 - //addr := ethutil.BigD(receiver.Address()) - //self.state.AddLog(&state.Log{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes(), [][]byte{sender.Address()}, nil}) - - return -} - -func (self *StateTransition) Eval(msg *state.Message, script []byte, context *state.StateObject) (ret []byte, err error) { - var ( - transactor = self.Sender() - state = self.state - env = NewEnv(state, self.tx, self.block) - callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) - ) - - evm := vm.New(env, vm.DebugVmTy) - // TMP this will change in the refactor - callerClosure.SetExecution(vm.NewExecution(evm, nil, nil, nil, nil, self.tx.Value)) - ret, _, err = callerClosure.Call(evm, self.tx.Data) - return } diff --git a/chain/vm_env.go b/chain/vm_env.go index c1911ff51..c2428c234 100644 --- a/chain/vm_env.go +++ b/chain/vm_env.go @@ -12,6 +12,7 @@ type VMEnv struct { state *state.State block *types.Block tx *types.Transaction + depth int } func NewEnv(state *state.State, tx *types.Transaction, block *types.Block) *VMEnv { @@ -32,9 +33,31 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *state.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) Depth() int { return self.depth } +func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) AddLog(log *state.Log) { self.state.AddLog(log) } func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } + +func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution { + evm := vm.New(self, vm.DebugVmTy) + + return NewExecution(evm, addr, data, gas, price, value) +} + +func (self *VMEnv) Call(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { + exe := self.vm(addr, data, gas, price, value) + return exe.Call(addr, me) +} +func (self *VMEnv) CallCode(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { + exe := self.vm(me.Address(), data, gas, price, value) + return exe.Call(addr, me) +} + +func (self *VMEnv) Create(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) { + exe := self.vm(addr, data, gas, price, value) + return exe.Create(me) +} |