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

     1  package ledger
     2  
     3  import (
     4  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     5  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
     6  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
     8  )
     9  
    10  func (l *Ledger) getStatementsFromTraces(conn *rpc.Connection, trans *types.Transaction, s *types.Statement) ([]types.Statement, error) {
    11  	statements := make([]types.Statement, 0, 20) // a high estimate of the number of statements we'll need
    12  
    13  	ret := *s
    14  	// clear all the internal accounting values. Keeps AmountIn, AmountOut and GasOut because
    15  	// those are at the top level (both the transaction itself and trace '0' have them). We
    16  	// skip trace '0' because it's the same as the transaction.
    17  	// ret.AmountIn.SetUint64(0)
    18  	ret.InternalIn.SetUint64(0)
    19  	ret.MinerBaseRewardIn.SetUint64(0)
    20  	ret.MinerNephewRewardIn.SetUint64(0)
    21  	ret.MinerTxFeeIn.SetUint64(0)
    22  	ret.MinerUncleRewardIn.SetUint64(0)
    23  	ret.CorrectingIn.SetUint64(0)
    24  	ret.PrefundIn.SetUint64(0)
    25  	ret.SelfDestructIn.SetUint64(0)
    26  
    27  	// ret.AmountOut.SetUint64(0)
    28  	// ret.GasOut.SetUint64(0)
    29  	ret.InternalOut.SetUint64(0)
    30  	ret.CorrectingOut.SetUint64(0)
    31  	ret.SelfDestructOut.SetUint64(0)
    32  
    33  	if traces, err := conn.GetTracesByTransactionHash(trans.Hash.Hex(), trans); err != nil {
    34  		return statements, err
    35  
    36  	} else {
    37  		// These values accumulate...so we use += instead of =
    38  		for i, trace := range traces {
    39  			if i == 0 {
    40  				// the first trace is identical to the transaction itself, so we can skip it
    41  				continue
    42  			}
    43  			if trace.Action.CallType == "delegatecall" && trace.Action.To != s.AccountedFor {
    44  				// delegate calls are not included in the transaction's gas cost, so we skip them
    45  				continue
    46  			}
    47  
    48  			plusEq := func(a1, a2 *base.Wei) base.Wei {
    49  				return *a1.Add(a1, a2)
    50  			}
    51  
    52  			// Do not collapse, more than one of these can be true at the same time
    53  			if trace.Action.From == s.AccountedFor {
    54  				ret.InternalOut = plusEq(&ret.InternalOut, &trace.Action.Value)
    55  				ret.Sender = trace.Action.From
    56  				if trace.Action.To.IsZero() {
    57  					if trace.Result != nil {
    58  						ret.Recipient = trace.Result.Address
    59  					}
    60  				} else {
    61  					ret.Recipient = trace.Action.To
    62  				}
    63  			}
    64  
    65  			if trace.Action.To == s.AccountedFor {
    66  				ret.InternalIn = plusEq(&ret.InternalIn, &trace.Action.Value)
    67  				ret.Sender = trace.Action.From
    68  				ret.Recipient = trace.Action.To
    69  			}
    70  
    71  			if trace.Action.SelfDestructed == s.AccountedFor {
    72  				ret.SelfDestructOut = plusEq(&ret.SelfDestructOut, &trace.Action.Balance)
    73  				ret.Sender = trace.Action.SelfDestructed
    74  				if ret.Sender.IsZero() {
    75  					ret.Sender = trace.Action.Address
    76  				}
    77  				ret.Recipient = trace.Action.RefundAddress
    78  			}
    79  
    80  			if trace.Action.RefundAddress == s.AccountedFor {
    81  				ret.SelfDestructIn = plusEq(&ret.SelfDestructIn, &trace.Action.Balance)
    82  				ret.Sender = trace.Action.SelfDestructed
    83  				if ret.Sender.IsZero() {
    84  					ret.Sender = trace.Action.Address
    85  				}
    86  				ret.Recipient = trace.Action.RefundAddress
    87  			}
    88  
    89  			if trace.Action.Address == s.AccountedFor && !trace.Action.RefundAddress.IsZero() {
    90  				ret.SelfDestructOut = plusEq(&ret.SelfDestructOut, &trace.Action.Balance)
    91  				// self destructed send
    92  				ret.Sender = trace.Action.Address
    93  				ret.Recipient = trace.Action.RefundAddress
    94  			}
    95  
    96  			if trace.Result != nil {
    97  				if trace.Result.Address == s.AccountedFor {
    98  					ret.InternalIn = plusEq(&ret.InternalIn, &trace.Action.Value)
    99  					ret.Sender = trace.Action.From
   100  					ret.Recipient = trace.Result.Address
   101  				}
   102  			}
   103  		}
   104  	}
   105  
   106  	if l.trialBalance("trace-eth", &ret) {
   107  		if ret.IsMaterial() {
   108  			statements = append(statements, ret)
   109  		} else {
   110  			logger.TestLog(true, "Tx reconciled with a zero value net amount. It's okay.")
   111  		}
   112  	} else {
   113  		// TODO: BOGUS PERF
   114  		// logger.Warn("Trace statement at", fmt.Sprintf("%d.%d", trans.BlockNumber, trans.TransactionIndex), " does not reconcile.")
   115  		statements = append(statements, ret)
   116  	}
   117  
   118  	return statements, nil
   119  }