tangle-network / relayer

🕸️ The Webb Relayer Network
https://webb-tools.github.io/relayer/
Apache License 2.0
22 stars 13 forks source link

Multiple Rpc support for Evm chains #529

Closed salman01zp closed 1 year ago

salman01zp commented 1 year ago

Summary of changes

1. Update EvmChainConfig to take multiple http-endpoints

pub struct EvmChainConfig {
    #[serde(skip_serializing)]
    pub http_endpoints: Vec<RpcUrl>,
}

2. Make evm_provider mutable so we can update and cache latest working client

pub struct RelayerContext {
  .
  .
 /// Evm Providers Cache.
 evm_providers: Arc<Mutex<HashMap<types::U256, Arc<EthersClient>>>>,
}

pub async fn evm_provider<I: Into<types::U256>>(
        &self,
        chain_id: I,
    ) -> webb_relayer_utils::Result<Arc<EthersClient>> {
        let chain_id: types::U256 = chain_id.into();
        // Check if the provider is already in the cache or else create new provider from http_endpoint array.
        // If the provider is not working, try creating a new provider from http_endpoint array.

        if let Some(provider) = self.evm_providers.lock().await.get(&chain_id) {
            // get gas price to check if the provider is working
            let response = provider.get_gas_price().await;
            match response {
                Ok(_) => Ok(provider.clone()),
                Err(e) => {
                    tracing::error!(
                        "EVM Provider for chain {} is not working: {}.Try Connecting with other http_endpoints, if any.",
                        chain_id,
                        e
                    );
                    self.create_evm_provider(chain_id).await
                }
            }
        } else {
            self.create_evm_provider(chain_id).await
        }
    }

3. Update retry count for RetryClient.

Since we want to switch between RPC providers, we should define a smaller limit for retires like ~50. Once retry limit exceeds the current client is dropped and a new client is created by iterating over available rpc endpoints. This will happen in the event_watcher::run() method

The evm_provider method will check the provider cache for the client and will do a sanity check for connection by making an API call. If the connection fails it will try to create a new evm_provider from the set of RPC endpoints in the loop.


let task = || async {
            let step = contract.max_blocks_per_step().as_u64();
            let provider = ctx.evm_provider(chain_id).await?;
            let client = Arc::new(TimeLag::new(
                provider,
                chain_config.block_confirmations,
            ));

     // drop client if retries exceed and create new clients after some back off time
}

Reference issue to close (if applicable)


Code Checklist

salman01zp commented 1 year ago

Will update in new PR