core,vm,eth,les: add precompiles to block context, re-enable tx tracing

This commit is contained in:
Martin Holst Swende 2018-05-29 10:13:01 +02:00
parent 56819e1de5
commit 58e01e4058
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
14 changed files with 118 additions and 95 deletions

View file

@ -283,9 +283,12 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
msg := callmsg{call} msg := callmsg{call}
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
// Ignore error, we're past header validation
beneficiary, _ := b.blockchain.Engine().Author(block.Header())
blockContext := core.NewBlockContext(block.Header(), beneficiary, b.config)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) vmenv := vm.NewEVM(evmContext, statedb, b.config, &vm.Config{}, blockContext)
gaspool := new(core.GasPool).AddGas(math.MaxUint64) gaspool := new(core.GasPool).AddGas(math.MaxUint64)
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()

View file

@ -53,8 +53,7 @@ type BlockGen struct {
config *params.ChainConfig config *params.ChainConfig
engine consensus.Engine engine consensus.Engine
}
}
// SetCoinbase sets the coinbase of the generated block. // SetCoinbase sets the coinbase of the generated block.
// It can be called at most once. // It can be called at most once.
@ -100,18 +99,8 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
} }
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
blockContext := &vm.BlockContext{ blockContext := NewBlockContext(b.header, b.header.Coinbase, b.config)
BlockNumber: b.header.Number, receipt, _, err := ApplyTransaction(b.config, bc, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, &vm.Config{}, blockContext)
Coinbase: b.header.Coinbase,
GasLimit: b.header.GasLimit,
Signer: types.MakeSigner(b.config, b.header.Number),
Precompiles: vm.PrecompiledContractsByzantium, // TODO fix
Intpool: vm.NewIntpool(),
Time: b.header.Time,
Difficulty: b.header.Difficulty,
}
receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, &vm.Config{}, blockContext)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
) )
// ChainContext supports retrieving headers and consensus parameters from the // ChainContext supports retrieving headers and consensus parameters from the
@ -36,7 +37,7 @@ type ChainContext interface {
} }
// NewEVMContext creates a new context for use in the EVM. // NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) *vm.Context { func NewEVMContext(msg Message, header *types.Header, chain ChainContext) *vm.Context {
return &vm.Context{ return &vm.Context{
CanTransfer: CanTransfer, CanTransfer: CanTransfer,
Transfer: Transfer, Transfer: Transfer,
@ -46,6 +47,20 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
} }
} }
// NewBlockContext creates a block-specific context for use in the EVM
func NewBlockContext(header *types.Header, beneficiary common.Address, chainConfig *params.ChainConfig) *vm.BlockContext {
return &vm.BlockContext{
Intpool: vm.NewIntpool(),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).Set(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: header.GasLimit,
Signer: types.MakeSigner(chainConfig, header.Number),
Precompiles: vm.PrecompilesAt(chainConfig, header.Number),
}
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number // GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
var cache map[uint64]common.Hash var cache map[uint64]common.Hash

View file

@ -17,7 +17,6 @@
package core package core
import ( import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -25,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"math/big"
) )
// StateProcessor is a basic Processor, which takes care of transitioning // StateProcessor is a basic Processor, which takes care of transitioning
@ -66,29 +64,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
// Ignore error, we're past header validation
precompiles := vm.PrecompiledContractsHomestead
if p.config.ByzantiumBlock.Cmp(block.Number()) <= 0 {
precompiles = vm.PrecompiledContractsByzantium
}
beneficiary, _ := p.engine.Author(block.Header()) beneficiary, _ := p.engine.Author(block.Header())
blockContext := NewBlockContext(block.Header(), beneficiary, p.config)
blockContext := &vm.BlockContext{
Intpool: vm.NewIntpool(),
Precompiles: precompiles,
BlockNumber: new(big.Int).Set(block.Header().Number),
Time: new(big.Int).Set(block.Header().Time),
Difficulty: new(big.Int).Set(block.Header().Difficulty),
GasLimit: block.Header().GasLimit,
Coinbase: beneficiary,
Signer: types.MakeSigner(p.config, block.Header().Number),
}
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
receipts = make([]*types.Receipt, len(block.Transactions())) receipts = make([]*types.Receipt, len(block.Transactions()))
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, &cfg, blockContext) receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, usedGas, &cfg, blockContext)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -105,13 +89,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// and uses the input parameters for its environment. It returns the receipt // and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg *vm.Config, blockContext *vm.BlockContext) (*types.Receipt, uint64, error) { func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg *vm.Config, blockContext *vm.BlockContext) (*types.Receipt, uint64, error) {
msg, err := tx.AsMessage(blockContext.Signer) msg, err := tx.AsMessage(blockContext.Signer)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
context := NewEVMContext(msg, header, bc, author) context := NewEVMContext(msg, header, bc)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, config, cfg, blockContext) vmenv := vm.NewEVM(context, statedb, config, cfg, blockContext)

View file

@ -64,6 +64,7 @@ type Contract struct {
DelegateCall bool DelegateCall bool
} }
// NewPrecompiledContract returns a new contract environment for the execution of a precompiled contract
func NewPrecompiledContract( caller ContractRef, object ContractRef,value *big.Int, gas uint64) *Contract{ func NewPrecompiledContract( caller ContractRef, object ContractRef,value *big.Int, gas uint64) *Contract{
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}

View file

@ -59,6 +59,14 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{8}): &bn256Pairing{}, common.BytesToAddress([]byte{8}): &bn256Pairing{},
} }
// PrecompilesAt returns the map of active precompiled contracts at the given blocknumber and config
func PrecompilesAt(c *params.ChainConfig, blockNumber *big.Int) map[common.Address]PrecompiledContract {
if c.ByzantiumBlock.Cmp(blockNumber) <= 0 {
return PrecompiledContractsByzantium
}
return PrecompiledContractsHomestead
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract. // RunPrecompiledContract runs and evaluates the output of a precompiled contract.
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
gas := p.RequiredGas(input) gas := p.RequiredGas(input)

View file

@ -22,9 +22,9 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/core/types"
) )
// emptyCodeHash is used by create to ensure deployment is disallowed to already // emptyCodeHash is used by create to ensure deployment is disallowed to already
@ -63,18 +63,11 @@ type Context struct {
// Message information // Message information
Origin common.Address // Provides information for ORIGIN Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE GasPrice *big.Int // Provides information for GASPRICE
//// Block information
//Coinbase common.Address // Provides information for COINBASE
//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
} }
// Blockcontext provides block-constant auxiliary information. Should never be modified after // Blockcontext provides block-constant auxiliary information. Should never be modified after
// creation // creation
type BlockContext struct{ type BlockContext struct {
Precompiles map[common.Address]PrecompiledContract Precompiles map[common.Address]PrecompiledContract
Signer types.Signer Signer types.Signer
Intpool *IntPool Intpool *IntPool
@ -125,7 +118,7 @@ type EVM struct {
// NewEVM returns a new EVM. The returned EVM is not thread safe and should // NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*. // only ever be used *once*.
func NewEVM(ctx *Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig *Config,blockContext *BlockContext) *EVM { func NewEVM(ctx *Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig *Config, blockContext *BlockContext) *EVM {
evm := &EVM{ evm := &EVM{
Context: ctx, Context: ctx,
StateDB: statedb, StateDB: statedb,
@ -170,7 +163,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
exists := evm.StateDB.Exist(addr) exists := evm.StateDB.Exist(addr)
precompile, isPrecompile := evm.BlockContext.Precompiles[addr] precompile, isPrecompile := evm.BlockContext.Precompiles[addr]
if !exists{ if !exists {
if !isPrecompile && evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) && value.Sign() == 0 { if !isPrecompile && evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer // Calling a non existing account, don't do anything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 { if evm.vmConfig.Debug && evm.depth == 0 {
@ -184,7 +177,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
var contract *Contract var contract *Contract
if isPrecompile{ if isPrecompile {
// A 'contract' is needed for gas accounting // A 'contract' is needed for gas accounting
contract = NewPrecompiledContract(caller, to, value, gas) contract = NewPrecompiledContract(caller, to, value, gas)
ret, err = RunPrecompiledContract(precompile, input, contract) ret, err = RunPrecompiledContract(precompile, input, contract)
@ -196,8 +189,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
}() }()
} }
}else{ } else {
if !exists{ if !exists {
// Shortcut execution -- account didn't exist, // Shortcut execution -- account didn't exist,
// so no need to lookup the code // so no need to lookup the code
// but make sure to set returndata to nil // but make sure to set returndata to nil

View file

@ -369,10 +369,10 @@ type storageEntry struct {
Key *common.Hash `json:"key"` Key *common.Hash `json:"key"`
Value common.Hash `json:"value"` Value common.Hash `json:"value"`
} }
/*
// StorageRangeAt returns the storage at the given block height and transaction index. // StorageRangeAt returns the storage at the given block height and transaction index.
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0) _, _, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
if err != nil { if err != nil {
return StorageRangeResult{}, err return StorageRangeResult{}, err
} }
@ -405,7 +405,7 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeRes
} }
return result, nil return result, nil
} }
*/
// GetModifiedAccountsByumber returns all accounts that have changed between the // GetModifiedAccountsByumber returns all accounts that have changed between the
// two blocks specified. A change is defined as a difference in nonce, balance, // two blocks specified. A change is defined as a difference in nonce, balance,
// code hash, or storage hash. // code hash, or storage hash.

View file

@ -22,19 +22,19 @@ import (
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/common/math"
) )
// EthAPIBackend implements ethapi.Backend for full nodes // EthAPIBackend implements ethapi.Backend for full nodes
@ -132,8 +132,11 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *sta
state.SetBalance(msg.From(), math.MaxBig256) state.SetBalance(msg.From(), math.MaxBig256)
vmError := func() error { return nil } vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) context := core.NewEVMContext(msg, header, b.eth.BlockChain())
return vm.NewEVM(context, state, b.eth.chainConfig, &vmCfg, &vm.BlockContext{} ), vmError, nil beneficiary, _ := b.eth.BlockChain().Engine().Author(header)
blockContext := core.NewBlockContext(header, beneficiary, b.ChainConfig())
return vm.NewEVM(context, state, b.eth.chainConfig, &vmCfg, blockContext), vmError, nil
} }
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {

View file

@ -24,12 +24,22 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"bytes"
"context"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"io/ioutil"
"runtime"
"sync"
) )
const ( const (
@ -80,7 +90,7 @@ type txTraceTask struct {
statedb *state.StateDB // Intermediate state prepped for tracing statedb *state.StateDB // Intermediate state prepped for tracing
index int // Transaction offset in the block index int // Transaction offset in the block
} }
/*
// TraceChain returns the structured logs created during the execution of EVM // TraceChain returns the structured logs created during the execution of EVM
// between two blocks (excluding start) and returns them as a JSON object. // between two blocks (excluding start) and returns them as a JSON object.
func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) {
@ -186,9 +196,10 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
// Trace all the transactions contained within // Trace all the transactions contained within
for i, tx := range task.block.Transactions() { for i, tx := range task.block.Transactions() {
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil) vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain)
beneficiary, _ := api.eth.blockchain.Engine().Author(task.block.Header())
res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) blockCtx := core.NewBlockContext(task.block.Header(), beneficiary, api.eth.chainConfig)
res, err := api.traceTx(ctx, msg, vmctx, blockCtx, task.statedb, config)
if err != nil { if err != nil {
task.results[i] = &txTraceResult{Error: err.Error()} task.results[i] = &txTraceResult{Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@ -378,7 +389,7 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
// traceBlock configures a new tracer according to the provided configuration, and // traceBlock configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item // executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requestd tracer. // per transaction, dependent on the requestd tracer.
/*
func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
// Create the parent state database // Create the parent state database
if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil { if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
@ -418,9 +429,10 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
// Fetch and execute the next transaction trace tasks // Fetch and execute the next transaction trace tasks
for task := range jobs { for task := range jobs {
msg, _ := txs[task.index].AsMessage(signer) msg, _ := txs[task.index].AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain)
beneficiary, _ := api.eth.blockchain.Engine().Author(block.Header())
res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) blockCtx := core.NewBlockContext(block.Header(), beneficiary, api.eth.chainConfig)
res, err := api.traceTx(ctx, msg, vmctx, blockCtx, task.statedb, config)
if err != nil { if err != nil {
results[task.index] = &txTraceResult{Error: err.Error()} results[task.index] = &txTraceResult{Error: err.Error()}
continue continue
@ -437,9 +449,11 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
// Generate the next state snapshot fast without tracing // Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain)
beneficiary, _ := api.eth.blockchain.Engine().Author(block.Header())
blockCtx := core.NewBlockContext(block.Header(), beneficiary, api.eth.chainConfig)
vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) vmenv := vm.NewEVM(vmctx, statedb, api.config, &vm.Config{}, blockCtx)
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err failed = err
break break
@ -456,7 +470,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
} }
return results, nil return results, nil
} }
*/
// computeStateDB retrieves the state database associated with a certain block. // computeStateDB retrieves the state database associated with a certain block.
// If no state is locally available for the given block, a number of blocks are // If no state is locally available for the given block, a number of blocks are
// attempted to be reexecuted to generate the desired state. // attempted to be reexecuted to generate the desired state.
@ -522,7 +536,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "size", database.TrieDB().Size()) log.Info("Historical state regenerated", "block", block.NumberU64(), "elapsed", time.Since(start), "size", database.TrieDB().Size())
return statedb, nil return statedb, nil
} }
/*
// TraceTransaction returns the structured logs created during the execution of EVM // TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object. // and returns them as a JSON object.
func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
@ -535,18 +549,18 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
if config != nil && config.Reexec != nil { if config != nil && config.Reexec != nil {
reexec = *config.Reexec reexec = *config.Reexec
} }
msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) msg, vmctx, blockCtx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Trace the transaction and return // Trace the transaction and return
return api.traceTx(ctx, msg, vmctx, statedb, config) return api.traceTx(ctx, msg, vmctx, blockCtx, statedb, config)
} }
// traceTx configures a new tracer according to the provided configuration, and // traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will // executes the given message in the provided environment. The return value will
// be tracer dependent. // be tracer dependent.
func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx *vm.Context, blockCtx *vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
// Assemble the structured logger or the JavaScript tracer // Assemble the structured logger or the JavaScript tracer
var ( var (
tracer vm.Tracer tracer vm.Tracer
@ -580,7 +594,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
tracer = vm.NewStructLogger(config.LogConfig) tracer = vm.NewStructLogger(config.LogConfig)
} }
// Run the transaction with tracing enabled. // Run the transaction with tracing enabled.
vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) vmenv := vm.NewEVM(vmctx, statedb, api.config, &vm.Config{Debug: true, Tracer: tracer}, blockCtx)
ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
if err != nil { if err != nil {
@ -605,19 +619,19 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
} }
// computeTxEnv returns the execution environment of a certain transaction. // computeTxEnv returns the execution environment of a certain transaction.
func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) { func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, *vm.Context, *vm.BlockContext, *state.StateDB, error) {
// Create the parent state database // Create the parent state database
block := api.eth.blockchain.GetBlockByHash(blockHash) block := api.eth.blockchain.GetBlockByHash(blockHash)
if block == nil { if block == nil {
return nil, vm.Context{}, nil, fmt.Errorf("block %x not found", blockHash) return nil, nil, nil, nil, fmt.Errorf("block %x not found", blockHash)
} }
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil { if parent == nil {
return nil, vm.Context{}, nil, fmt.Errorf("parent %x not found", block.ParentHash()) return nil, nil, nil, nil, fmt.Errorf("parent %x not found", block.ParentHash())
} }
statedb, err := api.computeStateDB(parent, reexec) statedb, err := api.computeStateDB(parent, reexec)
if err != nil { if err != nil {
return nil, vm.Context{}, nil, err return nil, nil, nil, nil, err
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(api.config, block.Number()) signer := types.MakeSigner(api.config, block.Number())
@ -625,18 +639,19 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain)
beneficiary, _ := api.eth.blockchain.Engine().Author(block.Header())
blockCtx := core.NewBlockContext(block.Header(), beneficiary, api.eth.chainConfig)
if idx == txIndex { if idx == txIndex {
return msg, context, statedb, nil return msg, context, blockCtx, statedb, nil
} }
// Not yet the searched for transaction, execute on top of the current state // Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) vmenv := vm.NewEVM(context, statedb, api.config, &vm.Config{}, blockCtx)
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) return nil, nil, nil, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
} }
// Ensure any modifications are committed to the state // Ensure any modifications are committed to the state
statedb.Finalise(true) statedb.Finalise(true)
} }
return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) return nil, nil, nil, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash)
} }
*/

View file

@ -104,8 +104,10 @@ func (b *LesApiBackend) GetTd(hash common.Hash) *big.Int {
func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256) state.SetBalance(msg.From(), math.MaxBig256)
context := core.NewEVMContext(msg, header, b.eth.blockchain, nil) context := core.NewEVMContext(msg, header, b.eth.blockchain)
return vm.NewEVM(context, state, b.eth.chainConfig, &vmCfg, &vm.BlockContext{}), state.Error, nil beneficiary, _ := b.eth.BlockChain().Engine().Author(header)
blockContext := core.NewBlockContext(header, beneficiary, b.ChainConfig())
return vm.NewEVM(context, state, b.eth.chainConfig, &vmCfg, blockContext), state.Error, nil
} }
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {

View file

@ -135,8 +135,11 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, bc, nil) context := core.NewEVMContext(msg, header, bc)
vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) beneficiary, _ := bc.Engine().Author(header)
blockContext := core.NewBlockContext(header, beneficiary, bc.Config())
vmenv := vm.NewEVM(context, statedb, config, &vm.Config{}, blockContext)
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
@ -148,8 +151,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
state := light.NewState(ctx, header, lc.Odr()) state := light.NewState(ctx, header, lc.Odr())
state.SetBalance(testBankAddress, math.MaxBig256) state.SetBalance(testBankAddress, math.MaxBig256)
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, lc, nil) context := core.NewEVMContext(msg, header, lc)
vmenv := vm.NewEVM(context, state, config, vm.Config{}) beneficiary, _ := bc.Engine().Author(header)
blockContext := core.NewBlockContext(header, beneficiary, bc.Config())
vmenv := vm.NewEVM(context, state, config, &vm.Config{}, blockContext)
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
if state.Error() == nil { if state.Error() == nil {

View file

@ -190,8 +190,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
// Perform read-only call. // Perform read-only call.
st.SetBalance(testBankAddress, math.MaxBig256) st.SetBalance(testBankAddress, math.MaxBig256)
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, chain, nil) context := core.NewEVMContext(msg, header, chain)
vmenv := vm.NewEVM(context, st, config, vm.Config{}) beneficiary, _ := bc.Engine().Author(header)
blockContext := core.NewBlockContext(header, beneficiary, bc.Config())
vmenv := vm.NewEVM(context, st, config, &vm.Config{}, blockContext)
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, ret...) res = append(res, ret...)

View file

@ -133,9 +133,12 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD
if err != nil { if err != nil {
return nil, err return nil, err
} }
context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) context := core.NewEVMContext(msg, block.Header(), nil)
beneficiary := t.json.Env.Coinbase
blockContext := core.NewBlockContext(block.Header(), beneficiary, config)
context.GetHash = vmTestBlockHash context.GetHash = vmTestBlockHash
evm := vm.NewEVM(context, statedb, config, vmconfig) evm := vm.NewEVM(context, statedb, config, &vmconfig, blockContext)
gaspool := new(core.GasPool) gaspool := new(core.GasPool)
gaspool.AddGas(block.GasLimit()) gaspool.AddGas(block.GasLimit())