mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-26 11:51:13 +00:00
feat(integration_tests): multi-node config
This commit is contained in:
@@ -14,11 +14,12 @@ use integration_tests::{
|
||||
};
|
||||
use lee::program::Program;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use test_fixtures::config::MultiNodeTestContextConfig;
|
||||
use tokio::test;
|
||||
|
||||
#[test]
|
||||
async fn reject_oversized_transaction() -> Result<()> {
|
||||
let ctx = TestContext::builder()
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.with_sequencer_partial_config(SequencerPartialConfig {
|
||||
max_num_tx_in_block: 100,
|
||||
max_block_size: ByteSize::mib(1),
|
||||
@@ -61,7 +62,7 @@ async fn reject_oversized_transaction() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
async fn accept_transaction_within_limit() -> Result<()> {
|
||||
let ctx = TestContext::builder()
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.with_sequencer_partial_config(SequencerPartialConfig {
|
||||
max_num_tx_in_block: 100,
|
||||
max_block_size: ByteSize::mib(1),
|
||||
@@ -102,7 +103,7 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
|
||||
let max_program_size = claimer.elf().len().max(chain_caller.elf().len());
|
||||
let block_size = ByteSize::b((max_program_size + 10 * 1024) as u64);
|
||||
|
||||
let ctx = TestContext::builder()
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.with_sequencer_partial_config(SequencerPartialConfig {
|
||||
max_num_tx_in_block: 100,
|
||||
max_block_size: block_size,
|
||||
|
||||
@@ -19,6 +19,7 @@ use indexer_ffi::{
|
||||
};
|
||||
use integration_tests::{BlockingTestContext, TestContext};
|
||||
use tempfile::TempDir;
|
||||
use test_fixtures::config::MultiNodeTestContextConfig;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub unsafe fn query_last_block(indexer: *const IndexerServiceFFI) -> LastBlockIdResult;
|
||||
@@ -83,7 +84,9 @@ pub fn setup_indexer_ffi(bedrock_addr: SocketAddr) -> Result<(IndexerServiceFFI,
|
||||
}
|
||||
|
||||
pub fn setup() -> Result<(BlockingTestContext, IndexerServiceFFI, TempDir)> {
|
||||
let ctx = TestContext::builder().disable_indexer().build_blocking()?;
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.disable_indexer()
|
||||
.build_blocking()?;
|
||||
// Don't borrow `ctx.runtime()`: `ctx` (and its by-value tokio runtime) is
|
||||
// moved into the returned tuple, which would leave any pointer into it
|
||||
// dangling. Pass a null runtime so the FFI owns its own — the same path the
|
||||
|
||||
@@ -10,6 +10,7 @@ use common::transaction::LeeTransaction;
|
||||
use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, get_account, new_account};
|
||||
use log::info;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use test_fixtures::config::MultiNodeTestContextConfig;
|
||||
use tokio::test;
|
||||
use wallet::{cli::Command, config::WalletConfigOverrides};
|
||||
|
||||
@@ -68,7 +69,7 @@ async fn deploy_invalid_program_fails() -> Result<()> {
|
||||
// An invalid program bytecode is rejected by the sequencer during block production, so the
|
||||
// deployment transaction is never included in a block. Shrink the wallet's polling window so
|
||||
// the command gives up quickly instead of waiting for the full default timeout.
|
||||
let mut ctx = TestContext::builder()
|
||||
let mut ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.with_wallet_config_overrides(WalletConfigOverrides {
|
||||
seq_poll_timeout: Some(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)),
|
||||
seq_tx_poll_max_blocks: Some(5),
|
||||
|
||||
@@ -29,6 +29,7 @@ use lee_core::{
|
||||
use log::info;
|
||||
use sequencer_core::config::GenesisAction;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use test_fixtures::config::MultiNodeTestContextConfig;
|
||||
use tokio::test;
|
||||
|
||||
pub(crate) struct TpsTestManager {
|
||||
@@ -177,7 +178,7 @@ pub async fn tps_test() -> Result<()> {
|
||||
let target_tps = 8;
|
||||
|
||||
let tps_test = TpsTestManager::new(target_tps, num_transactions);
|
||||
let ctx = TestContext::builder()
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.with_sequencer_partial_config(TpsTestManager::generate_sequencer_partial_config())
|
||||
.with_genesis(tps_test.generate_genesis())
|
||||
.build()
|
||||
|
||||
@@ -28,6 +28,7 @@ use lee::{
|
||||
};
|
||||
use lee_core::program::DEFAULT_PROGRAM_ID;
|
||||
use log::info;
|
||||
use test_fixtures::config::MultiNodeTestContextConfig;
|
||||
use wallet::{account::HumanReadableAccount, program_facades::vault::Vault};
|
||||
use wallet_ffi::{
|
||||
FfiAccount, FfiAccountIdWithPrivacy, FfiAccountIdentity, FfiAccountList, FfiBytes32,
|
||||
@@ -389,7 +390,7 @@ fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> {
|
||||
|
||||
#[test]
|
||||
fn wallet_ffi_create_public_accounts() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let n_accounts = 10;
|
||||
|
||||
// Create `n_accounts` public accounts with wallet FFI
|
||||
@@ -430,7 +431,7 @@ fn wallet_ffi_create_public_accounts() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn wallet_ffi_create_private_accounts() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let n_accounts = 10;
|
||||
// Create `n_accounts` receiving keys with wallet FFI
|
||||
let new_npks_ffi = unsafe {
|
||||
@@ -465,7 +466,7 @@ fn wallet_ffi_create_private_accounts() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
// Create a receiving key and save
|
||||
let first_npk = unsafe {
|
||||
@@ -505,7 +506,7 @@ fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_list_accounts() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
// Create the wallet FFI and track which account IDs were created as public/private
|
||||
let (wallet_ffi_handle, created_public_ids) = unsafe {
|
||||
let home = tempfile::tempdir()?;
|
||||
@@ -574,7 +575,7 @@ fn test_wallet_ffi_list_accounts() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_balance_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
@@ -607,7 +608,7 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_account_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
@@ -647,7 +648,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_account_private() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
@@ -686,7 +687,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
@@ -728,7 +729,7 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
@@ -814,7 +815,7 @@ fn wallet_ffi_base58_to_account_id() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -880,7 +881,7 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -940,7 +941,7 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -997,7 +998,7 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1080,7 +1081,7 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1143,7 +1144,7 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_private() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1226,7 +1227,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn restore_keys_from_seed_ffi() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1523,7 +1524,7 @@ fn restore_keys_from_seed_ffi() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1586,7 +1587,7 @@ fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1680,7 +1681,7 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1789,7 +1790,7 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1874,7 +1875,7 @@ fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_vault_balance_and_claim_private() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -1966,7 +1967,7 @@ fn test_wallet_ffi_vault_balance_and_claim_private() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_single_label() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
@@ -2015,7 +2016,7 @@ fn test_wallet_ffi_single_label() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_more_labels() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let ctx = BlockingTestContext::new(MultiNodeTestContextConfig::default())?;
|
||||
let home = tempfile::tempdir()?;
|
||||
let FfiCreateWalletOutput {
|
||||
wallet: wallet_ffi_handle,
|
||||
|
||||
@@ -57,7 +57,7 @@ async fn generate_prebuilt_fixture(dest: &Path) -> Result<()> {
|
||||
.context("Failed to setup Sequencer for fixture generation")?;
|
||||
|
||||
let (mut wallet, _temp_wallet_dir, _wallet_password) = setup_wallet(
|
||||
sequencer_handle.addr(),
|
||||
&[sequencer_handle.addr()],
|
||||
&initial_public_accounts,
|
||||
&initial_private_accounts,
|
||||
WalletConfigOverrides::default(),
|
||||
|
||||
@@ -75,6 +75,20 @@ impl std::fmt::Display for UrlProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// Config for test context in multi-node case.
|
||||
///
|
||||
/// For now have only one field: `num_nodes`.
|
||||
pub struct MultiNodeTestContextConfig {
|
||||
pub num_nodes: usize,
|
||||
}
|
||||
|
||||
impl Default for MultiNodeTestContextConfig {
|
||||
fn default() -> Self {
|
||||
Self { num_nodes: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sequencer_config(
|
||||
partial: SequencerPartialConfig,
|
||||
home: PathBuf,
|
||||
@@ -211,13 +225,19 @@ pub fn genesis_from_accounts(
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn wallet_config(sequencer_addr: SocketAddr) -> Result<WalletConfig> {
|
||||
Ok(WalletConfig {
|
||||
sequencers: vec![SequencerConnectionData {
|
||||
sequencer_addr: addr_to_url(UrlProtocol::Http, sequencer_addr)
|
||||
pub fn wallet_config(sequencer_addrs: &[SocketAddr]) -> Result<WalletConfig> {
|
||||
let mut sequencers = vec![];
|
||||
|
||||
for addr in sequencer_addrs {
|
||||
sequencers.push(SequencerConnectionData {
|
||||
sequencer_addr: addr_to_url(UrlProtocol::Http, *addr)
|
||||
.context("Failed to convert sequencer addr to URL")?,
|
||||
basic_auth: None,
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
Ok(WalletConfig {
|
||||
sequencers,
|
||||
seq_poll_timeout: Duration::from_secs(30),
|
||||
seq_tx_poll_max_blocks: 15,
|
||||
seq_poll_max_retries: 10,
|
||||
|
||||
+102
-51
@@ -1,7 +1,7 @@
|
||||
//! Shared test/bench fixtures: spins up bedrock + sequencer + indexer + wallet
|
||||
//! end-to-end against docker-compose, exposes a `TestContext` callers can drive.
|
||||
|
||||
use std::{net::SocketAddr, path::Path, sync::LazyLock};
|
||||
use std::{collections::HashMap, net::SocketAddr, path::Path, sync::LazyLock};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use common::{HashType, transaction::LeeTransaction};
|
||||
@@ -22,6 +22,7 @@ use wallet::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::MultiNodeTestContextConfig,
|
||||
indexer_client::IndexerClient,
|
||||
setup::{
|
||||
SequencerSetup, setup_bedrock_node, setup_indexer,
|
||||
@@ -76,28 +77,36 @@ pub struct DiskSizes {
|
||||
/// as each instance uses its own temporary directories for sequencer and wallet data.
|
||||
// NOTE: Order of fields is important for proper drop order.
|
||||
pub struct TestContext {
|
||||
sequencer_client: SequencerClient,
|
||||
sequencer_clients: HashMap<SocketAddr, SequencerClient>,
|
||||
wallet: WalletCore,
|
||||
wallet_password: String,
|
||||
/// Optional to move out value in Drop.
|
||||
sequencer_handle: Option<SequencerHandle>,
|
||||
sequencer_handles: Option<Vec<SequencerHandle>>,
|
||||
indexer_components: Option<IndexerComponents>,
|
||||
bedrock_compose: DockerCompose,
|
||||
bedrock_addr: SocketAddr,
|
||||
temp_sequencer_dir: TempDir,
|
||||
temp_sequencer_dirs: Vec<TempDir>,
|
||||
temp_wallet_dir: TempDir,
|
||||
config: MultiNodeTestContextConfig,
|
||||
}
|
||||
|
||||
impl TestContext {
|
||||
/// Create new test context.
|
||||
pub async fn new_custom(config: MultiNodeTestContextConfig) -> Result<Self> {
|
||||
Self::builder(config).build().await
|
||||
}
|
||||
|
||||
/// Create new test context with default config.
|
||||
pub async fn new() -> Result<Self> {
|
||||
Self::builder().build().await
|
||||
Self::builder(MultiNodeTestContextConfig::default())
|
||||
.build()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get a builder for the test context to customize its configuration.
|
||||
#[must_use]
|
||||
pub fn builder() -> TestContextBuilder {
|
||||
TestContextBuilder::new()
|
||||
pub fn builder(config: MultiNodeTestContextConfig) -> TestContextBuilder {
|
||||
TestContextBuilder::new(config)
|
||||
}
|
||||
|
||||
/// Get reference to the wallet.
|
||||
@@ -116,10 +125,19 @@ impl TestContext {
|
||||
&mut self.wallet
|
||||
}
|
||||
|
||||
/// Get reference to the sequencer client in default case (1 sequencer).
|
||||
#[must_use]
|
||||
pub fn sequencer_client(&self) -> &SequencerClient {
|
||||
self.sequencer_clients
|
||||
.values()
|
||||
.next()
|
||||
.expect("Must be at least one sequencer client")
|
||||
}
|
||||
|
||||
/// Get reference to the sequencer client.
|
||||
#[must_use]
|
||||
pub const fn sequencer_client(&self) -> &SequencerClient {
|
||||
&self.sequencer_client
|
||||
pub fn sequencer_client_getter(&self, addr: &SocketAddr) -> Option<&SequencerClient> {
|
||||
self.sequencer_clients.get(addr)
|
||||
}
|
||||
|
||||
/// Get the Bedrock Node address.
|
||||
@@ -166,12 +184,21 @@ impl TestContext {
|
||||
.expect("Called `TestContext::indexer_client()` on context with disabled indexer")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Get the multi-node config.
|
||||
pub const fn config(&self) -> &MultiNodeTestContextConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
/// Recursively-sized bytes on disk for sequencer + indexer + wallet tempdirs.
|
||||
/// Indexer bytes are zero if the indexer is disabled.
|
||||
#[must_use]
|
||||
pub fn disk_sizes(&self) -> DiskSizes {
|
||||
DiskSizes {
|
||||
sequencer_bytes: dir_size_bytes(self.temp_sequencer_dir.path()),
|
||||
sequencer_bytes: self
|
||||
.temp_sequencer_dirs
|
||||
.iter()
|
||||
.fold(0, |acc, dir| acc.saturating_add(dir_size_bytes(dir.path()))),
|
||||
indexer_bytes: self
|
||||
.indexer_components
|
||||
.as_ref()
|
||||
@@ -206,28 +233,32 @@ impl TestContext {
|
||||
impl Drop for TestContext {
|
||||
fn drop(&mut self) {
|
||||
let Self {
|
||||
sequencer_handle,
|
||||
sequencer_handles,
|
||||
bedrock_compose,
|
||||
bedrock_addr: _,
|
||||
indexer_components: _,
|
||||
sequencer_client: _,
|
||||
sequencer_clients: _,
|
||||
wallet: _,
|
||||
wallet_password: _,
|
||||
temp_sequencer_dir: _,
|
||||
temp_sequencer_dirs: _,
|
||||
temp_wallet_dir: _,
|
||||
config: _,
|
||||
} = self;
|
||||
|
||||
let sequencer_handle = sequencer_handle
|
||||
let sequencer_handles = sequencer_handles
|
||||
.take()
|
||||
.expect("Sequencer handle should be present in TestContext drop");
|
||||
if !sequencer_handle.is_healthy() {
|
||||
let Err(err) = sequencer_handle
|
||||
.failed()
|
||||
.now_or_never()
|
||||
.expect("Sequencer handle should not be running");
|
||||
error!(
|
||||
"Sequencer handle has unexpectedly stopped before TestContext drop with error: {err:#}"
|
||||
);
|
||||
|
||||
for sequencer_handle in sequencer_handles {
|
||||
if !sequencer_handle.is_healthy() {
|
||||
let Err(err) = sequencer_handle
|
||||
.failed()
|
||||
.now_or_never()
|
||||
.expect("Sequencer handle should not be running");
|
||||
error!(
|
||||
"Sequencer handle has unexpectedly stopped before TestContext drop with error: {err:#}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let container = bedrock_compose
|
||||
@@ -256,16 +287,18 @@ pub struct TestContextBuilder {
|
||||
enable_indexer: bool,
|
||||
wallet_config_overrides: WalletConfigOverrides,
|
||||
from_scratch: bool,
|
||||
config: MultiNodeTestContextConfig,
|
||||
}
|
||||
|
||||
impl TestContextBuilder {
|
||||
fn new() -> Self {
|
||||
fn new(config: MultiNodeTestContextConfig) -> Self {
|
||||
Self {
|
||||
genesis_transactions: None,
|
||||
sequencer_partial_config: None,
|
||||
enable_indexer: true,
|
||||
wallet_config_overrides: WalletConfigOverrides::default(),
|
||||
from_scratch: false,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +353,7 @@ impl TestContextBuilder {
|
||||
enable_indexer,
|
||||
wallet_config_overrides,
|
||||
from_scratch,
|
||||
config,
|
||||
} = self;
|
||||
|
||||
// Ensure logger is initialized only once
|
||||
@@ -357,29 +391,48 @@ impl TestContextBuilder {
|
||||
|
||||
let partial_config = sequencer_partial_config.unwrap_or_default();
|
||||
|
||||
let mut sequencer_setup = SequencerSetup::new(partial_config, bedrock_addr);
|
||||
if !use_prebuilt {
|
||||
// Wallet genesis must always be present so that
|
||||
// setup_public/private_accounts_with_initial_supply can claim from the vault PDAs.
|
||||
// When a test supplies custom genesis, merge rather than replace.
|
||||
let wallet_genesis =
|
||||
config::genesis_from_accounts(&initial_public_accounts, &initial_private_accounts);
|
||||
let genesis = match genesis_transactions {
|
||||
Some(mut custom) => {
|
||||
custom.extend(wallet_genesis);
|
||||
custom
|
||||
}
|
||||
None => wallet_genesis,
|
||||
};
|
||||
sequencer_setup = sequencer_setup.with_genesis(genesis);
|
||||
let mut sequencer_handles = vec![];
|
||||
let mut temp_sequencer_dirs = vec![];
|
||||
let mut sequencer_clients = HashMap::new();
|
||||
|
||||
for _ in 0..config.num_nodes {
|
||||
let mut sequencer_setup = SequencerSetup::new(partial_config, bedrock_addr);
|
||||
if !use_prebuilt {
|
||||
// Wallet genesis must always be present so that
|
||||
// setup_public/private_accounts_with_initial_supply can claim from the vault PDAs.
|
||||
// When a test supplies custom genesis, merge rather than replace.
|
||||
let wallet_genesis = config::genesis_from_accounts(
|
||||
&initial_public_accounts,
|
||||
&initial_private_accounts,
|
||||
);
|
||||
let genesis = match genesis_transactions.clone() {
|
||||
Some(mut custom) => {
|
||||
custom.extend(wallet_genesis);
|
||||
custom
|
||||
}
|
||||
None => wallet_genesis,
|
||||
};
|
||||
sequencer_setup = sequencer_setup.with_genesis(genesis);
|
||||
}
|
||||
let (sequencer_handle, temp_sequencer_dir) = sequencer_setup
|
||||
.setup()
|
||||
.await
|
||||
.context("Failed to setup Sequencer")?;
|
||||
|
||||
let sequencer_client = setup::sequencer_client(sequencer_handle.addr())
|
||||
.context("Failed to create sequencer client")?;
|
||||
|
||||
sequencer_clients.insert(sequencer_handle.addr(), sequencer_client);
|
||||
|
||||
sequencer_handles.push(sequencer_handle);
|
||||
temp_sequencer_dirs.push(temp_sequencer_dir);
|
||||
}
|
||||
let (sequencer_handle, temp_sequencer_dir) = sequencer_setup
|
||||
.setup()
|
||||
.await
|
||||
.context("Failed to setup Sequencer")?;
|
||||
|
||||
let (mut wallet, temp_wallet_dir, wallet_password) = setup_wallet(
|
||||
sequencer_handle.addr(),
|
||||
&sequencer_handles
|
||||
.iter()
|
||||
.map(sequencer_service::SequencerHandle::addr)
|
||||
.collect::<Vec<_>>(),
|
||||
&initial_public_accounts,
|
||||
&initial_private_accounts,
|
||||
wallet_config_overrides,
|
||||
@@ -402,19 +455,17 @@ impl TestContextBuilder {
|
||||
.context("Failed to initialize private accounts in wallet")?;
|
||||
}
|
||||
|
||||
let sequencer_client = setup::sequencer_client(sequencer_handle.addr())
|
||||
.context("Failed to create sequencer client")?;
|
||||
|
||||
Ok(TestContext {
|
||||
sequencer_client,
|
||||
sequencer_clients,
|
||||
wallet,
|
||||
wallet_password,
|
||||
bedrock_compose,
|
||||
bedrock_addr,
|
||||
sequencer_handle: Some(sequencer_handle),
|
||||
sequencer_handles: Some(sequencer_handles),
|
||||
indexer_components,
|
||||
temp_sequencer_dir,
|
||||
temp_sequencer_dirs,
|
||||
temp_wallet_dir,
|
||||
config,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -437,8 +488,8 @@ pub struct BlockingTestContext {
|
||||
}
|
||||
|
||||
impl BlockingTestContext {
|
||||
pub fn new() -> Result<Self> {
|
||||
TestContext::builder().build_blocking()
|
||||
pub fn new(config: MultiNodeTestContextConfig) -> Result<Self> {
|
||||
TestContext::builder(config).build_blocking()
|
||||
}
|
||||
|
||||
pub const fn ctx(&self) -> &TestContext {
|
||||
|
||||
@@ -277,12 +277,13 @@ pub async fn setup_indexer(
|
||||
}
|
||||
|
||||
pub async fn setup_wallet(
|
||||
sequencer_addr: SocketAddr,
|
||||
sequencer_addrs: &[SocketAddr],
|
||||
initial_public_accounts: &[(PrivateKey, u128)],
|
||||
initial_private_accounts: &[InitialPrivateAccountForWallet],
|
||||
config_overrides: WalletConfigOverrides,
|
||||
) -> Result<(WalletCore, TempDir, String)> {
|
||||
let config = config::wallet_config(sequencer_addr).context("Failed to create Wallet config")?;
|
||||
let config =
|
||||
config::wallet_config(sequencer_addrs).context("Failed to create Wallet config")?;
|
||||
let config_serialized =
|
||||
serde_json::to_string_pretty(&config).context("Failed to serialize Wallet config")?;
|
||||
|
||||
|
||||
@@ -7,14 +7,20 @@ use lee::{AccountId, PublicKey};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use test_fixtures::{
|
||||
TestContext,
|
||||
config::{default_private_accounts_for_wallet, default_public_accounts_for_wallet},
|
||||
config::{
|
||||
MultiNodeTestContextConfig, default_private_accounts_for_wallet,
|
||||
default_public_accounts_for_wallet,
|
||||
},
|
||||
verify_commitment_is_in_state,
|
||||
};
|
||||
|
||||
/// Builds from genesis (no prebuilt database) and checks the on-chain state follows the config.
|
||||
#[tokio::test]
|
||||
async fn genesis_from_scratch_follows_config() -> Result<()> {
|
||||
let ctx = TestContext::builder().from_scratch().build().await?;
|
||||
let ctx = TestContext::builder(MultiNodeTestContextConfig::default())
|
||||
.from_scratch()
|
||||
.build()
|
||||
.await?;
|
||||
assert_context_follows_config(&ctx).await
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user