erigon-pulse/eth/calltracer/calltracer.go
battlmonstr 47df98a499
Use "err" key for logging errors. (#3632)
log.Warn/Error uses "err" key to log errors in most places.
This renames "error" to "err" in some places to adhere to this convention.
2022-03-01 15:40:51 +00:00

122 lines
3.2 KiB
Go

package calltracer
import (
"encoding/binary"
"math/big"
"sort"
"time"
"github.com/ledgerwatch/erigon-lib/common/length"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/crypto"
"github.com/ledgerwatch/log/v3"
)
type CallTracer struct {
froms map[common.Address]struct{}
tos map[common.Address]bool // address -> isCreated
hasTEVM func(contractHash common.Hash) (bool, error)
}
func NewCallTracer(hasTEVM func(contractHash common.Hash) (bool, error)) *CallTracer {
return &CallTracer{
froms: make(map[common.Address]struct{}),
tos: make(map[common.Address]bool),
hasTEVM: hasTEVM,
}
}
func (ct *CallTracer) CaptureStart(evm *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, calltype vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) {
ct.froms[from] = struct{}{}
created, ok := ct.tos[to]
if !ok {
ct.tos[to] = false
}
if !created && create {
if len(code) > 0 && ct.hasTEVM != nil {
has, err := ct.hasTEVM(common.BytesToHash(crypto.Keccak256(code)))
if !has {
ct.tos[to] = true
}
if err != nil {
log.Warn("while CaptureStart", "err", err)
}
}
}
}
func (ct *CallTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
}
func (ct *CallTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
}
func (ct *CallTracer) CaptureEnd(depth int, output []byte, startGas, endGas uint64, t time.Duration, err error) {
}
func (ct *CallTracer) CaptureSelfDestruct(from common.Address, to common.Address, value *big.Int) {
ct.froms[from] = struct{}{}
ct.tos[to] = false
}
func (ct *CallTracer) CaptureAccountRead(account common.Address) error {
return nil
}
func (ct *CallTracer) CaptureAccountWrite(account common.Address) error {
return nil
}
func (ct *CallTracer) WriteToDb(tx kv.RwTx, block *types.Block, vmConfig vm.Config) error {
ct.tos[block.Coinbase()] = false
for _, uncle := range block.Uncles() {
ct.tos[uncle.Coinbase] = false
}
list := make(common.Addresses, len(ct.froms)+len(ct.tos))
i := 0
for addr := range ct.froms {
copy(list[i][:], addr[:])
i++
}
for addr := range ct.tos {
copy(list[i][:], addr[:])
i++
}
sort.Sort(list)
// List may contain duplicates
var blockNumEnc [8]byte
binary.BigEndian.PutUint64(blockNumEnc[:], block.Number().Uint64())
var prev common.Address
var created bool
for j, addr := range list {
if j > 0 && prev == addr {
continue
}
var v [length.Addr + 1]byte
copy(v[:], addr[:])
if _, ok := ct.froms[addr]; ok {
v[length.Addr] |= 1
}
if _, ok := ct.tos[addr]; ok {
v[length.Addr] |= 2
}
// TEVM marking still untranslated contracts
if vmConfig.EnableTEMV {
if created = ct.tos[addr]; created {
v[length.Addr] |= 4
}
}
if j == 0 {
if err := tx.Append(kv.CallTraceSet, blockNumEnc[:], v[:]); err != nil {
return err
}
} else {
if err := tx.AppendDup(kv.CallTraceSet, blockNumEnc[:], v[:]); err != nil {
return err
}
}
copy(prev[:], addr[:])
}
return nil
}