Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: missing DenyList feature #101

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion core/bin/zksync_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use zksync_config::{
},
fri_prover_group::FriProverGroupConfig,
house_keeper::HouseKeeperConfig,
tx_sink::TxSinkConfig,
BasicWitnessInputProducerConfig, ContractsConfig, DataAvailabilitySecrets, DatabaseSecrets,
ExperimentalVmConfig, ExternalPriceApiClientConfig, FriProofCompressorConfig,
FriProverConfig, FriProverGatewayConfig, FriWitnessGeneratorConfig,
Expand Down Expand Up @@ -44,7 +45,7 @@ struct Cli {
/// Comma-separated list of components to launch.
#[arg(
long,
default_value = "api,tree,eth,state_keeper,housekeeper,commitment_generator,da_dispatcher,vm_runner_protective_reads"
default_value = "api,tree,eth,state_keeper,housekeeper,commitment_generator,da_dispatcher,vm_runner_protective_reads,deny_list"
)]
components: ComponentsToRun,
/// Path to the yaml config. If set, it will be used instead of env vars.
Expand Down Expand Up @@ -196,5 +197,6 @@ fn load_env_config() -> anyhow::Result<TempConfigStore> {
experimental_vm_config: ExperimentalVmConfig::from_env().ok(),
prover_job_monitor_config: None,
timestamp_asserter_config: TimestampAsserterConfig::from_env().ok(),
tx_sink_config: TxSinkConfig::from_env().ok(),
})
}
26 changes: 20 additions & 6 deletions core/bin/zksync_server/src/node_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use zksync_node_framework::{
server::{Web3ServerLayer, Web3ServerOptionalConfig},
tree_api_client::TreeApiClientLayer,
tx_sender::{PostgresStorageCachesConfig, TxSenderLayer},
tx_sink::MasterPoolSinkLayer,
tx_sink::{DenyListPoolSinkLayer, MasterPoolSinkLayer},
},
},
service::{ZkStackService, ZkStackServiceBuilder},
Expand Down Expand Up @@ -299,7 +299,7 @@ impl MainNodeBuilder {
Ok(self)
}

fn add_tx_sender_layer(mut self) -> anyhow::Result<Self> {
fn add_tx_sender_layer(mut self, deny_list_enabled: bool) -> anyhow::Result<Self> {
let sk_config = try_load_config!(self.configs.state_keeper_config);
let rpc_config = try_load_config!(self.configs.api_config).web3_json_rpc;

Expand Down Expand Up @@ -328,8 +328,16 @@ impl MainNodeBuilder {
.clone()
.unwrap_or_default();

// On main node we always use master pool sink.
self.node.add_layer(MasterPoolSinkLayer);
let tx_sink_config = try_load_config!(self.configs.tx_sink_config);
if deny_list_enabled && tx_sink_config.deny_list().is_some() {
tracing::info!("run DenyListPoolSinkLayer {:?}", tx_sink_config.deny_list());
self.node.add_layer(DenyListPoolSinkLayer::new(
tx_sink_config.deny_list().unwrap(),
));
} else {
tracing::info!("run MasterPoolSinkLayer");
self.node.add_layer(MasterPoolSinkLayer);
}

let layer = TxSenderLayer::new(
TxSenderConfig::new(
Expand Down Expand Up @@ -702,6 +710,8 @@ impl MainNodeBuilder {
_ => 0,
});

let mut deny_list_enabled = false;

// Add "component-specific" layers.
// Note that the layers are added only once, so it's fine to add the same layer multiple times.
for component in &components {
Expand All @@ -718,15 +728,15 @@ impl MainNodeBuilder {
Component::HttpApi => {
self = self
.add_l1_gas_layer()?
.add_tx_sender_layer()?
.add_tx_sender_layer(deny_list_enabled)?
.add_tree_api_client_layer()?
.add_api_caches_layer()?
.add_http_web3_api_layer()?;
}
Component::WsApi => {
self = self
.add_l1_gas_layer()?
.add_tx_sender_layer()?
.add_tx_sender_layer(deny_list_enabled)?
.add_tree_api_client_layer()?
.add_api_caches_layer()?
.add_ws_web3_api_layer()?;
Expand Down Expand Up @@ -789,6 +799,10 @@ impl MainNodeBuilder {
Component::ExternalProofIntegrationApi => {
self = self.add_external_proof_integration_api_layer()?;
}
Component::TxSinkDenyList => {
tracing::info!("L2 denylist enabled.");
deny_list_enabled = true;
}
}
}
Ok(self.node.build())
Expand Down
2 changes: 2 additions & 0 deletions core/lib/config/src/configs/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
prover_job_monitor::ProverJobMonitorConfig,
pruning::PruningConfig,
snapshot_recovery::SnapshotRecoveryConfig,
tx_sink::TxSinkConfig,
vm_runner::{BasicWitnessInputProducerConfig, ProtectiveReadsWriterConfig},
CommitmentGeneratorConfig, ExperimentalVmConfig, ExternalPriceApiClientConfig,
FriProofCompressorConfig, FriProverConfig, FriProverGatewayConfig,
Expand Down Expand Up @@ -60,4 +61,5 @@ pub struct GeneralConfig {
pub experimental_vm_config: Option<ExperimentalVmConfig>,
pub prover_job_monitor_config: Option<ProverJobMonitorConfig>,
pub timestamp_asserter_config: Option<TimestampAsserterConfig>,
pub tx_sink_config: Option<TxSinkConfig>,
}
2 changes: 2 additions & 0 deletions core/lib/config/src/configs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub use self::{
secrets::{DataAvailabilitySecrets, DatabaseSecrets, L1Secrets, Secrets},
snapshot_recovery::SnapshotRecoveryConfig,
snapshots_creator::SnapshotsCreatorConfig,
tx_sink::TxSinkConfig,
utils::PrometheusConfig,
vm_runner::{BasicWitnessInputProducerConfig, ProtectiveReadsWriterConfig},
};
Expand Down Expand Up @@ -65,6 +66,7 @@ pub mod pruning;
pub mod secrets;
pub mod snapshot_recovery;
pub mod snapshots_creator;
pub mod tx_sink;
pub mod utils;
pub mod vm_runner;
pub mod wallets;
Expand Down
27 changes: 27 additions & 0 deletions core/lib/config/src/configs/tx_sink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::{collections::HashSet, str::FromStr};

use serde::Deserialize;
use zksync_basic_types::Address;

#[derive(Debug, Deserialize, Clone, PartialEq)]
pub struct TxSinkConfig {
pub deny_list: Option<String>,
}

impl TxSinkConfig {
pub fn deny_list(&self) -> Option<HashSet<Address>> {
// Return deny list is not set or empty
if self.deny_list.is_none() || self.deny_list.as_ref().unwrap().is_empty() {
return None;
}

// Parse deny list from a string and return it as a set of addresses
// Example: "0x1,0x2,0x3" -> { Address::from_str("0x1").unwrap(), Address::from_str("0x2").unwrap(), Address::from_str("0x3").unwrap() }
// Note: This assumes that the addresses are separated by commas and are in valid format.
self.deny_list.as_ref().map(|list| {
list.split(',')
.map(|element| Address::from_str(element).unwrap())
.collect()
})
}
}
9 changes: 9 additions & 0 deletions core/lib/config/src/testonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@ impl Distribution<configs::GeneralConfig> for EncodeDist {
experimental_vm_config: self.sample(rng),
prover_job_monitor_config: self.sample(rng),
timestamp_asserter_config: self.sample(rng),
tx_sink_config: self.sample(rng),
}
}
}
Expand All @@ -1194,3 +1195,11 @@ impl Distribution<TimestampAsserterConfig> for EncodeDist {
}
}
}

impl Distribution<configs::TxSinkConfig> for EncodeDist {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> configs::TxSinkConfig {
configs::TxSinkConfig {
deny_list: self.sample(rng),
}
}
}
1 change: 1 addition & 0 deletions core/lib/env_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod object_store;
mod observability;
mod proof_data_handler;
mod snapshots_creator;
mod tx_sink;
mod utils;

mod base_token_adjuster;
Expand Down
35 changes: 35 additions & 0 deletions core/lib/env_config/src/tx_sink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use zksync_config::configs::TxSinkConfig;

use crate::{envy_load, FromEnv};

impl FromEnv for TxSinkConfig {
fn from_env() -> anyhow::Result<Self> {
envy_load("tx_sink", "TX_SINK_")
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::EnvMutex;

static MUTEX: EnvMutex = EnvMutex::new();

fn expected_config() -> TxSinkConfig {
TxSinkConfig {
deny_list: Some("0x1234567890abcdef".to_string()),
}
}

#[test]
fn from_env() {
let mut lock = MUTEX.lock();
let config = r#"
TX_SINK_DENY_LIST="0x1234567890abcdef"
"#;
lock.set_env(config);

let actual = TxSinkConfig::from_env().unwrap();
assert_eq!(actual, expected_config());
}
}
2 changes: 2 additions & 0 deletions core/lib/protobuf_config/src/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ impl ProtoRepr for proto::GeneralConfig {
experimental_vm_config: read_optional_repr(&self.experimental_vm),
prover_job_monitor_config: read_optional_repr(&self.prover_job_monitor),
timestamp_asserter_config: read_optional_repr(&self.timestamp_asserter),
tx_sink_config: read_optional_repr(&self.tx_sink),
})
}

Expand Down Expand Up @@ -111,6 +112,7 @@ impl ProtoRepr for proto::GeneralConfig {
.timestamp_asserter_config
.as_ref()
.map(ProtoRepr::build),
tx_sink: this.tx_sink_config.as_ref().map(ProtoRepr::build),
}
}
}
1 change: 1 addition & 0 deletions core/lib/protobuf_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod snapshots_creator;
#[cfg(test)]
mod tests;
mod timestamp_asserter;
mod tx_sink;
mod utils;
mod vm_runner;
mod wallets;
Expand Down
2 changes: 2 additions & 0 deletions core/lib/protobuf_config/src/proto/config/general.proto
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import "zksync/core/consensus.proto";
import "zksync/config/prover_job_monitor.proto";
import "zksync/config/da_client.proto";
import "zksync/config/timestamp_asserter.proto";
import "zksync/config/tx_sink.proto";

message GeneralConfig {
optional database.Postgres postgres = 1;
Expand Down Expand Up @@ -64,4 +65,5 @@ message GeneralConfig {
optional prover_job_monitor.ProverJobMonitor prover_job_monitor = 45;
optional da_client.DataAvailabilityClient da_client = 46;
optional timestamp_asserter.TimestampAsserter timestamp_asserter = 47;
optional tx_sink.TxSink tx_sink = 100;
}
7 changes: 7 additions & 0 deletions core/lib/protobuf_config/src/proto/config/tx_sink.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
syntax = "proto3";

package zksync.config.tx_sink;

message TxSink {
optional string deny_list = 1; // optional
}
1 change: 1 addition & 0 deletions core/lib/protobuf_config/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ fn test_encoding() {
rng,
);
test_encode_all_formats::<ReprConv<proto::general::GeneralConfig>>(rng);
test_encode_all_formats::<ReprConv<proto::tx_sink::TxSink>>(rng);
}

#[test]
Expand Down
19 changes: 19 additions & 0 deletions core/lib/protobuf_config/src/tx_sink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use zksync_config::configs;
use zksync_protobuf::repr::ProtoRepr;

use crate::proto::tx_sink as proto;

impl ProtoRepr for proto::TxSink {
type Type = configs::tx_sink::TxSinkConfig;
fn read(&self) -> anyhow::Result<Self::Type> {
Ok(Self::Type {
deny_list: self.deny_list.clone(),
})
}

fn build(this: &Self::Type) -> Self {
Self {
deny_list: this.deny_list.clone(),
}
}
}
3 changes: 3 additions & 0 deletions core/lib/zksync_core_leftovers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub enum Component {
ExternalProofIntegrationApi,
/// VM runner-based component that allows to test experimental VM features. Doesn't save any data to Postgres.
VmPlayground,
/// Component for filtering L2 transactions by denylist
TxSinkDenyList,
}

#[derive(Debug)]
Expand Down Expand Up @@ -108,6 +110,7 @@ impl FromStr for Components {
"external_proof_integration_api" => {
Ok(Components(vec![Component::ExternalProofIntegrationApi]))
}
"deny_list" => Ok(Components(vec![Component::TxSinkDenyList])),
other => Err(format!("{} is not a valid component name", other)),
}
}
Expand Down
4 changes: 4 additions & 0 deletions core/lib/zksync_core_leftovers/src/temp_config_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use zksync_config::{
FriProverGatewayConfig, FriWitnessGeneratorConfig, FriWitnessVectorGeneratorConfig,
GeneralConfig, ObservabilityConfig, PrometheusConfig, ProofDataHandlerConfig,
ProtectiveReadsWriterConfig, ProverJobMonitorConfig, PruningConfig, SnapshotRecoveryConfig,
TxSinkConfig,
},
ApiConfig, BaseTokenAdjusterConfig, ContractVerifierConfig, DAClientConfig, DADispatcherConfig,
DBConfig, EthConfig, EthWatchConfig, ExternalProofIntegrationApiConfig, GasAdjusterConfig,
Expand Down Expand Up @@ -82,6 +83,7 @@ pub struct TempConfigStore {
pub experimental_vm_config: Option<ExperimentalVmConfig>,
pub prover_job_monitor_config: Option<ProverJobMonitorConfig>,
pub timestamp_asserter_config: Option<TimestampAsserterConfig>,
pub tx_sink_config: Option<TxSinkConfig>,
}

impl TempConfigStore {
Expand Down Expand Up @@ -124,6 +126,7 @@ impl TempConfigStore {
experimental_vm_config: self.experimental_vm_config.clone(),
prover_job_monitor_config: self.prover_job_monitor_config.clone(),
timestamp_asserter_config: self.timestamp_asserter_config.clone(),
tx_sink_config: self.tx_sink_config.clone(),
}
}

Expand Down Expand Up @@ -206,6 +209,7 @@ fn load_env_config() -> anyhow::Result<TempConfigStore> {
experimental_vm_config: ExperimentalVmConfig::from_env().ok(),
prover_job_monitor_config: ProverJobMonitorConfig::from_env().ok(),
timestamp_asserter_config: TimestampAsserterConfig::from_env().ok(),
tx_sink_config: TxSinkConfig::from_env().ok(),
})
}

Expand Down
43 changes: 43 additions & 0 deletions core/node/api_server/src/tx_sender/deny_list_pool_sink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::collections::HashSet;

use zksync_dal::transactions_dal::L2TxSubmissionResult;
use zksync_multivm::interface::{tracer::ValidationTraces, TransactionExecutionMetrics};
use zksync_types::{l2::L2Tx, Address};

use super::{master_pool_sink::MasterPoolSink, tx_sink::TxSink, SubmitTxError};
//use crate::api_server::tx_sender::master_pool_sink::MasterPoolSink;

/// Wrapper for the master DB pool that allows to submit transactions to the mempool.
#[derive(Debug)]
pub struct DenyListPoolSink {
deny_list: HashSet<Address>,
master_pool_sync: MasterPoolSink,
}

impl DenyListPoolSink {
pub fn new(master_pool_sync: MasterPoolSink, deny_list: HashSet<Address>) -> Self {
Self {
master_pool_sync,
deny_list,
}
}
}

#[async_trait::async_trait]
impl TxSink for DenyListPoolSink {
async fn submit_tx(
&self,
tx: &L2Tx,
execution_metrics: TransactionExecutionMetrics,
validation_traces: ValidationTraces,
) -> Result<L2TxSubmissionResult, SubmitTxError> {
let address_and_nonce = (tx.initiator_account(), tx.nonce());
if self.deny_list.contains(&address_and_nonce.0) {
return Err(SubmitTxError::SenderInDenyList(tx.initiator_account()));
}

self.master_pool_sync
.submit_tx(tx, execution_metrics, validation_traces)
.await
}
}
Loading
Loading