Skip to content

Commit

Permalink
feat(test): block conversion on sync tests (madara-alliance#283)
Browse files Browse the repository at this point in the history
Co-authored-by: 0xevolve <[email protected]>
  • Loading branch information
azurwastaken and EvolveArt authored Oct 2, 2024
1 parent 5e26c82 commit 7fb64ec
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Next release

- test: add block conversion task test
- fix(docs): updated readme and fixed launcher
- fix(ci): added gateway key to fix rate limit on tests
- feat(cli): launcher script and release workflows
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/client/block_import/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ repository.workspace = true
version.workspace = true
license.workspace = true

[features]
default = []
testing = []
[dependencies]
anyhow.workspace = true
bitvec.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/client/block_import/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#[cfg(test)]
#[cfg(any(test, feature = "testing"))]
pub mod block_import_utils;
28 changes: 27 additions & 1 deletion crates/client/block_import/src/tests/block_import_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use mp_block::header::{GasPrices, L1DataAvailabilityMode};
use mp_block::Header;
use mp_chain_config::StarknetVersion;
use mp_state_update::StateDiff;
use starknet_core::types::Felt;

use crate::{
BlockValidationContext, PreValidatedBlock, PreValidatedPendingBlock, UnverifiedHeader, ValidatedCommitments,
BlockValidationContext, PreValidatedBlock, PreValidatedPendingBlock, UnverifiedCommitments, UnverifiedFullBlock,
UnverifiedHeader, ValidatedCommitments,
};
use starknet_api::{core::ChainId, felt};

Expand Down Expand Up @@ -105,6 +107,30 @@ pub fn create_dummy_block() -> PreValidatedBlock {
}
}

/// Creates a dummy PreValidatedBlock for testing purposes.
///
/// This function generates a PreValidatedBlock with predefined values,
/// useful for testing update_tries scenarios.
pub fn create_dummy_unverified_full_block() -> UnverifiedFullBlock {
UnverifiedFullBlock {
header: UnverifiedHeader {
parent_block_hash: Some(Felt::ZERO),
sequencer_address: Felt::ZERO,
block_timestamp: 0,
protocol_version: StarknetVersion::default(),
l1_gas_price: GasPrices::default(),
l1_da_mode: L1DataAvailabilityMode::Blob,
},
transactions: vec![],
unverified_block_number: Some(0),
state_diff: StateDiff::default(),
receipts: vec![],
declared_classes: vec![],
commitments: UnverifiedCommitments::default(),
trusted_converted_classes: vec![],
}
}

/// Creates a dummy PreValidatedPendingBlock for testing purposes.
pub fn create_dummy_pending_block() -> PreValidatedPendingBlock {
PreValidatedPendingBlock {
Expand Down
3 changes: 3 additions & 0 deletions crates/client/sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mp-chain-config = { workspace = true }
mp-class = { workspace = true }
mp-convert = { workspace = true }
mp-receipt = { workspace = true }
mp-state-update = { workspace = true }
mp-transactions = { workspace = true }
mp-utils = { workspace = true }

Expand Down Expand Up @@ -61,3 +62,5 @@ url = { workspace = true }
httpmock = { workspace = true }
tempfile = { workspace = true }
rstest = { workspace = true }
mc-db = { workspace = true, features = ["testing"] }
mc-block-import = { workspace = true, features = ["testing"] }
174 changes: 174 additions & 0 deletions crates/client/sync/src/l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,177 @@ pub async fn sync(

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::tests::utils::gateway::{test_setup, TestContext};
use mc_block_import::tests::block_import_utils::create_dummy_unverified_full_block;
use mc_block_import::BlockImporter;
use mc_db::{db_block_id::DbBlockId, MadaraBackend};
use mc_metrics::MetricsRegistry;
use mc_telemetry::TelemetryService;
use mp_block::header::L1DataAvailabilityMode;
use mp_block::MadaraBlock;
use mp_chain_config::StarknetVersion;
use rstest::rstest;
use starknet_types_core::felt::Felt;
use std::sync::Arc;
use tokio::sync::mpsc;

/// Test the `l2_verify_and_apply_task` function.
///
///
/// This test verifies the behavior of the `l2_verify_and_apply_task` by simulating
/// a block verification and application process.
///
/// # Test Steps
/// 1. Initialize the backend and necessary components.
/// 2. Create a mock block.
/// 3. Spawn the `l2_verify_and_apply_task` in a new thread.
/// 4. Send the mock block for verification and application.
/// 5. Wait for the task to complete or for a timeout to occur.
/// 6. Verify that the block has been correctly applied to the backend.
///
/// # Panics
/// - If the task fails or if the waiting timeout is exceeded.
/// - If the block is not correctly applied to the backend.
#[rstest]
#[tokio::test]
async fn test_l2_verify_and_apply_task(test_setup: Arc<MadaraBackend>) {
let backend = test_setup;
let (block_conv_sender, block_conv_receiver) = mpsc::channel(100);
let block_importer =
Arc::new(BlockImporter::new(backend.clone(), &MetricsRegistry::dummy(), None, true).unwrap());
let validation = BlockValidationContext::new(backend.chain_config().chain_id.clone());
let telemetry = TelemetryService::new(true, vec![]).unwrap().new_handle();

let mock_block = create_dummy_unverified_full_block();

let task_handle = tokio::spawn(l2_verify_and_apply_task(
backend.clone(),
block_conv_receiver,
block_importer.clone(),
validation.clone(),
Some(1),
telemetry,
));

let mock_pre_validated_block = block_importer.pre_validate(mock_block, validation.clone()).await.unwrap();
block_conv_sender.send(mock_pre_validated_block).await.unwrap();

drop(block_conv_sender);

match tokio::time::timeout(std::time::Duration::from_secs(120), task_handle).await {
Ok(Ok(_)) => (),
Ok(Err(e)) => panic!("Task failed: {:?}", e),
Err(_) => panic!("Timeout reached while waiting for task completion"),
}

let applied_block = backend.get_block(&DbBlockId::BlockN(0)).unwrap();
assert!(applied_block.is_some(), "The block was not applied correctly");
let applied_block = MadaraBlock::try_from(applied_block.unwrap()).unwrap();

assert_eq!(applied_block.info.header.block_number, 0, "Block number does not match");
assert_eq!(applied_block.info.header.block_timestamp, 0, "Block timestamp does not match");
assert_eq!(applied_block.info.header.parent_block_hash, Felt::ZERO, "Parent block hash does not match");
assert!(applied_block.inner.transactions.is_empty(), "Block should not contain any transactions");
assert_eq!(
applied_block.info.header.protocol_version,
StarknetVersion::default(),
"Protocol version does not match"
);
assert_eq!(applied_block.info.header.sequencer_address, Felt::ZERO, "Sequencer address does not match");
assert_eq!(applied_block.info.header.l1_gas_price.eth_l1_gas_price, 0, "L1 gas price (ETH) does not match");
assert_eq!(applied_block.info.header.l1_gas_price.strk_l1_gas_price, 0, "L1 gas price (STRK) does not match");
assert_eq!(applied_block.info.header.l1_da_mode, L1DataAvailabilityMode::Blob, "L1 DA mode does not match");
}

/// Test the `l2_block_conversion_task` function.
///
/// Steps:
/// 1. Initialize necessary components.
/// 2. Create a mock block.
/// 3. Send the mock block to updates_sender
/// 4. Call the `l2_block_conversion_task` function with the mock data.
/// 5. Verify the results and ensure the function behaves as expected.
#[rstest]
#[tokio::test]
async fn test_l2_block_conversion_task(test_setup: Arc<MadaraBackend>) {
let backend = test_setup;
let (updates_sender, updates_receiver) = mpsc::channel(100);
let (output_sender, mut output_receiver) = mpsc::channel(100);
let block_import =
Arc::new(BlockImporter::new(backend.clone(), &MetricsRegistry::dummy(), None, true).unwrap());
let validation = BlockValidationContext::new(backend.chain_config().chain_id.clone());

let mock_block = create_dummy_unverified_full_block();

updates_sender.send(mock_block).await.unwrap();

let task_handle =
tokio::spawn(l2_block_conversion_task(updates_receiver, output_sender, block_import, validation));

let result = tokio::time::timeout(std::time::Duration::from_secs(5), output_receiver.recv()).await;
match result {
Ok(Some(b)) => {
assert_eq!(b.unverified_block_number, Some(0), "Block number does not match");
}
Ok(None) => panic!("Channel closed without receiving a result"),
Err(_) => panic!("Timeout reached while waiting for result"),
}

// Close the updates_sender channel to allow the task to complete
drop(updates_sender);

match tokio::time::timeout(std::time::Duration::from_secs(5), task_handle).await {
Ok(Ok(_)) => (),
Ok(Err(e)) => panic!("Task failed: {:?}", e),
Err(_) => panic!("Timeout reached while waiting for task completion"),
}
}

/// Test the `l2_pending_block_task` function.
///
/// This test function verifies the behavior of the `l2_pending_block_task`.
/// It simulates the necessary environment and checks that the task executes correctly
/// within a specified timeout.
///
/// # Test Steps
/// 1. Initialize the backend and test context.
/// 2. Create a `BlockImporter` and a `BlockValidationContext`.
/// 3. Spawn the `l2_pending_block_task` in a new thread.
/// 4. Simulate the "once_caught_up" signal.
/// 5. Wait for the task to complete or for a timeout to occur.
///
/// # Panics
/// - If the task fails or if the waiting timeout is exceeded.
#[rstest]
#[tokio::test]
async fn test_l2_pending_block_task(test_setup: Arc<MadaraBackend>) {
let backend = test_setup;
let ctx = TestContext::new(backend.clone());
let block_import =
Arc::new(BlockImporter::new(backend.clone(), &MetricsRegistry::dummy(), None, true).unwrap());
let validation = BlockValidationContext::new(backend.chain_config().chain_id.clone());

let task_handle = tokio::spawn(l2_pending_block_task(
backend.clone(),
block_import.clone(),
validation.clone(),
ctx.once_caught_up_receiver,
ctx.provider.clone(),
std::time::Duration::from_secs(5),
));

// Simulate the "once_caught_up" signal
ctx.once_caught_up_sender.send(()).unwrap();

// Wait for the task to complete
match tokio::time::timeout(std::time::Duration::from_secs(120), task_handle).await {
Ok(Ok(_)) => (),
Ok(Err(e)) => panic!("Task failed: {:?}", e),
Err(_) => panic!("Timeout reached while waiting for task completion"),
}
}
}

0 comments on commit 7fb64ec

Please sign in to comment.