Skip to content

Commit 23f42d9

Browse files
committed
Merge pull request #1964 from obscuren/evm-runtime
core/vm/runtime: added simple execution runtime
2 parents 4a93840 + 1372b99 commit 23f42d9

File tree

5 files changed

+399
-0
lines changed

5 files changed

+399
-0
lines changed

core/vm/runtime/doc.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2014 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
// Package runtime provides a basic execution model for executing EVM code.
18+
package runtime

core/vm/runtime/env.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2014 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package runtime
18+
19+
import (
20+
"math/big"
21+
22+
"github.com/ethereum/go-ethereum/common"
23+
"github.com/ethereum/go-ethereum/core"
24+
"github.com/ethereum/go-ethereum/core/state"
25+
"github.com/ethereum/go-ethereum/core/vm"
26+
)
27+
28+
// Env is a basic runtime environment required for running the EVM.
29+
type Env struct {
30+
depth int
31+
state *state.StateDB
32+
33+
origin common.Address
34+
coinbase common.Address
35+
36+
number *big.Int
37+
time *big.Int
38+
difficulty *big.Int
39+
gasLimit *big.Int
40+
41+
logs []vm.StructLog
42+
43+
getHashFn func(uint64) common.Hash
44+
}
45+
46+
// NewEnv returns a new vm.Environment
47+
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
48+
return &Env{
49+
state: state,
50+
origin: cfg.Origin,
51+
coinbase: cfg.Coinbase,
52+
number: cfg.BlockNumber,
53+
time: cfg.Time,
54+
difficulty: cfg.Difficulty,
55+
gasLimit: cfg.GasLimit,
56+
}
57+
}
58+
59+
func (self *Env) StructLogs() []vm.StructLog {
60+
return self.logs
61+
}
62+
63+
func (self *Env) AddStructLog(log vm.StructLog) {
64+
self.logs = append(self.logs, log)
65+
}
66+
67+
func (self *Env) Origin() common.Address { return self.origin }
68+
func (self *Env) BlockNumber() *big.Int { return self.number }
69+
func (self *Env) Coinbase() common.Address { return self.coinbase }
70+
func (self *Env) Time() *big.Int { return self.time }
71+
func (self *Env) Difficulty() *big.Int { return self.difficulty }
72+
func (self *Env) Db() vm.Database { return self.state }
73+
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
74+
func (self *Env) VmType() vm.Type { return vm.StdVmTy }
75+
func (self *Env) GetHash(n uint64) common.Hash {
76+
return self.getHashFn(n)
77+
}
78+
func (self *Env) AddLog(log *vm.Log) {
79+
self.state.AddLog(log)
80+
}
81+
func (self *Env) Depth() int { return self.depth }
82+
func (self *Env) SetDepth(i int) { self.depth = i }
83+
func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool {
84+
return self.state.GetBalance(from).Cmp(balance) >= 0
85+
}
86+
func (self *Env) MakeSnapshot() vm.Database {
87+
return self.state.Copy()
88+
}
89+
func (self *Env) SetSnapshot(copy vm.Database) {
90+
self.state.Set(copy.(*state.StateDB))
91+
}
92+
93+
func (self *Env) Transfer(from, to vm.Account, amount *big.Int) {
94+
core.Transfer(from, to, amount)
95+
}
96+
97+
func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
98+
return core.Call(self, caller, addr, data, gas, price, value)
99+
}
100+
func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
101+
return core.CallCode(self, caller, addr, data, gas, price, value)
102+
}
103+
104+
func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
105+
return core.Create(self, caller, data, gas, price, value)
106+
}

core/vm/runtime/runtime.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright 2014 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package runtime
18+
19+
import (
20+
"math/big"
21+
"time"
22+
23+
"github.com/ethereum/go-ethereum/common"
24+
"github.com/ethereum/go-ethereum/core/state"
25+
"github.com/ethereum/go-ethereum/core/vm"
26+
"github.com/ethereum/go-ethereum/crypto"
27+
"github.com/ethereum/go-ethereum/ethdb"
28+
)
29+
30+
// Config is a basic type specifing certain configuration flags for running
31+
// the EVM.
32+
type Config struct {
33+
Difficulty *big.Int
34+
Origin common.Address
35+
Coinbase common.Address
36+
BlockNumber *big.Int
37+
Time *big.Int
38+
GasLimit *big.Int
39+
GasPrice *big.Int
40+
Value *big.Int
41+
DisableJit bool // "disable" so it's enabled by default
42+
Debug bool
43+
44+
GetHashFn func(n uint64) common.Hash
45+
}
46+
47+
// sets defaults on the config
48+
func setDefaults(cfg *Config) {
49+
if cfg.Difficulty == nil {
50+
cfg.Difficulty = new(big.Int)
51+
}
52+
if cfg.Time == nil {
53+
cfg.Time = big.NewInt(time.Now().Unix())
54+
}
55+
if cfg.GasLimit == nil {
56+
cfg.GasLimit = new(big.Int).Set(common.MaxBig)
57+
}
58+
if cfg.GasPrice == nil {
59+
cfg.GasPrice = new(big.Int)
60+
}
61+
if cfg.Value == nil {
62+
cfg.Value = new(big.Int)
63+
}
64+
if cfg.BlockNumber == nil {
65+
cfg.BlockNumber = new(big.Int)
66+
}
67+
if cfg.GetHashFn == nil {
68+
cfg.GetHashFn = func(n uint64) common.Hash {
69+
return common.BytesToHash(crypto.Sha3([]byte(new(big.Int).SetUint64(n).String())))
70+
}
71+
}
72+
}
73+
74+
// Execute executes the code using the input as call data during the execution.
75+
// It returns the EVM's return value, the new state and an error if it failed.
76+
//
77+
// Executes sets up a in memory, temporarily, environment for the execution of
78+
// the given code. It enabled the JIT by default and make sure that it's restored
79+
// to it's original state afterwards.
80+
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
81+
if cfg == nil {
82+
cfg = new(Config)
83+
}
84+
setDefaults(cfg)
85+
86+
// defer the call to setting back the original values
87+
defer func(debug, forceJit, enableJit bool) {
88+
vm.Debug = debug
89+
vm.ForceJit = forceJit
90+
vm.EnableJit = enableJit
91+
}(vm.Debug, vm.ForceJit, vm.EnableJit)
92+
93+
vm.ForceJit = !cfg.DisableJit
94+
vm.EnableJit = !cfg.DisableJit
95+
vm.Debug = cfg.Debug
96+
97+
var (
98+
db, _ = ethdb.NewMemDatabase()
99+
statedb, _ = state.New(common.Hash{}, db)
100+
vmenv = NewEnv(cfg, statedb)
101+
sender = statedb.CreateAccount(cfg.Origin)
102+
receiver = statedb.CreateAccount(common.StringToAddress("contract"))
103+
)
104+
// set the receiver's (the executing contract) code for execution.
105+
receiver.SetCode(code)
106+
107+
// Call the code with the given configuration.
108+
ret, err := vmenv.Call(
109+
sender,
110+
receiver.Address(),
111+
input,
112+
cfg.GasLimit,
113+
cfg.GasPrice,
114+
cfg.Value,
115+
)
116+
117+
if cfg.Debug {
118+
vm.StdErrFormat(vmenv.StructLogs())
119+
}
120+
return ret, statedb, err
121+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2015 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package runtime_test
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/ethereum/go-ethereum/common"
23+
"github.com/ethereum/go-ethereum/core/vm/runtime"
24+
)
25+
26+
func ExampleExecute() {
27+
ret, _, err := runtime.Execute(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00"), nil, nil)
28+
if err != nil {
29+
fmt.Println(err)
30+
}
31+
fmt.Println(ret)
32+
// Output:
33+
// [96 96 96 64 82 96 8 86 91 0]
34+
}

0 commit comments

Comments
 (0)