mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
Make trace_block results closer to what OpenEthereum returns (#1862)
* Add block rewards to trace_block * Add rewards to trace_block * Remove printouts * Fix trace_block and trace_transaction * Fix getBlockByNumber * Fix for parent/non parent block * Reverse fix for trace_call * Fix eth_getTransactionBy * Fixes for TIMESTAMP etc opcodes * More fixes * Fixes to tracers * Don't call CaptureEnd twice * Corrent gasUsed for CaptureEnd in create * Do CaptureFault consistently * Correct gasUsed for create * Remove insufficient balance trace * Catch contract collision error * Compatibility * Compatibility * More error names * Out of gas * Clean up * more error messages * Restore CaptureFault * Errors * Fix test Co-authored-by: Alex Sharp <alexsharp@Alexs-MacBook-Pro.local>
This commit is contained in:
parent
964f8f76a2
commit
5168287784
@ -25,7 +25,7 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber
|
||||
}
|
||||
additionalFields := make(map[string]interface{})
|
||||
|
||||
block, err := rawdb.ReadBlockByNumber(tx, blockNum)
|
||||
block, _, err := rawdb.ReadBlockByNumberWithSenders(tx, blockNum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func (api *APIImpl) GetTransactionByBlockHashAndIndex(ctx context.Context, block
|
||||
defer tx.Rollback()
|
||||
|
||||
// https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByBlockHashAndIndex
|
||||
block, err := rawdb.ReadBlockByHash(tx, blockHash)
|
||||
block, _, err := rawdb.ReadBlockByHashWithSenders(tx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ const (
|
||||
STATICCALL = "staticcall"
|
||||
CREATE = "create"
|
||||
SUICIDE = "suicide"
|
||||
REWARD = "reward"
|
||||
TraceTypeTrace = "trace"
|
||||
TraceTypeStateDiff = "stateDiff"
|
||||
TraceTypeVmTrace = "vmTrace"
|
||||
@ -146,6 +147,7 @@ type OeTracer struct {
|
||||
r *TraceCallResult
|
||||
traceAddr []int
|
||||
traceStack []*ParityTrace
|
||||
lastTop *ParityTrace
|
||||
precompile bool // Whether the last CaptureStart was called with `precompile = true`
|
||||
}
|
||||
|
||||
@ -229,22 +231,45 @@ func (ot *OeTracer) CaptureEnd(depth int, output []byte, gasUsed uint64, t time.
|
||||
ot.r.Output = common.CopyBytes(output)
|
||||
}
|
||||
topTrace := ot.traceStack[len(ot.traceStack)-1]
|
||||
ot.lastTop = topTrace
|
||||
if err != nil {
|
||||
switch err {
|
||||
case vm.ErrInvalidJump:
|
||||
topTrace.Error = "Bad jump destination"
|
||||
case vm.ErrOutOfGas:
|
||||
topTrace.Error = "Out of gas"
|
||||
case vm.ErrExecutionReverted:
|
||||
topTrace.Error = "Reverted"
|
||||
default:
|
||||
switch err.(type) {
|
||||
case *vm.ErrStackUnderflow:
|
||||
topTrace.Error = "Stack underflow"
|
||||
case *vm.ErrInvalidOpCode:
|
||||
topTrace.Error = "Bad instruction"
|
||||
if topTrace.Type == CREATE {
|
||||
switch err {
|
||||
case vm.ErrContractAddressCollision, vm.ErrCodeStoreOutOfGas, vm.ErrOutOfGas:
|
||||
topTrace.Error = "Out of gas" // Only to be compatible with OE
|
||||
case vm.ErrExecutionReverted:
|
||||
if depth == 0 {
|
||||
topTrace.Error = "Reverted"
|
||||
} else {
|
||||
topTrace.Error = "Out of gas"
|
||||
}
|
||||
default:
|
||||
topTrace.Error = err.Error()
|
||||
switch err.(type) {
|
||||
case *vm.ErrStackUnderflow:
|
||||
topTrace.Error = "Stack underflow"
|
||||
case *vm.ErrInvalidOpCode:
|
||||
topTrace.Error = "Bad instruction"
|
||||
default:
|
||||
topTrace.Error = err.Error()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch err {
|
||||
case vm.ErrInvalidJump:
|
||||
topTrace.Error = "Bad jump destination"
|
||||
case vm.ErrOutOfGas:
|
||||
topTrace.Error = "Out of gas"
|
||||
case vm.ErrExecutionReverted:
|
||||
topTrace.Error = "Reverted"
|
||||
default:
|
||||
switch err.(type) {
|
||||
case *vm.ErrStackUnderflow:
|
||||
topTrace.Error = "Stack underflow"
|
||||
case *vm.ErrInvalidOpCode:
|
||||
topTrace.Error = "Bad instruction"
|
||||
default:
|
||||
topTrace.Error = err.Error()
|
||||
}
|
||||
}
|
||||
}
|
||||
topTrace.Result = nil
|
||||
@ -278,7 +303,6 @@ func (ot *OeTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost
|
||||
}
|
||||
|
||||
func (ot *OeTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *stack.Stack, contract *vm.Contract, opDepth int, err error) error {
|
||||
//fmt.Printf("CaptureFault depth %d\n", opDepth)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -518,6 +542,7 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp
|
||||
msg := args.ToMessage(api.gasCap)
|
||||
|
||||
blockCtx, txCtx := transactions.GetEvmContext(msg, header, blockNrOrHash.RequireCanonical, dbtx)
|
||||
//blockCtx.BlockNumber++
|
||||
|
||||
evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: traceTypeTrace, Tracer: &ot})
|
||||
|
||||
@ -530,11 +555,12 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp
|
||||
|
||||
gp := new(core.GasPool).AddGas(msg.Gas())
|
||||
var execResult *core.ExecutionResult
|
||||
ibs.Prepare(common.Hash{}, common.Hash{}, 0)
|
||||
execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, true /* gasBailout */)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
traceResult.Output = execResult.ReturnData
|
||||
traceResult.Output = common.CopyBytes(execResult.ReturnData)
|
||||
if traceTypeStateDiff {
|
||||
sdMap := make(map[common.Address]*StateDiffAccount)
|
||||
traceResult.StateDiff = sdMap
|
||||
@ -566,25 +592,25 @@ func (api *TraceAPIImpl) CallMany(ctx context.Context, calls json.RawMessage, bl
|
||||
}
|
||||
defer dbtx.Rollback()
|
||||
|
||||
return api.doCallMany(ctx, dbtx, calls, blockNrOrHash)
|
||||
return api.doCallMany(ctx, dbtx, calls, blockNrOrHash, nil)
|
||||
}
|
||||
|
||||
func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx ethdb.Tx, calls json.RawMessage, blockNrOrHash *rpc.BlockNumberOrHash) ([]*TraceCallResult, error) {
|
||||
func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx ethdb.Tx, calls json.RawMessage, parentNrOrHash *rpc.BlockNumberOrHash, header *types.Header) ([]*TraceCallResult, error) {
|
||||
chainConfig, err := api.chainConfig(dbtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if blockNrOrHash == nil {
|
||||
if parentNrOrHash == nil {
|
||||
var num = rpc.LatestBlockNumber
|
||||
blockNrOrHash = &rpc.BlockNumberOrHash{BlockNumber: &num}
|
||||
parentNrOrHash = &rpc.BlockNumberOrHash{BlockNumber: &num}
|
||||
}
|
||||
blockNumber, hash, err := rpchelper.GetBlockNumber(*blockNrOrHash, dbtx, api.pending)
|
||||
blockNumber, hash, err := rpchelper.GetBlockNumber(*parentNrOrHash, dbtx, api.pending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var stateReader state.StateReader
|
||||
if num, ok := blockNrOrHash.Number(); ok && num == rpc.LatestBlockNumber {
|
||||
if num, ok := parentNrOrHash.Number(); ok && num == rpc.LatestBlockNumber {
|
||||
stateReader = state.NewPlainStateReader(dbtx)
|
||||
} else {
|
||||
stateReader = state.NewPlainKvState(dbtx, blockNumber)
|
||||
@ -594,9 +620,9 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx ethdb.Tx, calls js
|
||||
noop := state.NewNoopWriter()
|
||||
cachedWriter := state.NewCachedWriter(noop, stateCache)
|
||||
|
||||
header := rawdb.ReadHeader(ethdb.NewRoTxDb(dbtx), hash, blockNumber)
|
||||
if header == nil {
|
||||
return nil, fmt.Errorf("block %d(%x) not found", blockNumber, hash)
|
||||
parentHeader := rawdb.ReadHeader(ethdb.NewRoTxDb(dbtx), hash, blockNumber)
|
||||
if parentHeader == nil {
|
||||
return nil, fmt.Errorf("parent header %d(%x) not found", blockNumber, hash)
|
||||
}
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
@ -668,7 +694,10 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx ethdb.Tx, calls js
|
||||
// Get a new instance of the EVM.
|
||||
msg := args.ToMessage(api.gasCap)
|
||||
|
||||
blockCtx, txCtx := transactions.GetEvmContext(msg, header, blockNrOrHash.RequireCanonical, dbtx)
|
||||
if header == nil {
|
||||
header = parentHeader
|
||||
}
|
||||
blockCtx, txCtx := transactions.GetEvmContext(msg, header, parentNrOrHash.RequireCanonical, dbtx)
|
||||
ibs := state.New(cachedReader)
|
||||
// Create initial IntraBlockState, we will compare it with ibs (IntraBlockState after the transaction)
|
||||
|
||||
@ -682,11 +711,12 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx ethdb.Tx, calls js
|
||||
cloneCache := stateCache.Clone()
|
||||
cloneReader = state.NewCachedReader(stateReader, cloneCache)
|
||||
}
|
||||
ibs.Prepare(common.Hash{}, header.Hash(), txIndex)
|
||||
execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, true /* gasBailout */)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("first run for txIndex %d error: %w", txIndex, err)
|
||||
}
|
||||
traceResult.Output = execResult.ReturnData
|
||||
traceResult.Output = common.CopyBytes(execResult.ReturnData)
|
||||
if traceTypeStateDiff {
|
||||
initialIbs := state.New(cloneReader)
|
||||
sdMap := make(map[common.Address]*StateDiffAccount)
|
||||
|
@ -65,13 +65,13 @@ func (api *TraceAPIImpl) Transaction(ctx context.Context, txHash common.Hash) (P
|
||||
}
|
||||
}
|
||||
|
||||
baseBn := bn
|
||||
if baseBn > 0 {
|
||||
baseBn -= 1
|
||||
parentNr := bn
|
||||
if parentNr > 0 {
|
||||
parentNr -= 1
|
||||
}
|
||||
|
||||
// Returns an array of trace arrays, one trace array for each transaction
|
||||
traces, err := api.callManyTransactions(ctx, tx, txs, hash, rpc.BlockNumber(baseBn))
|
||||
traces, err := api.callManyTransactions(ctx, tx, txs, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -158,12 +158,12 @@ func (api *TraceAPIImpl) Block(ctx context.Context, blockNr rpc.BlockNumber) (Pa
|
||||
})
|
||||
}
|
||||
|
||||
baseBn := bn
|
||||
if baseBn > 0 {
|
||||
baseBn -= 1
|
||||
parentNr := bn
|
||||
if parentNr > 0 {
|
||||
parentNr -= 1
|
||||
}
|
||||
|
||||
traces, err := api.callManyTransactions(ctx, tx, txs, hash, rpc.BlockNumber(baseBn))
|
||||
traces, err := api.callManyTransactions(ctx, tx, txs, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -181,6 +181,41 @@ func (api *TraceAPIImpl) Block(ctx context.Context, blockNr rpc.BlockNumber) (Pa
|
||||
out = append(out, *pt)
|
||||
}
|
||||
}
|
||||
chainConfig, err := api.chainConfig(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
minerReward, uncleRewards := ethash.AccumulateRewards(chainConfig, block.Header(), block.Uncles())
|
||||
var tr ParityTrace
|
||||
var rewardAction = &RewardTraceAction{}
|
||||
rewardAction.Author = block.Coinbase()
|
||||
rewardAction.RewardType = "block" // nolint: goconst
|
||||
rewardAction.Value.ToInt().Set(minerReward.ToBig())
|
||||
tr.Action = rewardAction
|
||||
tr.BlockHash = &common.Hash{}
|
||||
copy(tr.BlockHash[:], block.Hash().Bytes())
|
||||
tr.BlockNumber = new(uint64)
|
||||
*tr.BlockNumber = block.NumberU64()
|
||||
tr.Type = "reward" // nolint: goconst
|
||||
tr.TraceAddress = []int{}
|
||||
out = append(out, tr)
|
||||
for i, uncle := range block.Uncles() {
|
||||
if i < len(uncleRewards) {
|
||||
var tr ParityTrace
|
||||
rewardAction = &RewardTraceAction{}
|
||||
rewardAction.Author = uncle.Coinbase
|
||||
rewardAction.RewardType = "uncle" // nolint: goconst
|
||||
rewardAction.Value.ToInt().Set(uncleRewards[i].ToBig())
|
||||
tr.Action = rewardAction
|
||||
tr.BlockHash = &common.Hash{}
|
||||
copy(tr.BlockHash[:], block.Hash().Bytes())
|
||||
tr.BlockNumber = new(uint64)
|
||||
*tr.BlockNumber = block.NumberU64()
|
||||
tr.Type = "reward" // nolint: goconst
|
||||
tr.TraceAddress = []int{}
|
||||
out = append(out, tr)
|
||||
}
|
||||
}
|
||||
|
||||
return out, err
|
||||
}
|
||||
@ -411,7 +446,7 @@ type TransactionWithSender struct {
|
||||
sender common.Address
|
||||
}
|
||||
|
||||
func (api *TraceAPIImpl) callManyTransactions(ctx context.Context, dbtx ethdb.Tx, txs []TransactionWithSender, blockHash common.Hash, blockNo rpc.BlockNumber) ([]*TraceCallResult, error) {
|
||||
func (api *TraceAPIImpl) callManyTransactions(ctx context.Context, dbtx ethdb.Tx, txs []TransactionWithSender, parentHash common.Hash, parentNo rpc.BlockNumber, header *types.Header) ([]*TraceCallResult, error) {
|
||||
toExecute := []interface{}{}
|
||||
|
||||
for _, txWithSender := range txs {
|
||||
@ -435,10 +470,10 @@ func (api *TraceAPIImpl) callManyTransactions(ctx context.Context, dbtx ethdb.Tx
|
||||
return nil, callsErr
|
||||
}
|
||||
traces, cmErr := api.doCallMany(ctx, dbtx, calls, &rpc.BlockNumberOrHash{
|
||||
BlockNumber: &blockNo,
|
||||
BlockHash: &blockHash,
|
||||
BlockNumber: &parentNo,
|
||||
BlockHash: &parentHash,
|
||||
RequireCanonical: true,
|
||||
})
|
||||
}, header)
|
||||
|
||||
if cmErr != nil {
|
||||
return nil, cmErr
|
||||
|
@ -41,11 +41,11 @@ type ParityTrace struct {
|
||||
BlockHash *common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber *uint64 `json:"blockNumber,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
Result interface{} `json:"result"`
|
||||
Subtraces int `json:"subtraces"`
|
||||
TraceAddress []int `json:"traceAddress"`
|
||||
TransactionHash *common.Hash `json:"transactionHash,omitempty"`
|
||||
TransactionPosition *uint64 `json:"transactionPosition,omitempty"`
|
||||
TransactionHash *common.Hash `json:"transactionHash"`
|
||||
TransactionPosition *uint64 `json:"transactionPosition"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
@ -71,10 +71,10 @@ type TraceAction struct {
|
||||
|
||||
type CallTraceAction struct {
|
||||
From common.Address `json:"from"`
|
||||
To common.Address `json:"to"`
|
||||
CallType string `json:"callType"`
|
||||
Gas hexutil.Big `json:"gas"`
|
||||
Input hexutil.Bytes `json:"input"`
|
||||
To common.Address `json:"to"`
|
||||
Value hexutil.Big `json:"value"`
|
||||
}
|
||||
|
||||
@ -91,6 +91,12 @@ type SuicideTraceAction struct {
|
||||
Balance hexutil.Big `json:"balance"`
|
||||
}
|
||||
|
||||
type RewardTraceAction struct {
|
||||
Author common.Address `json:"author"`
|
||||
RewardType string `json:"rewardType"`
|
||||
Value hexutil.Big `json:"value"`
|
||||
}
|
||||
|
||||
type CreateTraceResult struct {
|
||||
// Do not change the ordering of these fields -- allows for easier comparison with other clients
|
||||
Address *common.Address `json:"address,omitempty"`
|
||||
|
@ -12,9 +12,9 @@ import (
|
||||
|
||||
// Transactions on which OpenEthereum reports incorrect traces
|
||||
var wrongTxs = []string{
|
||||
"0xe47180a05a7cc25c187b426fed5390365874add72a5681242ac4b288d4a6833a", // Block 7000000
|
||||
//"0xe47180a05a7cc25c187b426fed5390365874add72a5681242ac4b288d4a6833a", // Block 7000000
|
||||
"0x76e720b0530aa72926319853f62c97c5907b26e2fc5c8ad5f51173f531d98d11", // Block 7000063
|
||||
"0xc6f3cadc90aece146a7a90191d6668c7f152a2daf759ae97bde7df7f5d78ab3a", // Block 7000068
|
||||
//"0xc6f3cadc90aece146a7a90191d6668c7f152a2daf759ae97bde7df7f5d78ab3a", // Block 7000068
|
||||
"0xd5a9b32b262202cda422dd5a2ccf8d7d56e9b3425ba7d350548e62a5bd26b481", // Block 8000011
|
||||
"0x1953ad3591fa0f6f3f00dfa0f93a57e1dc7fa003e2192a18c64c71847cf64e0c", // Block 8000035
|
||||
"0xfbd66bcbc4cb374946f350ca6835571b09f68c5f635ff9fc533c3fa2ac0d19cb", // Block 9000004
|
||||
|
@ -1148,6 +1148,14 @@ func ReadBlockByHash(db ethdb.Tx, hash common.Hash) (*types.Block, error) {
|
||||
return ReadBlock(db, hash, *number), nil
|
||||
}
|
||||
|
||||
func ReadBlockByHashWithSenders(db ethdb.Tx, hash common.Hash) (*types.Block, []common.Address, error) {
|
||||
number := ReadHeaderNumber(db, hash)
|
||||
if number == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return ReadBlockWithSenders(db, hash, *number)
|
||||
}
|
||||
|
||||
func ReadBlocksByHash(db ethdb.Getter, hash common.Hash, n int) (blocks []*types.Block, err error) {
|
||||
number := ReadHeaderNumber(db, hash)
|
||||
if number == nil {
|
||||
|
@ -89,6 +89,12 @@ func ReadTransaction(db ethdb.Tx, hash common.Hash) (types.Transaction, common.H
|
||||
log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
|
||||
return nil, common.Hash{}, 0, 0
|
||||
}
|
||||
senders, err1 := ReadSenders(db, blockHash, *blockNumber)
|
||||
if err1 != nil {
|
||||
log.Error("ReadSenders failed", "err", err)
|
||||
return nil, common.Hash{}, 0, 0
|
||||
}
|
||||
body.SendersToTxs(senders)
|
||||
for txIndex, tx := range body.Transactions {
|
||||
if tx.Hash() == hash {
|
||||
return tx, blockHash, *blockNumber, uint64(txIndex)
|
||||
|
@ -73,6 +73,9 @@ func TestLookupStorage(t *testing.T) {
|
||||
if err := WriteBlock(tx, block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WriteSenders(tx, block.Hash(), block.NumberU64(), block.Body().SendersFromTxs()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tc.writeTxLookupEntries(tx, block)
|
||||
|
||||
for i, txn := range txs {
|
||||
|
@ -221,24 +221,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
}
|
||||
}
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
|
||||
var (
|
||||
to = AccountRef(addr)
|
||||
snapshot = evm.IntraBlockState.Snapshot()
|
||||
)
|
||||
if !evm.IntraBlockState.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||
// Calling a non existing account, don't do anything, but ping the tracer
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), addr, isPrecompile, false /* create */, CALLT, input, gas, value.ToBig())
|
||||
_ = evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, 0, 0, nil)
|
||||
}
|
||||
return nil, gas, nil
|
||||
}
|
||||
evm.IntraBlockState.CreateAccount(addr, false)
|
||||
}
|
||||
evm.Context.Transfer(evm.IntraBlockState, caller.Address(), to.Address(), value, bailout)
|
||||
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), addr, isPrecompile, false /* create */, CALLT, input, gas, value.ToBig())
|
||||
@ -247,6 +229,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
}(gas, time.Now())
|
||||
}
|
||||
|
||||
var (
|
||||
to = AccountRef(addr)
|
||||
snapshot = evm.IntraBlockState.Snapshot()
|
||||
)
|
||||
if !evm.IntraBlockState.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||
return nil, gas, nil
|
||||
}
|
||||
evm.IntraBlockState.CreateAccount(addr, false)
|
||||
}
|
||||
evm.Context.Transfer(evm.IntraBlockState, caller.Address(), to.Address(), value, bailout)
|
||||
|
||||
if isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
||||
} else {
|
||||
@ -302,10 +296,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||
if !evm.Context.CanTransfer(evm.IntraBlockState, caller.Address(), value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
}
|
||||
var (
|
||||
snapshot = evm.IntraBlockState.Snapshot()
|
||||
)
|
||||
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
@ -314,6 +304,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||
evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, startGas-gas, time.Since(startTime), err) //nolint:errcheck
|
||||
}(gas, time.Now())
|
||||
}
|
||||
var (
|
||||
snapshot = evm.IntraBlockState.Snapshot()
|
||||
)
|
||||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if isPrecompile {
|
||||
@ -349,8 +342,6 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
snapshot := evm.IntraBlockState.Snapshot()
|
||||
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
@ -359,6 +350,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||
evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, startGas-gas, time.Since(startTime), err) //nolint:errcheck
|
||||
}(gas, time.Now())
|
||||
}
|
||||
snapshot := evm.IntraBlockState.Snapshot()
|
||||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if isPrecompile {
|
||||
@ -392,6 +384,14 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), addr, isPrecompile, false, STATICCALLT, input, gas, big.NewInt(-2))
|
||||
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
||||
evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, startGas-gas, time.Since(startTime), err) //nolint:errcheck
|
||||
}(gas, time.Now())
|
||||
}
|
||||
// We take a snapshot here. This is a bit counter-intuitive, and could probably be skipped.
|
||||
// However, even a staticcall is considered a 'touch'. On mainnet, static calls were introduced
|
||||
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
||||
@ -405,15 +405,6 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
// future scenarios
|
||||
evm.IntraBlockState.AddBalance(addr, u256.Num0)
|
||||
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), addr, isPrecompile, false, STATICCALLT, input, gas, big.NewInt(-2))
|
||||
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
||||
evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, startGas-gas, time.Since(startTime), err) //nolint:errcheck
|
||||
}(gas, time.Now())
|
||||
}
|
||||
|
||||
if isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas)
|
||||
} else {
|
||||
@ -454,6 +445,8 @@ func (c *codeAndHash) Hash() common.Hash {
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, calltype CallType) ([]byte, common.Address, uint64, error) {
|
||||
var ret []byte
|
||||
var err error
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
@ -462,6 +455,12 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
if !evm.Context.CanTransfer(evm.IntraBlockState, caller.Address(), value) {
|
||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
||||
}
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), address, false /* precompile */, true /* create */, calltype, codeAndHash.code, gas, value.ToBig())
|
||||
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
||||
evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, startGas-gas, time.Since(startTime), err) //nolint:errcheck
|
||||
}(gas, time.Now())
|
||||
}
|
||||
nonce := evm.IntraBlockState.GetNonce(caller.Address())
|
||||
evm.IntraBlockState.SetNonce(caller.Address(), nonce+1)
|
||||
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
||||
@ -472,7 +471,8 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
// Ensure there's no existing contract already at the designated address
|
||||
contractHash := evm.IntraBlockState.GetCodeHash(address)
|
||||
if evm.IntraBlockState.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
|
||||
return nil, common.Address{}, 0, ErrContractAddressCollision
|
||||
err = ErrContractAddressCollision
|
||||
return nil, common.Address{}, 0, err
|
||||
}
|
||||
// Create a new account on the state
|
||||
snapshot := evm.IntraBlockState.Snapshot()
|
||||
@ -491,12 +491,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
return nil, address, gas, nil
|
||||
}
|
||||
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureStart(evm.depth, caller.Address(), address, false /* precompile */, true /* create */, calltype, codeAndHash.code, gas, value.ToBig())
|
||||
}
|
||||
start := time.Now()
|
||||
|
||||
ret, err := run(evm, contract, nil, false)
|
||||
ret, err = run(evm, contract, nil, false)
|
||||
|
||||
// check whether the max code size has been exceeded
|
||||
maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
|
||||
@ -529,13 +524,12 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
contract.UseGas(contract.Gas)
|
||||
}
|
||||
}
|
||||
gas = contract.Gas // For the CaptureEnd to work corrently with gasUsed
|
||||
// Assign err if contract code size exceeds the max while the err is still empty.
|
||||
if maxCodeSizeExceeded && err == nil {
|
||||
err = ErrMaxCodeSizeExceeded
|
||||
}
|
||||
if evm.vmConfig.Debug {
|
||||
_ = evm.vmConfig.Tracer.CaptureEnd(evm.depth, ret, gas-contract.Gas, time.Since(start), err)
|
||||
}
|
||||
|
||||
return ret, address, contract.Gas, err
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user