github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/export/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 exportPkg 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/filter" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/monitor" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 17 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 18 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 19 ) 20 21 func (opts *ExportOptions) HandleWithdrawals(rCtx *output.RenderCtx, monitorArray []monitor.Monitor) error { 22 chain := opts.Globals.Chain 23 testMode := opts.Globals.TestMode 24 nErrors := 0 25 first := base.Max(base.KnownBlock(chain, "shanghai"), opts.FirstBlock) 26 filter := filter.NewFilter( 27 opts.Reversed, 28 false, 29 []string{}, 30 base.BlockRange{First: first, Last: opts.LastBlock}, 31 // TODO: I feel (but have not investigated) that this may be a misake 32 // TODO: Shouldn't the RecordRange start with zero not block number? 33 // TODO: It means firstRecord, after all. 34 base.RecordRange{First: uint64(first), Last: opts.GetMax()}, 35 ) 36 37 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 38 for _, mon := range monitorArray { 39 if apps, cnt, err := mon.ReadAndFilterAppearances(filter, false /* withCount */); err != nil { 40 errorChan <- err 41 rCtx.Cancel() 42 43 } else if cnt == 0 { 44 errorChan <- fmt.Errorf("no blocks found for the query") 45 continue 46 47 } else { 48 if sliceOfMaps, _, err := types.AsSliceOfMaps[types.LightBlock](apps, filter.Reversed); err != nil { 49 errorChan <- err 50 rCtx.Cancel() 51 52 } else { 53 showProgress := opts.Globals.ShowProgress() 54 bar := logger.NewBar(logger.BarOptions{ 55 Prefix: mon.Address.Hex(), 56 Enabled: showProgress, 57 Total: int64(cnt), 58 }) 59 60 // TODO: BOGUS - THIS IS NOT CONCURRENCY SAFE 61 finished := false 62 for _, thisMap := range sliceOfMaps { 63 if rCtx.WasCanceled() { 64 return 65 } 66 67 if finished { 68 continue 69 } 70 71 for app := range thisMap { 72 thisMap[app] = new(types.LightBlock) 73 } 74 75 iterFunc := func(app types.Appearance, value *types.LightBlock) error { 76 var block types.LightBlock 77 if block, err = opts.Conn.GetBlockHeaderByNumber(base.Blknum(app.BlockNumber)); err != nil { 78 return err 79 } 80 81 withdrawals := make([]types.Withdrawal, 0, 16) 82 for _, w := range block.Withdrawals { 83 if w.Address == mon.Address { 84 withdrawals = append(withdrawals, w) 85 } 86 } 87 if len(withdrawals) > 0 { 88 block.Withdrawals = withdrawals 89 *value = block 90 } 91 92 bar.Tick() 93 return nil 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 // Sort the items back into an ordered array by block number 108 items := make([]*types.Withdrawal, 0, len(thisMap)) 109 for _, block := range thisMap { 110 for _, with := range block.Withdrawals { 111 items = append(items, &with) 112 } 113 } 114 115 sort.Slice(items, func(i, j int) bool { 116 if opts.Reversed { 117 i, j = j, i 118 } 119 return items[i].BlockNumber < items[j].BlockNumber 120 }) 121 122 for _, item := range items { 123 var passes bool 124 passes, finished = filter.ApplyCountFilter() 125 if passes { 126 modelChan <- item 127 } 128 if finished { 129 break 130 } 131 } 132 } 133 bar.Finish(true /* newLine */) 134 } 135 } 136 } 137 } 138 139 extraOpts := map[string]any{ 140 "export": true, 141 } 142 143 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 144 }