diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2016-12-06 09:16:03 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2016-12-06 09:16:03 +0800 |
commit | 3fc7c978277051391f8ea7831559e9f4f83c3166 (patch) | |
tree | b11b41c1723e02adc098ddc9f4188a8bad782ed8 /light | |
parent | 7f79d249a64ee72b185ffa9a9ed78f137b7938de (diff) | |
download | go-tangerine-3fc7c978277051391f8ea7831559e9f4f83c3166.tar.gz go-tangerine-3fc7c978277051391f8ea7831559e9f4f83c3166.tar.zst go-tangerine-3fc7c978277051391f8ea7831559e9f4f83c3166.zip |
core, core/vm: implemented a generic environment (#3348)
Environment is now a struct (not an interface). This
reduces a lot of tech-debt throughout the codebase where a virtual
machine environment had to be implemented in order to test or run it.
The new environment is suitable to be used en the json tests, core
consensus and light client.
Diffstat (limited to 'light')
-rw-r--r-- | light/odr_test.go | 13 | ||||
-rw-r--r-- | light/state.go | 9 | ||||
-rw-r--r-- | light/state_object.go | 2 | ||||
-rw-r--r-- | light/vm_env.go | 119 |
4 files changed, 40 insertions, 103 deletions
diff --git a/light/odr_test.go b/light/odr_test.go index 50255a7f3..2f60f32fd 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -157,6 +157,8 @@ func (callmsg) CheckNonce() bool { return false } func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") + config := params.TestChainConfig + var res []byte for i := 0; i < 3; i++ { data[35] = byte(i) @@ -168,7 +170,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} - vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{}) + + context := core.NewEVMContext(msg, header, bc) + vmenv := vm.NewEnvironment(context, statedb, config, vm.Config{}) + gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) @@ -176,15 +181,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } else { header := lc.GetHeaderByHash(bhash) state := NewLightState(StateTrieID(header), lc.Odr()) + vmstate := NewVMState(ctx, state) from, err := state.GetOrNewStateObject(ctx, testBankAddress) if err == nil { from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} - vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{}) + context := core.NewEVMContext(msg, header, lc) + vmenv := vm.NewEnvironment(context, vmstate, config, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) - if vmenv.Error() == nil { + if vmstate.Error() == nil { res = append(res, ret...) } } diff --git a/light/state.go b/light/state.go index 9f2376809..f8b75c588 100644 --- a/light/state.go +++ b/light/state.go @@ -141,6 +141,15 @@ func (self *LightState) AddBalance(ctx context.Context, addr common.Address, amo return err } +// SubBalance adds the given amount to the balance of the specified account +func (self *LightState) SubBalance(ctx context.Context, addr common.Address, amount *big.Int) error { + stateObject, err := self.GetOrNewStateObject(ctx, addr) + if err == nil && stateObject != nil { + stateObject.SubBalance(amount) + } + return err +} + // SetNonce sets the nonce of the specified account func (self *LightState) SetNonce(ctx context.Context, addr common.Address, nonce uint64) error { stateObject, err := self.GetOrNewStateObject(ctx, addr) diff --git a/light/state_object.go b/light/state_object.go index 6161d2dfb..56f607bff 100644 --- a/light/state_object.go +++ b/light/state_object.go @@ -179,7 +179,7 @@ func (c *StateObject) SetBalance(amount *big.Int) { } // ReturnGas returns the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(gas, price *big.Int) {} +func (c *StateObject) ReturnGas(gas *big.Int) {} // Copy creates a copy of the state object func (self *StateObject) Copy() *StateObject { diff --git a/light/vm_env.go b/light/vm_env.go index d4d7bcce7..cc0c568c9 100644 --- a/light/vm_env.go +++ b/light/vm_env.go @@ -20,123 +20,38 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" "golang.org/x/net/context" ) -// VMEnv is the light client version of the vm execution environment. -// Unlike other structures, VMEnv holds a context that is applied by state -// retrieval requests through the entire execution. If any state operation -// returns an error, the execution fails. -type VMEnv struct { - vm.Environment - ctx context.Context - chainConfig *params.ChainConfig - evm *vm.EVM - state *VMState - header *types.Header - msg core.Message - depth int - chain *LightChain - err error -} - -// NewEnv creates a new execution environment based on an ODR capable light state -func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv { - env := &VMEnv{ - chainConfig: chainConfig, - chain: chain, - header: header, - msg: msg, - } - env.state = &VMState{ctx: ctx, state: state, env: env} - - env.evm = vm.New(env, cfg) - return env -} - -func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig } -func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Origin() common.Address { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } -func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } -func (self *VMEnv) Time() *big.Int { return self.header.Time } -func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } -func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } -func (self *VMEnv) Db() vm.Database { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) GetHash(n uint64) common.Hash { - for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { - if header.Number.Uint64() == n { - return header.Hash() - } - } - - return common.Hash{} -} - -func (self *VMEnv) AddLog(log *vm.Log) { - //self.state.AddLog(log) -} -func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool { - return self.state.GetBalance(from).Cmp(balance) >= 0 -} - -func (self *VMEnv) SnapshotDatabase() int { - return self.state.SnapshotDatabase() -} - -func (self *VMEnv) RevertToSnapshot(idx int) { - self.state.RevertToSnapshot(idx) -} - -func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { - core.Transfer(from, to, amount) -} - -func (self *VMEnv) Call(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.Call(self, me, addr, data, gas, price, value) -} -func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.CallCode(self, me, addr, data, gas, price, value) -} - -func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return core.DelegateCall(self, me, addr, data, gas, price) -} - -func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return core.Create(self, me, data, gas, price, value) -} - -// Error returns the error (if any) that happened during execution. -func (self *VMEnv) Error() error { - return self.err -} - // VMState is a wrapper for the light state that holds the actual context and // passes it to any state operation that requires it. type VMState struct { - vm.Database ctx context.Context state *LightState snapshots []*LightState - env *VMEnv + err error +} + +func NewVMState(ctx context.Context, state *LightState) *VMState { + return &VMState{ctx: ctx, state: state} +} + +func (s *VMState) Error() error { + return s.err } +func (s *VMState) AddLog(log *vm.Log) {} + // errHandler handles and stores any state error that happens during execution. func (s *VMState) errHandler(err error) { - if err != nil && s.env.err == nil { - s.env.err = err + if err != nil && s.err == nil { + s.err = err } } -func (self *VMState) SnapshotDatabase() int { +func (self *VMState) Snapshot() int { self.snapshots = append(self.snapshots, self.state.Copy()) return len(self.snapshots) - 1 } @@ -175,6 +90,12 @@ func (s *VMState) AddBalance(addr common.Address, amount *big.Int) { s.errHandler(err) } +// SubBalance adds the given amount to the balance of the specified account +func (s *VMState) SubBalance(addr common.Address, amount *big.Int) { + err := s.state.SubBalance(s.ctx, addr, amount) + s.errHandler(err) +} + // GetBalance retrieves the balance from the given address or 0 if the account does // not exist func (s *VMState) GetBalance(addr common.Address) *big.Int { |