github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/traces/handle_show.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 tracesPkg 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/identifiers" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 18 ) 19 20 func (opts *TracesOptions) HandleShow(rCtx *output.RenderCtx) error { 21 chain := opts.Globals.Chain 22 testMode := opts.Globals.TestMode 23 nErrors := 0 24 25 abiCache := articulate.NewAbiCache(opts.Conn, opts.Articulate) 26 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 27 apps, _, err := identifiers.IdsToApps(chain, opts.TransactionIds) 28 if err != nil { 29 errorChan <- err 30 rCtx.Cancel() 31 } 32 33 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[types.Transaction](apps, false); err != nil { 34 errorChan <- err 35 rCtx.Cancel() 36 37 } else if cnt == 0 { 38 errorChan <- fmt.Errorf("no transactions found") 39 rCtx.Cancel() 40 41 } else { 42 showProgress := opts.Globals.ShowProgress() 43 bar := logger.NewBar(logger.BarOptions{ 44 Enabled: showProgress, 45 Total: int64(cnt), 46 }) 47 48 for _, thisMap := range sliceOfMaps { 49 if rCtx.WasCanceled() { 50 return 51 } 52 53 for app := range thisMap { 54 thisMap[app] = new(types.Transaction) 55 } 56 57 iterFunc := func(app types.Appearance, value *types.Transaction) error { 58 if tx, err := opts.Conn.GetTransactionByAppearance(&app, true); err != nil { 59 delete(thisMap, app) 60 return fmt.Errorf("transaction at %s returned an error: %w", app.Orig(), err) 61 62 } else if tx == nil || len(tx.Traces) == 0 { 63 delete(thisMap, app) 64 return fmt.Errorf("transaction at %s has no traces", app.Orig()) 65 66 } else { 67 for index := range tx.Traces { 68 if opts.Articulate { 69 if err = abiCache.ArticulateTrace(&tx.Traces[index]); err != nil { 70 errorChan <- err // continue even with an error 71 } 72 } 73 } 74 *value = *tx 75 bar.Tick() 76 return nil 77 } 78 } 79 80 iterErrorChan := make(chan error) 81 iterCtx, iterCancel := context.WithCancel(context.Background()) 82 defer iterCancel() 83 go utils.IterateOverMap(iterCtx, iterErrorChan, thisMap, iterFunc) 84 for err := range iterErrorChan { 85 if !testMode || nErrors == 0 { 86 errorChan <- err 87 nErrors++ 88 } 89 } 90 91 items := make([]types.Trace, 0, len(thisMap)) 92 for _, receipt := range thisMap { 93 items = append(items, receipt.Traces...) 94 } 95 sort.Slice(items, func(i, j int) bool { 96 if items[i].BlockNumber == items[j].BlockNumber { 97 if items[i].TransactionIndex == items[j].TransactionIndex { 98 return items[i].GetSortString() < items[j].GetSortString() 99 } 100 return items[i].TransactionIndex < items[j].TransactionIndex 101 } 102 return items[i].BlockNumber < items[j].BlockNumber 103 }) 104 105 for _, item := range items { 106 modelChan <- &item 107 } 108 } 109 bar.Finish(true /* newLine */) 110 } 111 } 112 113 extraOpts := map[string]any{ 114 "articulate": opts.Articulate, 115 } 116 117 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 118 }