diff --git a/api/service/explorer/storage.go b/api/service/explorer/storage.go index 18e6d5b5f..c17e6f8f6 100644 --- a/api/service/explorer/storage.go +++ b/api/service/explorer/storage.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) diff --git a/hmy/tracers/block_tracer.go b/hmy/tracers/block_tracer.go index f8100aa61..4358027d9 100644 --- a/hmy/tracers/block_tracer.go +++ b/hmy/tracers/block_tracer.go @@ -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.cur.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.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)) } } - finalize(root, make([]int, 0)) + 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 }