[tracer] change tracer to apply to block instead of tx

pull/3818/head
peekpi 3 years ago
parent 61263c6572
commit b2472d87c0
  1. 3
      api/service/explorer/storage.go
  2. 112
      hmy/tracers/block_tracer.go

@ -180,6 +180,7 @@ type taskManager struct {
func newTaskManager() *taskManager {
return &taskManager{
C: make(chan struct{}, numWorker),
T: make(chan *traceResult, numWorker),
}
}
@ -292,7 +293,7 @@ LOOP:
}
case traceData := <-bc.tm.T:
if exist, err := isTraceDataInDB(bc.db, traceData.hash); exist || err != nil {
break
continue
}
traceData.btc = bc.db.NewBatch()
_ = writeTraceData(traceData.btc, traceData.hash, traceData.data)

@ -186,7 +186,7 @@ func (c action) toJsonStr() (string, *string, *string) {
return "unkonw", nil, nil
}
type ParityBlockTracer struct {
type ParityTxTracer struct {
blockNumber uint64
blockHash common.Hash
transactionPosition uint64
@ -195,49 +195,54 @@ type ParityBlockTracer struct {
calls []*action
action
}
type ParityBlockTracer struct {
cur *ParityTxTracer
tracers []*ParityTxTracer
}
func (jst *ParityBlockTracer) push(ac *action) {
jst.calls = append(jst.calls, ac)
func (ptt *ParityTxTracer) push(ac *action) {
ptt.calls = append(ptt.calls, ac)
}
func (jst *ParityBlockTracer) pop() *action {
popIndex := len(jst.calls) - 1
ac := jst.calls[popIndex]
jst.calls = jst.calls[:popIndex]
func (ptt *ParityTxTracer) pop() *action {
popIndex := len(ptt.calls) - 1
ac := ptt.calls[popIndex]
ptt.calls = ptt.calls[:popIndex]
return ac
}
func (jst *ParityBlockTracer) last() *action {
return jst.calls[len(jst.calls)-1]
func (ptt *ParityTxTracer) last() *action {
return ptt.calls[len(ptt.calls)-1]
}
func (jst *ParityBlockTracer) len() int {
return len(jst.calls)
func (ptt *ParityTxTracer) len() int {
return len(ptt.calls)
}
// CaptureStart implements the ParityBlockTracer interface to initialize the tracing operation.
func (jst *ParityBlockTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
jst.op = vm.CALL // vritual call
jst.cur = &ParityTxTracer{}
jst.cur.op = vm.CALL // vritual call
if create {
jst.op = vm.CREATE // virtual create
}
jst.from = from
jst.to = to
jst.input = input
jst.gas = gas
jst.value = (&big.Int{}).Set(value)
jst.blockHash = env.StateDB.BlockHash()
jst.transactionPosition = uint64(env.StateDB.TxIndex())
jst.transactionHash = env.StateDB.TxHash()
jst.blockNumber = env.BlockNumber.Uint64()
jst.descended = false
jst.push(&jst.action)
jst.cur.op = vm.CREATE // virtual create
}
jst.cur.from = from
jst.cur.to = to
jst.cur.input = input
jst.cur.gas = gas
jst.cur.value = (&big.Int{}).Set(value)
jst.cur.blockHash = env.StateDB.BlockHash()
jst.cur.transactionPosition = uint64(env.StateDB.TxIndex())
jst.cur.transactionHash = env.StateDB.TxHash()
jst.cur.blockNumber = env.BlockNumber.Uint64()
jst.cur.descended = false
jst.cur.push(&jst.cur.action)
return nil
}
// CaptureState implements the ParityBlockTracer interface to trace a single step of VM execution.
func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
//if op < vm.CREATE && !jst.descended {
//if op < vm.CREATE && !jst.cur.descended {
// return nil
//}
var retErr error
@ -259,7 +264,7 @@ func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
if op == vm.CREATE || op == vm.CREATE2 {
inOff := stackPeek(1).Int64()
inSize := stackPeek(2).Int64()
jst.push(&action{
jst.cur.push(&action{
op: op,
from: contract.Address(),
input: memoryCopy(inOff, inSize),
@ -267,11 +272,11 @@ func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
gasCost: cost,
value: (&big.Int{}).Set(stackPeek(0)),
})
jst.descended = true
jst.cur.descended = true
return retErr
}
if op == vm.SELFDESTRUCT {
ac := jst.last()
ac := jst.cur.last()
ac.push(&action{
op: op,
from: contract.Address(),
@ -307,26 +312,26 @@ func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
if op != vm.DELEGATECALL && op != vm.STATICCALL {
callObj.value = (&big.Int{}).Set(stackPeek(2))
}
jst.push(callObj)
jst.descended = true
jst.cur.push(callObj)
jst.cur.descended = true
return retErr
}
if jst.descended {
jst.descended = false
if depth >= jst.len() { // >= to >
jst.last().gas = gas
if jst.cur.descended {
jst.cur.descended = false
if depth >= jst.cur.len() { // >= to >
jst.cur.last().gas = gas
}
}
if op == vm.REVERT {
last := jst.last()
last := jst.cur.last()
last.err = errors.New("execution reverted")
revertOff := stackPeek(0).Int64()
revertLen := stackPeek(1).Int64()
last.revert = memoryCopy(revertOff, revertLen)
return retErr
}
if depth == jst.len()-1 { // depth == len - 1
call := jst.pop()
if depth == jst.cur.len()-1 { // depth == len - 1
call := jst.cur.pop()
if call.op == vm.CREATE || call.op == vm.CREATE2 {
call.gasUsed = call.gasIn - call.gasCost - gas
@ -348,7 +353,7 @@ func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
call.err = errors.New("internal failure")
}
}
jst.last().push(call)
jst.cur.last().push(call)
}
return retErr
}
@ -359,7 +364,7 @@ func (jst *ParityBlockTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode,
if op == vm.REVERT {
return nil
}
call := jst.pop()
call := jst.cur.pop()
if call.err == nil {
// Consume all available gas and clean any leftovers
if call.gas != 0 {
@ -367,35 +372,31 @@ func (jst *ParityBlockTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode,
}
// Flatten the failed call into its parent
if jst.len() > 0 {
jst.last().push(call)
if jst.cur.len() > 0 {
jst.cur.last().push(call)
return nil
}
}
jst.push(call)
jst.cur.push(call)
return nil
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (jst *ParityBlockTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
jst.output = output
jst.gasUsed = gasUsed
jst.cur.output = output
jst.cur.gasUsed = gasUsed
if err != nil {
jst.err = err
jst.cur.err = err
}
jst.tracers = append(jst.tracers, jst.cur)
return nil
}
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
func (jst *ParityBlockTracer) GetResult() ([]json.RawMessage, error) {
root := &jst.action
headPiece := fmt.Sprintf(
`"blockNumber":%d,"blockHash":"%s","transactionHash":"%s","transactionPosition":%d`,
jst.blockNumber, jst.blockHash.Hex(), jst.transactionHash.Hex(), jst.transactionPosition,
)
var results []json.RawMessage
var err error
var headPiece string
var finalize func(ac *action, traceAddress []int)
finalize = func(ac *action, traceAddress []int) {
typStr, acStr, outStr := ac.toJsonStr()
@ -424,6 +425,13 @@ func (jst *ParityBlockTracer) GetResult() ([]json.RawMessage, error) {
finalize(subAc, append(traceAddress[:], i))
}
}
for _, curTx := range jst.tracers {
root := &curTx.action
headPiece = fmt.Sprintf(
`"blockNumber":%d,"blockHash":"%s","transactionHash":"%s","transactionPosition":%d`,
curTx.blockNumber, curTx.blockHash.Hex(), curTx.transactionHash.Hex(), curTx.transactionPosition,
)
finalize(root, make([]int, 0))
}
return results, err
}

Loading…
Cancel
Save