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

     1  package ledger
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/filter"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    14  )
    15  
    16  // GetStatements returns a statement from a given transaction
    17  func (l *Ledger) GetStatements(conn *rpc.Connection, filter *filter.AppearanceFilter, trans *types.Transaction) ([]types.Statement, error) {
    18  	// We need this below...
    19  	l.theTx = trans
    20  
    21  	if false && conn.StoreReadable() {
    22  		// walk.Cache_Statements
    23  		statementGroup := &types.StatementGroup{
    24  			BlockNumber:      trans.BlockNumber,
    25  			TransactionIndex: trans.TransactionIndex,
    26  			Address:          l.AccountFor,
    27  		}
    28  		if err := conn.Store.Read(statementGroup, nil); err == nil {
    29  			return statementGroup.Statements, nil
    30  		}
    31  	}
    32  
    33  	// make room for our results
    34  	statements := make([]types.Statement, 0, 20) // a high estimate of the number of statements we'll need
    35  
    36  	key := l.ctxKey(trans.BlockNumber, trans.TransactionIndex)
    37  	ctx := l.Contexts[key]
    38  
    39  	if l.assetOfInterest(base.FAKE_ETH_ADDRESS) {
    40  		// TODO: We ignore errors in the next few lines, but we should not
    41  		// TODO: BOGUS PERF - This greatly increases the number of times we call into eth_getBalance which is quite slow
    42  		prevBal, _ := conn.GetBalanceAt(l.AccountFor, ctx.PrevBlock)
    43  		if trans.BlockNumber == 0 {
    44  			prevBal = new(base.Wei)
    45  		}
    46  		begBal, _ := conn.GetBalanceAt(l.AccountFor, ctx.CurBlock-1)
    47  		endBal, _ := conn.GetBalanceAt(l.AccountFor, ctx.CurBlock)
    48  
    49  		ret := types.Statement{
    50  			AccountedFor:     l.AccountFor,
    51  			Sender:           trans.From,
    52  			Recipient:        trans.To,
    53  			BlockNumber:      trans.BlockNumber,
    54  			TransactionIndex: trans.TransactionIndex,
    55  			TransactionHash:  trans.Hash,
    56  			LogIndex:         0,
    57  			Timestamp:        trans.Timestamp,
    58  			AssetAddr:        base.FAKE_ETH_ADDRESS,
    59  			AssetSymbol:      "WEI",
    60  			Decimals:         18,
    61  			SpotPrice:        0.0,
    62  			PriceSource:      "not-priced",
    63  			PrevBal:          *prevBal,
    64  			BegBal:           *begBal,
    65  			EndBal:           *endBal,
    66  			ReconType:        ctx.ReconType,
    67  		}
    68  
    69  		if trans.To.IsZero() && trans.Receipt != nil && !trans.Receipt.ContractAddress.IsZero() {
    70  			ret.Recipient = trans.Receipt.ContractAddress
    71  		}
    72  
    73  		// Do not collapse. A single transaction may have many movements of money
    74  		if l.AccountFor == ret.Sender {
    75  			gasUsed := new(base.Wei)
    76  			if trans.Receipt != nil {
    77  				gasUsed.SetUint64(uint64(trans.Receipt.GasUsed))
    78  			}
    79  			gasPrice := new(base.Wei).SetUint64(uint64(trans.GasPrice))
    80  			gasOut := new(base.Wei).Mul(gasUsed, gasPrice)
    81  
    82  			ret.AmountOut = trans.Value
    83  			ret.GasOut = *gasOut
    84  		}
    85  
    86  		// Do not collapse. A single transaction may have many movements of money
    87  		if l.AccountFor == ret.Recipient {
    88  			if ret.BlockNumber == 0 {
    89  				ret.PrefundIn = trans.Value
    90  			} else {
    91  				if trans.Rewards != nil {
    92  					ret.MinerBaseRewardIn = trans.Rewards.Block
    93  					ret.MinerNephewRewardIn = trans.Rewards.Nephew
    94  					ret.MinerTxFeeIn = trans.Rewards.TxFee
    95  					ret.MinerUncleRewardIn = trans.Rewards.Uncle
    96  				} else {
    97  					ret.AmountIn = trans.Value
    98  				}
    99  				// TODO: BOGUS PERF - WHAT ABOUT WITHDRAWALS?
   100  			}
   101  		}
   102  
   103  		if l.AsEther {
   104  			ret.AssetSymbol = "ETH"
   105  		}
   106  
   107  		if !l.UseTraces && l.trialBalance("eth", &ret) {
   108  			if ret.IsMaterial() {
   109  				statements = append(statements, ret)
   110  			} else {
   111  				logger.TestLog(true, "Tx reconciled with a zero value net amount. It's okay.")
   112  			}
   113  		} else {
   114  			if !l.UseTraces {
   115  				logger.TestLog(!l.UseTraces, "Trial balance failed for ", ret.TransactionHash.Hex(), "need to decend into traces")
   116  			}
   117  			if traceStatements, err := l.getStatementsFromTraces(conn, trans, &ret); err != nil {
   118  				if !utils.IsFuzzing() {
   119  					logger.Warn(colors.Yellow+"Statement at ", fmt.Sprintf("%d.%d", trans.BlockNumber, trans.TransactionIndex), " does not reconcile."+colors.Off)
   120  				}
   121  			} else {
   122  				statements = append(statements, traceStatements...)
   123  			}
   124  		}
   125  	}
   126  
   127  	if receiptStatements, err := l.getStatementsFromReceipt(conn, filter, trans.Receipt); err != nil {
   128  		logger.Warn(l.TestMode, "Error getting statement from receipt")
   129  	} else {
   130  		statements = append(statements, receiptStatements...)
   131  	}
   132  
   133  	isFinal := base.IsFinal(conn.LatestBlockTimestamp, trans.Timestamp)
   134  	if false && isFinal && conn.StoreWritable() && conn.EnabledMap[walk.Cache_Statements] {
   135  		statementGroup := &types.StatementGroup{
   136  			BlockNumber:      trans.BlockNumber,
   137  			TransactionIndex: trans.TransactionIndex,
   138  			Address:          l.AccountFor,
   139  			Statements:       statements,
   140  		}
   141  		_ = conn.Store.Write(statementGroup, nil)
   142  	}
   143  
   144  	return statements, nil
   145  }