mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-08 17:19:45 +00:00
fix: comments fix 1
This commit is contained in:
parent
cb2a0ab4ee
commit
33557b122f
@ -1,12 +1,12 @@
|
||||
//! This library contains common code for integration tests.
|
||||
|
||||
use std::{net::SocketAddr, path::PathBuf, sync::LazyLock};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use anyhow::{Context as _, Result};
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use futures::FutureExt as _;
|
||||
use indexer_service::IndexerHandle;
|
||||
use log::{debug, error, warn};
|
||||
use log::{debug, error};
|
||||
use nssa::{AccountId, PrivacyPreservingTransaction};
|
||||
use nssa_core::Commitment;
|
||||
use sequencer_core::indexer_client::{IndexerClient, IndexerClientTrait as _};
|
||||
@ -14,9 +14,12 @@ use sequencer_service::SequencerHandle;
|
||||
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
|
||||
use tempfile::TempDir;
|
||||
use testcontainers::compose::DockerCompose;
|
||||
use wallet::{WalletCore, config::WalletConfigOverrides};
|
||||
use wallet::WalletCore;
|
||||
|
||||
use crate::setup::{setup_bedrock_node, setup_indexer, setup_sequencer, setup_wallet};
|
||||
|
||||
pub mod config;
|
||||
pub mod setup;
|
||||
pub mod test_context_ffi;
|
||||
|
||||
// TODO: Remove this and control time from tests
|
||||
@ -68,13 +71,13 @@ impl TestContext {
|
||||
|
||||
debug!("Test context setup");
|
||||
|
||||
let (bedrock_compose, bedrock_addr) = Self::setup_bedrock_node().await?;
|
||||
let (bedrock_compose, bedrock_addr) = setup_bedrock_node().await?;
|
||||
|
||||
let (indexer_handle, temp_indexer_dir) = Self::setup_indexer(bedrock_addr, &initial_data)
|
||||
let (indexer_handle, temp_indexer_dir) = setup_indexer(bedrock_addr, &initial_data)
|
||||
.await
|
||||
.context("Failed to setup Indexer")?;
|
||||
|
||||
let (sequencer_handle, temp_sequencer_dir) = Self::setup_sequencer(
|
||||
let (sequencer_handle, temp_sequencer_dir) = setup_sequencer(
|
||||
sequencer_partial_config,
|
||||
bedrock_addr,
|
||||
indexer_handle.addr(),
|
||||
@ -84,7 +87,7 @@ impl TestContext {
|
||||
.context("Failed to setup Sequencer")?;
|
||||
|
||||
let (wallet, temp_wallet_dir, wallet_password) =
|
||||
Self::setup_wallet(sequencer_handle.addr(), &initial_data)
|
||||
setup_wallet(sequencer_handle.addr(), &initial_data)
|
||||
.await
|
||||
.context("Failed to setup wallet")?;
|
||||
|
||||
@ -113,165 +116,6 @@ impl TestContext {
|
||||
})
|
||||
}
|
||||
|
||||
async fn setup_bedrock_node() -> Result<(DockerCompose, SocketAddr)> {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let bedrock_compose_path =
|
||||
PathBuf::from(manifest_dir).join("../bedrock/docker-compose.yml");
|
||||
|
||||
let mut compose = DockerCompose::with_auto_client(&[bedrock_compose_path])
|
||||
.await
|
||||
.context("Failed to setup docker compose for Bedrock")?
|
||||
// Setting port to 0 to avoid conflicts between parallel tests, actual port will be retrieved after container is up
|
||||
.with_env("PORT", "0");
|
||||
|
||||
#[expect(
|
||||
clippy::items_after_statements,
|
||||
reason = "This is more readable is this function used just after its definition"
|
||||
)]
|
||||
async fn up_and_retrieve_port(compose: &mut DockerCompose) -> Result<u16> {
|
||||
compose
|
||||
.up()
|
||||
.await
|
||||
.context("Failed to bring up Bedrock services")?;
|
||||
let container = compose
|
||||
.service(BEDROCK_SERVICE_WITH_OPEN_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to get Bedrock service container `{BEDROCK_SERVICE_WITH_OPEN_PORT}`"
|
||||
)
|
||||
})?;
|
||||
|
||||
let ports = container.ports().await.with_context(|| {
|
||||
format!(
|
||||
"Failed to get ports for Bedrock service container `{}`",
|
||||
container.id()
|
||||
)
|
||||
})?;
|
||||
ports
|
||||
.map_to_host_port_ipv4(BEDROCK_SERVICE_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to retrieve host port of {BEDROCK_SERVICE_PORT} container \
|
||||
port for container `{}`, existing ports: {ports:?}",
|
||||
container.id()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let mut port = None;
|
||||
let mut attempt = 0_u32;
|
||||
let max_attempts = 5_u32;
|
||||
while port.is_none() && attempt < max_attempts {
|
||||
attempt = attempt
|
||||
.checked_add(1)
|
||||
.expect("We check that attempt < max_attempts, so this won't overflow");
|
||||
match up_and_retrieve_port(&mut compose).await {
|
||||
Ok(p) => {
|
||||
port = Some(p);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to bring up Bedrock services: {err:?}, attempt {attempt}/{max_attempts}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(port) = port else {
|
||||
bail!("Failed to bring up Bedrock services after {max_attempts} attempts");
|
||||
};
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
Ok((compose, addr))
|
||||
}
|
||||
|
||||
async fn setup_indexer(
|
||||
bedrock_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(IndexerHandle, TempDir)> {
|
||||
let temp_indexer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for indexer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp indexer home at {}",
|
||||
temp_indexer_dir.path().display()
|
||||
);
|
||||
|
||||
let indexer_config = config::indexer_config(
|
||||
bedrock_addr,
|
||||
temp_indexer_dir.path().to_owned(),
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Indexer config")?;
|
||||
|
||||
indexer_service::run_server(indexer_config, 0)
|
||||
.await
|
||||
.context("Failed to run Indexer Service")
|
||||
.map(|handle| (handle, temp_indexer_dir))
|
||||
}
|
||||
|
||||
async fn setup_sequencer(
|
||||
partial: config::SequencerPartialConfig,
|
||||
bedrock_addr: SocketAddr,
|
||||
indexer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(SequencerHandle, TempDir)> {
|
||||
let temp_sequencer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for sequencer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp sequencer home at {}",
|
||||
temp_sequencer_dir.path().display()
|
||||
);
|
||||
|
||||
let config = config::sequencer_config(
|
||||
partial,
|
||||
temp_sequencer_dir.path().to_owned(),
|
||||
bedrock_addr,
|
||||
indexer_addr,
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Sequencer config")?;
|
||||
|
||||
let sequencer_handle = sequencer_service::run(config, 0).await?;
|
||||
|
||||
Ok((sequencer_handle, temp_sequencer_dir))
|
||||
}
|
||||
|
||||
async fn setup_wallet(
|
||||
sequencer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(WalletCore, TempDir, String)> {
|
||||
let config = config::wallet_config(sequencer_addr, initial_data)
|
||||
.context("Failed to create Wallet config")?;
|
||||
let config_serialized =
|
||||
serde_json::to_string_pretty(&config).context("Failed to serialize Wallet config")?;
|
||||
|
||||
let temp_wallet_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for wallet home")?;
|
||||
|
||||
let config_path = temp_wallet_dir.path().join("wallet_config.json");
|
||||
std::fs::write(&config_path, config_serialized)
|
||||
.context("Failed to write wallet config in temp dir")?;
|
||||
|
||||
let storage_path = temp_wallet_dir.path().join("storage.json");
|
||||
let config_overrides = WalletConfigOverrides::default();
|
||||
|
||||
let wallet_password = "test_pass".to_owned();
|
||||
let (wallet, _mnemonic) = WalletCore::new_init_storage(
|
||||
config_path,
|
||||
storage_path,
|
||||
Some(config_overrides),
|
||||
&wallet_password,
|
||||
)
|
||||
.context("Failed to init wallet")?;
|
||||
wallet
|
||||
.store_persistent_data()
|
||||
.await
|
||||
.context("Failed to store wallet persistent data")?;
|
||||
|
||||
Ok((wallet, temp_wallet_dir, wallet_password))
|
||||
}
|
||||
|
||||
/// Get reference to the wallet.
|
||||
#[must_use]
|
||||
pub const fn wallet(&self) -> &WalletCore {
|
||||
|
||||
220
integration_tests/src/setup.rs
Normal file
220
integration_tests/src/setup.rs
Normal file
@ -0,0 +1,220 @@
|
||||
use std::{
|
||||
ffi::{CString, c_char},
|
||||
fs::File,
|
||||
io::Write,
|
||||
net::SocketAddr,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use indexer_ffi::{IndexerServiceFFI, api::lifecycle::InitializedIndexerServiceFFIResult};
|
||||
use indexer_service::IndexerHandle;
|
||||
use log::{debug, warn};
|
||||
use sequencer_service::SequencerHandle;
|
||||
use tempfile::TempDir;
|
||||
use testcontainers::compose::DockerCompose;
|
||||
use wallet::{WalletCore, config::WalletConfigOverrides};
|
||||
|
||||
use crate::{BEDROCK_SERVICE_PORT, BEDROCK_SERVICE_WITH_OPEN_PORT, config};
|
||||
|
||||
unsafe extern "C" {
|
||||
fn start_indexer(config_path: *const c_char, port: u16) -> InitializedIndexerServiceFFIResult;
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_bedrock_node() -> Result<(DockerCompose, SocketAddr)> {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let bedrock_compose_path = PathBuf::from(manifest_dir).join("../bedrock/docker-compose.yml");
|
||||
|
||||
let mut compose = DockerCompose::with_auto_client(&[bedrock_compose_path])
|
||||
.await
|
||||
.context("Failed to setup docker compose for Bedrock")?
|
||||
// Setting port to 0 to avoid conflicts between parallel tests, actual port will be retrieved after container is up
|
||||
.with_env("PORT", "0");
|
||||
|
||||
#[expect(
|
||||
clippy::items_after_statements,
|
||||
reason = "This is more readable is this function used just after its definition"
|
||||
)]
|
||||
async fn up_and_retrieve_port(compose: &mut DockerCompose) -> Result<u16> {
|
||||
compose
|
||||
.up()
|
||||
.await
|
||||
.context("Failed to bring up Bedrock services")?;
|
||||
let container = compose
|
||||
.service(BEDROCK_SERVICE_WITH_OPEN_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to get Bedrock service container `{BEDROCK_SERVICE_WITH_OPEN_PORT}`"
|
||||
)
|
||||
})?;
|
||||
|
||||
let ports = container.ports().await.with_context(|| {
|
||||
format!(
|
||||
"Failed to get ports for Bedrock service container `{}`",
|
||||
container.id()
|
||||
)
|
||||
})?;
|
||||
ports
|
||||
.map_to_host_port_ipv4(BEDROCK_SERVICE_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to retrieve host port of {BEDROCK_SERVICE_PORT} container \
|
||||
port for container `{}`, existing ports: {ports:?}",
|
||||
container.id()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let mut port = None;
|
||||
let mut attempt = 0_u32;
|
||||
let max_attempts = 5_u32;
|
||||
while port.is_none() && attempt < max_attempts {
|
||||
attempt = attempt
|
||||
.checked_add(1)
|
||||
.expect("We check that attempt < max_attempts, so this won't overflow");
|
||||
match up_and_retrieve_port(&mut compose).await {
|
||||
Ok(p) => {
|
||||
port = Some(p);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to bring up Bedrock services: {err:?}, attempt {attempt}/{max_attempts}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(port) = port else {
|
||||
bail!("Failed to bring up Bedrock services after {max_attempts} attempts");
|
||||
};
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
Ok((compose, addr))
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_indexer(
|
||||
bedrock_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(IndexerHandle, TempDir)> {
|
||||
let temp_indexer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for indexer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp indexer home at {}",
|
||||
temp_indexer_dir.path().display()
|
||||
);
|
||||
|
||||
let indexer_config = config::indexer_config(
|
||||
bedrock_addr,
|
||||
temp_indexer_dir.path().to_owned(),
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Indexer config")?;
|
||||
|
||||
indexer_service::run_server(indexer_config, 0)
|
||||
.await
|
||||
.context("Failed to run Indexer Service")
|
||||
.map(|handle| (handle, temp_indexer_dir))
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_sequencer(
|
||||
partial: config::SequencerPartialConfig,
|
||||
bedrock_addr: SocketAddr,
|
||||
indexer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(SequencerHandle, TempDir)> {
|
||||
let temp_sequencer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for sequencer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp sequencer home at {}",
|
||||
temp_sequencer_dir.path().display()
|
||||
);
|
||||
|
||||
let config = config::sequencer_config(
|
||||
partial,
|
||||
temp_sequencer_dir.path().to_owned(),
|
||||
bedrock_addr,
|
||||
indexer_addr,
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Sequencer config")?;
|
||||
|
||||
let sequencer_handle = sequencer_service::run(config, 0).await?;
|
||||
|
||||
Ok((sequencer_handle, temp_sequencer_dir))
|
||||
}
|
||||
|
||||
pub(crate) async fn setup_wallet(
|
||||
sequencer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(WalletCore, TempDir, String)> {
|
||||
let config = config::wallet_config(sequencer_addr, initial_data)
|
||||
.context("Failed to create Wallet config")?;
|
||||
let config_serialized =
|
||||
serde_json::to_string_pretty(&config).context("Failed to serialize Wallet config")?;
|
||||
|
||||
let temp_wallet_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for wallet home")?;
|
||||
|
||||
let config_path = temp_wallet_dir.path().join("wallet_config.json");
|
||||
std::fs::write(&config_path, config_serialized)
|
||||
.context("Failed to write wallet config in temp dir")?;
|
||||
|
||||
let storage_path = temp_wallet_dir.path().join("storage.json");
|
||||
let config_overrides = WalletConfigOverrides::default();
|
||||
|
||||
let wallet_password = "test_pass".to_owned();
|
||||
let (wallet, _mnemonic) = WalletCore::new_init_storage(
|
||||
config_path,
|
||||
storage_path,
|
||||
Some(config_overrides),
|
||||
&wallet_password,
|
||||
)
|
||||
.context("Failed to init wallet")?;
|
||||
wallet
|
||||
.store_persistent_data()
|
||||
.await
|
||||
.context("Failed to store wallet persistent data")?;
|
||||
|
||||
Ok((wallet, temp_wallet_dir, wallet_password))
|
||||
}
|
||||
|
||||
pub(crate) fn setup_indexer_ffi(
|
||||
bedrock_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(IndexerServiceFFI, TempDir)> {
|
||||
let temp_indexer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for indexer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp indexer home at {}",
|
||||
temp_indexer_dir.path().display()
|
||||
);
|
||||
|
||||
let indexer_config = config::indexer_config(
|
||||
bedrock_addr,
|
||||
temp_indexer_dir.path().to_owned(),
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Indexer config")?;
|
||||
|
||||
let config_json = serde_json::to_vec(&indexer_config)?;
|
||||
let config_path = temp_indexer_dir.path().join("indexer_config.json");
|
||||
let mut file = File::create(config_path.as_path())?;
|
||||
file.write_all(&config_json)?;
|
||||
file.flush()?;
|
||||
|
||||
let res =
|
||||
// SAFETY: lib function ensures validity of value.
|
||||
unsafe { start_indexer(CString::new(config_path.to_str().unwrap())?.as_ptr(), 0) };
|
||||
|
||||
if res.error.is_error() {
|
||||
anyhow::bail!("Indexer FFI error {:?}", res.error);
|
||||
}
|
||||
|
||||
Ok((
|
||||
// SAFETY: lib function ensures validity of value.
|
||||
unsafe { std::ptr::read(res.value) },
|
||||
temp_indexer_dir,
|
||||
))
|
||||
}
|
||||
@ -1,33 +1,23 @@
|
||||
use std::{
|
||||
ffi::{CString, c_char},
|
||||
fs::File,
|
||||
io::Write as _,
|
||||
net::SocketAddr,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use anyhow::{Context as _, Result};
|
||||
use futures::FutureExt as _;
|
||||
use indexer_ffi::{IndexerServiceFFI, api::lifecycle::InitializedIndexerServiceFFIResult};
|
||||
use indexer_ffi::IndexerServiceFFI;
|
||||
use indexer_service_rpc::RpcClient as _;
|
||||
use log::{debug, error, warn};
|
||||
use log::{debug, error};
|
||||
use nssa::AccountId;
|
||||
use sequencer_core::indexer_client::{IndexerClient, IndexerClientTrait as _};
|
||||
use sequencer_service::SequencerHandle;
|
||||
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
|
||||
use tempfile::TempDir;
|
||||
use testcontainers::compose::DockerCompose;
|
||||
use wallet::{WalletCore, config::WalletConfigOverrides};
|
||||
use wallet::WalletCore;
|
||||
|
||||
use crate::{
|
||||
BEDROCK_SERVICE_PORT, BEDROCK_SERVICE_WITH_OPEN_PORT, LOGGER, TestContextBuilder, config,
|
||||
BEDROCK_SERVICE_WITH_OPEN_PORT, LOGGER, TestContextBuilder, config,
|
||||
setup::{setup_bedrock_node, setup_indexer_ffi, setup_sequencer, setup_wallet},
|
||||
};
|
||||
|
||||
unsafe extern "C" {
|
||||
fn start_indexer(config_path: *const c_char, port: u16) -> InitializedIndexerServiceFFIResult;
|
||||
}
|
||||
|
||||
/// Test context which sets up a sequencer, indexer through ffi and a wallet for integration tests.
|
||||
///
|
||||
/// It's memory and logically safe to create multiple instances of this struct in parallel tests,
|
||||
@ -86,13 +76,13 @@ impl TestContextFFI {
|
||||
|
||||
debug!("Test context setup");
|
||||
|
||||
let (bedrock_compose, bedrock_addr) = runtime.block_on(Self::setup_bedrock_node())?;
|
||||
let (bedrock_compose, bedrock_addr) = runtime.block_on(setup_bedrock_node())?;
|
||||
|
||||
let (indexer_ffi, temp_indexer_dir) = Self::setup_indexer_ffi(bedrock_addr, initial_data)
|
||||
.context("Failed to setup Indexer")?;
|
||||
let (indexer_ffi, temp_indexer_dir) =
|
||||
setup_indexer_ffi(bedrock_addr, initial_data).context("Failed to setup Indexer")?;
|
||||
|
||||
let (sequencer_handle, temp_sequencer_dir) = runtime
|
||||
.block_on(Self::setup_sequencer(
|
||||
.block_on(setup_sequencer(
|
||||
sequencer_partial_config,
|
||||
bedrock_addr,
|
||||
// SAFETY: addr is valid if indexer_ffi is valid.
|
||||
@ -102,7 +92,7 @@ impl TestContextFFI {
|
||||
.context("Failed to setup Sequencer")?;
|
||||
|
||||
let (wallet, temp_wallet_dir, wallet_password) = runtime
|
||||
.block_on(Self::setup_wallet(sequencer_handle.addr(), initial_data))
|
||||
.block_on(setup_wallet(sequencer_handle.addr(), initial_data))
|
||||
.context("Failed to setup wallet")?;
|
||||
|
||||
let sequencer_url = config::addr_to_url(config::UrlProtocol::Http, sequencer_handle.addr())
|
||||
@ -136,180 +126,6 @@ impl TestContextFFI {
|
||||
))
|
||||
}
|
||||
|
||||
async fn setup_bedrock_node() -> Result<(DockerCompose, SocketAddr)> {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
let bedrock_compose_path =
|
||||
PathBuf::from(manifest_dir).join("../bedrock/docker-compose.yml");
|
||||
|
||||
let mut compose = DockerCompose::with_auto_client(&[bedrock_compose_path])
|
||||
.await
|
||||
.context("Failed to setup docker compose for Bedrock")?
|
||||
// Setting port to 0 to avoid conflicts between parallel tests, actual port will be retrieved after container is up
|
||||
.with_env("PORT", "0");
|
||||
|
||||
#[expect(
|
||||
clippy::items_after_statements,
|
||||
reason = "This is more readable is this function used just after its definition"
|
||||
)]
|
||||
async fn up_and_retrieve_port(compose: &mut DockerCompose) -> Result<u16> {
|
||||
compose
|
||||
.up()
|
||||
.await
|
||||
.context("Failed to bring up Bedrock services")?;
|
||||
let container = compose
|
||||
.service(BEDROCK_SERVICE_WITH_OPEN_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to get Bedrock service container `{BEDROCK_SERVICE_WITH_OPEN_PORT}`"
|
||||
)
|
||||
})?;
|
||||
|
||||
let ports = container.ports().await.with_context(|| {
|
||||
format!(
|
||||
"Failed to get ports for Bedrock service container `{}`",
|
||||
container.id()
|
||||
)
|
||||
})?;
|
||||
ports
|
||||
.map_to_host_port_ipv4(BEDROCK_SERVICE_PORT)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to retrieve host port of {BEDROCK_SERVICE_PORT} container \
|
||||
port for container `{}`, existing ports: {ports:?}",
|
||||
container.id()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let mut port = None;
|
||||
let mut attempt = 0_u32;
|
||||
let max_attempts = 5_u32;
|
||||
while port.is_none() && attempt < max_attempts {
|
||||
attempt = attempt
|
||||
.checked_add(1)
|
||||
.expect("We check that attempt < max_attempts, so this won't overflow");
|
||||
match up_and_retrieve_port(&mut compose).await {
|
||||
Ok(p) => {
|
||||
port = Some(p);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to bring up Bedrock services: {err:?}, attempt {attempt}/{max_attempts}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(port) = port else {
|
||||
bail!("Failed to bring up Bedrock services after {max_attempts} attempts");
|
||||
};
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
Ok((compose, addr))
|
||||
}
|
||||
|
||||
fn setup_indexer_ffi(
|
||||
bedrock_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(IndexerServiceFFI, TempDir)> {
|
||||
let temp_indexer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for indexer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp indexer home at {}",
|
||||
temp_indexer_dir.path().display()
|
||||
);
|
||||
|
||||
let indexer_config = config::indexer_config(
|
||||
bedrock_addr,
|
||||
temp_indexer_dir.path().to_owned(),
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Indexer config")?;
|
||||
|
||||
let config_json = serde_json::to_vec(&indexer_config)?;
|
||||
let config_path = temp_indexer_dir.path().join("indexer_config.json");
|
||||
let mut file = File::create(config_path.as_path())?;
|
||||
file.write_all(&config_json)?;
|
||||
file.flush()?;
|
||||
|
||||
let res =
|
||||
// SAFETY: lib function ensures validity of value.
|
||||
unsafe { start_indexer(CString::new(config_path.to_str().unwrap())?.as_ptr(), 0) };
|
||||
|
||||
if res.error.is_error() {
|
||||
anyhow::bail!("Indexer FFI error {:?}", res.error);
|
||||
}
|
||||
|
||||
Ok((
|
||||
// SAFETY: lib function ensures validity of value.
|
||||
unsafe { std::ptr::read(res.value) },
|
||||
temp_indexer_dir,
|
||||
))
|
||||
}
|
||||
|
||||
async fn setup_sequencer(
|
||||
partial: config::SequencerPartialConfig,
|
||||
bedrock_addr: SocketAddr,
|
||||
indexer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(SequencerHandle, TempDir)> {
|
||||
let temp_sequencer_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for sequencer home")?;
|
||||
|
||||
debug!(
|
||||
"Using temp sequencer home at {}",
|
||||
temp_sequencer_dir.path().display()
|
||||
);
|
||||
|
||||
let config = config::sequencer_config(
|
||||
partial,
|
||||
temp_sequencer_dir.path().to_owned(),
|
||||
bedrock_addr,
|
||||
indexer_addr,
|
||||
initial_data,
|
||||
)
|
||||
.context("Failed to create Sequencer config")?;
|
||||
|
||||
let sequencer_handle = sequencer_service::run(config, 0).await?;
|
||||
|
||||
Ok((sequencer_handle, temp_sequencer_dir))
|
||||
}
|
||||
|
||||
async fn setup_wallet(
|
||||
sequencer_addr: SocketAddr,
|
||||
initial_data: &config::InitialData,
|
||||
) -> Result<(WalletCore, TempDir, String)> {
|
||||
let config = config::wallet_config(sequencer_addr, initial_data)
|
||||
.context("Failed to create Wallet config")?;
|
||||
let config_serialized =
|
||||
serde_json::to_string_pretty(&config).context("Failed to serialize Wallet config")?;
|
||||
|
||||
let temp_wallet_dir =
|
||||
tempfile::tempdir().context("Failed to create temp dir for wallet home")?;
|
||||
|
||||
let config_path = temp_wallet_dir.path().join("wallet_config.json");
|
||||
std::fs::write(&config_path, config_serialized)
|
||||
.context("Failed to write wallet config in temp dir")?;
|
||||
|
||||
let storage_path = temp_wallet_dir.path().join("storage.json");
|
||||
let config_overrides = WalletConfigOverrides::default();
|
||||
|
||||
let wallet_password = "test_pass".to_owned();
|
||||
let (wallet, _mnemonic) = WalletCore::new_init_storage(
|
||||
config_path,
|
||||
storage_path,
|
||||
Some(config_overrides),
|
||||
&wallet_password,
|
||||
)
|
||||
.context("Failed to init wallet")?;
|
||||
wallet
|
||||
.store_persistent_data()
|
||||
.await
|
||||
.context("Failed to store wallet persistent data")?;
|
||||
|
||||
Ok((wallet, temp_wallet_dir, wallet_password))
|
||||
}
|
||||
|
||||
/// Get reference to the wallet.
|
||||
#[must_use]
|
||||
pub const fn wallet(&self) -> &WalletCore {
|
||||
|
||||
@ -10,8 +10,7 @@ use anyhow::{Context as _, Result};
|
||||
use indexer_service_rpc::RpcClient as _;
|
||||
use integration_tests::{
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_private_account_id,
|
||||
format_public_account_id, test_context_ffi::BlockingTestContextFFI,
|
||||
verify_commitment_is_in_state,
|
||||
format_public_account_id, verify_commitment_is_in_state,
|
||||
};
|
||||
use log::info;
|
||||
use nssa::AccountId;
|
||||
@ -276,269 +275,3 @@ async fn indexer_state_consistency_with_labels() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_test_run_ffi() -> Result<()> {
|
||||
let blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime();
|
||||
|
||||
// RUN OBSERVATION
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let last_block_indexer = blocking_ctx.ctx().get_last_block_indexer(runtime_wrapped)?;
|
||||
|
||||
info!("Last block on ind now is {last_block_indexer}");
|
||||
|
||||
assert!(last_block_indexer > 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_block_batching() -> Result<()> {
|
||||
let blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime();
|
||||
let ctx = blocking_ctx.ctx();
|
||||
|
||||
// WAIT
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let last_block_indexer = runtime_wrapped
|
||||
.block_on(ctx.indexer_client().get_last_finalized_block_id())
|
||||
.unwrap();
|
||||
|
||||
info!("Last block on ind now is {last_block_indexer}");
|
||||
|
||||
assert!(last_block_indexer > 1);
|
||||
|
||||
// Getting wide batch to fit all blocks (from latest backwards)
|
||||
let mut block_batch = runtime_wrapped
|
||||
.block_on(ctx.indexer_client().get_blocks(None, 100))
|
||||
.unwrap();
|
||||
|
||||
// Reverse to check chain consistency from oldest to newest
|
||||
block_batch.reverse();
|
||||
|
||||
// Checking chain consistency
|
||||
let mut prev_block_hash = block_batch.first().unwrap().header.hash;
|
||||
|
||||
for block in &block_batch[1..] {
|
||||
assert_eq!(block.header.prev_block_hash, prev_block_hash);
|
||||
|
||||
info!("Block {} chain-consistent", block.header.block_id);
|
||||
|
||||
prev_block_hash = block.header.hash;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_state_consistency() -> Result<()> {
|
||||
let mut blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime_clone();
|
||||
let ctx = blocking_ctx.ctx_mut();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: Some(format_public_account_id(ctx.existing_public_accounts()[0])),
|
||||
from_label: None,
|
||||
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
|
||||
to_label: None,
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
info!("Checking correct balance move");
|
||||
let acc_1_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc_2_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
info!("Balance of sender: {acc_1_balance:#?}");
|
||||
info!("Balance of receiver: {acc_2_balance:#?}");
|
||||
|
||||
assert_eq!(acc_1_balance, 9900);
|
||||
assert_eq!(acc_2_balance, 20100);
|
||||
|
||||
let from: AccountId = ctx.existing_private_accounts()[0];
|
||||
let to: AccountId = ctx.existing_private_accounts()[1];
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: Some(format_private_account_id(from)),
|
||||
from_label: None,
|
||||
to: Some(format_private_account_id(to)),
|
||||
to_label: None,
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
let new_commitment1 = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(from)
|
||||
.context("Failed to get private account commitment for sender")?;
|
||||
let commitment_check1 = runtime_wrapped.block_on(verify_commitment_is_in_state(
|
||||
new_commitment1,
|
||||
ctx.sequencer_client(),
|
||||
));
|
||||
assert!(commitment_check1);
|
||||
|
||||
let new_commitment2 = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(to)
|
||||
.context("Failed to get private account commitment for receiver")?;
|
||||
let commitment_check2 = runtime_wrapped.block_on(verify_commitment_is_in_state(
|
||||
new_commitment2,
|
||||
ctx.sequencer_client(),
|
||||
));
|
||||
assert!(commitment_check2);
|
||||
|
||||
info!("Successfully transferred privately to owned account");
|
||||
|
||||
// WAIT
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let acc1_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[0].into()),
|
||||
)?;
|
||||
let acc2_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[1].into()),
|
||||
)?;
|
||||
|
||||
info!("Checking correct state transition");
|
||||
let acc1_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc2_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc1_ind_state, acc1_seq_state.into());
|
||||
assert_eq!(acc2_ind_state, acc2_seq_state.into());
|
||||
|
||||
// ToDo: Check private state transition
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_state_consistency_with_labels() -> Result<()> {
|
||||
let mut blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime_clone();
|
||||
let ctx = blocking_ctx.ctx_mut();
|
||||
|
||||
// Assign labels to both accounts
|
||||
let from_label = "idx-sender-label".to_owned();
|
||||
let to_label_str = "idx-receiver-label".to_owned();
|
||||
|
||||
let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label {
|
||||
account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])),
|
||||
account_label: None,
|
||||
label: from_label.clone(),
|
||||
});
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?;
|
||||
|
||||
let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label {
|
||||
account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
|
||||
account_label: None,
|
||||
label: to_label_str.clone(),
|
||||
});
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?;
|
||||
|
||||
// Send using labels instead of account IDs
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: None,
|
||||
from_label: Some(from_label),
|
||||
to: None,
|
||||
to_label: Some(to_label_str),
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
let acc_1_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc_2_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc_1_balance, 9900);
|
||||
assert_eq!(acc_2_balance, 20100);
|
||||
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let acc1_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[0].into()),
|
||||
)?;
|
||||
let acc1_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc1_ind_state, acc1_seq_state.into());
|
||||
|
||||
info!("Indexer state is consistent after label-based transfer");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
284
integration_tests/tests/indexer_ffi.rs
Normal file
284
integration_tests/tests/indexer_ffi.rs
Normal file
@ -0,0 +1,284 @@
|
||||
#![expect(
|
||||
clippy::shadow_unrelated,
|
||||
clippy::tests_outside_test_module,
|
||||
reason = "We don't care about these in tests"
|
||||
)]
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use indexer_service_rpc::RpcClient as _;
|
||||
use integration_tests::{
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS, format_private_account_id, format_public_account_id,
|
||||
test_context_ffi::BlockingTestContextFFI, verify_commitment_is_in_state,
|
||||
};
|
||||
use log::info;
|
||||
use nssa::AccountId;
|
||||
use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand};
|
||||
|
||||
/// Maximum time to wait for the indexer to catch up to the sequencer.
|
||||
const L2_TO_L1_TIMEOUT_MILLIS: u64 = 180_000;
|
||||
|
||||
#[test]
|
||||
fn indexer_test_run_ffi() -> Result<()> {
|
||||
let blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime();
|
||||
|
||||
// RUN OBSERVATION
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let last_block_indexer = blocking_ctx.ctx().get_last_block_indexer(runtime_wrapped)?;
|
||||
|
||||
info!("Last block on ind now is {last_block_indexer}");
|
||||
|
||||
assert!(last_block_indexer > 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_block_batching() -> Result<()> {
|
||||
let blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime();
|
||||
let ctx = blocking_ctx.ctx();
|
||||
|
||||
// WAIT
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let last_block_indexer = runtime_wrapped
|
||||
.block_on(ctx.indexer_client().get_last_finalized_block_id())
|
||||
.unwrap();
|
||||
|
||||
info!("Last block on ind now is {last_block_indexer}");
|
||||
|
||||
assert!(last_block_indexer > 1);
|
||||
|
||||
// Getting wide batch to fit all blocks (from latest backwards)
|
||||
let mut block_batch = runtime_wrapped
|
||||
.block_on(ctx.indexer_client().get_blocks(None, 100))
|
||||
.unwrap();
|
||||
|
||||
// Reverse to check chain consistency from oldest to newest
|
||||
block_batch.reverse();
|
||||
|
||||
// Checking chain consistency
|
||||
let mut prev_block_hash = block_batch.first().unwrap().header.hash;
|
||||
|
||||
for block in &block_batch[1..] {
|
||||
assert_eq!(block.header.prev_block_hash, prev_block_hash);
|
||||
|
||||
info!("Block {} chain-consistent", block.header.block_id);
|
||||
|
||||
prev_block_hash = block.header.hash;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_state_consistency() -> Result<()> {
|
||||
let mut blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime_clone();
|
||||
let ctx = blocking_ctx.ctx_mut();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: Some(format_public_account_id(ctx.existing_public_accounts()[0])),
|
||||
from_label: None,
|
||||
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
|
||||
to_label: None,
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
info!("Checking correct balance move");
|
||||
let acc_1_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc_2_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
info!("Balance of sender: {acc_1_balance:#?}");
|
||||
info!("Balance of receiver: {acc_2_balance:#?}");
|
||||
|
||||
assert_eq!(acc_1_balance, 9900);
|
||||
assert_eq!(acc_2_balance, 20100);
|
||||
|
||||
let from: AccountId = ctx.existing_private_accounts()[0];
|
||||
let to: AccountId = ctx.existing_private_accounts()[1];
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: Some(format_private_account_id(from)),
|
||||
from_label: None,
|
||||
to: Some(format_private_account_id(to)),
|
||||
to_label: None,
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
let new_commitment1 = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(from)
|
||||
.context("Failed to get private account commitment for sender")?;
|
||||
let commitment_check1 = runtime_wrapped.block_on(verify_commitment_is_in_state(
|
||||
new_commitment1,
|
||||
ctx.sequencer_client(),
|
||||
));
|
||||
assert!(commitment_check1);
|
||||
|
||||
let new_commitment2 = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(to)
|
||||
.context("Failed to get private account commitment for receiver")?;
|
||||
let commitment_check2 = runtime_wrapped.block_on(verify_commitment_is_in_state(
|
||||
new_commitment2,
|
||||
ctx.sequencer_client(),
|
||||
));
|
||||
assert!(commitment_check2);
|
||||
|
||||
info!("Successfully transferred privately to owned account");
|
||||
|
||||
// WAIT
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let acc1_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[0].into()),
|
||||
)?;
|
||||
let acc2_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[1].into()),
|
||||
)?;
|
||||
|
||||
info!("Checking correct state transition");
|
||||
let acc1_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc2_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc1_ind_state, acc1_seq_state.into());
|
||||
assert_eq!(acc2_ind_state, acc2_seq_state.into());
|
||||
|
||||
// ToDo: Check private state transition
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexer_ffi_state_consistency_with_labels() -> Result<()> {
|
||||
let mut blocking_ctx = BlockingTestContextFFI::new()?;
|
||||
let runtime_wrapped = blocking_ctx.runtime_clone();
|
||||
let ctx = blocking_ctx.ctx_mut();
|
||||
|
||||
// Assign labels to both accounts
|
||||
let from_label = "idx-sender-label".to_owned();
|
||||
let to_label_str = "idx-receiver-label".to_owned();
|
||||
|
||||
let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label {
|
||||
account_id: Some(format_public_account_id(ctx.existing_public_accounts()[0])),
|
||||
account_label: None,
|
||||
label: from_label.clone(),
|
||||
});
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?;
|
||||
|
||||
let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label {
|
||||
account_id: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
|
||||
account_label: None,
|
||||
label: to_label_str.clone(),
|
||||
});
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?;
|
||||
|
||||
// Send using labels instead of account IDs
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: None,
|
||||
from_label: Some(from_label),
|
||||
to: None,
|
||||
to_label: Some(to_label_str),
|
||||
to_npk: None,
|
||||
to_vpk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
runtime_wrapped.block_on(wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(
|
||||
TIME_TO_WAIT_FOR_BLOCK_SECONDS,
|
||||
))
|
||||
.await;
|
||||
});
|
||||
|
||||
let acc_1_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
let acc_2_balance =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account_balance(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[1],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc_1_balance, 9900);
|
||||
assert_eq!(acc_2_balance, 20100);
|
||||
|
||||
info!("Waiting for indexer to parse blocks");
|
||||
runtime_wrapped.block_on(async {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)).await;
|
||||
});
|
||||
|
||||
let acc1_ind_state = runtime_wrapped.block_on(
|
||||
ctx.indexer_client()
|
||||
.get_account(ctx.existing_public_accounts()[0].into()),
|
||||
)?;
|
||||
let acc1_seq_state =
|
||||
runtime_wrapped.block_on(sequencer_service_rpc::RpcClient::get_account(
|
||||
ctx.sequencer_client(),
|
||||
ctx.existing_public_accounts()[0],
|
||||
))?;
|
||||
|
||||
assert_eq!(acc1_ind_state, acc1_seq_state.into());
|
||||
|
||||
info!("Indexer state is consistent after label-based transfer");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user