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 }