Skip to content

Commit 50f3d2f

Browse files
refactor: integration test suite (#389)
* refactor: integration test suite start height test test test test test test test adding integration test to ci short circuit review fixes * all * clippy stuff * warn log * docs
1 parent 82d6dfb commit 50f3d2f

10 files changed

Lines changed: 365 additions & 168 deletions

File tree

.github/workflows/ci.yml

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
- uses: taiki-e/install-action@nextest
4242

4343
- name: Set up Docker Buildx
44-
uses: docker/setup-buildx-action@v2
44+
uses: docker/setup-buildx-action@v3
4545

4646
- name: Expose github actions runtime
4747
uses: crazy-max/ghaction-github-runtime@v1
@@ -127,6 +127,7 @@ jobs:
127127
env:
128128
SP1_PROVER: mock
129129
SP1_SKIP_PROGRAM_BUILD: true
130+
COVERAGE_TEST: true
130131
name: coverage
131132
steps:
132133
- name: Checkout sources
@@ -140,9 +141,66 @@ jobs:
140141
- uses: taiki-e/install-action@cargo-llvm-cov
141142
- uses: taiki-e/install-action@nextest
142143

144+
- name: Set up Docker Buildx
145+
uses: docker/setup-buildx-action@v3
146+
147+
- name: Expose github actions runtime
148+
uses: crazy-max/ghaction-github-runtime@v1
149+
150+
- name: Build the docker-compose stack
151+
run: |
152+
cat > ci/cache.json <<EOF
153+
{
154+
"target": {
155+
"validator": {
156+
"cache-from": ["type=gha,scope=validator"],
157+
"cache-to": ["type=gha,mode=max,scope=validator"],
158+
"output": ["type=docker"]
159+
},
160+
"bridge-0": {
161+
"cache-from": ["type=gha,scope=bridge-0"],
162+
"cache-to": ["type=gha,mode=max,scope=bridge-0"],
163+
"output": ["type=docker"]
164+
},
165+
"bridge-1": {
166+
"cache-from": ["type=gha,scope=bridge-1"],
167+
"cache-to": ["type=gha,mode=max,scope=bridge-1"],
168+
"output": ["type=docker"]
169+
},
170+
"light-0": {
171+
"cache-from": ["type=gha,scope=light-0"],
172+
"cache-to": ["type=gha,mode=max,scope=light-0"],
173+
"output": ["type=docker"]
174+
}
175+
}
176+
}
177+
EOF
178+
cd ci && docker buildx bake --file docker-compose.yml --file cache.json --load
179+
180+
- name: Run the docker-compose stack
181+
run: docker compose -f ci/docker-compose.yml up --no-build -d
182+
183+
- name: Wait for bridge node 0 to start
184+
run: |
185+
while ! docker compose -f ci/docker-compose.yml logs bridge-0 | grep -q 'Configuration finished. Running a bridge node'; do
186+
sleep 1
187+
done
188+
189+
- name: Wait for bridge node 1 to start
190+
run: |
191+
while ! docker compose -f ci/docker-compose.yml logs bridge-1 | grep -q 'Configuration finished. Running a bridge node'; do
192+
sleep 1
193+
done
194+
195+
- name: Wait for light node 0 to start
196+
run: |
197+
while ! docker compose -f ci/docker-compose.yml logs light-0 | grep -q 'Configuration finished. Running a light node'; do
198+
sleep 1
199+
done
200+
143201
- name: Collect unit-test coverage data
144202
run: |
145-
cargo llvm-cov --no-report nextest --lib --release -- --skip test_light_client_prover_talking
203+
cargo llvm-cov --no-report nextest --lib --release
146204
cargo llvm-cov report --release --codecov --output-path codecov.info
147205
148206
- name: Upload coverage data to codecov

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/src/apply_args/da.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ mod tests {
164164
fn test_light_client_da_args_application() -> Result<()> {
165165
// Test light client DA args
166166
let mut light_client_config = LightClientDAConfig::Celestia(CelestiaLightClientDAConfig {
167+
bootnodes: vec![],
167168
celestia_network: CelestiaNetwork::Arabica,
168169
snark_namespace_id: "old_namespace".to_string(),
169170
fetch_timeout: Duration::from_secs(30),
@@ -207,6 +208,7 @@ mod tests {
207208
#[test]
208209
fn test_light_client_da_args_partial_override() -> Result<()> {
209210
let mut light_client_config = LightClientDAConfig::Celestia(CelestiaLightClientDAConfig {
211+
bootnodes: vec![],
210212
celestia_network: CelestiaNetwork::Arabica,
211213
snark_namespace_id: "old_namespace".to_string(),
212214
fetch_timeout: Duration::from_secs(30),
@@ -317,6 +319,7 @@ mod tests {
317319
fn test_no_da_type_specified() -> Result<()> {
318320
// When no DA type is specified in CLI args, config should remain unchanged
319321
let original_config = LightClientDAConfig::Celestia(CelestiaLightClientDAConfig {
322+
bootnodes: vec![],
320323
celestia_network: CelestiaNetwork::Arabica,
321324
snark_namespace_id: "original_namespace".to_string(),
322325
fetch_timeout: Duration::from_secs(30),
@@ -368,6 +371,7 @@ mod tests {
368371
#[test]
369372
fn test_celestia_store_type_disk_without_path_error() {
370373
let mut config = LightClientDAConfig::Celestia(CelestiaLightClientDAConfig {
374+
bootnodes: vec![],
371375
celestia_network: CelestiaNetwork::Arabica,
372376
snark_namespace_id: "namespace".to_string(),
373377
fetch_timeout: Duration::from_secs(30),

crates/da/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ prism-events = { workspace = true }
3232
prism-presets = { workspace = true }
3333
mockall = { workspace = true }
3434
bincode = { workspace = true }
35+
libp2p = { workspace = true }
3536

3637
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
3738
dirs = { workspace = true }

crates/da/src/celestia/light_client.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use anyhow::{Result, anyhow};
22
use async_trait::async_trait;
33
use celestia_types::nmt::Namespace;
4+
use libp2p::Multiaddr;
45
use lumina_node::{Node, NodeBuilder};
5-
#[cfg(target_arch = "wasm32")]
6-
use lumina_node::{blockstore::IndexedDbBlockstore, store::IndexedDbStore};
76
use prism_errors::DataAvailabilityError;
87
use prism_events::{EventChannel, EventPublisher};
8+
use std::{self, str::FromStr, sync::Arc, time::Duration};
9+
use tokio::sync::{Mutex, RwLock};
10+
use tracing::{trace, warn};
11+
12+
#[cfg(target_arch = "wasm32")]
13+
use lumina_node::{blockstore::IndexedDbBlockstore, store::IndexedDbStore};
914
use prism_presets::{ApplyPreset, LightClientPreset, PresetError};
1015
use serde::{Deserialize, Serialize};
1116
use serde_with::{DurationSeconds, serde_as};
12-
use std::{self, sync::Arc, time::Duration};
13-
use tokio::sync::{Mutex, RwLock};
14-
use tracing::{trace, warn};
1517
#[cfg(not(target_arch = "wasm32"))]
1618
use {
1719
blockstore::EitherBlockstore,
@@ -63,6 +65,15 @@ pub struct CelestiaLightClientDAConfig {
6365
/// Different networks have different block times and fee structures.
6466
pub celestia_network: CelestiaNetwork,
6567

68+
/// List of bootnodes to connect to.
69+
///
70+
/// Bootnodes are used to bootstrap the connection to the network.
71+
/// They are not required for normal operation but can help with initial
72+
/// connection in case the network is not fully connected or a custom network are used.
73+
///
74+
/// Are the String representations of libp2p multiaddresses on the Celestia network.
75+
pub bootnodes: Vec<String>,
76+
6677
/// Hex-encoded namespace ID for SNARK proofs.
6778
///
6879
/// Light clients will only download and verify data from this namespace,
@@ -204,6 +215,7 @@ impl Default for CelestiaLightClientDAConfig {
204215
Self {
205216
celestia_network: CelestiaNetwork::Arabica,
206217
snark_namespace_id: "00000000000000de1008".to_string(),
218+
bootnodes: Vec::new(),
207219
pruning_window: DEFAULT_PRUNING_WINDOW,
208220
fetch_timeout: DEFAULT_FETCH_TIMEOUT,
209221
fetch_max_retries: DEFAULT_FETCH_MAX_RETRIES,
@@ -342,11 +354,31 @@ impl LightClientConnection {
342354
pub async fn new(config: &CelestiaLightClientDAConfig) -> Result<Self, DataAvailabilityError> {
343355
let (blockstore, store) = Self::setup_stores(&config.store).await?;
344356

345-
let (node, event_subscriber) = NodeBuilder::new()
357+
let mut node = NodeBuilder::new()
346358
.network(config.celestia_network.clone())
347359
.store(store)
348360
.blockstore(blockstore)
349-
.pruning_window(config.pruning_window)
361+
.pruning_window(config.pruning_window);
362+
363+
if !config.bootnodes.is_empty() {
364+
let multiaddrs: Vec<Multiaddr> = config
365+
.bootnodes
366+
.clone()
367+
.into_iter()
368+
.filter_map(|addr| Multiaddr::from_str(&addr).ok())
369+
.collect();
370+
371+
if multiaddrs.len() != config.bootnodes.len() {
372+
warn!(
373+
"Some bootnodes failed to parse to libp2p multiaddrs. Valid addresses contain: {:#?}",
374+
multiaddrs
375+
);
376+
}
377+
378+
node = node.bootnodes(multiaddrs);
379+
}
380+
381+
let (node, event_subscriber) = node
350382
.start_subscribed()
351383
.await
352384
.map_err(|e| DataAvailabilityError::InitializationError(e.to_string()))?;

crates/node_types/lightclient/src/lightclient.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub struct LightClient {
9292

9393
// The latest commitment.
9494
latest_commitment: Arc<RwLock<Option<Digest>>>,
95+
96+
mock_proof_verification: bool,
9597
}
9698

9799
#[derive(Default, Clone)]
@@ -126,9 +128,25 @@ impl LightClient {
126128
latest_commitment: Arc::new(RwLock::new(None)),
127129
sync_state,
128130
cancellation_token,
131+
mock_proof_verification: false,
129132
}
130133
}
131134

135+
/// Enables mock proof verification for testing purposes only.
136+
///
137+
/// # Safety
138+
/// This method disables cryptographic proof verification, which is a critical
139+
/// security mechanism. It should ONLY be used in test environments and NEVER
140+
/// in production code.
141+
///
142+
/// # Usage
143+
/// This is intended for integration tests where proof generation/verification
144+
/// may be too slow or unavailable.
145+
pub fn enable_mock_proof_verification(&mut self) {
146+
error!("PROOF VERIFICATION IS DISABLED - FOR TESTING ONLY");
147+
self.mock_proof_verification = true;
148+
}
149+
132150
pub async fn get_sync_state(&self) -> SyncState {
133151
self.sync_state.read().await.clone()
134152
}
@@ -396,7 +414,10 @@ impl LightClient {
396414
height: epoch.height(),
397415
error: e.to_string(),
398416
});
399-
return Err(anyhow::anyhow!(e));
417+
if !self.mock_proof_verification {
418+
return Err(anyhow::anyhow!(e));
419+
}
420+
epoch.commitments()
400421
}
401422
};
402423
let curr_commitment = commitments.current;

crates/tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ prism-storage.workspace = true
2020
prism-prover = { workspace = true }
2121
prism-keys = { workspace = true }
2222
prism-lightclient = { workspace = true }
23+
celestia-rpc = { workspace = true }
2324
tokio-util = { workspace = true }
2425
prism-da.workspace = true
2526
rand.workspace = true

0 commit comments

Comments
 (0)