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