-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlevm.go
116 lines (96 loc) · 3.28 KB
/
levm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package levm
import (
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/params"
vmi "github.com/cryptokass/levm/vminterface"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
)
// LEVM is a container for the go-ethereum EVM
// with methods to create and call contracts.
//
// LEVM contains the two most important objects
// for interacting with the EVM: stateDB and
// vm.EVM. The LEVM should be created with the
// LEVM.New() method, unless you know what you
// doing.
type LEVM struct {
stateDB *state.StateDB
evm *vm.EVM
edb ethdb.Database
}
// New creates a new instace of the LEVM
func New(dbPath string, blockNumber *big.Int, origin common.Address) *LEVM {
// create blank LEVM instance:
lvm := LEVM{}
// setup storage using dbpath
lvm.stateDB, lvm.edb = vmi.NewStateDB(common.Hash{}, dbPath)
// update the evm - creates new EVM
lvm.NewEVM(blockNumber, origin)
return &lvm
}
// NewEVM creates a fresh evm instance with
// new origin and blocknumber and time.
// This method recreates the contained EVM while
// keeping the stateDB the same.
func (lvm *LEVM) NewEVM(blockNumber *big.Int, origin common.Address) {
// create contexted for the evm context
chainContext := vmi.NewChainContext(origin)
vmContext := vmi.NewVMContext(origin, origin, blockNumber, chainContext)
// create vm config
logConfig := vm.LogConfig{}
structLogger := vm.NewStructLogger(&logConfig)
vmConfig := vm.Config{Debug: true, Tracer: structLogger /*JumpTable: vm.NewByzantiumInstructionSet()*/}
// create the evm
lvm.evm = vm.NewEVM(vmContext, lvm.stateDB, params.MainnetChainConfig, vmConfig)
}
// DeployContract will create and deploy a new
// contract from the contract data.
func (lvm *LEVM) DeployContract(fromAddr common.Address, contractData []byte) ([]byte, common.Address, uint64, error) {
// Get reference to the transaction sender
contractRef := vm.AccountRef(fromAddr)
leftOver := big.NewInt(0)
return lvm.evm.Create(
contractRef,
contractData,
lvm.stateDB.GetBalance(fromAddr).Uint64(),
leftOver,
)
}
// CallContract - make a call to a Contract Method
// using prepacked Inputs. To use ABI directly try
// lvm.CallContractABI()
func (lvm *LEVM) CallContract(callerAddr, contractAddr common.Address, value *big.Int, inputs []byte) ([]byte, error) {
// Get reference to the transaction sender
callerRef := vm.AccountRef(callerAddr)
output, gas, err := lvm.evm.Call(
callerRef,
contractAddr,
inputs,
lvm.stateDB.GetBalance(callerAddr).Uint64(),
value,
)
lvm.stateDB.SetBalance(callerAddr, big.NewInt(0).SetUint64(gas))
return output, err
}
// CallContractABI - make a call to a Contract Method
// using the ABI.
func (lvm *LEVM) CallContractABI(callerAddr, contractAddr common.Address, value *big.Int, abiObject abi.ABI, funcName string, args ...interface{}) ([]byte, error) {
inputs, err := abiObject.Pack(funcName, args...)
if err != nil {
return nil, err
}
callerRef := vm.AccountRef(callerAddr)
output, gas, err := lvm.evm.Call(
callerRef,
contractAddr,
inputs,
lvm.stateDB.GetBalance(callerAddr).Uint64(),
value,
)
lvm.stateDB.SetBalance(callerAddr, big.NewInt(0).SetUint64(gas))
return output, err
}