mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-25 21:17:16 +00:00
47df98a499
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.
122 lines
3.2 KiB
Go
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
|
|
}
|