Skip to content

Commit 4cc00c5

Browse files
authored
Preferred sequencer fail early and cleary on DA-address mismatch (#2607)
* Preferred sequencer fail early and cleary on DA-address mismatch * extend tests * Extract into method
1 parent fcd992b commit 4cc00c5

File tree

2 files changed

+110
-4
lines changed

2 files changed

+110
-4
lines changed

crates/full-node/sov-sequencer/src/preferred/initialization.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::preferred::db::SequencerRole;
44
use anyhow::Context;
55
use anyhow::Result;
66
use sov_db::ledger_db::LedgerDb;
7+
use sov_modules_api::capabilities::SequencerRemuneration;
78
use sov_modules_api::rest::StateUpdateReceiver;
89
use std::net::SocketAddr;
910
use std::path::Path;
@@ -64,6 +65,10 @@ where
6465
.await
6566
.context("Sequencer must have DaService configured with submit support")?;
6667

68+
// Early check: verify that this node's DA signer matches the preferred
69+
// sequencer registered in the runtime.
70+
Self::check_runtime_address_match(&latest_state_update, da_address)?;
71+
6772
debug!(
6873
?latest_state_update,
6974
%da_address,
@@ -277,6 +282,35 @@ where
277282
Ok((seq, handles))
278283
}
279284

285+
fn check_runtime_address_match(
286+
latest_state_update: &StateUpdateInfo<<S as Spec>::Storage>,
287+
da_address: <<S as Spec>::Da as DaSpec>::Address,
288+
) -> anyhow::Result<()> {
289+
let mut runtime: Rt = Default::default();
290+
let mut checkpoint =
291+
StateCheckpoint::new(latest_state_update.storage.clone(), &runtime.kernel(), None);
292+
let registry_preferred = runtime
293+
.sequencer_remuneration()
294+
.preferred_sequencer(&mut checkpoint);
295+
match registry_preferred {
296+
Some(ref expected) if *expected == da_address => Ok(()),
297+
Some(expected) => {
298+
anyhow::bail!(
299+
"DA address mismatch: this node's DaService signer address is {da_address}, \
300+
but the preferred sequencer DA address in the sequencer registry is {expected}. \
301+
Check your DA service configuration."
302+
);
303+
}
304+
None => {
305+
anyhow::bail!(
306+
"No preferred sequencer is registered in the sequencer registry, \
307+
but this node is configured as a preferred sequencer. \
308+
Check the sequencer registry genesis configuration."
309+
);
310+
}
311+
}
312+
}
313+
280314
fn api_state(
281315
storage: S::Storage,
282316
) -> (
@@ -285,9 +319,9 @@ where
285319
) {
286320
let mut runtime: Rt = Default::default();
287321
assert!(
288-
accepts_preferred_batches(runtime.blob_selector()),
289-
"Attempting to use preferred sequencer with an incompatible rollup. Set your sequencer config to `standard` in your rollup's config.toml file or change your kernel to be compatible with soft confirmations."
290-
);
322+
accepts_preferred_batches(runtime.blob_selector()),
323+
"Attempting to use preferred sequencer with an incompatible rollup. Set your sequencer config to `standard` in your rollup's config.toml file or change your kernel to be compatible with soft confirmations."
324+
);
291325
let checkpoint = StateCheckpoint::new(storage, &runtime.kernel(), None);
292326
// Preferred sequencer deliberately treats the latest available slot as finalized
293327
// when initializing API state (soft-confirmation semantics).

crates/full-node/sov-sequencer/tests/integration/preferred_end_to_end.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ use sov_rollup_interface::node::da::DaService;
3333
use sov_rollup_interface::node::ledger_api::IncludeChildren;
3434
use sov_sequencer::{SequencerKindConfig, StateUpdateNotification};
3535
use sov_test_modules::hooks_count::HooksCount;
36-
use sov_test_utils::runtime::genesis::optimistic::HighLevelOptimisticGenesisConfig;
36+
use sov_test_utils::runtime::genesis::optimistic::{
37+
HighLevelOptimisticGenesisConfig, MinimalOptimisticGenesisConfig,
38+
};
3739
use sov_test_utils::test_rollup::FullNodeBlueprint;
3840
use sov_test_utils::test_rollup::StoragePath;
3941
use sov_test_utils::test_rollup::{GenesisSource, RollupBuilder, RollupProverConfig, TestRollup};
@@ -3725,6 +3727,74 @@ fn tx_assert_state_root(
37253727
encode_call::<TestRuntime<TestSpec>>(key, nonce, &msg)
37263728
}
37273729

3730+
#[tokio::test(flavor = "multi_thread")]
3731+
#[should_panic(expected = "DA address mismatch")]
3732+
async fn preferred_sequencer_fails_on_da_address_mismatch() {
3733+
let genesis_config = HighLevelOptimisticGenesisConfig::generate();
3734+
let genesis_params = GenesisParams {
3735+
runtime: <TestRuntime<TestSpec> as Runtime<TestSpec>>::GenesisConfig::from_minimal_config(
3736+
genesis_config.into(),
3737+
ValueSetterConfig {
3738+
admin: sov_modules_api::Address::from([0; 28]),
3739+
},
3740+
(),
3741+
PaymasterConfig::default(),
3742+
(),
3743+
(),
3744+
),
3745+
};
3746+
3747+
RollupBuilder::<TestBlueprint>::new(
3748+
GenesisSource::CustomParams(genesis_params),
3749+
DEFAULT_BLOCK_PRODUCING_CONFIG,
3750+
0,
3751+
)
3752+
.set_config(|conf| {
3753+
conf.sequencer_config = SequencerKindConfig::Preferred(Default::default());
3754+
})
3755+
.start()
3756+
.await
3757+
.unwrap();
3758+
}
3759+
3760+
#[tokio::test(flavor = "multi_thread")]
3761+
#[should_panic(expected = "No preferred sequencer is registered in the sequencer registry")]
3762+
async fn preferred_sequencer_fails_when_no_preferred_sequencer_in_registry() {
3763+
let genesis_config = HighLevelOptimisticGenesisConfig::generate();
3764+
let seq_da_address = HighLevelOptimisticGenesisConfig::<TestSpec>::sequencer_da_addr();
3765+
let mut minimal: MinimalOptimisticGenesisConfig<TestSpec> = genesis_config.into();
3766+
minimal
3767+
.config
3768+
.sequencer_registry
3769+
.sequencer_config
3770+
.is_preferred_sequencer = false;
3771+
let genesis_params = GenesisParams {
3772+
runtime: <TestRuntime<TestSpec> as Runtime<TestSpec>>::GenesisConfig::from_minimal_config(
3773+
minimal,
3774+
ValueSetterConfig {
3775+
admin: sov_modules_api::Address::from([0; 28]),
3776+
},
3777+
(),
3778+
PaymasterConfig::default(),
3779+
(),
3780+
(),
3781+
),
3782+
};
3783+
3784+
RollupBuilder::<TestBlueprint>::new(
3785+
GenesisSource::CustomParams(genesis_params),
3786+
DEFAULT_BLOCK_PRODUCING_CONFIG,
3787+
0,
3788+
)
3789+
.set_config(|conf| {
3790+
conf.sequencer_config = SequencerKindConfig::Preferred(Default::default());
3791+
})
3792+
.set_da_config(|c| c.sender_address = seq_da_address)
3793+
.start()
3794+
.await
3795+
.unwrap();
3796+
}
3797+
37283798
mod tests_with_basic_kernel {
37293799
use sov_modules_stf_blueprint::GenesisParams;
37303800
use sov_test_utils::test_rollup::{GenesisSource, RollupBuilder};
@@ -3745,6 +3815,7 @@ mod tests_with_basic_kernel {
37453815
)]
37463816
async fn preferred_sequencer_panics_with_basic_kernel() {
37473817
let genesis_config = HighLevelOptimisticGenesisConfig::generate();
3818+
let seq_da_address = HighLevelOptimisticGenesisConfig::<TestSpec>::sequencer_da_addr();
37483819
let genesis_params = GenesisParams {
37493820
runtime: GenesisConfig::from_minimal_config(genesis_config.into()),
37503821
};
@@ -3758,6 +3829,7 @@ mod tests_with_basic_kernel {
37583829
conf.sequencer_config =
37593830
sov_sequencer::SequencerKindConfig::Preferred(Default::default());
37603831
})
3832+
.set_da_config(|c| c.sender_address = seq_da_address)
37613833
.start()
37623834
.await
37633835
.unwrap();

0 commit comments

Comments
 (0)