github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/state/validate.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 "errors" 9 "fmt" 10 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/call" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc" 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/validate" 16 ) 17 18 func (opts *StateOptions) validateState() error { 19 chain := opts.Globals.Chain 20 21 opts.testLog() 22 23 if opts.BadFlag != nil { 24 return opts.BadFlag 25 } 26 27 if !config.IsChainConfigured(chain) { 28 return validate.Usage("chain {0} is not properly configured.", chain) 29 } 30 31 err := validate.ValidateEnumSlice("--parts", opts.Parts, "[balance|nonce|code|proxy|deployed|accttype|some|all]") 32 if err != nil { 33 return err 34 } 35 36 if len(opts.Globals.File) > 0 { 37 // do nothing for now 38 39 } else { 40 if len(opts.Call) > 0 { 41 if len(opts.Parts) > 0 { 42 return validate.Usage("The {0} option is not available{1}.", "--parts", " with the --call option") 43 } 44 45 if opts.Changes { 46 return validate.Usage("The {0} option is not available{1}.", "--changes", " with the --call option") 47 } 48 49 if opts.NoZero { 50 return validate.Usage("The {0} option is not available{1}.", "--no_zero", " with the --call option") 51 } 52 53 if len(opts.Addrs) != 1 { 54 return validate.Usage("Exactly one address is required for the {0} option.", "--call") 55 } 56 57 callAddress := opts.GetCallAddress() 58 err := opts.Conn.IsContractAtLatest(base.HexToAddress(callAddress.Hex())) 59 if err != nil { 60 if errors.Is(err, rpc.ErrNotAContract) { 61 return validate.Usage("The address for the --call option must be a smart contract.") 62 } 63 return err 64 } 65 66 // Before we do anythinng, let's just make sure we have a valid four-byte 67 for _, c := range opts.Calls { 68 if _, suggestions, err := call.NewContractCall(opts.Conn, callAddress, c); err != nil { 69 message := fmt.Sprintf("the --call value provided (%s) was not found: %s", c, err) 70 if len(suggestions) > 0 { 71 if len(suggestions) > 0 { 72 message += " Suggestions: " 73 for index, suggestion := range suggestions { 74 if index > 0 { 75 message += " " 76 } 77 message += fmt.Sprintf("%d: %s.", index+1, suggestion) 78 } 79 } 80 } 81 return errors.New(message) 82 } 83 } 84 85 } else { 86 if opts.Articulate { 87 return validate.Usage("The {0} option is only available with the {1} option.", "--articulate", "--call") 88 } 89 90 proxy := base.HexToAddress(opts.ProxyFor) 91 if !proxy.IsZero() { 92 return validate.Usage("The {0} option is only available with the {1} option.", "--proxy_for", "--call") 93 } 94 95 err := validate.ValidateAtLeastOneAddr(opts.Addrs) 96 if err != nil { 97 return err 98 } 99 100 err = validate.ValidateAddresses(opts.Addrs) 101 if err != nil { 102 return err 103 } 104 } 105 } 106 107 // Blocks are optional, but if they are present, they must be valid 108 if len(opts.Blocks) > 0 { 109 bounds, err := validate.ValidateIdentifiersWithBounds( 110 chain, 111 opts.Blocks, 112 validate.ValidBlockIdWithRangeAndDate, 113 1, 114 &opts.BlockIds, 115 ) 116 117 if err != nil { 118 if invalidLiteral, ok := err.(*validate.InvalidIdentifierLiteralError); ok { 119 return invalidLiteral 120 } 121 122 if errors.Is(err, validate.ErrTooManyRanges) { 123 return validate.Usage("Specify only a single block range at a time.") 124 } 125 126 return err 127 } 128 129 latest := opts.Conn.GetLatestBlockNumber() 130 if bounds.First < (latest-250) && !opts.Conn.IsNodeArchive() { 131 return validate.Usage("The {0} requires {1}.", "query for historical state", "an archive node") 132 } 133 } 134 135 return opts.Globals.Validate() 136 }