github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/blockchain/config.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/kelseyhightower/envconfig"
    11  	"github.com/rs/zerolog/log"
    12  )
    13  
    14  var (
    15  	// SimulatedEVMNetwork ensures that the test will use a default simulated geth instance
    16  	SimulatedEVMNetwork = EVMNetwork{
    17  		Name:                 "Simulated Geth",
    18  		ClientImplementation: EthereumClientImplementation,
    19  		Simulated:            true,
    20  		ChainID:              1337,
    21  		URLs:                 []string{"ws://geth:8546"},
    22  		HTTPURLs:             []string{"http://geth:8544"},
    23  		PrivateKeys: []string{
    24  			"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
    25  			"59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
    26  			"5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a",
    27  			"8d351f5fc88484c65c15d44c7d3aa8779d12383373fb42d802e4576a50f765e5",
    28  			"44fd8327d465031c71b20d7a5ba60bb01d33df8256fba406467bcb04e6f7262c",
    29  			"809871f5c72d01a953f44f65d8b7bd0f3e39aee084d8cd0bc17ba3c386391814",
    30  			"f29f5fda630ac9c0e39a8b05ec5b4b750a2e6ef098e612b177c6641bb5a675e1",
    31  			"99b256477c424bb0102caab28c1792a210af906b901244fa67e2b704fac5a2bb",
    32  			"bb74c3a9439ca83d09bcb4d3e5e65d8bc4977fc5b94be4db73772b22c3ff3d1a",
    33  			"58845406a51d98fb2026887281b4e91b8843bbec5f16b89de06d5b9a62b231e8",
    34  		},
    35  		ChainlinkTransactionLimit: 500000,
    36  		Timeout:                   StrDuration{2 * time.Minute},
    37  		MinimumConfirmations:      1,
    38  		GasEstimationBuffer:       10000,
    39  	}
    40  )
    41  
    42  // EVMNetwork configures all the data the test needs to connect and operate on an EVM compatible network
    43  type EVMNetwork struct {
    44  	// Human-readable name of the network:
    45  	Name string `toml:"evm_name" json:"evm_name"`
    46  	// Chain ID for the blockchain
    47  	ChainID int64 `toml:"evm_chain_id" json:"evm_chain_id"`
    48  	// List of websocket URLs you want to connect to
    49  	URLs []string `toml:"evm_urls" json:"evm_urls"`
    50  	// List of websocket URLs you want to connect to
    51  	HTTPURLs []string `toml:"evm_http_urls" json:"evm_http_urls"`
    52  	// True if the network is simulated like a geth instance in dev mode. False if the network is a real test or mainnet
    53  	Simulated bool `toml:"evm_simulated" json:"evm_simulated"`
    54  	// Type of chain client node. Values: "none" | "geth" | "besu"
    55  	SimulationType string `toml:"evm_simulation_type" json:"evm_simulation_type"`
    56  	// List of private keys to fund the tests
    57  	PrivateKeys []string `toml:"evm_keys" json:"evm_keys"`
    58  	// Default gas limit to assume that Chainlink nodes will use. Used to try to estimate the funds that Chainlink
    59  	// nodes require to run the tests.
    60  	ChainlinkTransactionLimit uint64 `toml:"evm_chainlink_transaction_limit" json:"evm_chainlink_transaction_limit"`
    61  	// How long to wait for on-chain operations before timing out an on-chain operation
    62  	Timeout StrDuration `toml:"evm_transaction_timeout" json:"evm_transaction_timeout"`
    63  	// How many block confirmations to wait to confirm on-chain events
    64  	MinimumConfirmations int `toml:"evm_minimum_confirmations" json:"evm_minimum_confirmations"`
    65  	// How much WEI to add to gas estimations for sending transactions
    66  	GasEstimationBuffer uint64 `toml:"evm_gas_estimation_buffer" json:"evm_gas_estimation_buffer"`
    67  	// ClientImplementation is the blockchain client to use when interacting with the test chain
    68  	ClientImplementation ClientImplementation `toml:"client_implementation" json:"client_implementation"`
    69  	// SupportsEIP1559 indicates if the client should try to use EIP1559 style gas and transactions
    70  	SupportsEIP1559 bool `toml:"evm_supports_eip1559" json:"evm_supports_eip1559"`
    71  
    72  	// Default gaslimit to use when sending transactions. If set this will override the transactionOptions gaslimit in case the
    73  	// transactionOptions gaslimit is lesser than the defaultGasLimit.
    74  	DefaultGasLimit uint64 `toml:"evm_default_gas_limit" json:"evm_default_gas_limit"`
    75  	// Few chains use finality tags to mark blocks as finalized. This is used to determine if the chain uses finality tags.
    76  	FinalityTag bool `toml:"evm_finality_tag" json:"evm_finality_tag"`
    77  	// If the chain does not use finality tags, this is used to determine how many blocks to wait for before considering a block finalized.
    78  	FinalityDepth uint64 `toml:"evm_finality_depth" json:"evm_finality_depth"`
    79  
    80  	// TimeToReachFinality is the time it takes for a block to be considered final. This is used to determine how long to wait for a block to be considered final.
    81  	TimeToReachFinality StrDuration `toml:"evm_time_to_reach_finality" json:"evm_time_to_reach_finality"`
    82  
    83  	// Only used internally, do not set
    84  	URL string `ignored:"true"`
    85  }
    86  
    87  // LoadNetworkFromEnvironment loads an EVM network from default environment variables. Helpful in soak tests
    88  func LoadNetworkFromEnvironment() EVMNetwork {
    89  	var network EVMNetwork
    90  	if err := envconfig.Process("", &network); err != nil {
    91  		log.Fatal().Err(err).Msg("Error loading network settings from environment variables")
    92  	}
    93  	log.Debug().Str("Name", network.Name).Int64("Chain ID", network.ChainID).Msg("Loaded Network")
    94  	return network
    95  }
    96  
    97  // ToMap marshalls the network's values to a generic map, useful for setting env vars on instances like the remote runner
    98  // Map Structure
    99  // "envconfig_key": stringValue
   100  func (e *EVMNetwork) ToMap() map[string]interface{} {
   101  	return map[string]interface{}{
   102  		"evm_name":                        e.Name,
   103  		"evm_chain_id":                    fmt.Sprint(e.ChainID),
   104  		"evm_urls":                        strings.Join(e.URLs, ","),
   105  		"evm_http_urls":                   strings.Join(e.HTTPURLs, ","),
   106  		"evm_simulated":                   fmt.Sprint(e.Simulated),
   107  		"evm_simulation_type":             e.SimulationType,
   108  		"evm_keys":                        strings.Join(e.PrivateKeys, ","),
   109  		"evm_chainlink_transaction_limit": fmt.Sprint(e.ChainlinkTransactionLimit),
   110  		"evm_transaction_timeout":         fmt.Sprint(e.Timeout),
   111  		"evm_minimum_confirmations":       fmt.Sprint(e.MinimumConfirmations),
   112  		"evm_gas_estimation_buffer":       fmt.Sprint(e.GasEstimationBuffer),
   113  		"client_implementation":           fmt.Sprint(e.ClientImplementation),
   114  	}
   115  }
   116  
   117  var (
   118  	evmNetworkTOML = `[[EVM]]
   119  ChainID = '%d'
   120  MinContractPayment = '0'
   121  %s`
   122  
   123  	evmNodeTOML = `[[EVM.Nodes]]
   124  Name = '%s'
   125  WSURL = '%s'
   126  HTTPURL = '%s'`
   127  )
   128  
   129  // MustChainlinkTOML marshals EVM network values into a TOML setting snippet. Will fail if error is encountered
   130  // Can provide more detailed config for the network if non-default behaviors are desired.
   131  func (e *EVMNetwork) MustChainlinkTOML(networkDetails string) string {
   132  	if len(e.HTTPURLs) != len(e.URLs) || len(e.HTTPURLs) == 0 || len(e.URLs) == 0 {
   133  		log.Fatal().
   134  			Int("WS Count", len(e.URLs)).
   135  			Int("HTTP Count", len(e.HTTPURLs)).
   136  			Interface("WS URLs", e.URLs).
   137  			Interface("HTTP URLs", e.HTTPURLs).
   138  			Msg("Amount of HTTP and WS URLs should match, and not be empty")
   139  		return ""
   140  	}
   141  	netString := fmt.Sprintf(evmNetworkTOML, e.ChainID, networkDetails)
   142  	for index := range e.URLs {
   143  		netString = fmt.Sprintf("%s\n\n%s", netString,
   144  			fmt.Sprintf(evmNodeTOML, fmt.Sprintf("node-%d", index), e.URLs[index], e.HTTPURLs[index]))
   145  	}
   146  
   147  	return netString
   148  }
   149  
   150  // StrDuration is JSON/TOML friendly duration that can be parsed from "1h2m0s" Go format
   151  type StrDuration struct {
   152  	time.Duration
   153  }
   154  
   155  func (d *StrDuration) MarshalJSON() ([]byte, error) {
   156  	return json.Marshal(d.String())
   157  }
   158  
   159  func (d *StrDuration) UnmarshalJSON(b []byte) error {
   160  	var v interface{}
   161  	if err := json.Unmarshal(b, &v); err != nil {
   162  		return err
   163  	}
   164  	switch value := v.(type) {
   165  	case string:
   166  		var err error
   167  		d.Duration, err = time.ParseDuration(value)
   168  		if err != nil {
   169  			return err
   170  		}
   171  		return nil
   172  	default:
   173  		return errors.New("invalid duration")
   174  	}
   175  }
   176  
   177  // MarshalText implements the text.Marshaler interface (used by toml)
   178  func (d StrDuration) MarshalText() ([]byte, error) {
   179  	return []byte(d.Duration.String()), nil
   180  }
   181  
   182  // UnmarshalText implements the text.Unmarshaler interface (used by toml)
   183  func (d *StrDuration) UnmarshalText(b []byte) error {
   184  	var err error
   185  	d.Duration, err = time.ParseDuration(string(b))
   186  	if err != nil {
   187  		return err
   188  	}
   189  	return nil
   190  
   191  }