aboutsummaryrefslogblamecommitdiffstats
path: root/tests/helper/vm.go
blob: f1aaf74b8ed5dbae5c55cdad5e7bc50bf2ad06dd (plain) (tree)
1
2
3
4
5
6
7
8
9


              
                

                  
                                              
                                                
                                                 
                                               
                                            


                 
                        
                                   
                         
                         
                             







                           
                           

                       

                   

 
                                        




                             
                                                                                                         





                                                                      


                                                                     
                              



                  





                                                                  
                                                             
                                                                
                                                             
                                           
                                                                 
 
                                        

                                          

                                                      
                                                                       
                              





                                            


                                                                            

                          
         
                                            
 
 
                                                                                    
                                                                      



                   
                                                                                                            




                                            




                                                     
 
 
                                                                                                                

                                            

                               
         



                                                                 
                                                                                                                             
                                                     









                                                                                                    

 
                                                                                                     







                                                     

                                                                

                                                 
 
                                                
                           
                                 
                            
                                                                   
 
                                              
 
 
                                                                                                        






                                                                                                 
                                                            

         


                                                  
                                  

                                                                
 
                                                                             

                                                
                                                                  


                                                             
                                 
 
                                              
 


















                                                                            
package helper

import (
    "errors"
    "math/big"

    "github.com/ethereum/go-ethereum/core"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethutil"
    "github.com/ethereum/go-ethereum/state"
    "github.com/ethereum/go-ethereum/vm"
)

type Env struct {
    depth        int
    state        *state.StateDB
    skipTransfer bool
    initial      bool
    Gas          *big.Int

    origin   []byte
    parent   []byte
    coinbase []byte

    number     *big.Int
    time       int64
    difficulty *big.Int
    gasLimit   *big.Int

    logs state.Logs

    vmTest bool
}

func NewEnv(state *state.StateDB) *Env {
    return &Env{
        state: state,
    }
}

func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
    env := NewEnv(state)

    env.origin = ethutil.Hex2Bytes(exeValues["caller"])
    env.parent = ethutil.Hex2Bytes(envValues["previousHash"])
    env.coinbase = ethutil.Hex2Bytes(envValues["currentCoinbase"])
    env.number = ethutil.Big(envValues["currentNumber"])
    env.time = ethutil.Big(envValues["currentTimestamp"]).Int64()
    env.difficulty = ethutil.Big(envValues["currentDifficulty"])
    env.gasLimit = ethutil.Big(envValues["currentGasLimit"])
    env.Gas = new(big.Int)

    return env
}

func (self *Env) Origin() []byte        { return self.origin }
func (self *Env) BlockNumber() *big.Int { return self.number }
func (self *Env) PrevHash() []byte      { return self.parent }
func (self *Env) Coinbase() []byte      { 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) []byte {
    return crypto.Sha3([]byte(big.NewInt(int64(n)).String()))
}
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 {
    if self.skipTransfer {
        // ugly hack
        if self.initial {
            self.initial = false
            return nil
        }

        if from.Balance().Cmp(amount) < 0 {
            return errors.New("Insufficient balance in account")
        }

        return nil
    }
    return vm.Transfer(from, to, amount)
}

func (self *Env) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution {
    exec := core.NewExecution(self, addr, data, gas, price, value)

    return exec
}

func (self *Env) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
    if self.vmTest && self.depth > 0 {
        caller.ReturnGas(gas, price)

        return nil, nil
    }
    exe := self.vm(addr, data, gas, price, value)
    ret, err := exe.Call(addr, caller)
    self.Gas = exe.Gas

    return ret, err

}
func (self *Env) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
    if self.vmTest && self.depth > 0 {
        caller.ReturnGas(gas, price)

        return nil, nil
    }
    exe := self.vm(caller.Address(), data, gas, price, value)
    return exe.Call(addr, caller)
}

func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
    exe := self.vm(addr, data, gas, price, value)
    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) {
    var (
        to    = FromHex(exec["address"])
        from  = FromHex(exec["caller"])
        data  = FromHex(exec["data"])
        gas   = ethutil.Big(exec["gas"])
        price = ethutil.Big(exec["gasPrice"])
        value = ethutil.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)
    vmenv.vmTest = true
    vmenv.skipTransfer = true
    vmenv.initial = true
    ret, err := vmenv.Call(caller, to, data, gas, price, value)

    return ret, vmenv.logs, vmenv.Gas, err
}

func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) {
    var (
        keyPair, _ = crypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(tx["secretKey"])))
        to         = FromHex(tx["to"])
        data       = FromHex(tx["data"])
        gas        = ethutil.Big(tx["gasLimit"])
        price      = ethutil.Big(tx["gasPrice"])
        value      = ethutil.Big(tx["value"])
        caddr      = FromHex(env["currentCoinbase"])
    )

    // Set pre compiled contracts
    vm.Precompiled = vm.PrecompiledContracts()

    snapshot := statedb.Copy()
    coinbase := statedb.GetOrNewStateObject(caddr)
    coinbase.SetGasPool(ethutil.Big(env["currentGasLimit"]))

    message := NewMessage(keyPair.Address(), to, data, value, gas, price)
    vmenv := NewEnvFromMap(statedb, env, tx)
    vmenv.origin = 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
}

type Message struct {
    from, to          []byte
    value, gas, price *big.Int
    data              []byte
}

func NewMessage(from, to, data []byte, value, gas, price *big.Int) Message {
    return Message{from, to, value, gas, price, data}
}

func (self Message) Hash() []byte       { return nil }
func (self Message) From() []byte       { return self.from }
func (self Message) To() []byte         { 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 }