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  }