good morning!!!!

Skip to content
Snippets Groups Projects
vm.go 6.34 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    package helper
    
    import (
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	"errors"
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	"math/big"
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	"github.com/ethereum/go-ethereum/common"
    
    	"github.com/ethereum/go-ethereum/core"
    
    	"github.com/ethereum/go-ethereum/core/state"
    	"github.com/ethereum/go-ethereum/core/vm"
    
    	"github.com/ethereum/go-ethereum/crypto"
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    )
    
    type Env struct {
    
    	state        *state.StateDB
    
    	skipTransfer bool
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	initial      bool
    
    	Gas          *big.Int
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	origin common.Address
    	//parent   common.Hash
    	coinbase common.Address
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    	number     *big.Int
    	time       int64
    	difficulty *big.Int
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	gasLimit   *big.Int
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    	vmTest bool
    
    func NewEnv(state *state.StateDB) *Env {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	return &Env{
    		state: state,
    	}
    }
    
    
    func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	env := NewEnv(state)
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	env.origin = common.HexToAddress(exeValues["caller"])
    	//env.parent = common.Hex2Bytes(envValues["previousHash"])
    	env.coinbase = common.HexToAddress(envValues["currentCoinbase"])
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	env.number = common.Big(envValues["currentNumber"])
    	env.time = common.Big(envValues["currentTimestamp"]).Int64()
    	env.difficulty = common.Big(envValues["currentDifficulty"])
    	env.gasLimit = common.Big(envValues["currentGasLimit"])
    
    	env.Gas = new(big.Int)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    	return env
    }
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self *Env) Origin() common.Address { return self.origin }
    func (self *Env) BlockNumber() *big.Int  { return self.number }
    
    //func (self *Env) PrevHash() []byte      { return self.parent }
    func (self *Env) Coinbase() common.Address { return self.coinbase }
    func (self *Env) Time() int64              { return self.time }
    func (self *Env) Difficulty() *big.Int     { return self.difficulty }
    func (self *Env) State() *state.StateDB    { return self.state }
    func (self *Env) GasLimit() *big.Int       { return self.gasLimit }
    func (self *Env) VmType() vm.Type          { return vm.StdVmTy }
    func (self *Env) GetHash(n uint64) common.Hash {
    	return common.BytesToHash(crypto.Sha3([]byte(big.NewInt(int64(n)).String())))
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self *Env) AddLog(log state.Log) {
    
    	self.logs = append(self.logs, log)
    }
    
    func (self *Env) Depth() int     { return self.depth }
    func (self *Env) SetDepth(i int) { self.depth = i }
    
    func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	if self.skipTransfer {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		// ugly hack
    		if self.initial {
    			self.initial = false
    			return nil
    		}
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		if from.Balance().Cmp(amount) < 0 {
    			return errors.New("Insufficient balance in account")
    		}
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    		return nil
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	}
    
    	return vm.Transfer(from, to, amount)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self *Env) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *core.Execution {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	exec := core.NewExecution(self, addr, data, gas, price, value)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self *Env) Call(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	if self.vmTest && self.depth > 0 {
    		caller.ReturnGas(gas, price)
    
    		return nil, nil
    	}
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	exe := self.vm(&addr, data, gas, price, value)
    
    	ret, err := exe.Call(addr, caller)
    	self.Gas = exe.Gas
    
    	return ret, err
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self *Env) CallCode(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	if self.vmTest && self.depth > 0 {
    		caller.ReturnGas(gas, price)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    		return nil, nil
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	}
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    
    	caddr := caller.Address()
    	exe := self.vm(&caddr, data, gas, price, value)
    
    	return exe.Call(addr, caller)
    }
    
    
    func (self *Env) Create(caller vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
    	exe := self.vm(addr, data, gas, price, value)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	if self.vmTest {
    		caller.ReturnGas(gas, price)
    
    		nonce := self.state.GetNonce(caller.Address())
    		obj := self.state.GetOrNewStateObject(crypto.CreateAddress(caller.Address(), nonce))
    
    		return nil, nil, obj
    	} else {
    		return exe.Create(caller)
    	}
    
    func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Logs, *big.Int, error) {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		to    = common.HexToAddress(exec["address"])
    		from  = common.HexToAddress(exec["caller"])
    
    		data  = FromHex(exec["data"])
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		gas   = common.Big(exec["gas"])
    		price = common.Big(exec["gasPrice"])
    		value = common.Big(exec["value"])
    
    	// Reset the pre-compiled contracts for VM tests.
    	vm.Precompiled = make(map[string]*vm.PrecompiledAccount)
    
    
    	caller := state.GetOrNewStateObject(from)
    
    	vmenv := NewEnvFromMap(state, env, exec)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	vmenv.vmTest = true
    
    	vmenv.skipTransfer = true
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	vmenv.initial = true
    
    	ret, err := vmenv.Call(caller, to, data, gas, price, value)
    
    	return ret, vmenv.logs, vmenv.Gas, err
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    }
    
    func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		keyPair, _ = crypto.NewKeyPairFromSec([]byte(common.Hex2Bytes(tx["secretKey"])))
    
    		data       = FromHex(tx["data"])
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		gas        = common.Big(tx["gasLimit"])
    		price      = common.Big(tx["gasPrice"])
    		value      = common.Big(tx["value"])
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    		caddr      = common.HexToAddress(env["currentCoinbase"])
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	var to *common.Address
    	if len(tx["to"]) > 2 {
    		t := common.HexToAddress(tx["to"])
    		to = &t
    	}
    
    	// Set pre compiled contracts
    	vm.Precompiled = vm.PrecompiledContracts()
    
    
    	snapshot := statedb.Copy()
    
    	coinbase := statedb.GetOrNewStateObject(caddr)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	coinbase.SetGasPool(common.Big(env["currentGasLimit"]))
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	message := NewMessage(common.BytesToAddress(keyPair.Address()), to, data, value, gas, price)
    
    	vmenv := NewEnvFromMap(statedb, env, tx)
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	vmenv.origin = common.BytesToAddress(keyPair.Address())
    
    	ret, _, err := core.ApplyMessage(vmenv, message, coinbase)
    
    	if core.IsNonceErr(err) || core.IsInvalidTxErr(err) {
    		statedb.Set(snapshot)
    	}
    
    	statedb.Update(vmenv.Gas)
    
    	return ret, vmenv.logs, vmenv.Gas, err
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    }
    
    
    type Message struct {
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    	from              common.Address
    	to                *common.Address
    
    	value, gas, price *big.Int
    	data              []byte
    }
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int) Message {
    
    	return Message{from, to, value, gas, price, data}
    }
    
    
    Jeffrey Wilcke's avatar
    Jeffrey Wilcke committed
    func (self Message) Hash() []byte                  { return nil }
    func (self Message) From() (common.Address, error) { return self.from, nil }
    func (self Message) To() *common.Address           { return self.to }
    func (self Message) GasPrice() *big.Int            { return self.price }
    func (self Message) Gas() *big.Int                 { return self.gas }
    func (self Message) Value() *big.Int               { return self.value }
    func (self Message) Nonce() uint64                 { return 0 }
    func (self Message) Data() []byte                  { return self.data }