44 "context"
55 "fmt"
66 "math/big"
7+ "net/http"
8+ "strings"
79 "sync"
810 "time"
911
@@ -12,6 +14,7 @@ import (
1214 "github.com/ethereum/go-ethereum/common/hexutil"
1315 gethtypes "github.com/ethereum/go-ethereum/core/types"
1416 "github.com/ethereum/go-ethereum/ethclient"
17+ "github.com/ethereum/go-ethereum/rpc"
1518
1619 "github.com/bandprotocol/falcon/relayer/alert"
1720 "github.com/bandprotocol/falcon/relayer/chains"
@@ -59,6 +62,32 @@ type client struct {
5962 alert alert.Alert
6063}
6164
65+ // idleConnTimeout is intentionally shorter than the typical load-balancer idle
66+ // timeout (e.g. AWS ALB default is 60 s) so Go closes idle keep-alive
67+ // connections before the LB does, preventing "connection reset by peer" errors
68+ // caused by the LB sending a TCP RST on a stale connection that Go's transport
69+ // would otherwise attempt to reuse.
70+ const idleConnTimeout = 30 * time .Second
71+
72+ // dialEVMEndpoint connects to an EVM-compatible RPC endpoint.
73+ // For HTTP/HTTPS endpoints it injects a custom transport with a short
74+ // IdleConnTimeout to avoid stale-connection resets from load balancers.
75+ // For WebSocket endpoints it falls back to the standard ethclient dialer.
76+ func dialEVMEndpoint (ctx context.Context , endpoint string ) (* ethclient.Client , error ) {
77+ lower := strings .ToLower (endpoint )
78+ if strings .HasPrefix (lower , "http://" ) || strings .HasPrefix (lower , "https://" ) {
79+ transport := & http.Transport {
80+ IdleConnTimeout : idleConnTimeout ,
81+ }
82+ rpcCli , err := rpc .DialOptions (ctx , endpoint , rpc .WithHTTPClient (& http.Client {Transport : transport }))
83+ if err != nil {
84+ return nil , err
85+ }
86+ return ethclient .NewClient (rpcCli ), nil
87+ }
88+ return ethclient .DialContext (ctx , endpoint )
89+ }
90+
6291// NewClient creates a new EVM client from config file and load keys.
6392func NewClient (chainName string , cfg * EVMChainProviderConfig , log logger.Logger , alert alert.Alert ) * client {
6493 return & client {
@@ -84,7 +113,7 @@ func (c *client) Connect(ctx context.Context) error {
84113 wg .Add (1 )
85114 go func (endpoint string ) {
86115 defer wg .Done ()
87- client , err := ethclient . Dial ( endpoint )
116+ client , err := dialEVMEndpoint ( ctx , endpoint )
88117 if err != nil {
89118 c .Log .Warn (
90119 "Failed to connect to EVM chain" ,
0 commit comments