github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/blocks/handle_withdrawals.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/base" 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 *BlocksOptions) HandleWithdrawals(rCtx *output.RenderCtx) error { 21 chain := opts.Globals.Chain 22 testMode := opts.Globals.TestMode 23 nErrors := 0 24 25 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 26 apps, _, err := identifiers.IdsToApps(chain, opts.BlockIds) 27 if err != nil { 28 errorChan <- err 29 rCtx.Cancel() 30 } 31 32 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[types.LightBlock](apps, false); err != nil { 33 errorChan <- err 34 rCtx.Cancel() 35 36 } else if cnt == 0 { 37 errorChan <- fmt.Errorf("no blocks found for the query") 38 rCtx.Cancel() 39 40 } else { 41 showProgress := opts.Globals.ShowProgress() 42 bar := logger.NewBar(logger.BarOptions{ 43 Enabled: showProgress, 44 Total: int64(cnt), 45 }) 46 47 for _, thisMap := range sliceOfMaps { 48 if rCtx.WasCanceled() { 49 return 50 } 51 52 for app := range thisMap { 53 thisMap[app] = new(types.LightBlock) 54 } 55 56 items := make([]*types.Withdrawal, 0, len(thisMap)) 57 iterFunc := func(app types.Appearance, value *types.LightBlock) error { 58 bn := base.Blknum(app.BlockNumber) 59 if block, err := opts.Conn.GetBlockHeaderByNumber(bn); err != nil { 60 delete(thisMap, app) 61 return err 62 } else { 63 *value = block 64 bar.Tick() 65 } 66 return nil 67 } 68 69 iterErrorChan := make(chan error) 70 iterCtx, iterCancel := context.WithCancel(context.Background()) 71 defer iterCancel() 72 go utils.IterateOverMap(iterCtx, iterErrorChan, thisMap, iterFunc) 73 for err := range iterErrorChan { 74 if !testMode || nErrors == 0 { 75 errorChan <- err 76 nErrors++ 77 } 78 } 79 80 for _, item := range thisMap { 81 for _, w := range item.Withdrawals { 82 w.BlockNumber = item.BlockNumber 83 items = append(items, &w) 84 } 85 } 86 87 sort.Slice(items, func(i, j int) bool { 88 if items[i].BlockNumber == items[j].BlockNumber { 89 return items[i].Index < items[j].Index 90 } 91 return items[i].BlockNumber < items[j].BlockNumber 92 }) 93 94 for _, item := range items { 95 modelChan <- item 96 } 97 } 98 bar.Finish(true /* newLine */) 99 } 100 } 101 102 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOpts()) 103 }