aboutsummaryrefslogtreecommitdiffstats
path: root/light
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2016-12-06 09:16:03 +0800
committerFelix Lange <fjl@twurst.com>2016-12-06 09:16:03 +0800
commit3fc7c978277051391f8ea7831559e9f4f83c3166 (patch)
treeb11b41c1723e02adc098ddc9f4188a8bad782ed8 /light
parent7f79d249a64ee72b185ffa9a9ed78f137b7938de (diff)
downloadgo-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.go13
-rw-r--r--light/state.go9
-rw-r--r--light/state_object.go2
-rw-r--r--light/vm_env.go119
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 {