github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/ledger/ledger.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/names"
     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  // TODO: Two things to note. (1) if balances were part of this structure, we could fill those
    11  // TODO: balances in a concurrent way before spinning through the appearances. And (2) if we did that
    12  // TODO: prior to doing the accounting, we could easily travers in reverse order.
    13  
    14  // Ledger is a structure that carries enough information to complate a reconciliation
    15  type Ledger struct {
    16  	Chain       string
    17  	AccountFor  base.Address
    18  	FirstBlock  base.Blknum
    19  	LastBlock   base.Blknum
    20  	Names       map[base.Address]types.Name
    21  	TestMode    bool
    22  	Contexts    map[ledgerContextKey]*ledgerContext
    23  	AsEther     bool
    24  	NoZero      bool
    25  	Reversed    bool
    26  	UseTraces   bool
    27  	Conn        *rpc.Connection
    28  	assetFilter []base.Address
    29  	theTx       *types.Transaction
    30  }
    31  
    32  // NewLedger returns a new empty Ledger struct
    33  func NewLedger(conn *rpc.Connection, acctFor base.Address, fb, lb base.Blknum, asEther, testMode, noZero, useTraces, reversed bool, assetFilters *[]string) *Ledger {
    34  	l := &Ledger{
    35  		Conn:       conn,
    36  		AccountFor: acctFor,
    37  		FirstBlock: fb,
    38  		LastBlock:  lb,
    39  		Contexts:   make(map[ledgerContextKey]*ledgerContext),
    40  		AsEther:    asEther,
    41  		TestMode:   testMode,
    42  		NoZero:     noZero,
    43  		Reversed:   reversed,
    44  		UseTraces:  useTraces,
    45  	}
    46  
    47  	if assetFilters != nil {
    48  		l.assetFilter = make([]base.Address, len(*assetFilters))
    49  		for i, addr := range *assetFilters {
    50  			l.assetFilter[i] = base.HexToAddress(addr)
    51  		}
    52  	} else {
    53  		l.assetFilter = []base.Address{}
    54  	}
    55  
    56  	parts := types.Custom | types.Prefund | types.Regular
    57  	l.Names, _ = names.LoadNamesMap(conn.Chain, parts, []string{})
    58  
    59  	return l
    60  }
    61  
    62  // assetOfInterest returns true if the asset filter is empty or the asset matches
    63  func (l *Ledger) assetOfInterest(needle base.Address) bool {
    64  	if len(l.assetFilter) == 0 {
    65  		return true
    66  	}
    67  
    68  	for _, asset := range l.assetFilter {
    69  		if asset.Hex() == needle.Hex() {
    70  			return true
    71  		}
    72  	}
    73  
    74  	return false
    75  }
    76  
    77  // See issue #2791 - This is the code that used to generate extra traces to make reconcilation work
    78  // (or, at least, similar code in `chifra export` generated these traces.
    79  // bool isSuicide = trace.action.selfDestructed != "";
    80  // bool isCreation = trace.result.address != "";
    81  // // do not colapse
    82  // if (isCreation) {
    83  //   displayAsTrace(opt, trace);
    84  //   displayAsCreation(opt, trace);
    85  // }
    86  // // do not colapse
    87  // if (isSuicide) {
    88  //   displayAsSuicide(opt, trace);
    89  // }
    90  // // do not colapse
    91  // if (!isCreation && !isSuicide) {
    92  //   displayAsTrace(opt, trace);
    93  // }
    94  //--------------------------------------------------------------
    95  // bool displayAsCreation(COptions* opt, const CTrace& trace) {
    96  //     if (trace.result.address == "")
    97  //         return false;
    98  //     CTrace copy = trace;
    99  //     copy.action.from = "0x0";
   100  //     copy.action.to = trace.result.address;
   101  //     copy.action.callType = "creation";
   102  //     copy.action.value = trace.action.value;
   103  //     if (copy.traceAddress.size() == 0)
   104  //         copy.traceAddress.push_back("null");
   105  //     copy.traceAddress.push_back("s");
   106  //     copy.transactionHash = uint_2_Hex(trace.blockNumber * 100000 + trace.transactionIndex);
   107  //     copy.action.input = trace.action.input;
   108  //     return displayAsTrace(opt, copy);
   109  // }
   110  // //--------------------------------------------------------------
   111  // bool displayAsSuicide(COptions* opt, const CTrace& trace) {
   112  //     if (trace.action.refundAddress == "")
   113  //         return false;
   114  //     CTrace copy = trace;
   115  //     copy.action.from = trace.action.selfDestructed;
   116  //     copy.action.to = trace.action.refundAddress;
   117  //     copy.action.callType = "suicide";
   118  //     copy.action.value = trace.action.balance;
   119  //     copy.traceAddress.push_back("s");
   120  //     copy.transactionHash = uint_2_Hex(trace.blockNumber * 100000 + trace.transactionIndex);
   121  //     copy.action.input = "0x";
   122  //     return displayAsTrace(opt, copy);
   123  // }
   124  // //--------------------------------------------------------------
   125  // bool displayAsTrace(COptions* opt, const CTrace& trace) {
   126  //     bool isText = (expContext().exportFmt & (TXT1 | CSV1));
   127  //     if (isText) {
   128  //         cout << trim(trace.Format(expContext().fmtMap["format"]), '\t') << endl;
   129  //     } else {
   130  //         if (!opt->firstOut)
   131  //             cout << ",";
   132  //         cout << "  ";
   133  //         indent();
   134  //         trace.toJson(cout);
   135  //         unindent();
   136  //         opt->firstOut = false;
   137  //     }
   138  //     return true;
   139  // }