github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/state/handle_call.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 statePkg 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/call" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 16 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 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 *StateOptions) HandleCall(rCtx *output.RenderCtx) error { 23 chain := opts.Globals.Chain 24 testMode := opts.Globals.TestMode 25 nErrors := 0 26 27 artFunc := func(str string, function *types.Function) error { 28 return articulate.ArticulateFunction(function, "", str[2:]) 29 } 30 31 callAddress := opts.GetCallAddress() 32 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 33 apps, _, err := identifiers.IdsToApps(chain, opts.BlockIds) 34 if err != nil { 35 errorChan <- err 36 rCtx.Cancel() 37 } 38 39 if sliceOfMaps, cnt, err := types.AsSliceOfMaps[[]types.Result](apps, false); 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 rCtx.Cancel() 46 47 } else { 48 showProgress := opts.Globals.ShowProgress() 49 bar := logger.NewBar(logger.BarOptions{ 50 Enabled: showProgress, 51 Total: int64(cnt), 52 }) 53 54 for _, thisMap := range sliceOfMaps { 55 if rCtx.WasCanceled() { 56 return 57 } 58 59 for app := range thisMap { 60 thisMap[app] = new([]types.Result) 61 } 62 63 iterFunc := func(app types.Appearance, value *[]types.Result) error { 64 bn := base.Blknum(app.BlockNumber) 65 for _, c := range opts.Calls { 66 if contractCall, _, err := call.NewContractCall(opts.Conn, callAddress, c); err != nil { 67 delete(thisMap, app) 68 return fmt.Errorf("the --call value provided (%s) was not found: %s", c, err) 69 70 } else { 71 contractCall.BlockNumber = bn 72 results, err := contractCall.Call(artFunc) 73 if err != nil { 74 delete(thisMap, app) 75 return err 76 } else { 77 bar.Tick() 78 *value = append(*value, *results) 79 } 80 } 81 } 82 return nil 83 } 84 85 iterErrorChan := make(chan error) 86 iterCtx, iterCancel := context.WithCancel(context.Background()) 87 defer iterCancel() 88 go utils.IterateOverMap(iterCtx, iterErrorChan, thisMap, iterFunc) 89 for err := range iterErrorChan { 90 if !testMode || nErrors == 0 { 91 errorChan <- err 92 nErrors++ 93 } 94 } 95 96 items := make([]types.Result, 0, len(thisMap)) 97 for _, v := range thisMap { 98 items = append(items, *v...) 99 } 100 101 sort.Slice(items, func(i, j int) bool { 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 } 119 120 func (opts *StateOptions) GetCallAddress() base.Address { 121 // Note that the validator precludes the possibility of having more than one address 122 // if the call option is present. 123 callAddress := base.HexToAddress(opts.Addrs[0]) 124 proxy := base.HexToAddress(opts.ProxyFor) 125 if !proxy.IsZero() { 126 callAddress = proxy 127 } 128 return callAddress 129 }