[explorer][tracer] store trace result into explorer db

pull/3818/head
peekpi 3 years ago
parent 698e363f0a
commit 054ba5d712
  1. 19
      api/service/explorer/schema.go
  2. 5
      api/service/explorer/service.go
  3. 47
      api/service/explorer/storage.go
  4. 14
      cmd/harmony/flags.go
  5. 4
      cmd/harmony/main.go
  6. 39
      core/blockchain.go
  7. 2
      hmy/hmy.go
  8. 2
      internal/configs/harmony/harmony.go
  9. 2
      internal/configs/node/config.go
  10. 6
      internal/shardchain/shardchains.go
  11. 3
      node/node.go
  12. 29
      node/node_explorer.go
  13. 3
      rpc/tracerParity.go

@ -16,6 +16,7 @@ import (
const ( const (
LegAddressPrefix = "ad_" LegAddressPrefix = "ad_"
CheckpointPrefix = "dc" CheckpointPrefix = "dc"
TracePrefix = "tr_"
oneAddrByteLen = 42 // byte size of string "one1..." oneAddrByteLen = 42 // byte size of string "one1..."
) )
@ -36,6 +37,24 @@ func writeCheckpoint(db databaseWriter, bn uint64) error {
return db.Put(blockCheckpoint, []byte{}) return db.Put(blockCheckpoint, []byte{})
} }
func GetTraceDataKey(hash common.Hash) []byte {
return []byte(fmt.Sprintf("%s_%x", TracePrefix, hash))
}
func isTraceDataInDB(db databaseReader, hash common.Hash) (bool, error) {
key := GetTraceDataKey(hash)
return db.Has(key)
}
func writeTraceData(db databaseWriter, hash common.Hash, data []byte) error {
key := GetTraceDataKey(hash)
return db.Put(key, data)
}
func getTraceData(db databaseReader, hash common.Hash) ([]byte, error) {
key := GetTraceDataKey(hash)
return db.Get(key)
}
// New schema // New schema
var ( var (

@ -187,6 +187,11 @@ func (s *Service) GetStakingTxHashesByAccount(address string) ([]ethCommon.Hash,
return s.storage.GetStakingTxsByAddress(address) return s.storage.GetStakingTxsByAddress(address)
} }
// TraceNewBlock instruct the explorer storage to trace data in explorer DB
func (s *Service) TraceNewBlock(hash ethCommon.Hash, data []byte) {
s.storage.TraceNewBlock(hash, data)
}
// DumpNewBlock instruct the explorer storage to dump block data in explorer DB // DumpNewBlock instruct the explorer storage to dump block data in explorer DB
func (s *Service) DumpNewBlock(b *types.Block) { func (s *Service) DumpNewBlock(b *types.Block) {
s.storage.DumpNewBlock(b) s.storage.DumpNewBlock(b)

@ -2,6 +2,7 @@ package explorer
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -35,6 +36,7 @@ type (
// TODO: optimize this with priority queue // TODO: optimize this with priority queue
tm *taskManager tm *taskManager
resultC chan blockResult resultC chan blockResult
resultT chan *traceResult
available *abool.AtomicBool available *abool.AtomicBool
closeC chan struct{} closeC chan struct{}
@ -45,6 +47,12 @@ type (
btc batch btc batch
bn uint64 bn uint64
} }
traceResult struct {
btc batch
hash common.Hash
data []byte
}
) )
func newStorage(bc *core.BlockChain, dbPath string) (*storage, error) { func newStorage(bc *core.BlockChain, dbPath string) (*storage, error) {
@ -59,6 +67,7 @@ func newStorage(bc *core.BlockChain, dbPath string) (*storage, error) {
bc: bc, bc: bc,
tm: newTaskManager(), tm: newTaskManager(),
resultC: make(chan blockResult, numWorker), resultC: make(chan blockResult, numWorker),
resultT: make(chan *traceResult, numWorker),
available: abool.New(), available: abool.New(),
closeC: make(chan struct{}), closeC: make(chan struct{}),
log: utils.Logger().With().Str("module", "explorer storage").Logger(), log: utils.Logger().With().Str("module", "explorer storage").Logger(),
@ -73,6 +82,10 @@ func (s *storage) Close() {
close(s.closeC) close(s.closeC)
} }
func (s *storage) TraceNewBlock(hash common.Hash, data []byte) {
s.tm.AddNewTraceTask(hash, data)
}
func (s *storage) DumpNewBlock(b *types.Block) { func (s *storage) DumpNewBlock(b *types.Block) {
s.tm.AddNewTask(b) s.tm.AddNewTask(b)
} }
@ -113,6 +126,13 @@ func (s *storage) GetStakingTxsByAddress(addr string) ([]common.Hash, []TxType,
return getStakingTxnHashesByAccount(s.db, oneAddress(addr)) return getStakingTxnHashesByAccount(s.db, oneAddress(addr))
} }
func (s *storage) GetTraceDataByHash(hash common.Hash) (json.RawMessage, error) {
if !s.available.IsSet() {
return nil, ErrExplorerNotReady
}
return getTraceData(s.db, hash)
}
func (s *storage) run() { func (s *storage) run() {
if is, err := isVersionV100(s.db); !is || err != nil { if is, err := isVersionV100(s.db); !is || err != nil {
s.available.UnSet() s.available.UnSet()
@ -136,6 +156,11 @@ func (s *storage) loop() {
if err := res.btc.Write(); err != nil { if err := res.btc.Write(); err != nil {
s.log.Error().Err(err).Msg("explorer db failed to write") s.log.Error().Err(err).Msg("explorer db failed to write")
} }
case res := <-s.resultT:
s.log.Info().Str("block hash", res.hash.Hex()).Msg("writing trace into explorer DB")
if err := res.btc.Write(); err != nil {
s.log.Error().Err(err).Msg("explorer db failed to write trace data")
}
case <-s.closeC: case <-s.closeC:
return return
@ -149,6 +174,7 @@ type taskManager struct {
lock sync.Mutex lock sync.Mutex
C chan struct{} C chan struct{}
T chan *traceResult
} }
func newTaskManager() *taskManager { func newTaskManager() *taskManager {
@ -168,6 +194,13 @@ func (tm *taskManager) AddNewTask(b *types.Block) {
} }
} }
func (tm *taskManager) AddNewTraceTask(hash common.Hash, data []byte) {
tm.T <- &traceResult{
hash: hash,
data: data,
}
}
func (tm *taskManager) AddCatchupTask(b *types.Block) { func (tm *taskManager) AddCatchupTask(b *types.Block) {
tm.lock.Lock() tm.lock.Lock()
defer tm.lock.Unlock() defer tm.lock.Unlock()
@ -211,6 +244,7 @@ func (s *storage) makeWorkersAndStart() {
db: s.db, db: s.db,
bc: s.bc, bc: s.bc,
resultC: s.resultC, resultC: s.resultC,
resultT: s.resultT,
closeC: s.closeC, closeC: s.closeC,
log: s.log.With().Int("worker", i).Logger(), log: s.log.With().Int("worker", i).Logger(),
}) })
@ -225,6 +259,7 @@ type blockComputer struct {
db database db database
bc blockChainTxIndexer bc blockChainTxIndexer
resultC chan blockResult resultC chan blockResult
resultT chan *traceResult
closeC chan struct{} closeC chan struct{}
log zerolog.Logger log zerolog.Logger
} }
@ -255,7 +290,17 @@ LOOP:
return return
} }
} }
case traceData := <-bc.tm.T:
if exist, err := isTraceDataInDB(bc.db, traceData.hash); exist || err != nil {
break
}
traceData.btc = bc.db.NewBatch()
_ = writeTraceData(traceData.btc, traceData.hash, traceData.data)
select {
case bc.resultT <- traceData:
case <-bc.closeC:
return
}
case <-bc.closeC: case <-bc.closeC:
return return
} }

@ -29,7 +29,7 @@ var (
legacyIsArchiveFlag, legacyIsArchiveFlag,
legacyDataDirFlag, legacyDataDirFlag,
taraceDataDirFlag, taraceFlag,
} }
dnsSyncFlags = []cli.Flag{ dnsSyncFlags = []cli.Flag{
@ -274,10 +274,10 @@ var (
Deprecated: "use --datadir", Deprecated: "use --datadir",
} }
taraceDataDirFlag = cli.StringFlag{ taraceFlag = cli.BoolFlag{
Name: "trace_dir", Name: "tracing",
Usage: "trace block database directory", Usage: "indicates if full transaction tracing should be enabled",
DefValue: "", DefValue: false,
} }
) )
@ -351,8 +351,8 @@ func applyGeneralFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig)
config.General.IsOffline = cli.GetBoolFlagValue(cmd, isOfflineFlag) config.General.IsOffline = cli.GetBoolFlagValue(cmd, isOfflineFlag)
} }
if cli.IsFlagChanged(cmd, taraceDataDirFlag) { if cli.IsFlagChanged(cmd, taraceFlag) {
config.General.TraceDir = cli.GetStringFlagValue(cmd, taraceDataDirFlag) config.General.TraceEnable = cli.GetBoolFlagValue(cmd, taraceFlag)
} }
} }

@ -612,7 +612,7 @@ func createGlobalConfig(hc harmonyconfig.HarmonyConfig) (*nodeconfig.ConfigType,
nodeConfig.NtpServer = hc.Sys.NtpServer nodeConfig.NtpServer = hc.Sys.NtpServer
nodeConfig.TraceDir = hc.General.TraceDir nodeConfig.TraceEnable = hc.General.TraceEnable
return nodeConfig, nil return nodeConfig, nil
} }
@ -655,7 +655,7 @@ func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfi
// Current node. // Current node.
chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir} chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir}
currentNode := node.New(myHost, currentConsensus, chainDBFactory, nodeConfig.TraceDir, blacklist, nodeConfig.ArchiveModes(), &hc) currentNode := node.New(myHost, currentConsensus, chainDBFactory, blacklist, nodeConfig.ArchiveModes(), &hc)
if hc.Legacy != nil && hc.Legacy.TPBroadcastInvalidTxn != nil { if hc.Legacy != nil && hc.Legacy.TPBroadcastInvalidTxn != nil {
currentNode.BroadcastInvalidTx = *hc.Legacy.TPBroadcastInvalidTxn currentNode.BroadcastInvalidTx = *hc.Legacy.TPBroadcastInvalidTxn

@ -45,7 +45,6 @@ import (
"github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/hmy/tracers"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/numeric"
@ -167,7 +166,6 @@ type BlockChain struct {
processor Processor // block processor interface processor Processor // block processor interface
validator Validator // block and state validator interface validator Validator // block and state validator interface
vmConfig vm.Config vmConfig vm.Config
traceDB string
badBlocks *lru.Cache // Bad block cache badBlocks *lru.Cache // Bad block cache
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
pendingSlashes slash.Records pendingSlashes slash.Records
@ -179,7 +177,7 @@ type BlockChain struct {
// Processor. // Processor.
func NewBlockChain( func NewBlockChain(
db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig,
engine consensus_engine.Engine, vmConfig vm.Config, traceDB string, engine consensus_engine.Engine, vmConfig vm.Config,
shouldPreserve func(block *types.Block) bool, shouldPreserve func(block *types.Block) bool,
) (*BlockChain, error) { ) (*BlockChain, error) {
if cacheConfig == nil { if cacheConfig == nil {
@ -230,7 +228,6 @@ func NewBlockChain(
blockAccumulatorCache: blockAccumulatorCache, blockAccumulatorCache: blockAccumulatorCache,
engine: engine, engine: engine,
vmConfig: vmConfig, vmConfig: vmConfig,
traceDB: traceDB,
badBlocks: badBlocks, badBlocks: badBlocks,
pendingSlashes: slash.Records{}, pendingSlashes: slash.Records{},
maxGarbCollectedBlkNum: -1, maxGarbCollectedBlkNum: -1,
@ -258,8 +255,6 @@ func NewBlockChain(
return bc, nil return bc, nil
} }
var randname = time.Now().Nanosecond()
// ValidateNewBlock validates new block. // ValidateNewBlock validates new block.
func (bc *BlockChain) ValidateNewBlock(block *types.Block) error { func (bc *BlockChain) ValidateNewBlock(block *types.Block) error {
state, err := state.New(bc.CurrentBlock().Root(), bc.stateCache) state, err := state.New(bc.CurrentBlock().Root(), bc.stateCache)
@ -1289,7 +1284,13 @@ func (bc *BlockChain) GetMaxGarbageCollectedBlockNumber() int64 {
// //
// After insertion is done, all accumulated events will be fired. // After insertion is done, all accumulated events will be fired.
func (bc *BlockChain) InsertChain(chain types.Blocks, verifyHeaders bool) (int, error) { func (bc *BlockChain) InsertChain(chain types.Blocks, verifyHeaders bool) (int, error) {
n, events, logs, err := bc.insertChain(chain, verifyHeaders) n, events, logs, err := bc.insertChain(chain, verifyHeaders, nil)
bc.PostChainEvents(events, logs)
return n, err
}
func (bc *BlockChain) InsertAndTraceChain(chain types.Blocks, verifyHeaders bool, tracers []*vm.Config) (int, error) {
n, events, logs, err := bc.insertChain(chain, verifyHeaders, tracers)
bc.PostChainEvents(events, logs) bc.PostChainEvents(events, logs)
return n, err return n, err
} }
@ -1297,7 +1298,7 @@ func (bc *BlockChain) InsertChain(chain types.Blocks, verifyHeaders bool) (int,
// insertChain will execute the actual chain insertion and event aggregation. The // insertChain will execute the actual chain insertion and event aggregation. The
// only reason this method exists as a separate one is to make locking cleaner // only reason this method exists as a separate one is to make locking cleaner
// with deferred statements. // with deferred statements.
func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool) (int, []interface{}, []*types.Log, error) { func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool, tracers []*vm.Config) (int, []interface{}, []*types.Log, error) {
// Sanity check that we have something meaningful to import // Sanity check that we have something meaningful to import
if len(chain) == 0 { if len(chain) == 0 {
return 0, nil, nil, nil return 0, nil, nil, nil
@ -1425,7 +1426,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool) (int,
if len(winner) > 0 { if len(winner) > 0 {
// Import all the pruned blocks to make the state available // Import all the pruned blocks to make the state available
bc.chainmu.Unlock() bc.chainmu.Unlock()
_, evs, logs, err := bc.insertChain(winner, true /* verifyHeaders */) _, evs, logs, err := bc.insertChain(winner, true /* verifyHeaders */, nil)
bc.chainmu.Lock() bc.chainmu.Lock()
events, coalescedLogs = evs, logs events, coalescedLogs = evs, logs
@ -1452,11 +1453,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool) (int,
return i, events, coalescedLogs, err return i, events, coalescedLogs, err
} }
vmConfig := bc.vmConfig vmConfig := bc.vmConfig
if bc.traceDB != "" { if len(tracers) > i && tracers[i] != nil {
vmConfig = vm.Config{ vmConfig = *tracers[i]
Debug: true,
Tracer: &tracers.ParityBlockTracer{},
}
} }
// Process block using the parent state as reference point. // Process block using the parent state as reference point.
receipts, cxReceipts, logs, usedGas, payout, err := bc.processor.Process( receipts, cxReceipts, logs, usedGas, payout, err := bc.processor.Process(
@ -1480,19 +1478,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool) (int,
status, err := bc.WriteBlockWithState( status, err := bc.WriteBlockWithState(
block, receipts, cxReceipts, payout, state, block, receipts, cxReceipts, payout, state,
) )
if bc.traceDB != "" {
if tracer, ok := vmConfig.Tracer.(*tracers.ParityBlockTracer); ok {
result := make([]json.RawMessage, 0)
var err error
if block.Transactions().Len() > 0 {
result, err = tracer.GetResult()
}
if err == nil {
b, _ := json.Marshal(result)
fmt.Println(block.NumberU64(), string(b))
}
}
}
if err != nil { if err != nil {
return i, events, coalescedLogs, err return i, events, coalescedLogs, err
} }

@ -2,6 +2,7 @@ package hmy
import ( import (
"context" "context"
"encoding/json"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -86,6 +87,7 @@ type NodeAPI interface {
GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error) GetStakingTransactionsHistory(address, txType, order string) ([]common.Hash, error)
GetTransactionsCount(address, txType string) (uint64, error) GetTransactionsCount(address, txType string) (uint64, error)
GetStakingTransactionsCount(address, txType string) (uint64, error) GetStakingTransactionsCount(address, txType string) (uint64, error)
GetTraceResultByHash(hash common.Hash) (json.RawMessage, error)
IsCurrentlyLeader() bool IsCurrentlyLeader() bool
IsOutOfSync(shardID uint32) bool IsOutOfSync(shardID uint32) bool
SyncStatus(shardID uint32) (bool, uint64, uint64) SyncStatus(shardID uint32) (bool, uint64, uint64)

@ -59,7 +59,7 @@ type GeneralConfig struct {
IsBeaconArchival bool IsBeaconArchival bool
IsOffline bool IsOffline bool
DataDir string DataDir string
TraceDir string TraceEnable bool
} }
type ConsensusConfig struct { type ConsensusConfig struct {

@ -94,7 +94,7 @@ type ConfigType struct {
WebHooks struct { WebHooks struct {
Hooks *webhooks.Hooks Hooks *webhooks.Hooks
} }
TraceDir string TraceEnable bool
} }
// RPCServerConfig is the config for rpc listen addresses // RPCServerConfig is the config for rpc listen addresses

@ -40,7 +40,6 @@ type CollectionImpl struct {
pool map[uint32]*core.BlockChain pool map[uint32]*core.BlockChain
disableCache map[uint32]bool disableCache map[uint32]bool
chainConfig *params.ChainConfig chainConfig *params.ChainConfig
traceDB string
} }
// NewCollection creates and returns a new shard chain collection. // NewCollection creates and returns a new shard chain collection.
@ -50,7 +49,7 @@ type CollectionImpl struct {
// dbInit is the shard chain initializer to use when the database returned by // dbInit is the shard chain initializer to use when the database returned by
// the factory is brand new (empty). // the factory is brand new (empty).
func NewCollection( func NewCollection(
dbFactory DBFactory, dbInit DBInitializer, engine engine.Engine, traceDB string, dbFactory DBFactory, dbInit DBInitializer, engine engine.Engine,
chainConfig *params.ChainConfig, chainConfig *params.ChainConfig,
) *CollectionImpl { ) *CollectionImpl {
return &CollectionImpl{ return &CollectionImpl{
@ -60,7 +59,6 @@ func NewCollection(
pool: make(map[uint32]*core.BlockChain), pool: make(map[uint32]*core.BlockChain),
disableCache: make(map[uint32]bool), disableCache: make(map[uint32]bool),
chainConfig: chainConfig, chainConfig: chainConfig,
traceDB: traceDB,
} }
} }
@ -108,7 +106,7 @@ func (sc *CollectionImpl) ShardChain(shardID uint32) (*core.BlockChain, error) {
chainConfig.EthCompatibleChainID = big.NewInt(chainConfig.EthCompatibleShard0ChainID.Int64()) chainConfig.EthCompatibleChainID = big.NewInt(chainConfig.EthCompatibleShard0ChainID.Int64())
} }
bc, err := core.NewBlockChain( bc, err := core.NewBlockChain(
db, cacheConfig, &chainConfig, sc.engine, vm.Config{}, sc.traceDB, nil, db, cacheConfig, &chainConfig, sc.engine, vm.Config{}, nil,
) )
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "cannot create blockchain") return nil, errors.Wrapf(err, "cannot create blockchain")

@ -938,7 +938,6 @@ func New(
host p2p.Host, host p2p.Host,
consensusObj *consensus.Consensus, consensusObj *consensus.Consensus,
chainDBFactory shardchain.DBFactory, chainDBFactory shardchain.DBFactory,
traceDB string,
blacklist map[common.Address]struct{}, blacklist map[common.Address]struct{},
isArchival map[uint32]bool, isArchival map[uint32]bool,
harmonyconfig *harmonyconfig.HarmonyConfig, harmonyconfig *harmonyconfig.HarmonyConfig,
@ -967,7 +966,7 @@ func New(
engine := chain.NewEngine() engine := chain.NewEngine()
collection := shardchain.NewCollection( collection := shardchain.NewCollection(
chainDBFactory, &genesisInitializer{&node}, engine, traceDB, &chainConfig, chainDBFactory, &genesisInitializer{&node}, engine, &chainConfig,
) )
for shardID, archival := range isArchival { for shardID, archival := range isArchival {

@ -2,6 +2,7 @@ package node
import ( import (
"context" "context"
"encoding/json"
"sync" "sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -12,6 +13,8 @@ import (
"github.com/harmony-one/harmony/consensus" "github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/consensus/signature" "github.com/harmony-one/harmony/consensus/signature"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/hmy/tracers"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -122,10 +125,29 @@ func (node *Node) explorerMessageHandler(ctx context.Context, msg *msg_pb.Messag
// AddNewBlockForExplorer add new block for explorer. // AddNewBlockForExplorer add new block for explorer.
func (node *Node) AddNewBlockForExplorer(block *types.Block) { func (node *Node) AddNewBlockForExplorer(block *types.Block) {
utils.Logger().Info().Uint64("blockHeight", block.NumberU64()).Msg("[Explorer] Adding new block for explorer node") utils.Logger().Info().Uint64("blockHeight", block.NumberU64()).Msg("[Explorer] Adding new block for explorer node")
if _, err := node.Blockchain().InsertChain([]*types.Block{block}, false); err == nil {
vmConfig := &vm.Config{
Debug: node.NodeConfig.TraceEnable,
Tracer: &tracers.ParityBlockTracer{},
}
if _, err := node.Blockchain().InsertAndTraceChain([]*types.Block{block}, false, []*vm.Config{vmConfig}); err == nil {
if block.IsLastBlockInEpoch() { if block.IsLastBlockInEpoch() {
node.Consensus.UpdateConsensusInformation() node.Consensus.UpdateConsensusInformation()
} }
if vmConfig.Debug {
traceResults := make([]json.RawMessage, 0)
var err error
if block.Transactions().Len() > 0 {
traceResults, err = vmConfig.Tracer.(*tracers.ParityBlockTracer).GetResult()
}
if err == nil {
if exp, err := node.getExplorerService(); err == nil {
if raw, err := json.Marshal(traceResults); err == nil {
exp.TraceNewBlock(block.Hash(), raw)
}
}
}
}
// Clean up the blocks to avoid OOM. // Clean up the blocks to avoid OOM.
node.Consensus.FBFTLog.DeleteBlockByNumber(block.NumberU64()) node.Consensus.FBFTLog.DeleteBlockByNumber(block.NumberU64())
// Do dump all blocks from state syncing for explorer one time // Do dump all blocks from state syncing for explorer one time
@ -245,6 +267,11 @@ func (node *Node) GetStakingTransactionsCount(address, txType string) (uint64, e
return count, nil return count, nil
} }
// GetStakingTransactionsCount returns the number of staking transactions hashes of address for input type.
func (node *Node) GetTraceResultByHash(hash common.Hash) (json.RawMessage, error) {
return node.GetTraceResultByHash(hash)
}
func (node *Node) getExplorerService() (*explorer.Service, error) { func (node *Node) getExplorerService() (*explorer.Service, error) {
rawService := node.serviceManager.GetService(service.SupportExplorer) rawService := node.serviceManager.GetService(service.SupportExplorer)
if rawService == nil { if rawService == nil {

@ -28,6 +28,9 @@ func (s *PublicParityTracerService) Block(ctx context.Context, number rpc.BlockN
if block == nil { if block == nil {
return nil, nil return nil, nil
} }
if results, err := s.hmy.NodeAPI.GetTraceResultByHash(block.Hash()); err == nil {
return results, nil
}
results, err := s.hmy.TraceBlock(ctx, block, &hmy.TraceConfig{Tracer: &parityTraceGO}) results, err := s.hmy.TraceBlock(ctx, block, &hmy.TraceConfig{Tracer: &parityTraceGO})
if err != nil { if err != nil {
return results, err return results, err

Loading…
Cancel
Save