Skip to content

Commit

Permalink
feat: adds withdrawal finalizing logic. (#56)
Browse files Browse the repository at this point in the history
* adds finalization_data table migrations

* add_withdrawals_data method implementation

* adds a query to all newly executed withdrawals

* change l2_block_number type and fix sender address conversion

* add finalizer main loop and adding data to new table

* adds a storage method to query previously unfinalized withdrawals

* fixes is null check in storage

* withdrawal log data is rlp encoded

* conversion method from withdrawal data into requestfinalizewithdrawal

* adds finalizer specific values to config

* adds finalization status updates to db

* adds finalizing logic

* clippy

* refactors code

* refactor a couple of iterators

* adds config value for the account private key

* squash two structures together

* rename finalizer contract variable

* refactor a bit and add comments

* do not request finalization status in watcher

* remove redundant clone

* adds btreemap to accumulator

* document middlewares used by finalizer

* cap tx fee limit const

* reset accumulator with new gas price

* rename migrator to params fetcher

* use hashset for are withdrawals finalized results

* use monotonically increasing id field for withdrawals

* remove is_finalized field from withdrawals table

* change tx_fee_limit expect message

* rename id and make it a foreign key

* a single foreign key on withdrawals

* no lower boundary on finalization

* only use withdrawal id as a foreign key in finalization_data

* updates comment

* if no money do not bump failed attempts counter

* rename migrator handle
  • Loading branch information
montekki committed Jul 26, 2023
1 parent 7a375a9 commit 5297c02
Show file tree
Hide file tree
Showing 27 changed files with 1,194 additions and 252 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ resolver = "1"
members = [
"bin/withdrawal-finalizer",
"ethers-log-decode",
"finalizer",
"client",
"chain-events",
"storage",
Expand Down
1 change: 1 addition & 0 deletions bin/withdrawal-finalizer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ client = { path = "../../client" }
storage = { path = "../../storage" }
chain-events = { path = "../../chain-events" }
vlog = { path = "../../vlog" }
finalizer = { path = "../../finalizer" }
metrics-exporter-prometheus = "0.12.1"
metrics = "0.21.0"
18 changes: 17 additions & 1 deletion bin/withdrawal-finalizer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
use std::{env, fs, path::Path, str::FromStr};

use envconfig::Envconfig;
use ethers::types::{Address, H160, U256};
use ethers::{
abi::ethereum_types::FromStrRadixErr,
types::{Address, H160, U256},
};
use serde::Deserialize;
use url::Url;

Expand All @@ -29,6 +32,10 @@ pub struct Config {
#[envconfig(from = "CONTRACTS_DIAMOND_PROXY_ADDR")]
pub diamond_proxy_addr: Address,

/// Finalizer contract
#[envconfig(from = "CONTRACTS_WITHDRAWAL_FINALIZER_CONTRACT")]
pub withdrawal_finalizer_addr: Address,

/// L2 WS Endpoint
#[envconfig(from = "API_WEB3_JSON_RPC_WS_URL")]
pub api_web3_json_rpc_ws_url: Url,
Expand All @@ -41,6 +48,15 @@ pub struct Config {

#[envconfig(from = "UPDATER_BACKOFF")]
pub updater_backoff: Option<u64>,

#[envconfig(from = "GAS_LIMIT")]
pub one_withdrawal_gas_limit: String,

#[envconfig(from = "BATCH_FINALIZATION_GAS_LIMIT")]
pub batch_finalization_gas_limit: String,

#[envconfig(from = "WITHDRAWAL_FINALIZER_ACCOUNT_PRIVATE_KEY")]
pub account_private_key: String,
}

impl Config {
Expand Down
47 changes: 39 additions & 8 deletions bin/withdrawal-finalizer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ use std::{str::FromStr, sync::Arc, time::Duration};

use clap::Parser;
use envconfig::Envconfig;
use ethers::providers::{JsonRpcClient, Middleware, Provider, Ws};
use ethers::{
prelude::SignerMiddleware,
providers::{JsonRpcClient, Middleware, Provider, Ws},
signers::LocalWallet,
types::U256,
};
use eyre::{anyhow, Result};
use sqlx::{postgres::PgConnectOptions, ConnectOptions, PgConnection, PgPool};

Expand Down Expand Up @@ -219,7 +224,7 @@ async fn main() -> Result<()> {

vlog::info!("Starting from L1 block number {from_l1_block}");

let (tokens, last_token_seen_at_block) = storage::get_tokens(&pgpool).await?;
let (tokens, last_token_seen_at_block) = storage::get_tokens(&pgpool.clone()).await?;

let l2_events = L2EventsListener::new(
config.api_web3_json_rpc_ws_url.as_str(),
Expand All @@ -231,12 +236,7 @@ async fn main() -> Result<()> {

let zksync_contract = IZkSync::new(config.diamond_proxy_addr, client_l1.clone());

let wf = withdrawal_finalizer::WithdrawalFinalizer::new(
client_l2,
pgpool,
zksync_contract,
l1_bridge,
);
let wf = withdrawal_finalizer::WithdrawalFinalizer::new(client_l2.clone(), pgpool.clone());

let withdrawal_events_handle = tokio::spawn(l2_events.run_with_reconnects(
from_l2_block,
Expand All @@ -262,6 +262,34 @@ async fn main() -> Result<()> {
}
});

let wallet = config.account_private_key.parse::<LocalWallet>()?;

let client_l1_with_signer = Arc::new(SignerMiddleware::new(client_l1, wallet));

let contract = client::withdrawal_finalizer::codegen::WithdrawalFinalizer::new(
config.withdrawal_finalizer_addr,
client_l1_with_signer,
);
let batch_finalization_gas_limit = U256::from_dec_str(&config.batch_finalization_gas_limit)?;
let one_withdrawal_gas_limit = U256::from_dec_str(&config.one_withdrawal_gas_limit)?;

vlog::info!(
"finalization gas limits one: {}, batch: {}",
config.one_withdrawal_gas_limit,
config.batch_finalization_gas_limit,
);

let finalizer = finalizer::Finalizer::new(
pgpool,
one_withdrawal_gas_limit,
batch_finalization_gas_limit,
contract,
zksync_contract,
l1_bridge,
);

let actual_finalizer_handle = tokio::spawn(finalizer.run(client_l2));

tokio::select! {
r = block_events_handle => {
vlog::error!("Block Events stream ended with {r:?}");
Expand All @@ -275,6 +303,9 @@ async fn main() -> Result<()> {
r = prometheus_exporter_handle => {
vlog::error!("Prometheus exporter ended with {r:?}");
}
r = actual_finalizer_handle => {
vlog::error!("Finalizer ended with {r:?}");
}
}

Ok(())
Expand Down
50 changes: 5 additions & 45 deletions bin/withdrawal-finalizer/src/withdrawal_finalizer.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,31 @@
use std::sync::Arc;

use chain_events::L2Event;
use ethers::{
providers::{JsonRpcClient, Middleware},
types::{Address, H256},
};
use ethers::providers::{JsonRpcClient, Middleware};
use futures::{stream::StreamExt, Stream};
use sqlx::PgPool;
use storage::StoredWithdrawal;
use tokio::pin;

use client::{
l1bridge::codegen::IL1Bridge,
zksync_contract::{codegen::IZkSync, L2ToL1Event},
BlockEvent, WithdrawalEvent, ZksyncMiddleware,
};
use client::{zksync_contract::L2ToL1Event, BlockEvent, WithdrawalEvent, ZksyncMiddleware};

use crate::Result;

pub struct WithdrawalFinalizer<M1, M2> {
pub struct WithdrawalFinalizer<M2> {
l2_provider: Arc<M2>,
pgpool: PgPool,
l1_bridge: IL1Bridge<M1>,
zksync_contract: IZkSync<M1>,
}

impl<M1, M2> WithdrawalFinalizer<M1, M2>
impl<M2> WithdrawalFinalizer<M2>
where
M1: Middleware,
<M1 as Middleware>::Provider: JsonRpcClient,
M2: ZksyncMiddleware,
<M2 as Middleware>::Provider: JsonRpcClient,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
l2_provider: Arc<M2>,
pgpool: PgPool,
zksync_contract: IZkSync<M1>,
l1_bridge: IL1Bridge<M1>,
) -> Self {
pub fn new(l2_provider: Arc<M2>, pgpool: PgPool) -> Self {
Self {
l2_provider,
pgpool,
zksync_contract,
l1_bridge,
}
}

Expand Down Expand Up @@ -225,36 +207,14 @@ where
let mut stored_withdrawals = vec![];

for (event, index) in withdrawals_vec.into_iter() {
let is_finalized = self
.is_withdrawal_finalized(event.tx_hash, index, event.token)
.await?;

stored_withdrawals.push(StoredWithdrawal {
event,
index_in_tx: index,
is_finalized,
});
}

let mut pgconn = self.pgpool.acquire().await?;
storage::add_withdrawals(&mut pgconn, &stored_withdrawals).await?;
Ok(())
}

async fn is_withdrawal_finalized(
&self,
withdrawal_hash: H256,
index: usize,
sender: Address,
) -> Result<bool> {
Ok(client::is_withdrawal_finalized(
withdrawal_hash,
index,
sender,
&self.zksync_contract,
&self.l1_bridge,
&self.l2_provider,
)
.await?)
}
}
4 changes: 2 additions & 2 deletions chain-events/src/l2_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,6 @@ impl L2EventsListener {
WithdrawalFilter::signature(),
];

let tokens = self.tokens.iter().cloned().collect::<Vec<_>>();

vlog::debug!("last_seen_l2_token_block {last_seen_l2_token_block:?}");
vlog::debug!("from_block {from_block:?}");

Expand All @@ -345,6 +343,8 @@ impl L2EventsListener {
.await?;
}

let tokens = self.tokens.iter().cloned().collect::<Vec<_>>();

let past_filter = Filter::new()
.from_block(from_block)
.to_block(latest_block)
Expand Down
Loading

0 comments on commit 5297c02

Please sign in to comment.