diff --git a/charts/sequencer-relayer/Chart.yaml b/charts/sequencer-relayer/Chart.yaml index 5c393fef1e..772512cdb8 100644 --- a/charts/sequencer-relayer/Chart.yaml +++ b/charts/sequencer-relayer/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.8.3 +version: 0.8.4 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/sequencer-relayer/templates/configmaps.yaml b/charts/sequencer-relayer/templates/configmaps.yaml index 42dd63e23e..bcb1f68ecf 100644 --- a/charts/sequencer-relayer/templates/configmaps.yaml +++ b/charts/sequencer-relayer/templates/configmaps.yaml @@ -30,6 +30,8 @@ data: ASTRIA_SEQUENCER_RELAYER_ONLY_INCLUDE_ROLLUPS: "{{ .Values.config.relayer.onlyIncludeRollups }}" {{- if not .Values.global.dev }} {{- else }} + ASTRIA_SEQUENCER_RELAYER_SEQUENCER_CHAIN_ID: "{{ .Values.config.relayer.sequencerChainId }}" + ASTRIA_SEQUENCER_RELAYER_CELESTIA_CHAIN_ID: "{{ .Values.config.relayer.celestiaChainId }}" {{- end }} --- apiVersion: v1 diff --git a/charts/sequencer-relayer/values.yaml b/charts/sequencer-relayer/values.yaml index c2b2cba3ed..7b2d549022 100644 --- a/charts/sequencer-relayer/values.yaml +++ b/charts/sequencer-relayer/values.yaml @@ -18,6 +18,8 @@ images: config: relayer: + sequencerChainId: "" + celestiaChainId: "" celestiaAppGrpc: "" cometbftRpc: "" sequencerGrpc: "" diff --git a/charts/sequencer/Chart.lock b/charts/sequencer/Chart.lock index b70c65215a..119863c729 100644 --- a/charts/sequencer/Chart.lock +++ b/charts/sequencer/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: sequencer-relayer repository: file://../sequencer-relayer - version: 0.8.3 -digest: sha256:5299fcd71b8cac0aa3929a00830fa682d04d239700664a644b3010980704e867 -generated: "2024-05-28T13:16:38.413956-07:00" + version: 0.8.4 +digest: sha256:fa980cbe23353b162aad741afbf2ccde4d93b6d017be5fe478d5994bcfd1c992 +generated: "2024-05-30T17:09:44.161456347+01:00" diff --git a/charts/sequencer/Chart.yaml b/charts/sequencer/Chart.yaml index 203e1fdaf7..cf0d784873 100644 --- a/charts/sequencer/Chart.yaml +++ b/charts/sequencer/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.15.3 +version: 0.15.4 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,7 +25,7 @@ appVersion: "0.13.0" dependencies: - name: sequencer-relayer - version: "0.8.3" + version: "0.8.4" repository: "file://../sequencer-relayer" condition: sequencer-relayer.enabled diff --git a/crates/astria-sequencer-relayer/local.env.example b/crates/astria-sequencer-relayer/local.env.example index 968c136185..76b17a5828 100644 --- a/crates/astria-sequencer-relayer/local.env.example +++ b/crates/astria-sequencer-relayer/local.env.example @@ -19,6 +19,12 @@ ASTRIA_SEQUENCER_RELAYER_PRETTY_PRINT=false # `ASTRIA_SEQUENCER_RELAYER_PRETTY_PRINT` is set to `true`. NO_COLOR= +# The chain ID of the sequencer network from which this sequencer-relayer will fetch blocks. +ASTRIA_SEQUENCER_RELAYER_SEQUENCER_CHAIN_ID="sequencer-test-chain-0" + +# The chain ID of the Celestia network to which this sequencer-relayer will submit data. +ASTRIA_SEQUENCER_RELAYER_CELESTIA_CHAIN_ID="celestia-local-0" + # Address of cometbft/tendermint to request new block heights. # 127.0.0.1:26657 is the default socket address at which cometbft # serves RPCs. diff --git a/crates/astria-sequencer-relayer/src/config.rs b/crates/astria-sequencer-relayer/src/config.rs index a14d4f0ab4..c7dd7f8ae3 100644 --- a/crates/astria-sequencer-relayer/src/config.rs +++ b/crates/astria-sequencer-relayer/src/config.rs @@ -24,6 +24,8 @@ use serde::{ #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// The single config for creating an astria-sequencer-relayer service. pub struct Config { + pub sequencer_chain_id: String, + pub celestia_chain_id: String, pub cometbft_endpoint: String, pub sequencer_grpc_endpoint: String, pub celestia_app_grpc_endpoint: String, diff --git a/crates/astria-sequencer-relayer/src/relayer/builder.rs b/crates/astria-sequencer-relayer/src/relayer/builder.rs index d62fe04e6b..3943c20e13 100644 --- a/crates/astria-sequencer-relayer/src/relayer/builder.rs +++ b/crates/astria-sequencer-relayer/src/relayer/builder.rs @@ -27,6 +27,8 @@ use crate::{ pub(crate) struct Builder { pub(crate) shutdown_token: tokio_util::sync::CancellationToken, + pub(crate) sequencer_chain_id: String, + pub(crate) celestia_chain_id: String, pub(crate) celestia_app_grpc_endpoint: String, pub(crate) celestia_app_key_file: String, pub(crate) cometbft_endpoint: String, @@ -43,6 +45,8 @@ impl Builder { pub(crate) fn build(self) -> eyre::Result { let Self { shutdown_token, + sequencer_chain_id, + celestia_chain_id, celestia_app_grpc_endpoint, celestia_app_key_file, cometbft_endpoint, @@ -77,12 +81,13 @@ impl Builder { .wrap_err("failed parsing provided celestia app grpc endpoint as Uri")?; let celestia_keys = CelestiaKeys::from_path(celestia_app_key_file) .wrap_err("failed to get celestia keys from file")?; - CelestiaClientBuilder::new(uri, celestia_keys, state.clone()) + CelestiaClientBuilder::new(celestia_chain_id, uri, celestia_keys, state.clone()) .wrap_err("failed to create celestia client builder")? }; Ok(super::Relayer { shutdown_token, + sequencer_chain_id, sequencer_cometbft_client, sequencer_grpc_client, sequencer_poll_period, diff --git a/crates/astria-sequencer-relayer/src/relayer/celestia_client/builder.rs b/crates/astria-sequencer-relayer/src/relayer/celestia_client/builder.rs index b945e3d114..8ce86c130c 100644 --- a/crates/astria-sequencer-relayer/src/relayer/celestia_client/builder.rs +++ b/crates/astria-sequencer-relayer/src/relayer/celestia_client/builder.rs @@ -14,7 +14,10 @@ use tonic::transport::{ Channel, Endpoint, }; -use tracing::trace; +use tracing::{ + info, + trace, +}; use super::{ super::State, @@ -40,6 +43,14 @@ pub(in crate::relayer) enum BuilderError { /// The node info response was empty. #[error("the celestia node info response was empty")] EmptyNodeInfo, + /// Mismatch in Celestia chain ID. + #[error( + "mismatch in celestia chain id, configured id: `{configured}`, received id: `{received}`" + )] + MismatchedCelestiaChainId { + configured: String, + received: String, + }, } /// An error while encoding a Bech32 string. @@ -50,6 +61,7 @@ pub(in crate::relayer) struct Bech32EncodeError(#[from] bech32::EncodeError); /// A builder for a [`CelestiaClient`]. #[derive(Clone)] pub(in crate::relayer) struct Builder { + configured_celestia_chain_id: String, /// The inner `tonic` gRPC channel shared by the various generated gRPC clients. grpc_channel: Channel, /// The crypto keys associated with our Celestia account. @@ -63,6 +75,7 @@ pub(in crate::relayer) struct Builder { impl Builder { /// Returns a new `Builder`, or an error if Bech32-encoding the `signing_keys` address fails. pub(in crate::relayer) fn new( + configured_celestia_chain_id: String, uri: Uri, signing_keys: CelestiaKeys, state: Arc, @@ -70,6 +83,7 @@ impl Builder { let grpc_channel = Endpoint::from(uri).connect_lazy(); let address = bech32_encode(&signing_keys.address)?; Ok(Self { + configured_celestia_chain_id, grpc_channel, signing_keys, address, @@ -79,14 +93,24 @@ impl Builder { /// Returns a new `CelestiaClient` initialized with info retrieved from the Celestia app. pub(in crate::relayer) async fn try_build(self) -> Result { - let chain_id = self.fetch_chain_id().await?; + let reeceived_celestia_chain_id = self.fetch_celestia_chain_id().await?; let Self { + configured_celestia_chain_id, grpc_channel, signing_keys, address, state, } = self; + + if reeceived_celestia_chain_id != configured_celestia_chain_id { + return Err(BuilderError::MismatchedCelestiaChainId { + configured: configured_celestia_chain_id, + received: reeceived_celestia_chain_id, + }); + } + + info!(celestia_chain_id = %reeceived_celestia_chain_id, "confirmed celestia chain id"); state.set_celestia_connected(true); let tx_client = TxClient::new(grpc_channel.clone()); @@ -95,11 +119,11 @@ impl Builder { tx_client, signing_keys, address, - chain_id, + chain_id: reeceived_celestia_chain_id, }) } - async fn fetch_chain_id(&self) -> Result { + async fn fetch_celestia_chain_id(&self) -> Result { let mut node_info_client = NodeInfoClient::new(self.grpc_channel.clone()); let response = node_info_client.get_node_info(GetNodeInfoRequest {}).await; // trace-level logging, so using Debug format is ok. diff --git a/crates/astria-sequencer-relayer/src/relayer/mod.rs b/crates/astria-sequencer-relayer/src/relayer/mod.rs index 84ce3abf33..a6db75686e 100644 --- a/crates/astria-sequencer-relayer/src/relayer/mod.rs +++ b/crates/astria-sequencer-relayer/src/relayer/mod.rs @@ -14,6 +14,7 @@ use astria_core::{ use astria_eyre::eyre::{ self, bail, + ensure, eyre, WrapErr as _, }; @@ -27,6 +28,7 @@ use futures::{ }; use sequencer_client::{ tendermint::block::Height as SequencerHeight, + tendermint_rpc, HttpClient as SequencerClient, }; use tokio::{ @@ -46,7 +48,10 @@ use tracing::{ field::DisplayValue, info, instrument, + trace, warn, + Instrument, + Span, }; use crate::{ @@ -77,6 +82,9 @@ pub(crate) struct Relayer { /// A token to notify relayer that it should shut down. shutdown_token: CancellationToken, + /// The configured chain ID of the sequencer network. + sequencer_chain_id: String, + /// The client used to query the sequencer cometbft endpoint. sequencer_cometbft_client: SequencerClient, @@ -119,6 +127,14 @@ impl Relayer { .await .wrap_err("failed reading submission state from files")?; + select!( + () = self.shutdown_token.cancelled() => return Ok(()), + init_result = confirm_sequencer_chain_id( + self.sequencer_chain_id.clone(), + self.sequencer_cometbft_client.clone() + ) => init_result, + )?; + let last_submitted_sequencer_height = submission_state.last_submitted_height(); let mut latest_height_stream = { @@ -288,6 +304,62 @@ impl Relayer { } } +#[instrument(skip_all)] +async fn confirm_sequencer_chain_id( + configured_sequencer_chain_id: String, + sequencer_cometbft_client: SequencerClient, +) -> eyre::Result<()> { + let span = Span::current(); + + let retry_config = tryhard::RetryFutureConfig::new(u32::MAX) + .max_delay(Duration::from_secs(30)) + .exponential_backoff(Duration::from_secs(1)) + .on_retry( + |attempt: u32, next_delay: Option, error: &tendermint_rpc::Error| { + let wait_duration = next_delay + .map(humantime::format_duration) + .map(tracing::field::display); + warn!( + parent: &span, + attempt, + wait_duration, + error = %eyre::Report::new(error.clone()), + "failed to fetch sequencer chain id; retrying after backoff", + ); + futures::future::ready(()) + }, + ); + + let received_sequencer_chain_id = + tryhard::retry_fn(move || fetch_sequencer_chain_id(sequencer_cometbft_client.clone())) + .with_config(retry_config) + .in_current_span() + .await + .wrap_err("retry attempts exhausted; bailing")?; + + ensure!( + received_sequencer_chain_id == configured_sequencer_chain_id, + "configured sequencer chain ID does not match received; configured: \ + `{configured_sequencer_chain_id}`, received: `{received_sequencer_chain_id}`" + ); + info!(sequencer_chain_id = %configured_sequencer_chain_id, "confirmed sequencer chain id"); + Ok(()) +} + +async fn fetch_sequencer_chain_id( + sequencer_cometbft_client: SequencerClient, +) -> Result { + use sequencer_client::Client as _; + + let response = sequencer_cometbft_client.status().await; + // trace-level logging, so using Debug format is ok. + #[cfg_attr(dylint_lib = "tracing_debug_field", allow(tracing_debug_field))] + { + trace!(?response); + } + response.map(|status_response| status_response.node_info.network.to_string()) +} + async fn read_submission_state, P2: AsRef>( pre: P1, post: P2, diff --git a/crates/astria-sequencer-relayer/src/relayer/write/mod.rs b/crates/astria-sequencer-relayer/src/relayer/write/mod.rs index 03eaa6501f..28b23d4acc 100644 --- a/crates/astria-sequencer-relayer/src/relayer/write/mod.rs +++ b/crates/astria-sequencer-relayer/src/relayer/write/mod.rs @@ -156,6 +156,7 @@ impl BlobSubmitter { let client = init_result.map_err(|error| { let message = "failed to initialize celestia client"; error!(%error, message); + self.shutdown_token.cancel(); error.wrap_err(message) })?; @@ -355,9 +356,20 @@ async fn submit_blobs( async fn init_with_retry(client_builder: CelestiaClientBuilder) -> eyre::Result { let span = Span::current(); + let initial_retry_delay = Duration::from_secs(1); let retry_config = tryhard::RetryFutureConfig::new(u32::MAX) - .exponential_backoff(Duration::from_secs(1)) .max_delay(Duration::from_secs(30)) + .custom_backoff(|attempt: u32, error: &BuilderError| { + if matches!(error, BuilderError::MismatchedCelestiaChainId { .. }) { + // We got a good response from the Celestia app, but this is an unrecoverable error. + return tryhard::RetryPolicy::Break; + } + // This is equivalent to the `exponential_backoff` policy. Note that `max_delay` + // above is still respected regardless of what we return here. + let delay = + initial_retry_delay.saturating_mul(2_u32.saturating_pow(attempt.saturating_sub(1))); + tryhard::RetryPolicy::Delay(delay) + }) .on_retry( |attempt: u32, next_delay: Option, error: &BuilderError| { let wait_duration = next_delay @@ -378,7 +390,7 @@ async fn init_with_retry(client_builder: CelestiaClientBuilder) -> eyre::Result< .with_config(retry_config) .in_current_span() .await - .wrap_err("retry attempts exhausted; bailing")?; + .wrap_err("failed to initialize celestia client")?; info!("initialized celestia client"); Ok(celestia_client) } diff --git a/crates/astria-sequencer-relayer/src/sequencer_relayer.rs b/crates/astria-sequencer-relayer/src/sequencer_relayer.rs index a6d64da8c0..fa549b5a77 100644 --- a/crates/astria-sequencer-relayer/src/sequencer_relayer.rs +++ b/crates/astria-sequencer-relayer/src/sequencer_relayer.rs @@ -47,6 +47,8 @@ impl SequencerRelayer { let shutdown_handle = ShutdownHandle::new(); let rollup_filter = cfg.only_include_rollups()?; let Config { + sequencer_chain_id, + celestia_chain_id, cometbft_endpoint, sequencer_grpc_endpoint, celestia_app_grpc_endpoint, @@ -63,6 +65,8 @@ impl SequencerRelayer { let validator_key_path = relay_only_validator_key_blocks.then_some(validator_key_file); let relayer = relayer::Builder { shutdown_token: shutdown_handle.token(), + sequencer_chain_id, + celestia_chain_id, celestia_app_grpc_endpoint, celestia_app_key_file, cometbft_endpoint, diff --git a/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_celestia_app_server.rs b/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_celestia_app_server.rs index 0b74ff6269..a20690b70c 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_celestia_app_server.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/helpers/mock_celestia_app_server.rs @@ -91,7 +91,6 @@ use tonic::{ Status, }; -const CELESTIA_NETWORK_NAME: &str = "test-celestia"; const GET_NODE_INFO_GRPC_NAME: &str = "get_node_info"; const QUERY_ACCOUNT_GRPC_NAME: &str = "query_account"; const QUERY_AUTH_PARAMS_GRPC_NAME: &str = "query_auth_params"; @@ -108,14 +107,14 @@ pub struct MockCelestiaAppServer { } impl MockCelestiaAppServer { - pub async fn spawn() -> Self { + pub async fn spawn(celestia_chain_id: String) -> Self { use tokio_stream::wrappers::TcpListenerStream; let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let local_addr = listener.local_addr().unwrap(); let mock_server = MockServer::new(); - register_get_node_info(&mock_server).await; + register_get_node_info(&mock_server, celestia_chain_id).await; register_query_account(&mock_server).await; register_query_auth_params(&mock_server).await; register_query_blob_params(&mock_server).await; @@ -228,9 +227,9 @@ impl MockCelestiaAppServer { /// Registers a handler for all incoming `GetNodeInfoRequest`s which responds with the same /// `GetNodeInfoResponse` every time. -async fn register_get_node_info(mock_server: &MockServer) { +async fn register_get_node_info(mock_server: &MockServer, celestia_chain_id: String) { let default_node_info = Some(DefaultNodeInfo { - network: CELESTIA_NETWORK_NAME.to_string(), + network: celestia_chain_id, ..Default::default() }); let response = GetNodeInfoResponse { diff --git a/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs b/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs index dcba5ca0ea..bd87832690 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/helpers/test_sequencer_relayer.rs @@ -64,6 +64,9 @@ use super::{ SequencerBlockToMount, }; +const SEQUENCER_CHAIN_ID: &str = "test-sequencer"; +const CELESTIA_CHAIN_ID: &str = "test-celestia"; + /// Copied verbatim from /// [tendermint-rs](https://github.com/informalsystems/tendermint-rs/blob/main/config/tests/support/config/priv_validator_key.ed25519.json) const PRIVATE_VALIDATOR_KEY: &str = r#" @@ -80,6 +83,46 @@ const PRIVATE_VALIDATOR_KEY: &str = r#" } "#; +const STATUS_RESPONSE: &str = r#" +{ + "node_info": { + "protocol_version": { + "p2p": "8", + "block": "11", + "app": "0" + }, + "id": "a1d3bbddb7800c6da2e64169fec281494e963ba3", + "listen_addr": "tcp://0.0.0.0:26656", + "network": "test", + "version": "0.38.6", + "channels": "40202122233038606100", + "moniker": "fullnode", + "other": { + "tx_index": "on", + "rpc_address": "tcp://0.0.0.0:26657" + } + }, + "sync_info": { + "latest_block_hash": "A4202E4E367712AC2A797860265A7EBEA8A3ACE513CB0105C2C9058449641202", + "latest_app_hash": "BCC9C9B82A49EC37AADA41D32B4FBECD2441563703955413195BDA2236775A68", + "latest_block_height": "452605", + "latest_block_time": "2024-05-09T15:59:17.849713071Z", + "earliest_block_hash": "C34B7B0B82423554B844F444044D7D08A026D6E413E6F72848DB2F8C77ACE165", + "earliest_app_hash": "6B776065775471CEF46AC75DE09A4B869A0E0EB1D7725A04A342C0E46C16F472", + "earliest_block_height": "1", + "earliest_block_time": "2024-04-23T00:49:11.964127Z", + "catching_up": false + }, + "validator_info": { + "address": "0B46F33BA2FA5C2E2AD4C4C4E5ECE3F1CA03D195", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "bA6GipHUijVuiYhv+4XymdePBsn8EeTqjGqNQrBGZ4I=" + }, + "voting_power": "0" + } +}"#; + static TELEMETRY: Lazy<()> = Lazy::new(|| { astria_eyre::install().unwrap(); if std::env::var_os("TEST_LOG").is_some() { @@ -132,6 +175,12 @@ pub struct TestSequencerRelayer { pub pre_submit_file: NamedTempFile, pub post_submit_file: NamedTempFile, + /// The sequencer chain ID which will be returned by the mock `cometbft` instance, and set via + /// `TestSequencerRelayerConfig`. + pub actual_sequencer_chain_id: String, + /// The Celestia chain ID which will be returned by the mock `celestia_app` instance, and set + /// via `TestSequencerRelayerConfig`. + pub actual_celestia_chain_id: String, } impl Drop for TestSequencerRelayer { @@ -596,6 +645,24 @@ impl TestSequencerRelayer { }), ); } + + /// Mounts a `CometBFT` status response with the chain ID set as per + /// `TestSequencerRelayerConfig::sequencer_chain_id`. + async fn mount_cometbft_status_response(&self) { + use tendermint_rpc::endpoint::status; + + let mut status_response: status::Response = serde_json::from_str(STATUS_RESPONSE).unwrap(); + status_response.node_info.network = self.actual_sequencer_chain_id.parse().unwrap(); + + let response = Wrapper::new_with_id(Id::Num(1), Some(status_response), None); + wiremock::Mock::given(body_partial_json(json!({"method": "status"}))) + .respond_with(ResponseTemplate::new(200).set_body_json(response)) + .up_to_n_times(1) + .expect(1..) + .named("CometBFT status") + .mount(&self.cometbft) + .await; + } } // allow: want the name to reflect this is a test config. @@ -610,6 +677,10 @@ pub struct TestSequencerRelayerConfig { /// The rollup ID filter, to be stringified and provided as `Config::only_include_rollups` /// value. pub only_include_rollups: HashSet, + /// The sequencer chain ID. + pub sequencer_chain_id: String, + /// The Celestia chain ID. + pub celestia_chain_id: String, } impl TestSequencerRelayerConfig { @@ -622,7 +693,7 @@ impl TestSequencerRelayerConfig { ); Lazy::force(&TELEMETRY); - let celestia_app = MockCelestiaAppServer::spawn().await; + let celestia_app = MockCelestiaAppServer::spawn(self.celestia_chain_id.clone()).await; let celestia_app_grpc_endpoint = format!("http://{}", celestia_app.local_addr); let celestia_keyfile = write_file( b"c8076374e2a4a58db1c924e3dafc055e9685481054fe99e58ed67f5c6ed80e62".as_slice(), @@ -658,6 +729,8 @@ impl TestSequencerRelayerConfig { let only_include_rollups = self.only_include_rollups.iter().join(",").to_string(); let config = Config { + sequencer_chain_id: SEQUENCER_CHAIN_ID.to_string(), + celestia_chain_id: CELESTIA_CHAIN_ID.to_string(), cometbft_endpoint: cometbft.uri(), sequencer_grpc_endpoint, celestia_app_grpc_endpoint, @@ -683,7 +756,7 @@ impl TestSequencerRelayerConfig { let api_address = sequencer_relayer.local_addr(); let sequencer_relayer = tokio::task::spawn(sequencer_relayer.run()); - TestSequencerRelayer { + let test_sequencer_relayer = TestSequencerRelayer { api_address, celestia_app, config, @@ -696,6 +769,26 @@ impl TestSequencerRelayerConfig { validator_keyfile, pre_submit_file, post_submit_file, + actual_sequencer_chain_id: self.sequencer_chain_id, + actual_celestia_chain_id: self.celestia_chain_id, + }; + + test_sequencer_relayer + .mount_cometbft_status_response() + .await; + + test_sequencer_relayer + } +} + +impl Default for TestSequencerRelayerConfig { + fn default() -> Self { + Self { + relay_only_self: false, + last_written_sequencer_height: None, + only_include_rollups: HashSet::new(), + sequencer_chain_id: SEQUENCER_CHAIN_ID.to_string(), + celestia_chain_id: CELESTIA_CHAIN_ID.to_string(), } } } diff --git a/crates/astria-sequencer-relayer/tests/blackbox/main.rs b/crates/astria-sequencer-relayer/tests/blackbox/main.rs index bcd165f4f0..75f90060ec 100644 --- a/crates/astria-sequencer-relayer/tests/blackbox/main.rs +++ b/crates/astria-sequencer-relayer/tests/blackbox/main.rs @@ -20,13 +20,7 @@ const RELAY_ALL: bool = false; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn one_block_is_relayed_to_celestia() { - let sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, - last_written_sequencer_height: None, - only_include_rollups: HashSet::new(), - } - .spawn_relayer() - .await; + let sequencer_relayer = TestSequencerRelayerConfig::default().spawn_relayer().await; sequencer_relayer.mount_abci_response(1).await; let block_to_mount = SequencerBlockToMount::GoodAtHeight(1); @@ -69,13 +63,7 @@ async fn one_block_is_relayed_to_celestia() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn report_degraded_if_block_fetch_fails() { - let sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, - last_written_sequencer_height: None, - only_include_rollups: HashSet::new(), - } - .spawn_relayer() - .await; + let sequencer_relayer = TestSequencerRelayerConfig::default().spawn_relayer().await; // Relayer reports 200 on /readyz after start. let readyz_status = sequencer_relayer @@ -136,9 +124,8 @@ async fn report_degraded_if_block_fetch_fails() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn later_height_in_state_leads_to_expected_relay() { let sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, last_written_sequencer_height: Some(5), - only_include_rollups: HashSet::new(), + ..TestSequencerRelayerConfig::default() } .spawn_relayer() .await; @@ -183,13 +170,7 @@ async fn later_height_in_state_leads_to_expected_relay() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn three_blocks_are_relayed() { - let sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, - last_written_sequencer_height: None, - only_include_rollups: HashSet::new(), - } - .spawn_relayer() - .await; + let sequencer_relayer = TestSequencerRelayerConfig::default().spawn_relayer().await; sequencer_relayer.mount_abci_response(1).await; let block_to_mount = SequencerBlockToMount::GoodAtHeight(1); @@ -259,8 +240,7 @@ async fn three_blocks_are_relayed() { async fn block_from_other_proposer_is_skipped() { let sequencer_relayer = TestSequencerRelayerConfig { relay_only_self: true, - last_written_sequencer_height: None, - only_include_rollups: HashSet::new(), + ..TestSequencerRelayerConfig::default() } .spawn_relayer() .await; @@ -329,9 +309,8 @@ async fn should_filter_rollup() { let excluded_rollup_ids: HashSet<_> = (0..5).map(|x| RollupId::new([100 + x; 32])).collect(); let sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, - last_written_sequencer_height: None, only_include_rollups: included_rollup_ids.clone(), + ..TestSequencerRelayerConfig::default() } .spawn_relayer() .await; @@ -389,13 +368,7 @@ async fn should_filter_rollup() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn should_shut_down() { - let mut sequencer_relayer = TestSequencerRelayerConfig { - relay_only_self: false, - last_written_sequencer_height: None, - only_include_rollups: HashSet::new(), - } - .spawn_relayer() - .await; + let mut sequencer_relayer = TestSequencerRelayerConfig::default().spawn_relayer().await; // Start handling a block. sequencer_relayer.mount_abci_response(1).await; @@ -430,3 +403,27 @@ async fn should_shut_down() { sequencer_relayer.wait_for_relayer_shutdown(1_000).await; } + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn should_exit_if_sequencer_chain_id_mismatch() { + let mut sequencer_relayer = TestSequencerRelayerConfig { + sequencer_chain_id: "bad-id".to_string(), + ..TestSequencerRelayerConfig::default() + } + .spawn_relayer() + .await; + + sequencer_relayer.wait_for_relayer_shutdown(100).await; +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn should_exit_if_celestia_chain_id_mismatch() { + let mut sequencer_relayer = TestSequencerRelayerConfig { + celestia_chain_id: "bad-id".to_string(), + ..TestSequencerRelayerConfig::default() + } + .spawn_relayer() + .await; + + sequencer_relayer.wait_for_relayer_shutdown(100).await; +} diff --git a/dev/values/validators/node0.yml b/dev/values/validators/node0.yml index 907ce45e05..c58627c0c0 100644 --- a/dev/values/validators/node0.yml +++ b/dev/values/validators/node0.yml @@ -57,6 +57,8 @@ sequencer-relayer: enabled: true config: relayer: + sequencerChainId: sequencer-test-chain-0 + celestiaChainId: celestia-local-0 celestiaAppGrpc: http://celestia-app-service.astria-dev-cluster.svc.cluster.local:9090 cometbftRpc: http://node0-sequencer-rpc-service.astria-dev-cluster.svc.cluster.local:26657 sequencerGrpc: http://node0-sequencer-grpc-service.astria-dev-cluster.svc.cluster.local:8080 diff --git a/dev/values/validators/single.yml b/dev/values/validators/single.yml index 506ce8a560..b5f15f051a 100644 --- a/dev/values/validators/single.yml +++ b/dev/values/validators/single.yml @@ -33,12 +33,14 @@ sequencer-relayer: enabled: true config: relayer: + sequencerChainId: sequencer-test-chain-0 + celestiaChainId: celestia-local-0 celestiaAppGrpc: http://celestia-app-service.astria-dev-cluster.svc.cluster.local:9090 cometbftRpc: http://node0-sequencer-rpc-service.astria-dev-cluster.svc.cluster.local:26657 sequencerGrpc: http://node0-sequencer-grpc-service.astria-dev-cluster.svc.cluster.local:8080 celestiaAppPrivateKey: devContent: 8241386890823ca14743e5d4d583f879a5236af29f454ed4da6fe62b8439e2ab - + storage: enabled: false