github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/blockchain/ethereum.go (about) 1 package blockchain 2 3 // Contains implementations for multi and single node ethereum clients 4 import ( 5 "bytes" 6 "context" 7 "crypto/ecdsa" 8 "encoding/hex" 9 "errors" 10 "fmt" 11 "math/big" 12 "regexp" 13 "strconv" 14 "strings" 15 "sync" 16 "time" 17 18 "github.com/ethereum/go-ethereum" 19 "github.com/ethereum/go-ethereum/accounts/abi" 20 "github.com/ethereum/go-ethereum/accounts/abi/bind" 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/common/hexutil" 23 "github.com/ethereum/go-ethereum/core/types" 24 "github.com/ethereum/go-ethereum/crypto" 25 "github.com/ethereum/go-ethereum/ethclient" 26 "github.com/ethereum/go-ethereum/rpc" 27 "github.com/rs/zerolog" 28 "go.uber.org/atomic" 29 "golang.org/x/sync/errgroup" 30 31 "github.com/smartcontractkit/chainlink-testing-framework/libs/k8s/environment" 32 "github.com/smartcontractkit/chainlink-testing-framework/libs/utils/conversions" 33 ) 34 35 const MaxTimeoutForFinality = 15 * time.Minute 36 37 // EthereumClient wraps the client and the BlockChain network to interact with an EVM based Blockchain 38 type EthereumClient struct { 39 ID int 40 Client *ethclient.Client 41 rawRPC *rpc.Client 42 NetworkConfig EVMNetwork 43 Wallets []*EthereumWallet 44 DefaultWallet *EthereumWallet 45 NonceSettings *NonceSettings 46 FinalizedHeader atomic.Pointer[FinalizedHeader] 47 headerSubscriptions map[string]HeaderEventSubscription 48 subscriptionMutex *sync.Mutex 49 queueTransactions bool 50 gasStats *GasStats 51 connectionIssueCh chan time.Time 52 connectionRestoredCh chan time.Time 53 doneChan chan struct{} 54 l zerolog.Logger 55 subscriptionWg sync.WaitGroup 56 } 57 58 // newEVMClient creates an EVM client for a single node/URL 59 func newEVMClient(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) { 60 logger.Info(). 61 Str("Name", networkSettings.Name). 62 Str("URL", networkSettings.URL). 63 Int64("Chain ID", networkSettings.ChainID). 64 Bool("Simulated", networkSettings.Simulated). 65 Bool("Supports EIP-1559", networkSettings.SupportsEIP1559). 66 Bool("Finality Tag", networkSettings.FinalityTag). 67 Msg("Connecting client") 68 cl, err := ethclient.Dial(networkSettings.URL) 69 if err != nil { 70 return nil, err 71 } 72 raw, err := rpc.Dial(networkSettings.URL) 73 if err != nil { 74 return nil, err 75 } 76 77 ec := &EthereumClient{ 78 NetworkConfig: networkSettings, 79 Client: cl, 80 rawRPC: raw, 81 Wallets: make([]*EthereumWallet, 0), 82 headerSubscriptions: map[string]HeaderEventSubscription{}, 83 subscriptionMutex: &sync.Mutex{}, 84 queueTransactions: false, 85 86 connectionIssueCh: make(chan time.Time, 100), // buffered to prevent blocking, size is probably overkill, but some tests might not care 87 connectionRestoredCh: make(chan time.Time, 100), 88 doneChan: make(chan struct{}), 89 l: logger, 90 } 91 92 if ec.NetworkConfig.Simulated { 93 ec.NonceSettings = newNonceSettings() 94 } else { // un-simulated chain means potentially running tests in parallel, need to share nonces 95 ec.NonceSettings = useGlobalNonceManager(ec.GetChainID()) 96 } 97 98 if err := ec.LoadWallets(networkSettings); err != nil { 99 return nil, err 100 } 101 ec.gasStats = NewGasStats(ec.ID) 102 err = ec.subscribeToNewHeaders() 103 if err != nil { 104 return nil, err 105 } 106 107 // Check if the chain supports EIP-1559 108 // https://eips.ethereum.org/EIPS/eip-1559 109 if networkSettings.SupportsEIP1559 { 110 ec.l.Debug().Msg("Network supports EIP-1559, using Dynamic transactions") 111 } else { 112 ec.l.Debug().Msg("Network does NOT support EIP-1559, using Legacy transactions") 113 } 114 115 return wrapSingleClient(networkSettings, ec), nil 116 } 117 118 // SyncNonce sets the NonceMu and Nonces value based on existing EVMClient 119 // it ensures the instance of EthereumClient is synced with passed EVMClient's nonce updates. 120 func (e *EthereumClient) SyncNonce(c EVMClient) { 121 n := c.GetNonceSetting() 122 n.NonceMu.Lock() 123 defer n.NonceMu.Unlock() 124 e.NonceSettings.NonceMu = n.NonceMu 125 e.NonceSettings.Nonces = n.Nonces 126 } 127 128 // Get returns the underlying client type to be used generically across the framework for switching 129 // network types 130 func (e *EthereumClient) Get() interface{} { 131 return e 132 } 133 134 // GetNetworkName retrieves the ID of the network that the client interacts with 135 func (e *EthereumClient) GetNetworkName() string { 136 return e.NetworkConfig.Name 137 } 138 139 // NetworkSimulated returns true if the network is a simulated geth instance, false otherwise 140 func (e *EthereumClient) NetworkSimulated() bool { 141 return e.NetworkConfig.Simulated 142 } 143 144 func (e *EthereumClient) GetNonceSetting() NonceSettings { 145 e.NonceSettings.NonceMu.Lock() 146 defer e.NonceSettings.NonceMu.Unlock() 147 return NonceSettings{ 148 NonceMu: e.NonceSettings.NonceMu, 149 Nonces: e.NonceSettings.Nonces, 150 } 151 } 152 153 // GetChainID retrieves the ChainID of the network that the client interacts with 154 func (e *EthereumClient) GetChainID() *big.Int { 155 return big.NewInt(e.NetworkConfig.ChainID) 156 } 157 158 // GetClients not used, only applicable to EthereumMultinodeClient 159 func (e *EthereumClient) GetClients() []EVMClient { 160 return []EVMClient{e} 161 } 162 163 // DefaultWallet returns the default wallet for the network 164 func (e *EthereumClient) GetDefaultWallet() *EthereumWallet { 165 return e.DefaultWallet 166 } 167 168 // DefaultWallet returns the default wallet for the network 169 func (e *EthereumClient) GetWallets() []*EthereumWallet { 170 return e.Wallets 171 } 172 173 // DefaultWallet returns the default wallet for the network 174 func (e *EthereumClient) GetNetworkConfig() *EVMNetwork { 175 return &e.NetworkConfig 176 } 177 178 // SetID sets client id, only used for multi-node networks 179 func (e *EthereumClient) SetID(id int) { 180 e.ID = id 181 } 182 183 // SetDefaultWallet sets default wallet 184 func (e *EthereumClient) SetDefaultWallet(num int) error { 185 if num >= len(e.GetWallets()) { 186 return fmt.Errorf("no wallet #%d found for default client", num) 187 } 188 e.DefaultWallet = e.Wallets[num] 189 return nil 190 } 191 192 // SetWallets sets all wallets to be used by the client 193 func (e *EthereumClient) SetWallets(wallets []*EthereumWallet) { 194 e.Wallets = wallets 195 } 196 197 // LoadWallets loads wallets from config 198 func (e *EthereumClient) LoadWallets(cfg EVMNetwork) error { 199 pkStrings := cfg.PrivateKeys 200 for _, pks := range pkStrings { 201 w, err := NewEthereumWallet(pks) 202 if err != nil { 203 return err 204 } 205 e.Wallets = append(e.Wallets, w) 206 } 207 if len(e.Wallets) == 0 { 208 return fmt.Errorf("no private keys found to load wallets") 209 } 210 e.DefaultWallet = e.Wallets[0] 211 return nil 212 } 213 214 // BalanceAt returns the ETH balance of the specified address 215 func (e *EthereumClient) BalanceAt(ctx context.Context, address common.Address) (*big.Int, error) { 216 return e.Client.BalanceAt(ctx, address, nil) 217 } 218 219 // SwitchNode not used, only applicable to EthereumMultinodeClient 220 func (e *EthereumClient) SwitchNode(_ int) error { 221 return nil 222 } 223 224 // HeaderHashByNumber gets header hash by block number 225 func (e *EthereumClient) HeaderHashByNumber(ctx context.Context, bn *big.Int) (string, error) { 226 h, err := e.HeaderByNumber(ctx, bn) 227 if err != nil { 228 return "", err 229 } 230 return h.Hash.String(), nil 231 } 232 233 // HeaderTimestampByNumber gets header timestamp by number 234 func (e *EthereumClient) HeaderTimestampByNumber(ctx context.Context, bn *big.Int) (uint64, error) { 235 h, err := e.HeaderByNumber(ctx, bn) 236 if err != nil { 237 return 0, err 238 } 239 return uint64(h.Timestamp.UTC().Unix()), nil 240 } 241 242 // BlockNumber gets latest block number 243 func (e *EthereumClient) LatestBlockNumber(ctx context.Context) (uint64, error) { 244 bn, err := e.Client.BlockNumber(ctx) 245 if err != nil { 246 return 0, err 247 } 248 return bn, nil 249 } 250 251 func (e *EthereumClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { 252 // for instant txs, wait for permission to go 253 if e.NetworkConfig.MinimumConfirmations <= 0 { 254 fromAddr, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) 255 if err != nil { 256 return err 257 } 258 <-e.NonceSettings.registerInstantTransaction(fromAddr.Hex(), tx.Nonce()) 259 } 260 return e.Client.SendTransaction(ctx, tx) 261 } 262 263 // Fund sends some ETH to an address using the default wallet 264 func (e *EthereumClient) Fund( 265 toAddress string, 266 amount *big.Float, 267 gasEstimations GasEstimations, 268 ) error { 269 privateKey, err := crypto.HexToECDSA(e.DefaultWallet.PrivateKey()) 270 if err != nil { 271 return fmt.Errorf("invalid private key: %w", err) 272 } 273 to := common.HexToAddress(toAddress) 274 275 nonce, err := e.GetNonce(context.Background(), common.HexToAddress(e.DefaultWallet.Address())) 276 if err != nil { 277 return err 278 } 279 280 tx, err := e.NewTx(privateKey, nonce, to, conversions.EtherToWei(amount), gasEstimations) 281 if err != nil { 282 return err 283 } 284 285 e.l.Info(). 286 Str("Token", "ETH"). 287 Str("From", e.DefaultWallet.Address()). 288 Str("To", toAddress). 289 Str("Hash", tx.Hash().Hex()). 290 Uint64("Nonce", tx.Nonce()). 291 Str("Network Name", e.GetNetworkName()). 292 Str("Amount", amount.String()). 293 Uint64("Estimated Gas Cost", tx.Cost().Uint64()). 294 Msg("Funding Address") 295 if err := e.SendTransaction(context.Background(), tx); err != nil { 296 if strings.Contains(err.Error(), "nonce") { 297 err = fmt.Errorf("using nonce %d err: %w", nonce, err) 298 } 299 return err 300 } 301 302 return e.ProcessTransaction(tx) 303 } 304 305 // ReturnFunds achieves a lazy method of fund return as too many guarantees get too complex 306 func (e *EthereumClient) ReturnFunds(fromKey *ecdsa.PrivateKey) error { 307 fromAddress, err := conversions.PrivateKeyToAddress(fromKey) 308 if err != nil { 309 return err 310 } 311 nonce, err := e.Client.PendingNonceAt(context.Background(), fromAddress) 312 if err != nil { 313 return err 314 } 315 balance, err := e.Client.BalanceAt(context.Background(), fromAddress, nil) 316 if err != nil { 317 return err 318 319 } 320 gasLimit, err := e.Client.EstimateGas(context.Background(), ethereum.CallMsg{ 321 From: fromAddress, 322 To: &e.DefaultWallet.address, 323 }) 324 if err != nil { 325 e.l.Warn().Int("Default", 21_000).Msg("Could not estimate gas for return funds transaction, using default") 326 gasLimit = 21_000 327 } 328 gasPrice, err := e.Client.SuggestGasPrice(context.Background()) 329 if err != nil { 330 return err 331 } 332 totalGasCost := new(big.Int).Mul(big.NewInt(0).SetUint64(gasLimit), gasPrice) 333 toSend := new(big.Int).Sub(balance, totalGasCost) 334 335 tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil) 336 signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey) 337 if err != nil { 338 return err 339 } 340 341 // There are several errors that can happen when trying to drain an ETH wallet. 342 // Ultimately, we want our money back, so we'll catch errors and react to them until we get something through. 343 344 // Try to send the money back, see if we hit any issues, and if we recognize them 345 fundReturnErr := e.Client.SendTransaction(context.Background(), signedTx) 346 347 // Handle overshot error 348 overshotRe := regexp.MustCompile(`overshot (\d+)`) 349 for fundReturnErr != nil && strings.Contains(fundReturnErr.Error(), "overshot") { 350 submatches := overshotRe.FindStringSubmatch(fundReturnErr.Error()) 351 if len(submatches) < 1 { 352 return fmt.Errorf("error parsing overshot amount in error: %w", err) 353 } 354 numberString := submatches[1] 355 overshotAmount, err := strconv.Atoi(numberString) 356 if err != nil { 357 return err 358 } 359 toSend.Sub(toSend, big.NewInt(int64(overshotAmount))) 360 tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil) 361 signedTx, err = types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey) 362 if err != nil { 363 return err 364 } 365 fundReturnErr = e.Client.SendTransaction(context.Background(), signedTx) 366 } 367 368 // Handle insufficient funds error 369 // We don't get an overshot calculation, we just know it was too much, so subtract by 1 GWei and try again 370 for fundReturnErr != nil && (strings.Contains(fundReturnErr.Error(), "insufficient funds") || strings.Contains(fundReturnErr.Error(), "gas too low")) { 371 toSend.Sub(toSend, big.NewInt(GWei)) 372 gasLimit += 21_000 // Add 21k gas for each attempt in case gas limit is too low 373 tx := types.NewTransaction(nonce, e.DefaultWallet.address, toSend, gasLimit, gasPrice, nil) 374 signedTx, err = types.SignTx(tx, types.LatestSignerForChainID(e.GetChainID()), fromKey) 375 if err != nil { 376 return err 377 } 378 fundReturnErr = e.Client.SendTransaction(context.Background(), signedTx) 379 } 380 381 e.l.Info(). 382 Uint64("Funds", toSend.Uint64()). 383 Str("From", fromAddress.Hex()). 384 Str("To", e.DefaultWallet.Address()). 385 Msg("Returning funds to Default Wallet") 386 return fundReturnErr 387 } 388 389 // EstimateCostForChainlinkOperations calculates required amount of ETH for amountOfOperations Chainlink operations 390 // based on the network's suggested gas price and the chainlink gas limit. This is fairly imperfect and should be used 391 // as only a rough, upper-end estimate instead of an exact calculation. 392 // See https://ethereum.org/en/developers/docs/gas/#post-london for info on how gas calculation works 393 func (e *EthereumClient) EstimateCostForChainlinkOperations(amountOfOperations int) (*big.Float, error) { 394 bigAmountOfOperations := big.NewInt(int64(amountOfOperations)) 395 gasPriceInWei, err := e.Client.SuggestGasPrice(context.Background()) 396 if err != nil { 397 return nil, err 398 } 399 400 // https://ethereum.stackexchange.com/questions/19665/how-to-calculate-transaction-fee 401 // total gas limit = chainlink gas limit + gas limit buffer 402 gasLimit := e.NetworkConfig.GasEstimationBuffer + e.NetworkConfig.ChainlinkTransactionLimit 403 // gas cost for TX = total gas limit * estimated gas price 404 gasCostPerOperationWei := big.NewInt(1).Mul(big.NewInt(1).SetUint64(gasLimit), gasPriceInWei) 405 gasCostPerOperationETH := conversions.WeiToEther(gasCostPerOperationWei) 406 // total Wei needed for all TXs = total value for TX * number of TXs 407 totalWeiForAllOperations := big.NewInt(1).Mul(gasCostPerOperationWei, bigAmountOfOperations) 408 totalEthForAllOperations := conversions.WeiToEther(totalWeiForAllOperations) 409 410 e.l.Debug(). 411 Int("Number of Operations", amountOfOperations). 412 Uint64("Gas Limit per Operation", gasLimit). 413 Str("Value per Operation (ETH)", gasCostPerOperationETH.String()). 414 Str("Total (ETH)", totalEthForAllOperations.String()). 415 Msg("Calculated ETH for Chainlink Operations") 416 417 return totalEthForAllOperations, nil 418 } 419 420 func (e *EthereumClient) RawJsonRPCCall(ctx context.Context, result interface{}, method string, params ...interface{}) error { 421 err := e.rawRPC.CallContext(ctx, &result, method, params...) 422 423 return err 424 } 425 426 // DeployContract acts as a general contract deployment tool to an ethereum chain 427 func (e *EthereumClient) DeployContract( 428 contractName string, 429 deployer ContractDeployer, 430 ) (*common.Address, *types.Transaction, interface{}, error) { 431 opts, err := e.TransactionOpts(e.DefaultWallet) 432 if err != nil { 433 return nil, nil, nil, err 434 } 435 if !e.NetworkConfig.SupportsEIP1559 { 436 opts.GasPrice, err = e.EstimateGasPrice() 437 if err != nil { 438 return nil, nil, nil, err 439 } 440 } 441 442 contractAddress, transaction, contractInstance, err := deployer(opts, e.Client) 443 if err != nil { 444 if strings.Contains(err.Error(), "nonce") { 445 err = fmt.Errorf("using nonce %d err: %w", opts.Nonce.Uint64(), err) 446 } 447 return nil, nil, nil, err 448 } 449 450 if err = e.ProcessTransaction(transaction); err != nil { 451 return nil, nil, nil, err 452 } 453 454 e.l.Info(). 455 Str("Contract Address", contractAddress.Hex()). 456 Str("Contract Name", contractName). 457 Str("From", e.DefaultWallet.Address()). 458 Str("Total Gas Cost", conversions.WeiToEther(transaction.Cost()).String()). 459 Str("Network Name", e.NetworkConfig.Name). 460 Msg("Deployed contract") 461 return &contractAddress, transaction, contractInstance, err 462 } 463 464 // LoadContract load already deployed contract instance 465 func (e *EthereumClient) LoadContract(contractName string, contractAddress common.Address, loader ContractLoader) (interface{}, error) { 466 contractInstance, err := loader(contractAddress, e.Client) 467 if err != nil { 468 return nil, err 469 } 470 e.l.Info(). 471 Str("Contract Address", contractAddress.Hex()). 472 Str("Contract Name", contractName). 473 Str("Network Name", e.NetworkConfig.Name). 474 Msg("Loaded contract instance") 475 return contractInstance, err 476 } 477 478 // TransactionOpts returns the base Tx options for 'transactions' that interact with a smart contract. Since most 479 // contract interactions in this framework are designed to happen through abigen calls, it's intentionally quite bare. 480 func (e *EthereumClient) TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error) { 481 privateKey, err := crypto.HexToECDSA(from.PrivateKey()) 482 if err != nil { 483 return nil, fmt.Errorf("invalid private key: %w", err) 484 } 485 opts, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(e.NetworkConfig.ChainID)) 486 if err != nil { 487 return nil, err 488 } 489 opts.From = common.HexToAddress(from.Address()) 490 opts.Context = context.Background() 491 492 nonce, err := e.GetNonce(context.Background(), common.HexToAddress(from.Address())) 493 if err != nil { 494 return nil, err 495 } 496 opts.Nonce = big.NewInt(int64(nonce)) 497 498 if e.NetworkConfig.MinimumConfirmations <= 0 { // Wait for your turn to send on an L2 chain 499 <-e.NonceSettings.registerInstantTransaction(from.Address(), nonce) 500 } 501 // if the gas limit is less than the default gas limit, use the default 502 if e.NetworkConfig.DefaultGasLimit > opts.GasLimit { 503 opts.GasLimit = e.NetworkConfig.DefaultGasLimit 504 } 505 if !e.NetworkConfig.SupportsEIP1559 { 506 opts.GasPrice, err = e.EstimateGasPrice() 507 if err != nil { 508 return nil, err 509 } 510 } 511 return opts, nil 512 } 513 514 func (e *EthereumClient) NewTx( 515 fromPrivateKey *ecdsa.PrivateKey, 516 nonce uint64, 517 to common.Address, 518 value *big.Int, 519 gasEstimations GasEstimations, 520 ) (*types.Transaction, error) { 521 var ( 522 tx *types.Transaction 523 err error 524 ) 525 if e.NetworkConfig.SupportsEIP1559 { 526 tx, err = types.SignNewTx(fromPrivateKey, types.LatestSignerForChainID(e.GetChainID()), &types.DynamicFeeTx{ 527 ChainID: e.GetChainID(), 528 Nonce: nonce, 529 To: &to, 530 Value: value, 531 GasTipCap: gasEstimations.GasTipCap, 532 GasFeeCap: gasEstimations.GasFeeCap, 533 Gas: gasEstimations.GasUnits, 534 }) 535 if err != nil { 536 return nil, err 537 } 538 } else { 539 tx, err = types.SignNewTx(fromPrivateKey, types.LatestSignerForChainID(e.GetChainID()), &types.LegacyTx{ 540 Nonce: nonce, 541 To: &to, 542 Value: value, 543 GasPrice: gasEstimations.GasPrice, 544 Gas: gasEstimations.GasUnits, 545 }) 546 if err != nil { 547 return nil, err 548 } 549 } 550 return tx, nil 551 } 552 553 // MarkTxAsSent On an L2 chain, indicate the tx has been sent 554 func (e *EthereumClient) MarkTxAsSentOnL2(tx *types.Transaction) error { 555 if e.NetworkConfig.MinimumConfirmations > 0 { 556 return nil 557 } 558 fromAddr, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) 559 if err != nil { 560 return err 561 } 562 e.NonceSettings.sentInstantTransaction(fromAddr.Hex()) 563 return nil 564 } 565 566 // ProcessTransaction will queue or wait on a transaction depending on whether parallel transactions are enabled 567 func (e *EthereumClient) ProcessTransaction(tx *types.Transaction) error { 568 e.l.Trace().Str("Hash", tx.Hash().Hex()).Msg("Processing Tx") 569 var txConfirmer HeaderEventSubscription 570 if e.GetNetworkConfig().MinimumConfirmations <= 0 { 571 err := e.MarkTxAsSentOnL2(tx) 572 if err != nil { 573 return err 574 } 575 txConfirmer = NewInstantConfirmer(e, tx.Hash(), nil, nil, e.l) 576 } else { 577 txConfirmer = NewTransactionConfirmer(e, tx, e.GetNetworkConfig().MinimumConfirmations, e.l) 578 } 579 580 e.AddHeaderEventSubscription(tx.Hash().String(), txConfirmer) 581 582 if !e.queueTransactions { // For sequential transactions 583 e.l.Debug().Str("Hash", tx.Hash().String()).Msg("Waiting for TX to confirm before moving on") 584 defer e.DeleteHeaderEventSubscription(tx.Hash().String()) 585 return txConfirmer.Wait() 586 } 587 return nil 588 } 589 590 // ProcessEvent will queue or wait on an event depending on whether parallel transactions are enabled 591 func (e *EthereumClient) ProcessEvent(name string, event *types.Log, confirmedChan chan bool, errorChan chan error) error { 592 var eventConfirmer HeaderEventSubscription 593 if e.GetNetworkConfig().MinimumConfirmations <= 0 { 594 eventConfirmer = NewInstantConfirmer(e, event.TxHash, confirmedChan, errorChan, e.l) 595 } else { 596 eventConfirmer = NewEventConfirmer(name, e, event, e.GetNetworkConfig().MinimumConfirmations, confirmedChan, errorChan) 597 } 598 599 subscriptionHash := fmt.Sprintf("%s-%s", event.TxHash.Hex(), name) // Many events can occupy the same tx hash 600 e.AddHeaderEventSubscription(subscriptionHash, eventConfirmer) 601 602 if !e.queueTransactions { // For sequential transactions 603 e.l.Debug().Str("Hash", event.Address.Hex()).Msg("Waiting for Event to confirm before moving on") 604 defer e.DeleteHeaderEventSubscription(subscriptionHash) 605 return eventConfirmer.Wait() 606 } 607 return nil 608 } 609 610 // PollFinalizedHeader continuously polls the latest finalized header and stores it in the client 611 func (e *EthereumClient) PollFinality() error { 612 if e.NetworkConfig.FinalityDepth > 0 { 613 return fmt.Errorf("finality depth is greater than zero. no need to poll for finality") 614 } 615 f := newGlobalFinalizedHeaderManager(e) 616 if f == nil { 617 return fmt.Errorf("could not create finalized header manager") 618 } 619 e.FinalizedHeader.Store(f) 620 e.AddHeaderEventSubscription(FinalizedHeaderKey, f) 621 return nil 622 } 623 624 // CancelFinalityPolling stops polling for the latest finalized header 625 func (e *EthereumClient) CancelFinalityPolling() { 626 if _, ok := e.headerSubscriptions[FinalizedHeaderKey]; ok { 627 e.DeleteHeaderEventSubscription(FinalizedHeaderKey) 628 } 629 } 630 631 // WaitForFinalizedTx waits for a transaction to be finalized 632 // If the network is simulated, it will return immediately 633 // otherwise it waits for the transaction to be finalized and returns the block number and time of the finalization 634 func (e *EthereumClient) WaitForFinalizedTx(txHash common.Hash) (*big.Int, time.Time, error) { 635 if e.NetworkSimulated() { 636 return nil, time.Time{}, nil 637 } 638 639 receipt, err := e.Client.TransactionReceipt(context.Background(), txHash) 640 if err != nil { 641 return nil, time.Time{}, err 642 } 643 txHdr, err := e.HeaderByNumber(context.Background(), receipt.BlockNumber) 644 if err != nil { 645 return nil, time.Time{}, err 646 } 647 finalizer := NewTransactionFinalizer(e, txHdr, receipt.TxHash) 648 key := "txFinalizer-" + txHash.String() 649 e.AddHeaderEventSubscription(key, finalizer) 650 defer e.DeleteHeaderEventSubscription(key) 651 err = finalizer.Wait() 652 if err != nil { 653 return nil, time.Time{}, err 654 } 655 return finalizer.FinalizedBy, finalizer.FinalizedAt, nil 656 } 657 658 // IsTxHeadFinalized checks if the transaction is finalized on chain 659 // in case of network with finality tag if the tx is not finalized it returns false, 660 // the latest finalized header number and the time at which it was finalized 661 // if the tx is finalized it returns true, the finalized header number by which the tx was considered finalized and the time at which it was finalized 662 // In case of simulated network, it always returns true 663 func (e *EthereumClient) IsTxHeadFinalized(txHdr, header *SafeEVMHeader) (bool, *big.Int, time.Time, error) { 664 if e.NetworkSimulated() { 665 return true, nil, time.Time{}, nil 666 } 667 if e.NetworkConfig.FinalityDepth > 0 { 668 if header.Number.Cmp(new(big.Int).Add(txHdr.Number, 669 big.NewInt(int64(e.NetworkConfig.FinalityDepth)))) > 0 { 670 return true, header.Number, header.Timestamp, nil 671 } 672 return false, nil, time.Time{}, nil 673 } 674 fHead := e.FinalizedHeader.Load() 675 if fHead != nil { 676 latestFinalized := fHead.LatestFinalized.Load().(*big.Int) 677 latestFinalizedAt := fHead.FinalizedAt.Load().(time.Time) 678 if latestFinalized.Cmp(txHdr.Number) >= 0 { 679 return true, latestFinalized, latestFinalizedAt, nil 680 } 681 return false, latestFinalized, latestFinalizedAt, nil 682 } 683 return false, nil, time.Time{}, fmt.Errorf("no finalized head found. start polling for finalized header") 684 } 685 686 // IsTxConfirmed checks if the transaction is confirmed on chain or not 687 func (e *EthereumClient) IsTxConfirmed(txHash common.Hash) (bool, error) { 688 ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 689 tx, isPending, err := e.Client.TransactionByHash(ctx, txHash) 690 cancel() 691 if err != nil { 692 if errors.Is(err, ethereum.NotFound) { // not found is fine, it's not on chain yet 693 return false, nil 694 } 695 return !isPending, err 696 } 697 if !isPending && e.NetworkConfig.MinimumConfirmations > 0 { // Instant chains don't bother with this receipt nonsense 698 ctx, cancel = context.WithTimeout(context.Background(), time.Second*5) 699 receipt, err := e.Client.TransactionReceipt(ctx, txHash) 700 cancel() 701 if err != nil { 702 if errors.Is(err, ethereum.NotFound) { // not found is fine, it's not on chain yet 703 return false, nil 704 } 705 return !isPending, err 706 } 707 e.gasStats.AddClientTXData(TXGasData{ 708 TXHash: txHash.String(), 709 Value: tx.Value().Uint64(), 710 GasLimit: tx.Gas(), 711 GasUsed: receipt.GasUsed, 712 GasPrice: tx.GasPrice().Uint64(), 713 CumulativeGasUsed: receipt.CumulativeGasUsed, 714 }) 715 if receipt.Status == 0 { // 0 indicates failure, 1 indicates success 716 reason, err := e.errorReason(e.Client, tx, receipt) 717 if err != nil { 718 e.l.Warn().Str("TX Hash", txHash.Hex()). 719 Str("To", tx.To().Hex()). 720 Uint64("Nonce", tx.Nonce()). 721 Str("Error extracting reason", err.Error()). 722 Msg("Transaction failed and was reverted! Unable to retrieve reason!") 723 } else { 724 e.l.Warn().Str("TX Hash", txHash.Hex()). 725 Str("Revert reason", reason). 726 Msg("Transaction failed and was reverted!") 727 } 728 return false, fmt.Errorf("transaction failed and was reverted") 729 } 730 } 731 return !isPending, err 732 } 733 734 // IsEventConfirmed returns if eth client can confirm that the event happened 735 func (e *EthereumClient) IsEventConfirmed(event *types.Log) (confirmed, removed bool, err error) { 736 if event.Removed { 737 return false, event.Removed, nil 738 } 739 eventTx, isPending, err := e.Client.TransactionByHash(context.Background(), event.TxHash) 740 if err != nil { 741 return false, event.Removed, err 742 } 743 if isPending { 744 return false, event.Removed, nil 745 } 746 eventReceipt, err := e.Client.TransactionReceipt(context.Background(), eventTx.Hash()) 747 if err != nil { 748 return false, event.Removed, err 749 } 750 if eventReceipt.Status == 0 { // Failed event tx 751 reason, err := e.errorReason(e.Client, eventTx, eventReceipt) 752 if err != nil { 753 e.l.Warn().Str("TX Hash", eventTx.Hash().Hex()). 754 Str("Error extracting reason", err.Error()). 755 Msg("Transaction failed and was reverted! Unable to retrieve reason!") 756 } else { 757 e.l.Warn().Str("TX Hash", eventTx.Hash().Hex()). 758 Str("Revert reason", reason). 759 Msg("Transaction failed and was reverted!") 760 } 761 return false, event.Removed, err 762 } 763 headerByNumber, err := e.HeaderByNumber(context.Background(), big.NewInt(0).SetUint64(event.BlockNumber)) 764 if err != nil || headerByNumber == nil { 765 return false, event.Removed, err 766 } 767 if headerByNumber.Hash != event.BlockHash { 768 return false, event.Removed, nil 769 } 770 771 return true, event.Removed, nil 772 } 773 774 // GetTxReceipt returns the receipt of the transaction if available, error otherwise 775 func (e *EthereumClient) GetTxReceipt(txHash common.Hash) (*types.Receipt, error) { 776 receipt, err := e.Client.TransactionReceipt(context.Background(), txHash) 777 if err != nil { 778 return nil, err 779 } 780 return receipt, nil 781 } 782 783 // RevertReasonFromTx returns the revert reason for the transaction error by parsing through abi defined error list 784 func (e *EthereumClient) RevertReasonFromTx(txHash common.Hash, abiString string) (string, interface{}, error) { 785 tx, _, err := e.Client.TransactionByHash(context.Background(), txHash) 786 if err != nil { 787 return "", nil, err 788 } 789 re, err := e.GetTxReceipt(txHash) 790 if err != nil { 791 return "", nil, err 792 } 793 errData, err := e.errorReason(e.Client, tx, re) 794 if err != nil { 795 return "", nil, err 796 } 797 if errData == "" { 798 return "", nil, fmt.Errorf("no revert reason found") 799 } 800 data, err := hex.DecodeString(errData[2:]) 801 if err != nil { 802 return "", nil, err 803 } 804 jsonABI, err := abi.JSON(strings.NewReader(abiString)) 805 if err != nil { 806 return "", nil, err 807 } 808 for errName, abiError := range jsonABI.Errors { 809 if bytes.Equal(data[:4], abiError.ID.Bytes()[:4]) { 810 // Found a matching error 811 v, err := abiError.Unpack(data) 812 if err != nil { 813 return "", nil, err 814 } 815 return errName, v, nil 816 } 817 } 818 return "", nil, fmt.Errorf("revert Reason could not be found for given abistring") 819 } 820 821 // ParallelTransactions when enabled, sends the transaction without waiting for transaction confirmations. The hashes 822 // are then stored within the client and confirmations can be waited on by calling WaitForEvents. 823 func (e *EthereumClient) ParallelTransactions(enabled bool) { 824 e.queueTransactions = enabled 825 } 826 827 // Close tears down the current open Ethereum client 828 func (e *EthereumClient) Close() error { 829 // close(e.NonceSettings.doneChan) 830 close(e.doneChan) 831 e.subscriptionWg.Wait() 832 return nil 833 } 834 835 // EstimateTransactionGasCost estimates the current total gas cost for a simple transaction 836 func (e *EthereumClient) EstimateTransactionGasCost() (*big.Int, error) { 837 gasPrice, err := e.Client.SuggestGasPrice(context.Background()) 838 if err != nil { 839 return nil, err 840 } 841 return gasPrice.Mul(gasPrice, big.NewInt(21000)), err 842 } 843 844 // GasStats retrieves all information on gas spent by this client 845 func (e *EthereumClient) GasStats() *GasStats { 846 return e.gasStats 847 } 848 849 // EstimateGas estimates all gas values based on call data 850 func (e *EthereumClient) EstimateGas(callMsg ethereum.CallMsg) (GasEstimations, error) { 851 var ( 852 gasUnits uint64 853 gasTipCap *big.Int 854 gasFeeCap *big.Int 855 err error 856 ) 857 if callMsg.To == nil && callMsg.Data == nil { 858 return GasEstimations{}, fmt.Errorf("you've called EstimateGas with a nil To address, this can cause weird errors and inaccuracies, provide a To address in your callMsg, or use EstimateGasPrice for just a price") 859 } 860 ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration) 861 // Gas Units 862 gasUnits, err = e.Client.EstimateGas(ctx, callMsg) 863 cancel() 864 if err != nil { 865 return GasEstimations{}, err 866 } 867 868 gasPriceBuffer := big.NewInt(0).SetUint64(e.NetworkConfig.GasEstimationBuffer) 869 // Legacy Gas Price 870 ctx, cancel = context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration) 871 gasPrice, err := e.Client.SuggestGasPrice(ctx) 872 cancel() 873 if err != nil { 874 return GasEstimations{}, err 875 } 876 gasPrice.Add(gasPrice, gasPriceBuffer) 877 878 if e.NetworkConfig.SupportsEIP1559 { 879 // GasTipCap 880 ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration) 881 gasTipCap, err = e.Client.SuggestGasTipCap(ctx) 882 cancel() 883 if err != nil { 884 return GasEstimations{}, err 885 } 886 gasTipCap.Add(gasTipCap, gasPriceBuffer) 887 888 // GasFeeCap 889 ctx, cancel = context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration) 890 latestHeader, err := e.HeaderByNumber(ctx, nil) 891 cancel() 892 if err != nil { 893 return GasEstimations{}, err 894 } 895 baseFeeMult := big.NewInt(1).Mul(latestHeader.BaseFee, big.NewInt(2)) 896 gasFeeCap = baseFeeMult.Add(baseFeeMult, gasTipCap) 897 } else { 898 gasFeeCap = gasPrice 899 gasTipCap = gasPrice 900 } 901 902 // Total Gas Cost 903 totalGasCost := big.NewInt(0).Mul(gasFeeCap, new(big.Int).SetUint64(gasUnits)) 904 905 return GasEstimations{ 906 GasUnits: gasUnits, 907 GasPrice: gasPrice, 908 GasFeeCap: gasFeeCap, 909 GasTipCap: gasTipCap, 910 TotalGasCost: totalGasCost, 911 }, nil 912 } 913 914 func (e *EthereumClient) EstimateGasPrice() (*big.Int, error) { 915 ctx, cancel := context.WithTimeout(context.Background(), e.NetworkConfig.Timeout.Duration) 916 defer cancel() 917 return e.Client.SuggestGasPrice(ctx) 918 } 919 920 // ConnectionIssue returns a channel that will receive a timestamp when the connection is lost 921 func (e *EthereumClient) ConnectionIssue() chan time.Time { 922 return e.connectionIssueCh 923 } 924 925 // ConnectionRestored returns a channel that will receive a timestamp when the connection is restored 926 func (e *EthereumClient) ConnectionRestored() chan time.Time { 927 return e.connectionRestoredCh 928 } 929 930 func (e *EthereumClient) Backend() bind.ContractBackend { 931 return e.Client 932 } 933 934 func (e *EthereumClient) DeployBackend() bind.DeployBackend { 935 return e.Client 936 } 937 938 func (e *EthereumClient) SubscribeNewHeaders( 939 ctx context.Context, 940 headerChan chan *SafeEVMHeader, 941 ) (ethereum.Subscription, error) { 942 clientSub, err := e.rawRPC.EthSubscribe(ctx, headerChan, "newHeads") 943 if err != nil { 944 return nil, err 945 } 946 947 return clientSub, err 948 } 949 950 // HeaderByNumber retrieves a Safe EVM header by number, nil for latest 951 func (e *EthereumClient) HeaderByNumber( 952 ctx context.Context, 953 number *big.Int, 954 ) (*SafeEVMHeader, error) { 955 var head *SafeEVMHeader 956 err := e.rawRPC.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) 957 if err == nil && head == nil { 958 err = ethereum.NotFound 959 } 960 return head, err 961 } 962 963 // HeaderByHash retrieves a Safe EVM header by hash 964 func (e *EthereumClient) HeaderByHash(ctx context.Context, hash common.Hash) (*SafeEVMHeader, error) { 965 var head *SafeEVMHeader 966 err := e.rawRPC.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) 967 if err == nil && head == nil { 968 err = ethereum.NotFound 969 } 970 return head, err 971 } 972 973 // toBlockNumArg translates a block number to the correct argument for the RPC call 974 func toBlockNumArg(number *big.Int) string { 975 if number == nil { 976 return "latest" 977 } 978 pending := big.NewInt(-1) 979 if number.Cmp(pending) == 0 { 980 return "pending" 981 } 982 return hexutil.EncodeBig(number) 983 } 984 985 // AddHeaderEventSubscription adds a new header subscriber within the client to receive new headers 986 func (e *EthereumClient) AddHeaderEventSubscription(key string, subscriber HeaderEventSubscription) { 987 e.subscriptionMutex.Lock() 988 defer e.subscriptionMutex.Unlock() 989 e.headerSubscriptions[key] = subscriber 990 } 991 992 // DeleteHeaderEventSubscription removes a header subscriber from the map 993 func (e *EthereumClient) DeleteHeaderEventSubscription(key string) { 994 e.subscriptionMutex.Lock() 995 defer e.subscriptionMutex.Unlock() 996 delete(e.headerSubscriptions, key) 997 } 998 999 // WaitForEvents is a blocking function that waits for all event subscriptions that have been queued within the client. 1000 func (e *EthereumClient) WaitForEvents() error { 1001 e.l.Debug().Msg("Waiting for blockchain events to finish before continuing") 1002 queuedEvents := e.GetHeaderSubscriptions() 1003 1004 g := errgroup.Group{} 1005 1006 for subName, sub := range queuedEvents { 1007 subName := subName 1008 sub := sub 1009 g.Go(func() error { 1010 defer func() { 1011 // if the subscription is complete, delete it from the queue 1012 if sub.Complete() { 1013 e.DeleteHeaderEventSubscription(subName) 1014 } 1015 }() 1016 return sub.Wait() 1017 }) 1018 } 1019 1020 return g.Wait() 1021 } 1022 1023 // SubscribeFilterLogs subscribes to the results of a streaming filter query. 1024 func (e *EthereumClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { 1025 return e.Client.SubscribeFilterLogs(ctx, q, ch) 1026 } 1027 1028 // FilterLogs executes a filter query 1029 func (e *EthereumClient) FilterLogs(ctx context.Context, filterQuery ethereum.FilterQuery) ([]types.Log, error) { 1030 return e.Client.FilterLogs(ctx, filterQuery) 1031 } 1032 1033 // GetLatestFinalizedBlockHeader returns the latest finalized block header 1034 // if finality tag is enabled, it returns the latest finalized block header 1035 // otherwise it returns the block header for the block obtained by latest block number - finality depth 1036 func (e *EthereumClient) GetLatestFinalizedBlockHeader(ctx context.Context) (*types.Header, error) { 1037 if e.NetworkConfig.FinalityTag { 1038 return e.Client.HeaderByNumber(ctx, big.NewInt(rpc.FinalizedBlockNumber.Int64())) 1039 } 1040 if e.NetworkConfig.FinalityDepth == 0 { 1041 return nil, fmt.Errorf("finality depth is 0 and finality tag is not enabled") 1042 } 1043 header, err := e.Client.HeaderByNumber(ctx, nil) 1044 if err != nil { 1045 return nil, err 1046 } 1047 latestBlockNumber := header.Number.Uint64() 1048 finalizedBlockNumber := latestBlockNumber - e.NetworkConfig.FinalityDepth 1049 return e.Client.HeaderByNumber(ctx, big.NewInt(int64(finalizedBlockNumber))) 1050 } 1051 1052 // EstimatedFinalizationTime returns the estimated time it takes for a block to be finalized 1053 // for networks with finality tag enabled, it returns the time between the current and next finalized block 1054 // for networks with finality depth enabled, it returns the time to mine blocks equal to finality depth 1055 func (e *EthereumClient) EstimatedFinalizationTime(ctx context.Context) (time.Duration, error) { 1056 if e.NetworkConfig.TimeToReachFinality.Duration != 0 { 1057 return e.NetworkConfig.TimeToReachFinality.Duration, nil 1058 } 1059 e.l.Info().Msg("TimeToReachFinality is not provided. Calculating estimated finalization time") 1060 if e.NetworkConfig.FinalityTag { 1061 return e.TimeBetweenFinalizedBlocks(ctx, MaxTimeoutForFinality) 1062 } 1063 blckTime, err := e.AvgBlockTime(ctx) 1064 if err != nil { 1065 return 0, err 1066 } 1067 if e.NetworkConfig.FinalityDepth == 0 { 1068 return 0, fmt.Errorf("finality depth is 0 and finality tag is not enabled") 1069 } 1070 timeBetween := time.Duration(e.NetworkConfig.FinalityDepth) * blckTime 1071 e.l.Info(). 1072 Str("Time", timeBetween.String()). 1073 Str("Network", e.GetNetworkName()). 1074 Msg("Estimated finalization time") 1075 return timeBetween, nil 1076 1077 } 1078 1079 // TimeBetweenFinalizedBlocks is used to calculate the time between finalized blocks for chains with finality tag enabled 1080 func (e *EthereumClient) TimeBetweenFinalizedBlocks(ctx context.Context, maxTimeToWait time.Duration) (time.Duration, error) { 1081 if !e.NetworkConfig.FinalityTag { 1082 return 0, fmt.Errorf("finality tag is not enabled; cannot calculate time between finalized blocks") 1083 } 1084 currentFinalizedHeader, err := e.GetLatestFinalizedBlockHeader(ctx) 1085 if err != nil { 1086 return 0, err 1087 } 1088 hdrChannel := make(chan *types.Header) 1089 var sub ethereum.Subscription 1090 sub, err = e.Client.SubscribeNewHead(ctx, hdrChannel) 1091 if err != nil { 1092 return 0, err 1093 } 1094 defer sub.Unsubscribe() 1095 c, cancel := context.WithTimeout(ctx, maxTimeToWait) 1096 defer cancel() 1097 for { 1098 select { 1099 case <-c.Done(): 1100 return 0, fmt.Errorf("timed out waiting for next finalized block. If the finality time is more than %s, provide it as TimeToReachFinality in Network config: %w", maxTimeToWait, c.Err()) 1101 case <-hdrChannel: 1102 // a new header is received now query the finalized block 1103 nextFinalizedHeader, err := e.GetLatestFinalizedBlockHeader(ctx) 1104 if err != nil { 1105 return 0, err 1106 } 1107 if nextFinalizedHeader.Number.Cmp(currentFinalizedHeader.Number) > 0 { 1108 timeBetween := time.Unix(int64(nextFinalizedHeader.Time), 0).Sub(time.Unix(int64(currentFinalizedHeader.Time), 0)) 1109 e.l.Info(). 1110 Str("Time", timeBetween.String()). 1111 Str("Network", e.GetNetworkName()). 1112 Msg("Time between finalized blocks") 1113 return timeBetween, nil 1114 } 1115 case subErr := <-sub.Err(): 1116 return 0, subErr 1117 } 1118 } 1119 } 1120 1121 // AvgBlockTime calculates the average block time over the last 100 blocks for non-simulated networks 1122 // and the last 10 blocks for simulated networks. 1123 func (e *EthereumClient) AvgBlockTime(ctx context.Context) (time.Duration, error) { 1124 header, err := e.Client.HeaderByNumber(ctx, nil) 1125 if err != nil { 1126 return 0, err 1127 } 1128 latestBlockNumber := header.Number.Uint64() 1129 numBlocks := uint64(100) // Number of blocks to consider for calculating block time 1130 if e.NetworkSimulated() { 1131 numBlocks = uint64(10) 1132 } 1133 startBlockNumber := latestBlockNumber - numBlocks + 1 1134 if startBlockNumber <= 0 { 1135 return 0, fmt.Errorf("not enough blocks mined to calculate block time") 1136 } 1137 totalTime := time.Duration(0) 1138 var previousHeader *types.Header 1139 previousHeader, err = e.Client.HeaderByNumber(ctx, big.NewInt(int64(startBlockNumber-1))) 1140 if err != nil { 1141 return totalTime, err 1142 } 1143 for i := startBlockNumber; i <= latestBlockNumber; i++ { 1144 hdr, err := e.Client.HeaderByNumber(ctx, big.NewInt(int64(i))) 1145 if err != nil { 1146 return totalTime, err 1147 } 1148 1149 blockTime := time.Unix(int64(hdr.Time), 0) 1150 if err != nil { 1151 return totalTime, err 1152 } 1153 previousBlockTime := time.Unix(int64(previousHeader.Time), 0) 1154 blockDuration := blockTime.Sub(previousBlockTime) 1155 totalTime += blockDuration 1156 previousHeader = hdr 1157 } 1158 1159 averageBlockTime := totalTime / time.Duration(numBlocks) 1160 1161 return averageBlockTime, nil 1162 } 1163 1164 // EthereumMultinodeClient wraps the client and the BlockChain network to interact with an EVM based Blockchain with multiple nodes 1165 type EthereumMultinodeClient struct { 1166 DefaultClient EVMClient 1167 Clients []EVMClient 1168 } 1169 1170 func (e *EthereumMultinodeClient) Backend() bind.ContractBackend { 1171 return e.DefaultClient.Backend() 1172 } 1173 1174 func (e *EthereumMultinodeClient) DeployBackend() bind.DeployBackend { 1175 return e.DefaultClient.DeployBackend() 1176 } 1177 1178 func (e *EthereumMultinodeClient) SubscribeNewHeaders( 1179 ctx context.Context, 1180 headerChan chan *SafeEVMHeader, 1181 ) (ethereum.Subscription, error) { 1182 return e.DefaultClient.SubscribeNewHeaders(ctx, headerChan) 1183 } 1184 1185 // HeaderByNumber retrieves a Safe EVM header by number, nil for latest 1186 func (e *EthereumMultinodeClient) HeaderByNumber( 1187 ctx context.Context, 1188 number *big.Int, 1189 ) (*SafeEVMHeader, error) { 1190 return e.DefaultClient.HeaderByNumber(ctx, number) 1191 } 1192 1193 // HeaderByHash retrieves a Safe EVM header by hash 1194 func (e *EthereumMultinodeClient) HeaderByHash(ctx context.Context, hash common.Hash) (*SafeEVMHeader, error) { 1195 return e.DefaultClient.HeaderByHash(ctx, hash) 1196 } 1197 1198 func (e *EthereumMultinodeClient) RawJsonRPCCall(ctx context.Context, result interface{}, method string, params ...interface{}) error { 1199 err := e.DefaultClient.RawJsonRPCCall(ctx, result, method, params) 1200 1201 return err 1202 } 1203 1204 // LoadContract load already deployed contract instance 1205 func (e *EthereumMultinodeClient) LoadContract(contractName string, address common.Address, loader ContractLoader) (interface{}, error) { 1206 return e.DefaultClient.LoadContract(contractName, address, loader) 1207 } 1208 1209 // EstimateCostForChainlinkOperations calculates TXs cost as a dirty estimation based on transactionLimit for that network 1210 func (e *EthereumMultinodeClient) EstimateCostForChainlinkOperations(amountOfOperations int) (*big.Float, error) { 1211 return e.DefaultClient.EstimateCostForChainlinkOperations(amountOfOperations) 1212 } 1213 1214 func (e *EthereumMultinodeClient) GetHeaderSubscriptions() map[string]HeaderEventSubscription { 1215 return e.DefaultClient.GetHeaderSubscriptions() 1216 } 1217 1218 // NewEVMClientFromNetwork returns a multi-node EVM client connected to the specified network 1219 func NewEVMClientFromNetwork(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) { 1220 ecl := &EthereumMultinodeClient{} 1221 for idx, networkURL := range networkSettings.URLs { 1222 networkSettings.URL = networkURL 1223 ec, err := newEVMClient(networkSettings, logger) 1224 if err != nil { 1225 return nil, err 1226 } 1227 // a call to BalanceAt (can be any on chain call) to ensure the client is connected 1228 _, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address) 1229 if err == nil { 1230 ec.SetID(idx) 1231 ecl.Clients = append(ecl.Clients, ec) 1232 break 1233 } 1234 } 1235 ecl.DefaultClient = ecl.Clients[0] 1236 wrappedClient := wrapMultiClient(networkSettings, ecl) 1237 // required in Geth when you need to call "simulate" transactions from nodes 1238 if ecl.NetworkSimulated() { 1239 zero := common.HexToAddress("0x0") 1240 gasEstimations, err := wrappedClient.EstimateGas(ethereum.CallMsg{ 1241 To: &zero, 1242 }) 1243 if err != nil { 1244 return nil, err 1245 } 1246 if err := ecl.Fund("0x0", big.NewFloat(1000), gasEstimations); err != nil { 1247 return nil, err 1248 } 1249 } 1250 return wrappedClient, nil 1251 } 1252 1253 // NewEVMClient returns a multi-node EVM client connected to the specified network 1254 // Note: This should mostly be deprecated in favor of ConnectEVMClient. This is really only used when needing to connect 1255 // to simulated networks 1256 func NewEVMClient(networkSettings EVMNetwork, env *environment.Environment, logger zerolog.Logger) (EVMClient, error) { 1257 if env == nil { 1258 return nil, fmt.Errorf("environment nil, use ConnectEVMClient or provide a non-nil environment") 1259 } 1260 1261 if networkSettings.Simulated { 1262 if _, ok := env.URLs[networkSettings.Name]; !ok { 1263 return nil, fmt.Errorf("network %s not found in environment", networkSettings.Name) 1264 } 1265 networkSettings.URLs = env.URLs[networkSettings.Name] 1266 } 1267 1268 return ConnectEVMClient(networkSettings, logger) 1269 } 1270 1271 // ConnectEVMClient returns a multi-node EVM client connected to a specified network, using only URLs. 1272 // Should mostly be used for inside K8s, non-simulated tests. 1273 func ConnectEVMClient(networkSettings EVMNetwork, logger zerolog.Logger) (EVMClient, error) { 1274 if len(networkSettings.URLs) == 0 { 1275 return nil, fmt.Errorf("no URLs provided to connect to network") 1276 } 1277 1278 ecl := &EthereumMultinodeClient{} 1279 1280 for idx, networkURL := range networkSettings.URLs { 1281 networkSettings.URL = networkURL 1282 ec, err := newEVMClient(networkSettings, logger) 1283 1284 if err != nil { 1285 logger.Info(). 1286 Err(err). 1287 Str("URL Suffix", networkURL[len(networkURL)-6:]). 1288 Msg("failed to create new EVM client") 1289 continue 1290 } 1291 // a call to BalanceAt to ensure the client is connected 1292 _, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address) 1293 if err == nil { 1294 ec.SetID(idx) 1295 ecl.Clients = append(ecl.Clients, ec) 1296 break 1297 } 1298 } 1299 if len(ecl.Clients) == 0 { 1300 return nil, fmt.Errorf("failed to create new EVM client") 1301 } 1302 ecl.DefaultClient = ecl.Clients[0] 1303 wrappedClient := wrapMultiClient(networkSettings, ecl) 1304 // required in Geth when you need to call "simulate" transactions from nodes 1305 if ecl.NetworkSimulated() { 1306 zero := common.HexToAddress("0x0") 1307 gasEstimations, err := wrappedClient.EstimateGas(ethereum.CallMsg{ 1308 To: &zero, 1309 }) 1310 if err != nil { 1311 return nil, err 1312 } 1313 if err := ecl.Fund("0x0", big.NewFloat(1000), gasEstimations); err != nil { 1314 return nil, err 1315 } 1316 } 1317 1318 return wrappedClient, nil 1319 } 1320 1321 // ConcurrentEVMClient returns a multi-node EVM client connected to a specified network 1322 // It is used for concurrent interactions from different threads with the same network and from same owner 1323 // account. This ensures that correct nonce value is fetched when an instance of EVMClient is initiated using this method. 1324 // This is mainly useful for simulated networks as we don't use global nonce manager for them. 1325 func ConcurrentEVMClient(networkSettings EVMNetwork, env *environment.Environment, existing EVMClient, logger zerolog.Logger) (EVMClient, error) { 1326 // if not simulated use the NewEVMClient 1327 if !networkSettings.Simulated { 1328 return ConnectEVMClient(networkSettings, logger) 1329 } 1330 ecl := &EthereumMultinodeClient{} 1331 if env != nil { 1332 if _, ok := env.URLs[existing.GetNetworkConfig().Name]; !ok { 1333 return nil, fmt.Errorf("network %s not found in environment", existing.GetNetworkConfig().Name) 1334 } 1335 networkSettings.URLs = env.URLs[existing.GetNetworkConfig().Name] 1336 } 1337 for idx, networkURL := range networkSettings.URLs { 1338 networkSettings.URL = networkURL 1339 ec, err := newEVMClient(networkSettings, logger) 1340 if err != nil { 1341 logger.Info(). 1342 Err(err). 1343 Str("URL Suffix", networkURL[len(networkURL)-6:]). 1344 Msg("failed to create new EVM client") 1345 continue 1346 } 1347 // a call to BalanceAt (can be any on chain call) to ensure the client is connected 1348 _, err = ec.BalanceAt(context.Background(), ec.GetDefaultWallet().address) 1349 if err == nil { 1350 ec.SyncNonce(existing) 1351 ec.SetID(idx) 1352 ecl.Clients = append(ecl.Clients, ec) 1353 break 1354 } 1355 } 1356 if len(ecl.Clients) == 0 { 1357 return nil, fmt.Errorf("failed to create new EVM client") 1358 } 1359 ecl.DefaultClient = ecl.Clients[0] 1360 wrappedClient := wrapMultiClient(networkSettings, ecl) 1361 // no need to fund the account as it is already funded in the existing client 1362 return wrappedClient, nil 1363 } 1364 1365 // Get gets default client as an interface{} 1366 func (e *EthereumMultinodeClient) Get() interface{} { 1367 return e.DefaultClient 1368 } 1369 func (e *EthereumMultinodeClient) GetNonceSetting() NonceSettings { 1370 return e.DefaultClient.GetNonceSetting() 1371 } 1372 1373 func (e *EthereumMultinodeClient) SyncNonce(c EVMClient) { 1374 e.DefaultClient.SyncNonce(c) 1375 } 1376 1377 // GetNetworkName gets the ID of the chain that the clients are connected to 1378 func (e *EthereumMultinodeClient) GetNetworkName() string { 1379 return e.DefaultClient.GetNetworkName() 1380 } 1381 1382 // GetNetworkType retrieves the type of network this is running on 1383 func (e *EthereumMultinodeClient) NetworkSimulated() bool { 1384 return e.DefaultClient.NetworkSimulated() 1385 } 1386 1387 // GetChainID retrieves the ChainID of the network that the client interacts with 1388 func (e *EthereumMultinodeClient) GetChainID() *big.Int { 1389 return e.DefaultClient.GetChainID() 1390 } 1391 1392 // GetClients gets clients for all nodes connected 1393 func (e *EthereumMultinodeClient) GetClients() []EVMClient { 1394 cl := make([]EVMClient, 0) 1395 cl = append(cl, e.Clients...) 1396 return cl 1397 } 1398 1399 // GetDefaultWallet returns the default wallet for the network 1400 func (e *EthereumMultinodeClient) GetDefaultWallet() *EthereumWallet { 1401 return e.DefaultClient.GetDefaultWallet() 1402 } 1403 1404 // GetWallets returns the default wallet for the network 1405 func (e *EthereumMultinodeClient) GetWallets() []*EthereumWallet { 1406 return e.DefaultClient.GetWallets() 1407 } 1408 1409 // GetNetworkConfig return the network config 1410 func (e *EthereumMultinodeClient) GetNetworkConfig() *EVMNetwork { 1411 return e.DefaultClient.GetNetworkConfig() 1412 } 1413 1414 // SetID sets client ID in a multi-node environment 1415 func (e *EthereumMultinodeClient) SetID(id int) { 1416 e.DefaultClient.SetID(id) 1417 } 1418 1419 // SetDefaultWallet sets default wallet 1420 func (e *EthereumMultinodeClient) SetDefaultWallet(num int) error { 1421 return e.DefaultClient.SetDefaultWallet(num) 1422 } 1423 1424 // SetWallets sets the default client's wallets 1425 func (e *EthereumMultinodeClient) SetWallets(wallets []*EthereumWallet) { 1426 e.DefaultClient.SetWallets(wallets) 1427 } 1428 1429 // LoadWallets loads wallets using private keys provided in the config 1430 func (e *EthereumMultinodeClient) LoadWallets(cfg EVMNetwork) error { 1431 pkStrings := cfg.PrivateKeys 1432 wallets := make([]*EthereumWallet, 0) 1433 for _, pks := range pkStrings { 1434 w, err := NewEthereumWallet(pks) 1435 if err != nil { 1436 return err 1437 } 1438 wallets = append(wallets, w) 1439 } 1440 for _, c := range e.Clients { 1441 c.SetWallets(wallets) 1442 } 1443 return nil 1444 } 1445 1446 // BalanceAt returns the ETH balance of the specified address 1447 func (e *EthereumMultinodeClient) BalanceAt(ctx context.Context, address common.Address) (*big.Int, error) { 1448 return e.DefaultClient.BalanceAt(ctx, address) 1449 } 1450 1451 // SwitchNode sets default client to perform calls to the network 1452 func (e *EthereumMultinodeClient) SwitchNode(clientID int) error { 1453 if clientID > len(e.Clients) { 1454 return fmt.Errorf("client for node %d not found", clientID) 1455 } 1456 e.DefaultClient = e.Clients[clientID] 1457 return nil 1458 } 1459 1460 // HeaderHashByNumber gets header hash by block number 1461 func (e *EthereumMultinodeClient) HeaderHashByNumber(ctx context.Context, bn *big.Int) (string, error) { 1462 return e.DefaultClient.HeaderHashByNumber(ctx, bn) 1463 } 1464 1465 // HeaderTimestampByNumber gets header timestamp by number 1466 func (e *EthereumMultinodeClient) HeaderTimestampByNumber(ctx context.Context, bn *big.Int) (uint64, error) { 1467 return e.DefaultClient.HeaderTimestampByNumber(ctx, bn) 1468 } 1469 1470 // LatestBlockNumber gets the latest block number from the default client 1471 func (e *EthereumMultinodeClient) LatestBlockNumber(ctx context.Context) (uint64, error) { 1472 return e.DefaultClient.LatestBlockNumber(ctx) 1473 } 1474 1475 // SendTransaction wraps ethereum's SendTransaction to make it safe with instant transaction types 1476 func (e *EthereumMultinodeClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { 1477 return e.DefaultClient.SendTransaction(ctx, tx) 1478 } 1479 1480 // Fund funds a specified address with ETH from the given wallet 1481 func (e *EthereumMultinodeClient) Fund(toAddress string, nativeAmount *big.Float, gasEstimations GasEstimations) error { 1482 return e.DefaultClient.Fund(toAddress, nativeAmount, gasEstimations) 1483 } 1484 1485 func (e *EthereumMultinodeClient) ReturnFunds(fromKey *ecdsa.PrivateKey) error { 1486 return e.DefaultClient.ReturnFunds(fromKey) 1487 } 1488 1489 // DeployContract deploys a specified contract 1490 func (e *EthereumMultinodeClient) DeployContract( 1491 contractName string, 1492 deployer ContractDeployer, 1493 ) (*common.Address, *types.Transaction, interface{}, error) { 1494 return e.DefaultClient.DeployContract(contractName, deployer) 1495 } 1496 1497 // TransactionOpts returns the base Tx options for 'transactions' that interact with a smart contract. Since most 1498 // contract interactions in this framework are designed to happen through abigen calls, it's intentionally quite bare. 1499 func (e *EthereumMultinodeClient) TransactionOpts(from *EthereumWallet) (*bind.TransactOpts, error) { 1500 return e.DefaultClient.TransactionOpts(from) 1501 } 1502 1503 func (e *EthereumMultinodeClient) NewTx( 1504 fromPrivateKey *ecdsa.PrivateKey, 1505 nonce uint64, 1506 to common.Address, 1507 value *big.Int, 1508 gasEstimations GasEstimations, 1509 ) (*types.Transaction, error) { 1510 return e.DefaultClient.NewTx(fromPrivateKey, nonce, to, value, gasEstimations) 1511 } 1512 1513 // ProcessTransaction returns the result of the default client's processed transaction 1514 func (e *EthereumMultinodeClient) ProcessTransaction(tx *types.Transaction) error { 1515 return e.DefaultClient.ProcessTransaction(tx) 1516 } 1517 1518 // ProcessEvent returns the result of the default client's processed event 1519 func (e *EthereumMultinodeClient) ProcessEvent(name string, event *types.Log, confirmedChan chan bool, errorChan chan error) error { 1520 return e.DefaultClient.ProcessEvent(name, event, confirmedChan, errorChan) 1521 } 1522 1523 // IsTxConfirmed returns the default client's transaction confirmations 1524 func (e *EthereumMultinodeClient) IsTxConfirmed(txHash common.Hash) (bool, error) { 1525 return e.DefaultClient.IsTxConfirmed(txHash) 1526 } 1527 1528 // IsEventConfirmed returns if the default client can confirm the event has happened 1529 func (e *EthereumMultinodeClient) IsEventConfirmed(event *types.Log) (confirmed, removed bool, err error) { 1530 return e.DefaultClient.IsEventConfirmed(event) 1531 } 1532 1533 // IsTxFinalized returns if the default client can confirm the transaction has been finalized 1534 func (e *EthereumMultinodeClient) IsTxHeadFinalized(txHdr, header *SafeEVMHeader) (bool, *big.Int, time.Time, error) { 1535 return e.DefaultClient.IsTxHeadFinalized(txHdr, header) 1536 } 1537 1538 // WaitForTxTobeFinalized waits for the transaction to be finalized 1539 func (e *EthereumMultinodeClient) WaitForFinalizedTx(txHash common.Hash) (*big.Int, time.Time, error) { 1540 return e.DefaultClient.WaitForFinalizedTx(txHash) 1541 } 1542 1543 // MarkTxAsSentOnL2 marks the transaction as sent on L2 1544 func (e *EthereumMultinodeClient) MarkTxAsSentOnL2(tx *types.Transaction) error { 1545 return e.DefaultClient.MarkTxAsSentOnL2(tx) 1546 } 1547 1548 // PollFinality polls for finality 1549 func (e *EthereumMultinodeClient) PollFinality() error { 1550 return e.DefaultClient.PollFinality() 1551 } 1552 1553 // StopPollingForFinality stops polling for finality 1554 func (e *EthereumMultinodeClient) CancelFinalityPolling() { 1555 e.DefaultClient.CancelFinalityPolling() 1556 } 1557 1558 // GetTxReceipt returns the receipt of the transaction if available, error otherwise 1559 func (e *EthereumMultinodeClient) GetTxReceipt(txHash common.Hash) (*types.Receipt, error) { 1560 return e.DefaultClient.GetTxReceipt(txHash) 1561 } 1562 1563 func (e *EthereumMultinodeClient) RevertReasonFromTx(txHash common.Hash, abiString string) (string, interface{}, error) { 1564 return e.DefaultClient.RevertReasonFromTx(txHash, abiString) 1565 } 1566 1567 // ParallelTransactions when enabled, sends the transaction without waiting for transaction confirmations. The hashes 1568 // are then stored within the client and confirmations can be waited on by calling WaitForEvents. 1569 // When disabled, the minimum confirmations are waited on when the transaction is sent, so parallelisation is disabled. 1570 func (e *EthereumMultinodeClient) ParallelTransactions(enabled bool) { 1571 for _, c := range e.Clients { 1572 c.ParallelTransactions(enabled) 1573 } 1574 } 1575 1576 // Close tears down the all the clients 1577 func (e *EthereumMultinodeClient) Close() error { 1578 for _, c := range e.Clients { 1579 if err := c.Close(); err != nil { 1580 return err 1581 } 1582 } 1583 return nil 1584 } 1585 1586 func (e *EthereumMultinodeClient) EstimateTransactionGasCost() (*big.Int, error) { 1587 return e.DefaultClient.EstimateTransactionGasCost() 1588 } 1589 1590 // GasStats gets gas stats instance 1591 func (e *EthereumMultinodeClient) GasStats() *GasStats { 1592 return e.DefaultClient.GasStats() 1593 } 1594 1595 func (e *EthereumMultinodeClient) EstimateGas(callMsg ethereum.CallMsg) (GasEstimations, error) { 1596 return e.DefaultClient.EstimateGas(callMsg) 1597 } 1598 1599 func (e *EthereumMultinodeClient) EstimateGasPrice() (*big.Int, error) { 1600 return e.DefaultClient.EstimateGasPrice() 1601 } 1602 1603 func (e *EthereumMultinodeClient) ConnectionIssue() chan time.Time { 1604 return e.DefaultClient.ConnectionIssue() 1605 } 1606 func (e *EthereumMultinodeClient) ConnectionRestored() chan time.Time { 1607 return e.DefaultClient.ConnectionRestored() 1608 } 1609 1610 // AddHeaderEventSubscription adds a new header subscriber within the client to receive new headers 1611 func (e *EthereumMultinodeClient) AddHeaderEventSubscription(key string, subscriber HeaderEventSubscription) { 1612 e.DefaultClient.AddHeaderEventSubscription(key, subscriber) 1613 } 1614 1615 // SubscribeFilterLogs subscribes to the results of a streaming filter query. 1616 func (e *EthereumMultinodeClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, logs chan<- types.Log) (ethereum.Subscription, error) { 1617 return e.DefaultClient.SubscribeFilterLogs(ctx, q, logs) 1618 } 1619 1620 // FilterLogs executes a filter query 1621 func (e *EthereumMultinodeClient) FilterLogs(ctx context.Context, filterQuery ethereum.FilterQuery) ([]types.Log, error) { 1622 return e.DefaultClient.FilterLogs(ctx, filterQuery) 1623 } 1624 1625 func (e *EthereumMultinodeClient) GetLatestFinalizedBlockHeader(ctx context.Context) (*types.Header, error) { 1626 return e.DefaultClient.GetLatestFinalizedBlockHeader(ctx) 1627 } 1628 1629 func (e *EthereumMultinodeClient) EstimatedFinalizationTime(ctx context.Context) (time.Duration, error) { 1630 return e.DefaultClient.EstimatedFinalizationTime(ctx) 1631 } 1632 1633 func (e *EthereumMultinodeClient) AvgBlockTime(ctx context.Context) (time.Duration, error) { 1634 return e.DefaultClient.AvgBlockTime(ctx) 1635 } 1636 1637 // DeleteHeaderEventSubscription removes a header subscriber from the map 1638 func (e *EthereumMultinodeClient) DeleteHeaderEventSubscription(key string) { 1639 e.DefaultClient.DeleteHeaderEventSubscription(key) 1640 } 1641 1642 // WaitForEvents is a blocking function that waits for all event subscriptions for all clients 1643 func (e *EthereumMultinodeClient) WaitForEvents() error { 1644 g := errgroup.Group{} 1645 for _, c := range e.Clients { 1646 c := c 1647 g.Go(func() error { 1648 return c.WaitForEvents() 1649 }) 1650 } 1651 return g.Wait() 1652 }