github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/rpc/get_traces.go (about)

     1  // Copyright 2021 The TrueBlocks Authors. All rights reserved.
     2  // Use of this source code is governed by a license that can
     3  // be found in the LICENSE file.
     4  
     5  package rpc
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc/query"
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    14  )
    15  
    16  // GetTracesByBlockNumber returns a slice of traces in the given block
    17  func (conn *Connection) GetTracesByBlockNumber(bn base.Blknum) ([]types.Trace, error) {
    18  	if conn.StoreReadable() {
    19  		// walk.Cache_Traces
    20  		traceGroup := &types.TraceGroup{
    21  			BlockNumber:      bn,
    22  			TransactionIndex: base.NOPOSN, // no tx id means we're storing the whole block
    23  		}
    24  		if err := conn.Store.Read(traceGroup, nil); err == nil {
    25  			return traceGroup.Traces, nil
    26  		}
    27  	}
    28  
    29  	curTs := conn.GetBlockTimestamp(bn) // same for every trace
    30  	isFinal := base.IsFinal(conn.LatestBlockTimestamp, curTs)
    31  
    32  	method := "trace_block"
    33  	params := query.Params{fmt.Sprintf("0x%x", bn)}
    34  
    35  	if traces, err := query.Query[[]types.Trace](conn.Chain, method, params); err != nil {
    36  		return []types.Trace{{
    37  			Action: &types.TraceAction{},
    38  			Result: &types.TraceResult{},
    39  		}}, err
    40  
    41  	} else if traces == nil || len(*traces) == 0 {
    42  		return []types.Trace{{
    43  			Action: &types.TraceAction{},
    44  			Result: &types.TraceResult{},
    45  		}}, err
    46  
    47  	} else {
    48  		curTx := base.NOPOSN
    49  
    50  		var traceIndex base.Tracenum
    51  		for i := range *traces {
    52  			traces := &(*traces)[i]
    53  			traces.Timestamp = curTs
    54  			if traces.Result == nil {
    55  				traces.Result = &types.TraceResult{}
    56  			}
    57  			traces.TransactionIndex = traces.TransactionPosition
    58  			if traces.TransactionIndex != base.Txnum(curTx) {
    59  				curTx = traces.TransactionIndex
    60  				traceIndex = 0
    61  			}
    62  			traces.TraceIndex = traceIndex
    63  			traceIndex++
    64  		}
    65  
    66  		if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Traces] {
    67  			traceGroup := &types.TraceGroup{
    68  				Traces:           *traces,
    69  				BlockNumber:      bn,
    70  				TransactionIndex: base.NOPOSN,
    71  			}
    72  			_ = conn.Store.Write(traceGroup, nil)
    73  		}
    74  		return *traces, nil
    75  	}
    76  }
    77  
    78  // GetTracesByTransactionHash returns a slice of traces in a given transaction's hash
    79  func (conn *Connection) GetTracesByTransactionHash(txHash string, transaction *types.Transaction) ([]types.Trace, error) {
    80  	if conn.StoreReadable() && transaction != nil {
    81  		// walk.Cache_Traces
    82  		traceGroup := &types.TraceGroup{
    83  			BlockNumber:      transaction.BlockNumber,
    84  			TransactionIndex: transaction.TransactionIndex,
    85  			Traces:           make([]types.Trace, 0, len(transaction.Traces)),
    86  		}
    87  		if err := conn.Store.Read(traceGroup, nil); err == nil {
    88  			return traceGroup.Traces, nil
    89  		}
    90  	}
    91  
    92  	method := "trace_transaction"
    93  	params := query.Params{txHash}
    94  
    95  	if traces, err := query.Query[[]types.Trace](conn.Chain, method, params); err != nil {
    96  		return []types.Trace{{
    97  			Action: &types.TraceAction{},
    98  			Result: &types.TraceResult{},
    99  		}}, err
   100  
   101  	} else if traces == nil || len(*traces) == 0 {
   102  		return []types.Trace{{
   103  			Action: &types.TraceAction{},
   104  			Result: &types.TraceResult{},
   105  		}}, err
   106  
   107  	} else {
   108  		curApp := types.Appearance{BlockNumber: uint32(^uint32(0))}
   109  		var traceIndex base.Tracenum
   110  		for i := range *traces {
   111  			traces := &(*traces)[i]
   112  			if transaction != nil {
   113  				traces.Timestamp = transaction.Timestamp
   114  			}
   115  			if traces.Result == nil {
   116  				traces.Result = &types.TraceResult{}
   117  			}
   118  			traces.TransactionIndex = traces.TransactionPosition
   119  			if traces.BlockNumber != base.Blknum(curApp.BlockNumber) || traces.TransactionIndex != base.Txnum(curApp.TransactionIndex) {
   120  				curApp = types.Appearance{
   121  					BlockNumber:      uint32(traces.BlockNumber),
   122  					TransactionIndex: uint32(traces.TransactionIndex),
   123  				}
   124  				traceIndex = 0
   125  			}
   126  			traces.TraceIndex = traceIndex
   127  			traceIndex++
   128  		}
   129  
   130  		if transaction != nil {
   131  			isFinal := base.IsFinal(conn.LatestBlockTimestamp, transaction.Timestamp)
   132  			if isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Traces] {
   133  				traceGroup := &types.TraceGroup{
   134  					BlockNumber:      transaction.BlockNumber,
   135  					TransactionIndex: transaction.TransactionIndex,
   136  					Traces:           *traces,
   137  				}
   138  				_ = conn.Store.Write(traceGroup, nil)
   139  			}
   140  		}
   141  
   142  		return *traces, nil
   143  	}
   144  }