github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/state/handle_show.go (about) 1 package statePkg 2 3 import ( 4 "errors" 5 6 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 7 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers" 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output" 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/tslib" 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 12 "github.com/ethereum/go-ethereum" 13 ) 14 15 func (opts *StateOptions) HandleShow(rCtx *output.RenderCtx) error { 16 chain := opts.Globals.Chain 17 18 previousBalance := make(map[base.Address]*base.Wei, len(opts.Addrs)) 19 var filters rpc.StateFilters 20 if opts.Changes || opts.NoZero { 21 filters = rpc.StateFilters{ 22 BalanceCheck: func(address base.Address, balance *base.Wei) bool { 23 if opts.Changes { 24 previous := previousBalance[address] 25 if balance.Text(10) == previous.Text(10) { 26 return false 27 } 28 previousBalance[address] = balance 29 } 30 31 if opts.NoZero { 32 return len(balance.Bytes()) > 0 33 } 34 35 return true 36 }, 37 } 38 } 39 40 stateFields, outputFields, none := types.SliceToStateParts(opts.Parts) 41 42 cnt := 0 43 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 44 for _, addressStr := range opts.Addrs { 45 address := base.HexToAddress(addressStr) 46 currentBn := base.Blknum(0) 47 currentTs := base.Timestamp(0) 48 for _, br := range opts.BlockIds { // TODO: use the regular way to do this 49 blockNums, err := br.ResolveBlocks(chain) 50 if err != nil { 51 errorChan <- err 52 if errors.Is(err, ethereum.NotFound) { 53 continue 54 } 55 rCtx.Cancel() 56 return 57 } 58 59 for _, bn := range blockNums { 60 if none { 61 modelChan <- &types.State{ 62 Address: address, 63 BlockNumber: bn, 64 } 65 cnt++ 66 return 67 } 68 69 if br.StartType == identifiers.BlockHash { 70 block, _ := opts.Conn.GetBlockHeaderByNumber(bn) 71 if base.HexToHash(br.Orig) != block.Hash { 72 errorChan <- errors.New("block hash " + br.Orig + " not found") 73 continue 74 } 75 } 76 77 state, err := opts.Conn.GetState(stateFields, address, bn, filters) 78 if err != nil { 79 errorChan <- err 80 } 81 // state may be nil if it was skipped by a filter for example 82 if state != nil { 83 if opts.Globals.Verbose { 84 if bn == 0 || bn != currentBn { 85 currentTs, _ = tslib.FromBnToTs(chain, bn) 86 } 87 state.Timestamp = currentTs 88 currentBn = bn 89 } 90 cnt++ 91 modelChan <- state 92 } 93 } 94 } 95 } 96 if cnt == 0 { 97 errorChan <- errors.New("no state results were reported") 98 } 99 } 100 101 extraOpts := map[string]any{ 102 "fields": outputFields, 103 } 104 105 return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts)) 106 }