aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm
diff options
context:
space:
mode:
authorJanos Guljas <janos@resenje.org>2018-02-09 19:23:30 +0800
committerJanos Guljas <janos@resenje.org>2018-02-22 21:23:17 +0800
commita3a07350dcef0ba39829a20d8ddba4bd3463d293 (patch)
tree100f2515cadd92105537a12e6981fab2193435ee /core/vm
parent820cf09c98706f71d4b02b6c25e62db15830f3fb (diff)
parent1a4e68721a901e86322631fed1191025a6d14c52 (diff)
downloaddexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar.gz
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar.bz2
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar.lz
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar.xz
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.tar.zst
dexon-a3a07350dcef0ba39829a20d8ddba4bd3463d293.zip
swarm, cmd/swarm: Merge branch 'master' into multiple-ens-endpoints
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/evm.go45
-rw-r--r--core/vm/gas_table.go6
-rw-r--r--core/vm/gen_structlog.go34
-rw-r--r--core/vm/instructions.go2
-rw-r--r--core/vm/interface.go4
-rw-r--r--core/vm/interpreter.go23
-rw-r--r--core/vm/logger.go50
-rw-r--r--core/vm/noop.go4
-rw-r--r--core/vm/runtime/env.go4
9 files changed, 110 insertions, 62 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 344435f73..46e7baff4 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -19,6 +19,7 @@ package vm
import (
"math/big"
"sync/atomic"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@@ -38,7 +39,7 @@ type (
)
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
-func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) {
+func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
@@ -48,7 +49,7 @@ func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, erro
return RunPrecompiledContract(p, input, contract)
}
}
- return evm.interpreter.Run(snapshot, contract, input)
+ return evm.interpreter.Run(contract, input)
}
// Context provides the EVM with auxiliary information. Once provided
@@ -68,7 +69,7 @@ type Context struct {
// Block information
Coinbase common.Address // Provides information for COINBASE
- GasLimit *big.Int // Provides information for GASLIMIT
+ GasLimit uint64 // Provides information for GASLIMIT
BlockNumber *big.Int // Provides information for NUMBER
Time *big.Int // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
@@ -165,13 +166,23 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
- // initialise a new contract and set the code that is to be used by the
- // E The contract is a scoped environment for this execution context
- // only.
+ // Initialise a new contract and set the code that is to be used by the EVM.
+ // The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- ret, err = run(evm, snapshot, contract, input)
+ start := time.Now()
+
+ // Capture the tracer start/end events in debug mode
+ if evm.vmConfig.Debug && evm.depth == 0 {
+ evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
+
+ defer func() { // Lazy evaluation of the parameters
+ evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
+ }()
+ }
+ ret, err = run(evm, contract, input)
+
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
@@ -215,7 +226,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- ret, err = run(evm, snapshot, contract, input)
+ ret, err = run(evm, contract, input)
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted {
@@ -248,7 +259,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
contract := NewContract(caller, to, nil, gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- ret, err = run(evm, snapshot, contract, input)
+ ret, err = run(evm, contract, input)
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted {
@@ -291,7 +302,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
- ret, err = run(evm, snapshot, contract, input)
+ ret, err = run(evm, contract, input)
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted {
@@ -338,7 +349,14 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, contractAddr, gas, nil
}
- ret, err = run(evm, snapshot, contract, nil)
+
+ if evm.vmConfig.Debug && evm.depth == 0 {
+ evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value)
+ }
+ start := time.Now()
+
+ ret, err = run(evm, contract, nil)
+
// check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned
@@ -367,10 +385,13 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if maxCodeSizeExceeded && err == nil {
err = errMaxCodeSizeExceeded
}
+ if evm.vmConfig.Debug && evm.depth == 0 {
+ evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
+ }
return ret, contractAddr, contract.Gas, err
}
-// ChainConfig returns the evmironment's chain configuration
+// ChainConfig returns the environment's chain configuration
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
// Interpreter returns the EVM interpreter
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index ff109af57..83adba428 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -17,8 +17,6 @@
package vm
import (
- "math/big"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
@@ -130,7 +128,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
// 0 => non 0
return params.SstoreSetGas, nil
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
- evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
+ evm.StateDB.AddRefund(params.SstoreRefundGas)
return params.SstoreClearGas, nil
} else {
@@ -405,7 +403,7 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
}
if !evm.StateDB.HasSuicided(contract.Address()) {
- evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
+ evm.StateDB.AddRefund(params.SuicideRefundGas)
}
return gas, nil
}
diff --git a/core/vm/gen_structlog.go b/core/vm/gen_structlog.go
index 88df942dc..ade3ca631 100644
--- a/core/vm/gen_structlog.go
+++ b/core/vm/gen_structlog.go
@@ -11,19 +11,22 @@ import (
"github.com/ethereum/go-ethereum/common/math"
)
+var _ = (*structLogMarshaling)(nil)
+
func (s StructLog) MarshalJSON() ([]byte, error) {
type StructLog struct {
- Pc uint64 `json:"pc"`
- Op OpCode `json:"op"`
- Gas math.HexOrDecimal64 `json:"gas"`
- GasCost math.HexOrDecimal64 `json:"gasCost"`
- Memory hexutil.Bytes `json:"memory"`
- MemorySize int `json:"memSize"`
- Stack []*math.HexOrDecimal256 `json:"stack"`
- Storage map[common.Hash]common.Hash `json:"-"`
- Depth int `json:"depth"`
- Err error `json:"error"`
- OpName string `json:"opName"`
+ Pc uint64 `json:"pc"`
+ Op OpCode `json:"op"`
+ Gas math.HexOrDecimal64 `json:"gas"`
+ GasCost math.HexOrDecimal64 `json:"gasCost"`
+ Memory hexutil.Bytes `json:"memory"`
+ MemorySize int `json:"memSize"`
+ Stack []*math.HexOrDecimal256 `json:"stack"`
+ Storage map[common.Hash]common.Hash `json:"-"`
+ Depth int `json:"depth"`
+ Err error `json:"-"`
+ OpName string `json:"opName"`
+ ErrorString string `json:"error"`
}
var enc StructLog
enc.Pc = s.Pc
@@ -42,6 +45,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.Depth = s.Depth
enc.Err = s.Err
enc.OpName = s.OpName()
+ enc.ErrorString = s.ErrorString()
return json.Marshal(&enc)
}
@@ -51,12 +55,12 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
Op *OpCode `json:"op"`
Gas *math.HexOrDecimal64 `json:"gas"`
GasCost *math.HexOrDecimal64 `json:"gasCost"`
- Memory hexutil.Bytes `json:"memory"`
+ Memory *hexutil.Bytes `json:"memory"`
MemorySize *int `json:"memSize"`
Stack []*math.HexOrDecimal256 `json:"stack"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth *int `json:"depth"`
- Err *error `json:"error"`
+ Err error `json:"-"`
}
var dec StructLog
if err := json.Unmarshal(input, &dec); err != nil {
@@ -75,7 +79,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s.GasCost = uint64(*dec.GasCost)
}
if dec.Memory != nil {
- s.Memory = dec.Memory
+ s.Memory = *dec.Memory
}
if dec.MemorySize != nil {
s.MemorySize = *dec.MemorySize
@@ -93,7 +97,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s.Depth = *dec.Depth
}
if dec.Err != nil {
- s.Err = *dec.Err
+ s.Err = dec.Err
}
return nil
}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 1d1585fca..766172501 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -472,7 +472,7 @@ func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
}
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
- stack.push(math.U256(new(big.Int).Set(evm.GasLimit)))
+ stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit)))
return nil, nil
}
diff --git a/core/vm/interface.go b/core/vm/interface.go
index c0c52732b..1ef91cf1d 100644
--- a/core/vm/interface.go
+++ b/core/vm/interface.go
@@ -39,8 +39,8 @@ type StateDB interface {
SetCode(common.Address, []byte)
GetCodeSize(common.Address) int
- AddRefund(*big.Int)
- GetRefund() *big.Int
+ AddRefund(uint64)
+ GetRefund() uint64
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash)
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index ac6000f97..482e67a3a 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -107,9 +107,9 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
// the return byte-slice and an error if one occurred.
//
// It's important to note that any errors returned by the interpreter should be
-// considered a revert-and-consume-all-gas operation. No error specific checks
-// should be handled to reduce complexity and errors further down the in.
-func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) {
+// considered a revert-and-consume-all-gas operation except for
+// errExecutionReverted which means revert-and-keep-gas-left.
+func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Increment the call depth which is restricted to 1024
in.evm.depth++
defer func() { in.evm.depth-- }()
@@ -144,12 +144,17 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
)
contract.Input = input
- defer func() {
- if err != nil && !logged && in.cfg.Debug {
- in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
- }
- }()
-
+ if in.cfg.Debug {
+ defer func() {
+ if err != nil {
+ if !logged {
+ in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
+ } else {
+ in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
+ }
+ }
+ }()
+ }
// The Interpreter main run loop (contextual). This loop runs until either an
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
// the execution of one of the operations or until the done flag is set by the
diff --git a/core/vm/logger.go b/core/vm/logger.go
index 75309da92..4c820d8b5 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -62,29 +62,39 @@ type StructLog struct {
Stack []*big.Int `json:"stack"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
- Err error `json:"error"`
+ Err error `json:"-"`
}
// overrides for gencodec
type structLogMarshaling struct {
- Stack []*math.HexOrDecimal256
- Gas math.HexOrDecimal64
- GasCost math.HexOrDecimal64
- Memory hexutil.Bytes
- OpName string `json:"opName"`
+ Stack []*math.HexOrDecimal256
+ Gas math.HexOrDecimal64
+ GasCost math.HexOrDecimal64
+ Memory hexutil.Bytes
+ OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
+ ErrorString string `json:"error"` // adds call to ErrorString() in MarshalJSON
}
func (s *StructLog) OpName() string {
return s.Op.String()
}
+func (s *StructLog) ErrorString() string {
+ if s.Err != nil {
+ return s.Err.Error()
+ }
+ return ""
+}
+
// Tracer is used to collect execution traces from an EVM transaction
// execution. CaptureState is called for each step of the VM with the
// current VM state.
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type Tracer interface {
+ CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
+ CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
}
@@ -98,6 +108,8 @@ type StructLogger struct {
logs []StructLog
changedValues map[common.Address]Storage
+ output []byte
+ err error
}
// NewStructLogger returns a new logger
@@ -111,6 +123,10 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
return logger
}
+func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
+ return nil
+}
+
// CaptureState logs a new structured log message and pushes it out to the environment
//
// CaptureState also tracks SSTORE ops to track dirty values.
@@ -161,19 +177,25 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
return nil
}
-func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
- fmt.Printf("0x%x", output)
- if err != nil {
- fmt.Printf(" error: %v\n", err)
- }
+func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
return nil
}
-// StructLogs returns a list of captured log entries
-func (l *StructLogger) StructLogs() []StructLog {
- return l.logs
+func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
+ l.output = output
+ l.err = err
+ return nil
}
+// StructLogs returns the captured log entries.
+func (l *StructLogger) StructLogs() []StructLog { return l.logs }
+
+// Error returns the VM error captured by the trace.
+func (l *StructLogger) Error() error { return l.err }
+
+// Output returns the VM return value captured by the trace.
+func (l *StructLogger) Output() []byte { return l.output }
+
// WriteTrace writes a formatted trace to the given writer
func WriteTrace(writer io.Writer, logs []StructLog) {
for _, log := range logs {
diff --git a/core/vm/noop.go b/core/vm/noop.go
index 2a04a9565..b71ead0d7 100644
--- a/core/vm/noop.go
+++ b/core/vm/noop.go
@@ -55,8 +55,8 @@ func (NoopStateDB) GetCodeHash(common.Address) common.Hash
func (NoopStateDB) GetCode(common.Address) []byte { return nil }
func (NoopStateDB) SetCode(common.Address, []byte) {}
func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
-func (NoopStateDB) AddRefund(*big.Int) {}
-func (NoopStateDB) GetRefund() *big.Int { return nil }
+func (NoopStateDB) AddRefund(uint64) {}
+func (NoopStateDB) GetRefund() uint64 { return 0 }
func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
func (NoopStateDB) Suicide(common.Address) bool { return false }
diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go
index 818da1be2..31c9b9cf9 100644
--- a/core/vm/runtime/env.go
+++ b/core/vm/runtime/env.go
@@ -17,8 +17,6 @@
package runtime
import (
- "math/big"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/vm"
@@ -35,7 +33,7 @@ func NewEnv(cfg *Config) *vm.EVM {
BlockNumber: cfg.BlockNumber,
Time: cfg.Time,
Difficulty: cfg.Difficulty,
- GasLimit: new(big.Int).SetUint64(cfg.GasLimit),
+ GasLimit: cfg.GasLimit,
GasPrice: cfg.GasPrice,
}