2021-11-21 20:52:36 +00:00
|
|
|
package calltracer
|
|
|
|
|
|
|
|
import (
|
2021-11-21 21:47:33 +00:00
|
|
|
"encoding/binary"
|
2021-11-21 20:52:36 +00:00
|
|
|
"math/big"
|
2021-11-21 21:47:33 +00:00
|
|
|
"sort"
|
2021-11-21 20:52:36 +00:00
|
|
|
"time"
|
|
|
|
|
2021-11-21 21:47:33 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/common/length"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
2021-11-21 20:52:36 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common"
|
2021-11-21 21:47:33 +00:00
|
|
|
"github.com/ledgerwatch/erigon/core/types"
|
2021-11-21 20:52:36 +00:00
|
|
|
"github.com/ledgerwatch/erigon/core/vm"
|
|
|
|
"github.com/ledgerwatch/erigon/crypto"
|
|
|
|
"github.com/ledgerwatch/log/v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
type CallTracer struct {
|
2021-11-21 21:47:33 +00:00
|
|
|
froms map[common.Address]struct{}
|
|
|
|
tos map[common.Address]bool // address -> isCreated
|
|
|
|
hasTEVM func(contractHash common.Hash) (bool, error)
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewCallTracer(hasTEVM func(contractHash common.Hash) (bool, error)) *CallTracer {
|
|
|
|
return &CallTracer{
|
2021-11-21 21:47:33 +00:00
|
|
|
froms: make(map[common.Address]struct{}),
|
|
|
|
tos: make(map[common.Address]bool),
|
|
|
|
hasTEVM: hasTEVM,
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-15 13:19:58 +00:00
|
|
|
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) {
|
2021-11-21 21:47:33 +00:00
|
|
|
ct.froms[from] = struct{}{}
|
2021-11-21 20:52:36 +00:00
|
|
|
|
2021-11-21 21:47:33 +00:00
|
|
|
created, ok := ct.tos[to]
|
2021-11-21 20:52:36 +00:00
|
|
|
if !ok {
|
2021-11-21 21:47:33 +00:00
|
|
|
ct.tos[to] = false
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !created && create {
|
2021-11-21 21:47:33 +00:00
|
|
|
if len(code) > 0 && ct.hasTEVM != nil {
|
|
|
|
has, err := ct.hasTEVM(common.BytesToHash(crypto.Keccak256(code)))
|
2021-11-21 20:52:36 +00:00
|
|
|
if !has {
|
2021-11-21 21:47:33 +00:00
|
|
|
ct.tos[to] = true
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("while CaptureStart", "error", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-15 13:19:58 +00:00
|
|
|
func (ct *CallTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
2021-12-15 13:19:58 +00:00
|
|
|
func (ct *CallTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
2021-12-15 13:19:58 +00:00
|
|
|
func (ct *CallTracer) CaptureEnd(depth int, output []byte, startGas, endGas uint64, t time.Duration, err error) {
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
func (ct *CallTracer) CaptureSelfDestruct(from common.Address, to common.Address, value *big.Int) {
|
2021-11-21 21:47:33 +00:00
|
|
|
ct.froms[from] = struct{}{}
|
|
|
|
ct.tos[to] = false
|
2021-11-21 20:52:36 +00:00
|
|
|
}
|
|
|
|
func (ct *CallTracer) CaptureAccountRead(account common.Address) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (ct *CallTracer) CaptureAccountWrite(account common.Address) error {
|
|
|
|
return nil
|
|
|
|
}
|
2021-11-21 21:47:33 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|