github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/state/options.go (about)

     1  // Copyright 2016, 2024 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   * Parts of this file were auto generated. Edit only those parts of
     6   * the code inside of 'EXISTING_CODE' tags.
     7   */
     8  
     9  package statePkg
    10  
    11  import (
    12  	// EXISTING_CODE
    13  	"encoding/json"
    14  	"io"
    15  	"net/http"
    16  	"net/url"
    17  	"strings"
    18  
    19  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/internal/globals"
    20  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    21  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/caps"
    22  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/identifiers"
    23  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    24  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
    25  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/validate"
    26  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    27  	// EXISTING_CODE
    28  )
    29  
    30  // StateOptions provides all command options for the chifra state command.
    31  type StateOptions struct {
    32  	Addrs      []string                 `json:"addrs,omitempty"`      // One or more addresses (0x...) from which to retrieve balances
    33  	Blocks     []string                 `json:"blocks,omitempty"`     // An optional list of one or more blocks at which to report balances, defaults to 'latest'
    34  	BlockIds   []identifiers.Identifier `json:"blockIds,omitempty"`   // Block identifiers
    35  	Parts      []string                 `json:"parts,omitempty"`      // Control which state to export
    36  	Changes    bool                     `json:"changes,omitempty"`    // Only report a balance when it changes from one block to the next
    37  	NoZero     bool                     `json:"noZero,omitempty"`     // Suppress the display of zero balance accounts
    38  	Call       string                   `json:"call,omitempty"`       // Call a smart contract with one or more solidity calls, four-byte plus parameters, or encoded call data strings
    39  	Articulate bool                     `json:"articulate,omitempty"` // For the --call option only, articulate the retrieved data if ABIs can be found
    40  	ProxyFor   string                   `json:"proxyFor,omitempty"`   // For the --call option only, redirects calls to this implementation
    41  	Globals    globals.GlobalOptions    `json:"globals,omitempty"`    // The global options
    42  	Conn       *rpc.Connection          `json:"conn,omitempty"`       // The connection to the RPC server
    43  	BadFlag    error                    `json:"badFlag,omitempty"`    // An error flag if needed
    44  	// EXISTING_CODE
    45  	Calls []string `json:"-"`
    46  	// EXISTING_CODE
    47  }
    48  
    49  var defaultStateOptions = StateOptions{}
    50  
    51  // testLog is used only during testing to export the options for this test case.
    52  func (opts *StateOptions) testLog() {
    53  	logger.TestLog(len(opts.Addrs) > 0, "Addrs: ", opts.Addrs)
    54  	logger.TestLog(len(opts.Blocks) > 0, "Blocks: ", opts.Blocks)
    55  	logger.TestLog(len(opts.Parts) > 0, "Parts: ", opts.Parts)
    56  	logger.TestLog(opts.Changes, "Changes: ", opts.Changes)
    57  	logger.TestLog(opts.NoZero, "NoZero: ", opts.NoZero)
    58  	logger.TestLog(len(opts.Call) > 0, "Call: ", opts.Call)
    59  	logger.TestLog(opts.Articulate, "Articulate: ", opts.Articulate)
    60  	logger.TestLog(len(opts.ProxyFor) > 0, "ProxyFor: ", opts.ProxyFor)
    61  	opts.Conn.TestLog(opts.getCaches())
    62  	opts.Globals.TestLog()
    63  }
    64  
    65  // String implements the Stringer interface
    66  func (opts *StateOptions) String() string {
    67  	b, _ := json.MarshalIndent(opts, "", "  ")
    68  	return string(b)
    69  }
    70  
    71  // stateFinishParseApi finishes the parsing for server invocations. Returns a new StateOptions.
    72  func stateFinishParseApi(w http.ResponseWriter, r *http.Request) *StateOptions {
    73  	values := r.URL.Query()
    74  	if r.Header.Get("User-Agent") == "testRunner" {
    75  		values.Set("testRunner", "true")
    76  	}
    77  	return StateFinishParseInternal(w, values)
    78  }
    79  
    80  func StateFinishParseInternal(w io.Writer, values url.Values) *StateOptions {
    81  	copy := defaultStateOptions
    82  	copy.Globals.Caps = getCaps()
    83  	opts := &copy
    84  	for key, value := range values {
    85  		switch key {
    86  		case "addrs":
    87  			for _, val := range value {
    88  				s := strings.Split(val, " ") // may contain space separated items
    89  				opts.Addrs = append(opts.Addrs, s...)
    90  			}
    91  		case "blocks":
    92  			for _, val := range value {
    93  				s := strings.Split(val, " ") // may contain space separated items
    94  				opts.Blocks = append(opts.Blocks, s...)
    95  			}
    96  		case "parts":
    97  			for _, val := range value {
    98  				s := strings.Split(val, " ") // may contain space separated items
    99  				opts.Parts = append(opts.Parts, s...)
   100  			}
   101  		case "changes":
   102  			opts.Changes = true
   103  		case "noZero":
   104  			opts.NoZero = true
   105  		case "call":
   106  			opts.Call = value[0]
   107  		case "articulate":
   108  			opts.Articulate = true
   109  		case "proxyFor":
   110  			opts.ProxyFor = value[0]
   111  		default:
   112  			if !copy.Globals.Caps.HasKey(key) {
   113  				err := validate.Usage("Invalid key ({0}) in {1} route.", key, "state")
   114  				if opts.BadFlag == nil || opts.BadFlag.Error() > err.Error() {
   115  					opts.BadFlag = err
   116  				}
   117  			}
   118  		}
   119  	}
   120  	opts.Conn = opts.Globals.FinishParseApi(w, values, opts.getCaches())
   121  
   122  	// EXISTING_CODE
   123  	opts.Call = strings.Replace(strings.Trim(opts.Call, "'"), "'", "\"", -1)
   124  	opts.Calls = strings.Split(opts.Call, ":")
   125  	if len(opts.Blocks) == 0 {
   126  		if opts.Globals.TestMode {
   127  			opts.Blocks = []string{"17000000"}
   128  		} else {
   129  			opts.Blocks = []string{"latest"}
   130  		}
   131  	}
   132  	// EXISTING_CODE
   133  	opts.Addrs, _ = opts.Conn.GetEnsAddresses(opts.Addrs)
   134  	opts.ProxyFor, _ = opts.Conn.GetEnsAddress(opts.ProxyFor)
   135  
   136  	return opts
   137  }
   138  
   139  // stateFinishParse finishes the parsing for command line invocations. Returns a new StateOptions.
   140  func stateFinishParse(args []string) *StateOptions {
   141  	// remove duplicates from args if any (not needed in api mode because the server does it).
   142  	dedup := map[string]int{}
   143  	if len(args) > 0 {
   144  		tmp := []string{}
   145  		for _, arg := range args {
   146  			if value := dedup[arg]; value == 0 {
   147  				tmp = append(tmp, arg)
   148  			}
   149  			dedup[arg]++
   150  		}
   151  		args = tmp
   152  	}
   153  
   154  	defFmt := "txt"
   155  	opts := GetOptions()
   156  	opts.Conn = opts.Globals.FinishParse(args, opts.getCaches())
   157  
   158  	// EXISTING_CODE
   159  	for _, arg := range args {
   160  		if base.IsValidAddress(arg) {
   161  			opts.Addrs = append(opts.Addrs, arg)
   162  		} else {
   163  			opts.Blocks = append(opts.Blocks, arg)
   164  		}
   165  	}
   166  	opts.Call = strings.Replace(strings.Trim(opts.Call, "'"), "'", "\"", -1)
   167  	opts.Calls = strings.Split(opts.Call, ":")
   168  	if len(opts.Blocks) == 0 {
   169  		if opts.Globals.TestMode {
   170  			opts.Blocks = []string{"17000000"}
   171  		} else {
   172  			opts.Blocks = []string{"latest"}
   173  		}
   174  	}
   175  	// EXISTING_CODE
   176  	opts.Addrs, _ = opts.Conn.GetEnsAddresses(opts.Addrs)
   177  	opts.ProxyFor, _ = opts.Conn.GetEnsAddress(opts.ProxyFor)
   178  	if len(opts.Globals.Format) == 0 || opts.Globals.Format == "none" {
   179  		opts.Globals.Format = defFmt
   180  	}
   181  
   182  	return opts
   183  }
   184  
   185  func GetOptions() *StateOptions {
   186  	// EXISTING_CODE
   187  	// EXISTING_CODE
   188  	return &defaultStateOptions
   189  }
   190  
   191  func getCaps() caps.Capability {
   192  	var capabilities caps.Capability // capabilities for chifra state
   193  	capabilities = capabilities.Add(caps.Default)
   194  	capabilities = capabilities.Add(caps.Caching)
   195  	capabilities = capabilities.Add(caps.Ether)
   196  	capabilities = capabilities.Add(caps.Names)
   197  	// EXISTING_CODE
   198  	// EXISTING_CODE
   199  	return capabilities
   200  }
   201  
   202  func ResetOptions(testMode bool) {
   203  	// We want to keep writer between command file calls
   204  	w := GetOptions().Globals.Writer
   205  	opts := StateOptions{}
   206  	globals.SetDefaults(&opts.Globals)
   207  	opts.Globals.TestMode = testMode
   208  	opts.Globals.Writer = w
   209  	opts.Globals.Caps = getCaps()
   210  	defaultStateOptions = opts
   211  }
   212  
   213  func (opts *StateOptions) getCaches() (caches map[walk.CacheType]bool) {
   214  	// EXISTING_CODE
   215  	caches = map[walk.CacheType]bool{
   216  		walk.Cache_State:   true,
   217  		walk.Cache_Results: len(opts.Call) > 0,
   218  	}
   219  	// EXISTING_CODE
   220  	return
   221  }
   222  
   223  // EXISTING_CODE
   224  // EXISTING_CODE