github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/export/handle_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 exportPkg 6 7 import ( 8 "context" 9 "fmt" 10 "sort" 11 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/articulate" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/filter" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/monitor" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 18 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 19 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 20 ) 21 22 func (opts *ExportOptions) HandleTraces(rCtx *output.RenderCtx, monitorArray []monitor.Monitor) error { 23 abiCache := articulate.NewAbiCache(opts.Conn, opts.Articulate) 24 filter := filter.NewFilter( 25 opts.Reversed, 26 opts.Reverted, 27 opts.Fourbytes, 28 base.BlockRange{First: opts.FirstBlock, Last: opts.LastBlock}, 29 base.RecordRange{First: opts.FirstRecord, Last: opts.GetMax()}, 30 ) 31 32 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 33 for _, mon := range monitorArray { 34 if apps, cnt, err := mon.ReadAndFilterAppearances(filter, false /* withCount */); err != nil { 35 errorChan <- err 36 rCtx.Cancel() 37 38 } else if cnt == 0 { 39 errorChan <- fmt.Errorf("no blocks found for the query") 40 continue 41 42 } else { 43 if sliceOfMaps, _, err := types.AsSliceOfMaps[types.Transaction](apps, filter.Reversed); err != nil { 44 errorChan <- err 45 rCtx.Cancel() 46 47 } else { 48 showProgress := opts.Globals.ShowProgress() 49 bar := logger.NewBar(logger.BarOptions{ 50 Prefix: mon.Address.Hex(), 51 Enabled: showProgress, 52 Total: int64(cnt), 53 }) 54 55 // TODO: BOGUS - THIS IS NOT CONCURRENCY SAFE 56 finished := false 57 for _, thisMap := range sliceOfMaps { 58 if rCtx.WasCanceled() { 59 return 60 } 61 62 if finished { 63 continue 64 } 65 66 for app := range thisMap { 67 thisMap[app] = new(types.Transaction) 68 } 69 70 iterFunc := func(app types.Appearance, value *types.Transaction) error { 71 if tx, err := opts.Conn.GetTransactionByAppearance(&app, true); err != nil { 72 return err 73 } else { 74 passes, _ := filter.ApplyTxFilters(tx) 75 if passes { 76 *value = *tx 77 } 78 if bar != nil { 79 bar.Tick() 80 } 81 return nil 82 } 83 } 84 85 // Set up and interate over the map calling iterFunc for each appearance 86 iterCtx, iterCancel := context.WithCancel(context.Background()) 87 defer iterCancel() 88 errChan := make(chan error) 89 go utils.IterateOverMap(iterCtx, errChan, thisMap, iterFunc) 90 if stepErr := <-errChan; stepErr != nil { 91 errorChan <- stepErr 92 return 93 } 94 95 items := make([]*types.Trace, 0, len(thisMap)) 96 for _, tx := range thisMap { 97 for index, trace := range tx.Traces { 98 trace.TraceIndex = base.Tracenum(index) 99 isCreate := trace.Action.CallType == "creation" || trace.TraceType == "create" 100 if !opts.Factory || isCreate { 101 if opts.Articulate { 102 if err := abiCache.ArticulateTrace(&trace); err != nil { 103 errorChan <- fmt.Errorf("error articulating trace: %v", err) 104 } 105 } 106 items = append(items, &trace) 107 } 108 } 109 } 110 sort.Slice(items, func(i, j int) bool { 111 if opts.Reversed { 112 i, j = j, i 113 } 114 if items[i].BlockNumber == items[j].BlockNumber { 115 if items[i].TransactionIndex == items[j].TransactionIndex { 116 return items[i].TraceIndex < items[j].TraceIndex 117 } 118 return items[i].TransactionIndex < items[j].TransactionIndex 119 } 120 return items[i].BlockNumber < items[j].BlockNumber 121 }) 122 123 for _, item := range items { 124 if item.BlockHash.IsZero() { 125 continue 126 } 127 var passes bool 128 passes, finished = filter.ApplyCountFilter() 129 if passes { 130 modelChan <- item 131 } 132 if finished { 133 break 134 } 135 } 136 } 137 bar.Finish(true /* newLine */) 138 } 139 } 140 } 141 } 142 143 extraOpts := map[string]any{ 144 "articulate": opts.Articulate, 145 "export": true, 146 } 147 148 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 149 } 150 151 /* 152 TODO: NOTE 153 bool isSelfDestruct = trace.action.selfDestructed != ""; 154 if (isSelfDestruct) { 155 copy.action.from = trace.action.selfDestructed; 156 copy.action.to = trace.action.refundAddress; 157 copy.action.callType = "suicide"; 158 copy.action.value = trace.action.balance; 159 copy.traceAddress.push_back("s"); 160 copy.transactionHash = uint_2_Hex(trace.blockNumber * 100000 + trace.transactionIndex); 161 copy.action.input = "0x"; 162 } 163 cout << ((isJson() && !opt->firstOut) ? ", " : ""); 164 cout << copy; 165 opt->firstOut = false; 166 bool isCreation = trace.result.address != ""; 167 if (isCreation) { 168 copy.action.from = "0x0"; 169 copy.action.to = trace.result.address; 170 copy.action.callType = "creation"; 171 copy.action.value = trace.action.value; 172 if (copy.traceAddress.size() == 0) 173 copy.traceAddress.push_back("null"); 174 copy.traceAddress.push_back("s"); 175 copy.transactionHash = uint_2_Hex(trace.blockNumber * 100000 + trace.transactionIndex); 176 copy.action.input = trace.action.input; 177 cout << ((isJson() && !opt->firstOut) ? ", " : ""); 178 cout << copy; 179 opt->firstOut = false; 180 181 */