github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/blocks/handle_logs.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 blocksPkg 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/identifiers" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc" 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 *BlocksOptions) HandleLogs(rCtx *output.RenderCtx) error { 23 chain := opts.Globals.Chain 24 testMode := opts.Globals.TestMode 25 nErrors := 0 26 27 abiCache := articulate.NewAbiCache(opts.Conn, opts.Articulate) 28 logFilter := rpc.NewLogFilter(opts.Emitter, opts.Topic) 29 30 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 31 apps, _, err := identifiers.IdsToApps(chain, opts.BlockIds) 32 if err != nil { 33 errorChan <- err 34 rCtx.Cancel() 35 } 36 37 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[types.Transaction](apps, false); err != nil { 38 errorChan <- err 39 rCtx.Cancel() 40 41 } else if cnt == 0 { 42 errorChan <- fmt.Errorf("no blocks found for the query") 43 rCtx.Cancel() 44 45 } else { 46 showProgress := opts.Globals.ShowProgress() 47 bar := logger.NewBar(logger.BarOptions{ 48 Enabled: showProgress, 49 Total: int64(cnt), 50 }) 51 52 for _, thisMap := range sliceOfMaps { 53 if rCtx.WasCanceled() { 54 return 55 } 56 57 for app := range thisMap { 58 thisMap[app] = new(types.Transaction) 59 } 60 61 iterFunc := func(app types.Appearance, value *types.Transaction) error { 62 if value.Receipt == nil { 63 value.Receipt = &types.Receipt{} 64 } 65 66 bn := base.Blknum(app.BlockNumber) 67 ts := opts.Conn.GetBlockTimestamp(bn) 68 if logs, err := opts.Conn.GetLogsByNumber(bn, ts); err != nil { 69 errMutex.Lock() 70 defer errMutex.Unlock() 71 delete(thisMap, app) 72 return fmt.Errorf("block at %d returned an error: %w", bn, err) 73 74 } else if len(logs) == 0 { 75 errMutex.Lock() 76 defer errMutex.Unlock() 77 delete(thisMap, app) 78 return fmt.Errorf("block at %d has no logs", bn) 79 80 } else { 81 l := make([]types.Log, 0, len(logs)) 82 for index := range logs { 83 if opts.Articulate { 84 if err = abiCache.ArticulateLog(&logs[index]); err != nil { 85 errorChan <- err // continue even with an error 86 } 87 } 88 l = append(l, logs[index]) 89 } 90 value.Receipt.Logs = append(value.Receipt.Logs, l...) 91 bar.Tick() 92 return nil 93 } 94 } 95 96 iterErrorChan := make(chan error) 97 iterCtx, iterCancel := context.WithCancel(context.Background()) 98 defer iterCancel() 99 go utils.IterateOverMap(iterCtx, iterErrorChan, thisMap, iterFunc) 100 for err := range iterErrorChan { 101 if !testMode || nErrors == 0 { 102 errorChan <- err 103 nErrors++ 104 } 105 } 106 107 items := make([]types.Log, 0, len(thisMap)) 108 for _, tx := range thisMap { 109 if tx.Receipt != nil { 110 items = append(items, tx.Receipt.Logs...) 111 } 112 } 113 sort.Slice(items, func(i, j int) bool { 114 if items[i].BlockNumber == items[j].BlockNumber { 115 if items[i].TransactionIndex == items[j].TransactionIndex { 116 return items[i].LogIndex < items[j].LogIndex 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 !logFilter.PassesFilter(&item) { 125 continue 126 } 127 modelChan <- &item 128 } 129 } 130 bar.Finish(true /* newLine */) 131 } 132 } 133 134 extraOpts := map[string]any{ 135 "articulate": opts.Articulate, 136 } 137 138 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 139 }