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(conductor)!: implement chain ID checks #1482

Merged
merged 24 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f63218c
Implemented chain ID checks for conductor
ethanoroshiba Sep 10, 2024
6b249a4
Minor updates
ethanoroshiba Sep 10, 2024
2e2bec9
Helm update
ethanoroshiba Sep 10, 2024
000cc2d
Evm stack version bump
ethanoroshiba Sep 10, 2024
5389721
evm-rollup inherits celestiaChainId from evm-stack
ethanoroshiba Sep 11, 2024
a5841c7
fix charts and smoke test
ethanoroshiba Sep 11, 2024
a6a0922
Merge branch 'main' into ENG-73/conductor_chain_id_verification
ethanoroshiba Sep 11, 2024
94ea853
minor improvements
ethanoroshiba Sep 11, 2024
0629f41
Slight improvements
ethanoroshiba Sep 11, 2024
fc1c5e5
Merge branch 'main' into ENG-73/conductor_chain_id_verification
ethanoroshiba Sep 16, 2024
5d75531
Bump chart versions
ethanoroshiba Sep 16, 2024
8a6c3ab
Merge branch 'main' into ENG-73/conductor_chain_id_verification
ethanoroshiba Sep 20, 2024
ee4e63c
Requested changes
ethanoroshiba Sep 20, 2024
0e01787
Clean up tests
ethanoroshiba Sep 20, 2024
a3f704a
Merge branch 'main' into ENG-73/conductor_chain_id_verification
ethanoroshiba Sep 25, 2024
7898474
Requested changes
ethanoroshiba Sep 25, 2024
f71c000
tapl fmt
ethanoroshiba Sep 25, 2024
1940d37
Chart bumps
ethanoroshiba Sep 25, 2024
878e84f
Requested changes
ethanoroshiba Sep 30, 2024
8510b64
Merge branch 'main' into ENG-73/conductor_chain_id_verification
ethanoroshiba Sep 30, 2024
c0be38b
requested changes
ethanoroshiba Sep 30, 2024
05a50b3
Merge branch 'ENG-73/conductor_chain_id_verification' of https://gith…
ethanoroshiba Sep 30, 2024
4d1f5aa
fix lasta few nits
SuperFluffy Oct 1, 2024
91c9768
Remove last ErrReport
ethanoroshiba Oct 1, 2024
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: 2 additions & 2 deletions charts/evm-rollup/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ 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.27.2
version: 0.27.3

# 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
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.14.0"
appVersion: "0.14.1"

maintainers:
- name: wafflesvonmaple
Expand Down
2 changes: 2 additions & 0 deletions charts/evm-rollup/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ data:
OTEL_SERVICE_NAME: "{{ tpl .Values.otel.serviceNamePrefix . }}-conductor"
{{- if not .Values.global.dev }}
{{- else }}
ASTRIA_CONDUCTOR_SEQUENCER_CHAIN_ID: "{{ tpl .Values.config.conductor.sequencerChainId . }}"
ASTRIA_CONDUCTOR_CELESTIA_CHAIN_ID: "{{ tpl .Values.config.conductor.celestiaChainId . }}"
{{- end }}
---
apiVersion: v1
Expand Down
4 changes: 3 additions & 1 deletion charts/evm-rollup/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ images:
conductor:
repo: ghcr.io/astriaorg/conductor
pullPolicy: IfNotPresent
tag: "0.20.0"
tag: "0.20.1"
devTag: latest


Expand Down Expand Up @@ -178,6 +178,8 @@ config:
sequencerGrpc: ""
# The maximum number of requests to make to the sequencer per second
sequencerRequestsPerSecond: 500
# The chain id of the celestia network the conductor communicates with
celestiaChainId: ""

celestia:
# if config.rollup.executionLevel is NOT 'SoftOnly' AND celestia-node is not enabled
Expand Down
6 changes: 3 additions & 3 deletions charts/evm-stack/Chart.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dependencies:
version: 0.3.6
- name: evm-rollup
repository: file://../evm-rollup
version: 0.27.2
version: 0.27.3
- name: composer
repository: file://../composer
version: 0.1.3
Expand All @@ -20,5 +20,5 @@ dependencies:
- name: blockscout-stack
repository: https://blockscout.github.io/helm-charts
version: 1.6.2
digest: sha256:7c27d6da529e8d1167805ece49047209936f51816b1d54c487e46c240dd4ed7a
generated: "2024-09-12T10:11:18.397241-07:00"
digest: sha256:0e67490b80b16f04e1e0ee5a1c5b904ff68084ecdd201ea74877e7e0e424da6f
generated: "2024-09-16T14:33:09.843263-05:00"
4 changes: 2 additions & 2 deletions charts/evm-stack/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ 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.5.2
version: 0.5.3

dependencies:
- name: celestia-node
version: 0.3.6
repository: "file://../celestia-node"
condition: celestia-node.enabled
- name: evm-rollup
version: 0.27.2
version: 0.27.3
repository: "file://../evm-rollup"
- name: composer
version: 0.1.3
Expand Down
2 changes: 2 additions & 0 deletions charts/evm-stack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ global:
rollupName: ""
evmChainId: ""
sequencerChainId: ""
celestiaChainId: ""
otel:
endpoint: ""
tracesEndpoint: ""
Expand All @@ -29,6 +30,7 @@ evm-rollup:
config:
conductor:
sequencerChainId: "{{ .Values.global.sequencerChainId }}"
celestiaChainId: "{{ .Values.global.celestiaChainId }}"
sequencerRpc: "{{ .Values.global.sequencerRpc }}"
sequencerGrpc: "{{ .Values.global.sequencerGrpc }}"
otel:
Expand Down
6 changes: 6 additions & 0 deletions crates/astria-conductor/local.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ ASTRIA_CONDUCTOR_SEQUENCER_BLOCK_TIME_MS=2000
# CometBFT node.
ASTRIA_CONDUCTOR_SEQUENCER_REQUESTS_PER_SECOND=500

# The chain ID of the sequencer network the conductor should be communicating with.
ASTRIA_CONDUCTOR_SEQUENCER_CHAIN_ID="test-sequencer-1000"

# The chain ID of the Celestia network the conductor should be communicating with.
ASTRIA_CONDUCTOR_CELESTIA_CHAIN_ID="test-celestia-1000"

# Set to true to enable prometheus metrics.
ASTRIA_CONDUCTOR_NO_METRICS=true

Expand Down
3 changes: 3 additions & 0 deletions crates/astria-conductor/src/celestia/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub(crate) struct Builder {
pub(crate) executor: executor::Handle,
pub(crate) sequencer_cometbft_client: SequencerClient,
pub(crate) sequencer_requests_per_second: u32,
pub(crate) celestia_chain_id: String,
ethanoroshiba marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) shutdown: CancellationToken,
pub(crate) metrics: &'static Metrics,
}
Expand All @@ -37,6 +38,7 @@ impl Builder {
executor,
sequencer_cometbft_client,
sequencer_requests_per_second,
celestia_chain_id,
shutdown,
metrics,
} = self;
Expand All @@ -50,6 +52,7 @@ impl Builder {
executor,
sequencer_cometbft_client,
sequencer_requests_per_second,
celestia_chain_id,
shutdown,
metrics,
})
Expand Down
56 changes: 55 additions & 1 deletion crates/astria-conductor/src/celestia/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use astria_core::{
use astria_eyre::eyre::{
self,
bail,
ensure,
WrapErr as _,
};
use bytes::Bytes;
use celestia_rpc::HeaderClient as _;
use celestia_types::nmt::Namespace;
use futures::{
future::{
Expand Down Expand Up @@ -95,6 +97,14 @@ use crate::{
executor,
};

#[derive(Debug, thiserror::Error)]
pub enum ValidateChainIdError {
#[error("failed to get the Celestia network head")]
GetCelestiaNetworkHead(#[source] jsonrpsee::core::Error),
#[error("expected Celestia chain id `{expected}` does not match actual: `{actual}`")]
MismatchedCelestiaChainId { expected: String, actual: String },
}

/// Sequencer Block information reconstructed from Celestia blobs.
///
/// Will be forwarded to the executor as a firm block.
Expand Down Expand Up @@ -139,6 +149,9 @@ pub(crate) struct Reader {
/// (usually to verify block data retrieved from Celestia blobs).
sequencer_requests_per_second: u32,

/// The chain ID of the Celestia network the reader should be communicating with.
celestia_chain_id: String,

/// Token to listen for Conductor being shut down.
shutdown: CancellationToken,

Expand Down Expand Up @@ -170,6 +183,17 @@ impl Reader {
async fn initialize(
ethanoroshiba marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
) -> eyre::Result<(executor::Handle<StateIsInit>, tendermint::chain::Id)> {
let actual_chain_id = get_celestia_chain_id(&self.celestia_client)
.await
.wrap_err("failed to fetch Celestia chain ID")?;
ensure!(
self.celestia_chain_id == actual_chain_id,
ValidateChainIdError::MismatchedCelestiaChainId {
expected: self.celestia_chain_id.clone(),
actual: actual_chain_id,
}
);

let wait_for_init_executor = async {
self.executor
.wait_for_init()
Expand All @@ -187,6 +211,34 @@ impl Reader {
}
}

#[instrument(skip_all, err)]
async fn get_celestia_chain_id(
celestia_client: &CelestiaClient,
) -> Result<String, ValidateChainIdError> {
let retry_config = tryhard::RetryFutureConfig::new(u32::MAX)
.exponential_backoff(Duration::from_millis(100))
.max_delay(Duration::from_secs(20))
.on_retry(
|attempt: u32, next_delay: Option<Duration>, error: &jsonrpsee::core::Error| {
let wait_duration = next_delay
.map(humantime::format_duration)
.map(tracing::field::display);
warn!(
attempt,
wait_duration,
error = error as &dyn std::error::Error,
"attempt to fetch celestia network header info; retrying after backoff",
);
futures::future::ready(())
},
);
let network_head = tryhard::retry_fn(|| celestia_client.header_network_head())
.with_config(retry_config)
.await
.map_err(ValidateChainIdError::GetCelestiaNetworkHead)?;
Ok(network_head.chain_id().to_string())
}

struct RunningReader {
block_cache: BlockCache<ReconstructedBlock>,

Expand Down Expand Up @@ -610,7 +662,9 @@ async fn enqueue_block(
}

#[instrument(skip_all, err)]
async fn get_sequencer_chain_id(client: SequencerClient) -> eyre::Result<tendermint::chain::Id> {
pub(crate) async fn get_sequencer_chain_id(
ethanoroshiba marked this conversation as resolved.
Show resolved Hide resolved
client: SequencerClient,
) -> eyre::Result<tendermint::chain::Id> {
use sequencer_client::Client as _;

let retry_config = tryhard::RetryFutureConfig::new(u32::MAX)
Expand Down
15 changes: 10 additions & 5 deletions crates/astria-conductor/src/conductor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use astria_eyre::eyre::{
eyre,
WrapErr as _,
};
pub use celestia::ValidateChainIdError as CelestiaChainIdError;
use itertools::Itertools as _;
use pin_project_lite::pin_project;
pub use sequencer::ValidateChainIdError as SequencerChainIdError;
use sequencer_client::HttpClient;
use tokio::{
select,
Expand Down Expand Up @@ -40,7 +42,7 @@ pin_project! {
/// A handle returned by [`Conductor::spawn`].
pub struct Handle {
shutdown_token: CancellationToken,
task: Option<tokio::task::JoinHandle<()>>,
task: Option<tokio::task::JoinHandle<eyre::Result<()>>>,
}
}

Expand All @@ -53,15 +55,15 @@ impl Handle {
/// # Panics
/// Panics if called twice.
#[instrument(skip_all, err)]
pub async fn shutdown(&mut self) -> Result<(), tokio::task::JoinError> {
pub async fn shutdown(&mut self) -> Result<eyre::Result<()>, tokio::task::JoinError> {
self.shutdown_token.cancel();
let task = self.task.take().expect("shutdown must not be called twice");
task.await
}
}

impl Future for Handle {
type Output = Result<(), tokio::task::JoinError>;
type Output = Result<eyre::Result<()>, tokio::task::JoinError>;

fn poll(
self: std::pin::Pin<&mut Self>,
Expand Down Expand Up @@ -131,6 +133,7 @@ impl Conductor {
sequencer_grpc_client,
sequencer_cometbft_client: sequencer_cometbft_client.clone(),
sequencer_block_time: Duration::from_millis(cfg.sequencer_block_time_ms),
sequencer_chain_id: cfg.sequencer_chain_id,
shutdown: shutdown.clone(),
executor: executor_handle.clone(),
}
Expand All @@ -152,6 +155,7 @@ impl Conductor {
executor: executor_handle.clone(),
sequencer_cometbft_client: sequencer_cometbft_client.clone(),
sequencer_requests_per_second: cfg.sequencer_requests_per_second,
celestia_chain_id: cfg.celestia_chain_id,
shutdown: shutdown.clone(),
metrics,
}
Expand All @@ -171,7 +175,7 @@ impl Conductor {
///
/// # Panics
/// Panics if it could not install a signal handler.
async fn run_until_stopped(mut self) {
async fn run_until_stopped(mut self) -> eyre::Result<()> {
info_span!("Conductor::run_until_stopped").in_scope(|| info!("conductor is running"));

let exit_reason = select! {
Expand All @@ -184,14 +188,15 @@ impl Conductor {
Some((name, res)) = self.tasks.join_next() => {
match flatten(res) {
Ok(()) => Err(eyre!("task `{name}` exited unexpectedly")),
Err(err) => Err(err).wrap_err_with(|| "task `{name}` failed"),
Err(err) => Err(err).wrap_err_with(|| "task `{name}` failed")?,
}
}
};

let message = "initiating shutdown";
report_exit(exit_reason, message);
self.shutdown().await;
Ok(())
}

/// Spawns Conductor on the tokio runtime.
Expand Down
6 changes: 6 additions & 0 deletions crates/astria-conductor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ pub struct Config {
/// The number of requests per second that will be sent to Sequencer.
pub sequencer_requests_per_second: u32,

/// The chain ID of the sequencer network the conductor should be communiacting with.
pub sequencer_chain_id: String,
ethanoroshiba marked this conversation as resolved.
Show resolved Hide resolved

/// The chain ID of the Celestia network the conductor should be communicating with.
pub celestia_chain_id: String,

/// Address of the RPC server for execution
pub execution_rpc_url: String,

Expand Down
3 changes: 3 additions & 0 deletions crates/astria-conductor/src/sequencer/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) struct Builder {
pub(crate) sequencer_grpc_client: SequencerGrpcClient,
pub(crate) sequencer_cometbft_client: sequencer_client::HttpClient,
pub(crate) sequencer_block_time: Duration,
pub(crate) sequencer_chain_id: String,
ethanoroshiba marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) shutdown: CancellationToken,
}

Expand All @@ -20,13 +21,15 @@ impl Builder {
sequencer_grpc_client,
sequencer_cometbft_client,
sequencer_block_time,
sequencer_chain_id,
shutdown,
} = self;
super::Reader {
executor,
sequencer_grpc_client,
sequencer_cometbft_client,
sequencer_block_time,
sequencer_chain_id,
shutdown,
}
}
Expand Down
Loading
Loading