use std::time::Duration;
use anyhow::bail;
use tokio::sync::watch;
use zksync_basic_types::{ethabi::Contract, settlement::SettlementLayer, L2ChainId};
use zksync_config::configs::contracts::SettlementLayerSpecificContracts;
use zksync_contracts::getters_facet_contract;
use zksync_eth_client::{ContractCallError, EthInterface};
use zksync_settlement_layer_data::{current_settlement_layer, SettlementLayerError};
pub mod node;
#[derive(Debug, thiserror::Error)]
pub enum GatewayMigratorError {
#[error("ContractCall Error: {0}")]
ContractCall(#[from] ContractCallError),
#[error("Error: {0}")]
Internal(#[from] anyhow::Error),
}
#[derive(Debug)]
pub struct GatewayMigrator {
eth_client: Box<dyn EthInterface>,
gateway_client: Option<Box<dyn EthInterface>>,
l1_settlement_layer_specific_contracts: SettlementLayerSpecificContracts,
settlement_layer: Option<SettlementLayer>,
l2_chain_id: L2ChainId,
getters_facet_abi: Contract,
eth_node_poll_interval: Duration,
}
impl GatewayMigrator {
pub fn new(
eth_client: Box<dyn EthInterface>,
gateway_client: Option<Box<dyn EthInterface>>,
l2_chain_id: L2ChainId,
settlement_layer: Option<SettlementLayer>,
l1_settlement_layer_specific_contracts: SettlementLayerSpecificContracts,
eth_node_poll_interval: Duration,
) -> Self {
let abi = getters_facet_contract();
Self {
eth_client,
gateway_client,
l1_settlement_layer_specific_contracts,
settlement_layer,
l2_chain_id,
getters_facet_abi: abi,
eth_node_poll_interval,
}
}
pub async fn run(self, stop_receiver: watch::Receiver<bool>) -> anyhow::Result<()> {
let gateway_client = self.gateway_client.as_deref();
loop {
if *stop_receiver.borrow() {
tracing::info!("Stop request received, GatewayMigrator is shutting down");
return Ok(());
}
let current_settlement_layer = current_settlement_layer(
self.eth_client.as_ref(),
gateway_client,
&self.l1_settlement_layer_specific_contracts,
self.l2_chain_id,
&self.getters_facet_abi,
)
.await;
match current_settlement_layer {
Ok(current_settlement_layer) => {
if self.settlement_layer
!= current_settlement_layer.settlement_layer_for_sending_txs()
{
bail!(
"Settlement layer changed, from {:?} to {:?}",
self.settlement_layer,
current_settlement_layer.settlement_layer_for_sending_txs()
);
}
}
Err(SettlementLayerError::ContractCall(ContractCallError::EthereumGateway(
err,
))) if err.is_retryable() => {
tracing::info!("Transient error fetching data from SL: {err}");
}
Err(err) => {
tracing::error!("Failed to fetch data from SL: {err}");
}
}
tokio::time::sleep(self.eth_node_poll_interval).await;
}
}
}