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 }