Skip to content
3 changes: 2 additions & 1 deletion configs/args/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"n_blocks_to_sync": null,
"stop_on_sync": false,
"backup_every_n_blocks": null,
"bouncer_config_sync_enable": false
"bouncer_config_sync_enable": false,
"disable_reorg": false
},
"l1_sync_params": {
"l1_sync_disabled": true,
Expand Down
30 changes: 29 additions & 1 deletion madara/crates/client/sync/src/gateway/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,17 @@ pub fn block_with_state_update_pipeline(
batch_size: usize,
keep_pre_v0_13_2_hashes: bool,
sync_bouncer_config: bool,
disable_reorg: bool,
) -> GatewayBlockSync {
PipelineController::new(
GatewaySyncSteps { _backend: backend, importer, client, keep_pre_v0_13_2_hashes, sync_bouncer_config },
GatewaySyncSteps {
_backend: backend,
importer,
client,
keep_pre_v0_13_2_hashes,
sync_bouncer_config,
disable_reorg,
},
parallelization,
batch_size,
starting_block_n,
Expand All @@ -44,6 +52,7 @@ pub struct GatewaySyncSteps {
client: Arc<GatewayProvider>,
keep_pre_v0_13_2_hashes: bool,
sync_bouncer_config: bool,
disable_reorg: bool,
}

impl GatewaySyncSteps {
Expand Down Expand Up @@ -291,6 +300,25 @@ impl PipelineSteps for GatewaySyncSteps {
block_n, incoming_parent_hash, local_parent_hash
);

// Check if reorg is disabled
if self.disable_reorg {
tracing::error!("❌ REORG DETECTED but reorg is explicitly denied by config!");
tracing::error!(" Block number: {}", block_n);
tracing::error!(" Expected parent hash: {:#x}", local_parent_hash);
tracing::error!(" Incoming parent hash: {:#x}", incoming_parent_hash);
tracing::error!("");
tracing::error!("⚠️ Divergent state detected - the local chain has diverged from the upstream chain.");
tracing::error!("⚠️ Blockchain reorganization is required but disabled by reorg is explicitly denied by config.");
tracing::error!("");
tracing::error!("To resolve this issue, you can:");
tracing::error!(" 1. Allow auto reorgs using the config");
tracing::error!(" 2. Manually investigate the divergence and wipe the database if needed");
anyhow::bail!(
"Reorg required but disabled by config. Parent hash mismatch at block {}: expected {:#x}, got {:#x}",
block_n, local_parent_hash, incoming_parent_hash
);
}

// Try to find common ancestor
match self.find_common_ancestor(block_n - 1).await {
Ok(common_ancestor_hash) => {
Expand Down
6 changes: 6 additions & 0 deletions madara/crates/client/sync/src/gateway/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct ForwardSyncConfig {
pub snap_sync: bool,
pub keep_pre_v0_13_2_hashes: bool,
pub enable_bouncer_config_sync: bool,
pub disable_reorg: bool,
}

impl Default for ForwardSyncConfig {
Expand All @@ -42,6 +43,7 @@ impl Default for ForwardSyncConfig {
snap_sync: false,
keep_pre_v0_13_2_hashes: false,
enable_bouncer_config_sync: false,
disable_reorg: false,
}
}
}
Expand All @@ -60,6 +62,9 @@ impl ForwardSyncConfig {
pub fn enable_bouncer_config_sync(self, val: bool) -> Self {
Self { enable_bouncer_config_sync: val, ..self }
}
pub fn disable_reorg(self, val: bool) -> Self {
Self { disable_reorg: val, ..self }
}
}

pub type GatewaySync = SyncController<GatewayForwardSync>;
Expand Down Expand Up @@ -110,6 +115,7 @@ impl GatewayForwardSync {
config.block_batch_size,
config.keep_pre_v0_13_2_hashes,
config.enable_bouncer_config_sync,
config.disable_reorg,
);
let classes_pipeline = classes::classes_pipeline(
backend.clone(),
Expand Down
6 changes: 6 additions & 0 deletions madara/node/src/cli/l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ pub struct L2SyncParams {
/// Enable bouncer config syncing.
#[arg(env = "MADARA_ENABLE_BOUNCER_CONFIG_SYNCING", long, default_value_t = false)]
pub bouncer_config_sync_enable: bool,

/// Disable blockchain reorganization. When enabled, if a divergent state is discovered,
/// the node will stop with an error instead of performing a reorg. This is useful for
/// operators who want to manually handle chain divergences.
#[clap(env = "MADARA_DISABLE_REORG", long, default_value_t = false)]
pub disable_reorg: bool,
}

impl L2SyncParams {
Expand Down
6 changes: 4 additions & 2 deletions madara/node/src/service/l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ impl Service for SyncService {
.disable_tries(this.params.disable_tries)
.snap_sync(this.params.snap_sync)
.keep_pre_v0_13_2_hashes(this.params.keep_pre_v0_13_2_hashes())
.enable_bouncer_config_sync(this.params.bouncer_config_sync_enable),
.enable_bouncer_config_sync(this.params.bouncer_config_sync_enable)
.disable_reorg(this.params.disable_reorg),
)
.run(ctx.clone())
.await?;
Expand Down Expand Up @@ -160,7 +161,8 @@ impl Service for SyncService {
.disable_tries(this.params.disable_tries)
.snap_sync(this.params.snap_sync)
.keep_pre_v0_13_2_hashes(this.params.keep_pre_v0_13_2_hashes())
.enable_bouncer_config_sync(this.params.bouncer_config_sync_enable),
.enable_bouncer_config_sync(this.params.bouncer_config_sync_enable)
.disable_reorg(this.params.disable_reorg),
)
.run(ctx)
.await
Expand Down
Loading