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

Add more e2e tests #45

Merged
merged 5 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ sov-ledger-rpc = { git = "https://github.com/chainwayxyz/citrea", rev = "42693cc
sov-rollup-interface = { git = "https://github.com/chainwayxyz/citrea", rev = "42693cc"}

[patch.crates-io]
bitcoincore-rpc = { version = "0.18.0", git = "https://github.com/chainwayxyz/rust-bitcoincore-rpc.git", rev = "ede8097" }
bitcoincore-rpc = { version = "0.18.0", git = "https://github.com/chainwayxyz/rust-bitcoincore-rpc.git", rev = "5ce1bed" }
130 changes: 130 additions & 0 deletions tests/bitcoin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::time::Duration;

use anyhow::bail;
use async_trait::async_trait;
use bitcoincore_rpc::{json::IndexStatus, RpcApi};
use citrea_e2e::{
config::{BitcoinConfig, TestCaseConfig, TestCaseDockerConfig},
framework::TestFramework,
test_case::{TestCase, TestCaseRunner},
traits::Restart,
Result,
};

struct BasicSyncTest;

#[async_trait]
impl TestCase for BasicSyncTest {
fn test_config() -> TestCaseConfig {
TestCaseConfig {
with_sequencer: false,
n_nodes: 2,
timeout: Duration::from_secs(60),
docker: TestCaseDockerConfig {
bitcoin: true,
citrea: true,
},
..Default::default()
}
}

async fn run_test(&mut self, f: &mut TestFramework) -> Result<()> {
let (Some(da0), Some(da1)) = (f.bitcoin_nodes.get(0), f.bitcoin_nodes.get(1)) else {
bail!("bitcoind not running. Test should run with two da nodes")
};
let initial_height = f.initial_da_height;

f.bitcoin_nodes.wait_for_sync(None).await?;
let height0 = da0.get_block_count().await?;
let height1 = da1.get_block_count().await?;

// Assert that nodes are in sync before disconnection
assert_eq!(height0, height1, "Block heights don't match");

f.bitcoin_nodes.disconnect_nodes().await?;

// Generate some blocks on node0
da0.generate(5, None).await?;

let height0 = da0.get_block_count().await?;
let height1 = da1.get_block_count().await?;

// Nodes are now out of sync
assert_eq!(height0, initial_height + 5);
assert_eq!(height1, initial_height);

// Reconnect nodes and sync
f.bitcoin_nodes.connect_nodes().await?;
f.bitcoin_nodes.wait_for_sync(None).await?;

let height0 = da0.get_block_count().await?;
let height1 = da1.get_block_count().await?;

// Assert that nodes are back in sync
assert_eq!(height0, height1, "Block heights don't match");

Ok(())
}
}

#[tokio::test]
async fn test_basic_sync() -> Result<()> {
TestCaseRunner::new(BasicSyncTest).run().await
}

struct RestartBitcoinTest;

#[async_trait]
impl TestCase for RestartBitcoinTest {
fn test_config() -> TestCaseConfig {
TestCaseConfig {
with_sequencer: false,
docker: TestCaseDockerConfig {
bitcoin: true,
citrea: true,
},
..Default::default()
}
}

fn bitcoin_config() -> BitcoinConfig {
BitcoinConfig {
extra_args: vec!["-txindex=0"],
..Default::default()
}
}

async fn run_test(&mut self, f: &mut TestFramework) -> Result<()> {
let da = f.bitcoin_nodes.get_mut(0).unwrap();
// Add txindex flag to check that restart takes into account the extra args
let new_conf = BitcoinConfig {
extra_args: vec!["-txindex=1"],
..da.config.clone()
};

let block_before = da.get_block_count().await?;
let info = da.get_index_info().await?;

assert_eq!(info.txindex, None);

// Restart node with txindex
da.restart(Some(new_conf)).await?;

let block_after = da.get_block_count().await?;
let info = da.get_index_info().await?;

assert!(matches!(
info.txindex,
Some(IndexStatus { synced: true, .. })
));
// Assert that state is kept between restarts
assert_eq!(block_before, block_after);

Ok(())
}
}

#[tokio::test]
async fn test_restart_bitcoin() -> Result<()> {
TestCaseRunner::new(RestartBitcoinTest).run().await
}
71 changes: 71 additions & 0 deletions tests/docker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use async_trait::async_trait;
use bitcoincore_rpc::RpcApi;
use citrea_e2e::{
bitcoin::FINALITY_DEPTH,
config::{TestCaseConfig, TestCaseDockerConfig},
framework::TestFramework,
test_case::{TestCase, TestCaseRunner},
Result,
};

struct DockerIntegrationTest;

#[async_trait]
impl TestCase for DockerIntegrationTest {
fn test_config() -> TestCaseConfig {
TestCaseConfig {
with_batch_prover: true,
with_full_node: true,
docker: TestCaseDockerConfig {
bitcoin: true,
citrea: true,
},
..Default::default()
}
}

async fn run_test(&mut self, f: &mut TestFramework) -> Result<()> {
let sequencer = f.sequencer.as_ref().unwrap();
let batch_prover = f.batch_prover.as_ref().unwrap();
let full_node = f.full_node.as_ref().unwrap();
let da = f.bitcoin_nodes.get(0).unwrap();

let min_soft_confirmations_per_commitment =
sequencer.min_soft_confirmations_per_commitment();

for _ in 0..min_soft_confirmations_per_commitment {
sequencer.client.send_publish_batch_request().await?;
}

// Wait for blob inscribe tx to be in mempool
da.wait_mempool_len(1, None).await?;

da.generate(FINALITY_DEPTH, None).await?;
let finalized_height = da.get_finalized_height().await?;

batch_prover
.wait_for_l1_height(finalized_height, None)
.await?;

let commitments = full_node
.wait_for_sequencer_commitments(finalized_height, None)
.await?;

assert_eq!(commitments.len(), 1);

let unspent_sequencer = sequencer
.da
.list_unspent(None, None, None, None, None)
.await?;
let unspent_da = da.list_unspent(None, None, None, None, None).await?;
// Make sure sequencer.da and da don't hit the same wallet
assert_ne!(unspent_sequencer, unspent_da);

Ok(())
}
}

#[tokio::test]
async fn test_docker_integration() -> Result<()> {
TestCaseRunner::new(DockerIntegrationTest).run().await
}
73 changes: 2 additions & 71 deletions tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,2 @@
use async_trait::async_trait;
use bitcoincore_rpc::RpcApi;
use citrea_e2e::{
bitcoin::FINALITY_DEPTH,
config::{TestCaseConfig, TestCaseDockerConfig},
framework::TestFramework,
test_case::{TestCase, TestCaseRunner},
Result,
};

struct DockerIntegrationTest;

#[async_trait]
impl TestCase for DockerIntegrationTest {
fn test_config() -> TestCaseConfig {
TestCaseConfig {
with_batch_prover: true,
with_full_node: true,
docker: TestCaseDockerConfig {
bitcoin: true,
citrea: true,
},
..Default::default()
}
}

async fn run_test(&mut self, f: &mut TestFramework) -> Result<()> {
let sequencer = f.sequencer.as_ref().unwrap();
let batch_prover = f.batch_prover.as_ref().unwrap();
let full_node = f.full_node.as_ref().unwrap();
let da = f.bitcoin_nodes.get(0).unwrap();

let min_soft_confirmations_per_commitment =
sequencer.min_soft_confirmations_per_commitment();

for _ in 0..min_soft_confirmations_per_commitment {
sequencer.client.send_publish_batch_request().await?;
}

// Wait for blob inscribe tx to be in mempool
da.wait_mempool_len(1, None).await?;

da.generate(FINALITY_DEPTH, None).await?;
let finalized_height = da.get_finalized_height().await?;

batch_prover
.wait_for_l1_height(finalized_height, None)
.await?;

let commitments = full_node
.wait_for_sequencer_commitments(finalized_height, None)
.await?;

assert_eq!(commitments.len(), 1);

let unspent_sequencer = sequencer
.da
.list_unspent(None, None, None, None, None)
.await?;
let unspent_da = da.list_unspent(None, None, None, None, None).await?;
// Make sure sequencer.da and da don't hit the same wallet
assert_ne!(unspent_sequencer, unspent_da);

Ok(())
}
}

#[tokio::test]
async fn test_docker_integration() -> Result<()> {
TestCaseRunner::new(DockerIntegrationTest).run().await
}
mod bitcoin;
mod docker;
Loading