mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-07-09 15:29:34 +00:00
Merge pull request #587 from logos-blockchain/arjentix/wallet-wait-for-tx-committed
feat!(wallet): wait for deploy tx inclusion in block
This commit is contained in:
commit
2921438e93
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1854,9 +1854,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
version = "0.9.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
@ -343,4 +343,4 @@ clippy.cargo = { level = "deny", priority = -1 }
|
||||
clippy.cargo-common-metadata = "allow"
|
||||
# Reason: hard to address right now and mostly comes from dependencies
|
||||
# so the fix would be just a long list of exceptions.
|
||||
clippy.multiple-crate-versions = "allow"
|
||||
clippy.multiple-crate-versions = "allow"
|
||||
|
||||
@ -69,8 +69,8 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
|
||||
});
|
||||
|
||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = result else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash } = result else {
|
||||
anyhow::bail!("Expected TransactionExecuted return value");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
@ -158,8 +158,8 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> {
|
||||
});
|
||||
|
||||
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash } = sub_ret else {
|
||||
anyhow::bail!("Expected TransactionExecuted return value");
|
||||
};
|
||||
|
||||
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
||||
@ -237,8 +237,8 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> {
|
||||
});
|
||||
|
||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = result else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash } = result else {
|
||||
anyhow::bail!("Expected TransactionExecuted return value");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
@ -297,7 +297,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> {
|
||||
});
|
||||
|
||||
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash } = sub_ret else {
|
||||
anyhow::bail!("Failed to send transaction");
|
||||
};
|
||||
|
||||
|
||||
@ -57,8 +57,8 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> {
|
||||
});
|
||||
|
||||
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash } = sub_ret else {
|
||||
anyhow::bail!("Expected TransactionExecuted return value");
|
||||
};
|
||||
|
||||
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
|
||||
|
||||
@ -162,8 +162,8 @@ async fn claim_pinata_to_existing_private_account() -> Result<()> {
|
||||
let pinata_balance_pre = account_balance(&ctx, system_accounts::pinata_account_id()).await?;
|
||||
|
||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash: _ } = result else {
|
||||
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
|
||||
let SubcommandReturnValue::TransactionExecuted { tx_hash: _ } = result else {
|
||||
anyhow::bail!("Expected TransactionExecuted return value");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
|
||||
@ -11,7 +11,7 @@ use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, get_account
|
||||
use log::info;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use tokio::test;
|
||||
use wallet::cli::Command;
|
||||
use wallet::{cli::Command, config::WalletConfigOverrides};
|
||||
|
||||
#[test]
|
||||
async fn deploy_and_execute_program() -> Result<()> {
|
||||
@ -29,9 +29,6 @@ async fn deploy_and_execute_program() -> Result<()> {
|
||||
|
||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let account_id = new_account(&mut ctx, false, None).await?;
|
||||
|
||||
let nonces = ctx.wallet().get_accounts_nonces(vec![account_id]).await?;
|
||||
@ -65,3 +62,37 @@ async fn deploy_and_execute_program() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
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()
|
||||
.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),
|
||||
seq_poll_max_retries: Some(2),
|
||||
..WalletConfigOverrides::default()
|
||||
})
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
let mut tempfile = tempfile::NamedTempFile::new()?;
|
||||
tempfile.write_all(b"this is not a valid program binary")?;
|
||||
|
||||
let command = Command::DeployProgram {
|
||||
binary_filepath: tempfile.path().to_owned(),
|
||||
};
|
||||
|
||||
let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await;
|
||||
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Deploying an invalid program should fail, but got: {result:?}"
|
||||
);
|
||||
|
||||
info!("Deploying an invalid program failed as expected");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ async fn public_transfer_and_public_claim() -> Result<()> {
|
||||
.get_account_balance(recipient_vault_id)
|
||||
.await?;
|
||||
|
||||
let transfer_result = wallet::cli::execute_subcommand(
|
||||
wallet::cli::execute_subcommand(
|
||||
ctx.wallet_mut(),
|
||||
Command::Vault(VaultSubcommand::Transfer {
|
||||
from: public_mention(sender),
|
||||
@ -39,10 +39,6 @@ async fn public_transfer_and_public_claim() -> Result<()> {
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
assert!(
|
||||
matches!(transfer_result, SubcommandReturnValue::Empty),
|
||||
"Expected Empty return value for public vault transfer"
|
||||
);
|
||||
|
||||
let sender_balance_after_transfer = ctx.sequencer_client().get_account_balance(sender).await?;
|
||||
let recipient_balance_after_transfer = ctx
|
||||
@ -64,7 +60,7 @@ async fn public_transfer_and_public_claim() -> Result<()> {
|
||||
recipient_vault_balance_before + amount
|
||||
);
|
||||
|
||||
let claim_result = wallet::cli::execute_subcommand(
|
||||
wallet::cli::execute_subcommand(
|
||||
ctx.wallet_mut(),
|
||||
Command::Vault(VaultSubcommand::Claim {
|
||||
account_id: public_mention(recipient),
|
||||
@ -72,10 +68,6 @@ async fn public_transfer_and_public_claim() -> Result<()> {
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
assert!(
|
||||
matches!(claim_result, SubcommandReturnValue::Empty),
|
||||
"Expected Empty return value for public vault claim"
|
||||
);
|
||||
|
||||
let sender_balance_after_claim = ctx.sequencer_client().get_account_balance(sender).await?;
|
||||
let recipient_balance_after_claim = ctx
|
||||
@ -138,9 +130,9 @@ async fn private_transfer_and_private_claim() -> Result<()> {
|
||||
assert!(
|
||||
matches!(
|
||||
transfer_result,
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { .. }
|
||||
SubcommandReturnValue::TransactionExecuted { .. }
|
||||
),
|
||||
"Expected PrivacyPreservingTransfer return value for private vault transfer"
|
||||
"Expected TransactionExecuted return value for private vault transfer"
|
||||
);
|
||||
|
||||
let sender_balance_after_transfer = ctx
|
||||
@ -179,9 +171,9 @@ async fn private_transfer_and_private_claim() -> Result<()> {
|
||||
assert!(
|
||||
matches!(
|
||||
claim_result,
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { .. }
|
||||
SubcommandReturnValue::TransactionExecuted { .. }
|
||||
),
|
||||
"Expected PrivacyPreservingTransfer return value for private vault claim"
|
||||
"Expected TransactionExecuted return value for private vault claim"
|
||||
);
|
||||
|
||||
let sender_balance_after_claim = ctx
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Message {
|
||||
pub(crate) bytecode: Vec<u8>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Message {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Message")
|
||||
.field("bytecode", &format_args!("<{} bytes>", self.bytecode.len()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Message {
|
||||
#[must_use]
|
||||
pub const fn new(bytecode: Vec<u8>) -> Self {
|
||||
|
||||
@ -7,6 +7,7 @@ use common::{
|
||||
transaction::LeeTransaction,
|
||||
};
|
||||
use lee::V03State;
|
||||
use lee_core::BlockId;
|
||||
use log::info;
|
||||
use logos_blockchain_zone_sdk::sequencer::SequencerCheckpoint;
|
||||
pub use storage::DbResult;
|
||||
@ -18,7 +19,7 @@ use storage::sequencer::{
|
||||
pub struct SequencerStore {
|
||||
dbio: Arc<RocksDBIO>,
|
||||
// TODO: Consider adding the hashmap to the database for faster recovery.
|
||||
tx_hash_to_block_map: HashMap<HashType, u64>,
|
||||
tx_hash_to_block_map: HashMap<HashType, BlockId>,
|
||||
genesis_id: u64,
|
||||
signing_key: lee::PrivateKey,
|
||||
}
|
||||
@ -96,7 +97,7 @@ impl SequencerStore {
|
||||
|
||||
/// Returns the transaction corresponding to the given hash, if it exists in the blockchain.
|
||||
#[must_use]
|
||||
pub fn get_transaction_by_hash(&self, hash: HashType) -> Option<LeeTransaction> {
|
||||
pub fn get_transaction_by_hash(&self, hash: HashType) -> Option<(LeeTransaction, BlockId)> {
|
||||
let block_id = *self.tx_hash_to_block_map.get(&hash)?;
|
||||
let block = self
|
||||
.get_block_at_id(block_id)
|
||||
@ -105,7 +106,7 @@ impl SequencerStore {
|
||||
.expect("Block should be present since the hash is in the map");
|
||||
for transaction in block.body.transactions {
|
||||
if transaction.hash() == hash {
|
||||
return Some(transaction);
|
||||
return Some((transaction, block_id));
|
||||
}
|
||||
}
|
||||
panic!(
|
||||
@ -181,8 +182,6 @@ pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap<HashType, u64>
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![expect(clippy::shadow_unrelated, reason = "We don't care about it in tests")]
|
||||
|
||||
use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing};
|
||||
use tempfile::tempdir;
|
||||
|
||||
@ -224,8 +223,8 @@ mod tests {
|
||||
.update(&block, &[], vec![], &dummy_state)
|
||||
.unwrap();
|
||||
// Try again
|
||||
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
|
||||
assert_eq!(Some(tx), retrieved_tx);
|
||||
let output = node_store.get_transaction_by_hash(tx.hash());
|
||||
assert_eq!(Some((tx, 1)), output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -383,7 +382,7 @@ mod tests {
|
||||
// Re-open the store and verify that the transaction is still retrievable (which means it
|
||||
// was cached correctly)
|
||||
let node_store = SequencerStore::open_db(path, signing_key).unwrap();
|
||||
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
|
||||
assert_eq!(Some(tx), retrieved_tx);
|
||||
let output = node_store.get_transaction_by_hash(tx.hash());
|
||||
assert_eq!(Some((tx, 1)), output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ pub trait Rpc {
|
||||
async fn get_transaction(
|
||||
&self,
|
||||
tx_hash: HashType,
|
||||
) -> Result<Option<LeeTransaction>, ErrorObjectOwned>;
|
||||
) -> Result<Option<(LeeTransaction, BlockId)>, ErrorObjectOwned>;
|
||||
|
||||
#[method(name = "getAccountsNonces")]
|
||||
async fn get_accounts_nonces(
|
||||
|
||||
@ -131,7 +131,7 @@ impl<BC: BlockPublisherTrait + Send + 'static> sequencer_service_rpc::RpcServer
|
||||
async fn get_transaction(
|
||||
&self,
|
||||
tx_hash: HashType,
|
||||
) -> Result<Option<LeeTransaction>, ErrorObjectOwned> {
|
||||
) -> Result<Option<(LeeTransaction, BlockId)>, ErrorObjectOwned> {
|
||||
let sequencer = self.sequencer.lock().await;
|
||||
Ok(sequencer.block_store().get_transaction_by_hash(tx_hash))
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ use common::{HashType, transaction::LeeTransaction};
|
||||
use derive_more::Display;
|
||||
use futures::TryFutureExt as _;
|
||||
use lee::ProgramDeploymentTransaction;
|
||||
use lee_core::BlockId;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
|
||||
pub use crate::helperfunctions::{read_mnemonic, read_pin};
|
||||
@ -117,11 +118,11 @@ pub struct Args {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SubcommandReturnValue {
|
||||
PrivacyPreservingTransfer { tx_hash: HashType },
|
||||
TransactionExecuted { tx_hash: HashType },
|
||||
RegisterAccount { account_id: lee::AccountId },
|
||||
Account(lee::Account),
|
||||
Empty,
|
||||
SyncedToBlock(u64),
|
||||
SyncedToBlock(BlockId),
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, PartialEq, Eq, Hash)]
|
||||
@ -286,13 +287,16 @@ pub async fn execute_subcommand(
|
||||
))?;
|
||||
let message = lee::program_deployment_transaction::Message::new(bytecode);
|
||||
let transaction = ProgramDeploymentTransaction::new(message);
|
||||
let _response = wallet_core
|
||||
let tx_hash = wallet_core
|
||||
.sequencer_client
|
||||
.send_transaction(LeeTransaction::ProgramDeployment(transaction))
|
||||
.await
|
||||
.context("Transaction submission error")?;
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
wallet_core
|
||||
.poll_and_finalize_public_transaction(tx_hash)
|
||||
.await
|
||||
.context("Transaction finalization error")?
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -47,9 +47,10 @@ impl WalletSubcommand for BridgeSubcommand {
|
||||
.send_withdraw(sender_account_id, amount, bedrock_account_pk)
|
||||
.await?;
|
||||
|
||||
println!("Transaction hash is {tx_hash}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
wallet_core
|
||||
.poll_and_finalize_public_transaction(tx_hash)
|
||||
.await
|
||||
.context("Transaction finalization error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +443,7 @@ impl NativeTokenTransferProgramSubcommandShielded {
|
||||
|
||||
wallet_core.store_persistent_data()?;
|
||||
|
||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
Ok(SubcommandReturnValue::TransactionExecuted { tx_hash })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -490,11 +490,6 @@ impl WalletCore {
|
||||
Some(Commitment::new(&account_id, account))
|
||||
}
|
||||
|
||||
/// Poll transactions.
|
||||
pub async fn poll_native_token_transfer(&self, hash: HashType) -> Result<LeeTransaction> {
|
||||
self.poller.poll_tx(hash).await
|
||||
}
|
||||
|
||||
pub async fn check_private_account_initialized(
|
||||
&self,
|
||||
account_id: AccountId,
|
||||
@ -549,7 +544,6 @@ impl WalletCore {
|
||||
}
|
||||
}
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -558,10 +552,11 @@ impl WalletCore {
|
||||
tx_hash: HashType,
|
||||
) -> Result<cli::SubcommandReturnValue> {
|
||||
println!("Transaction hash is {tx_hash}");
|
||||
let transfer_tx = self.poll_native_token_transfer(tx_hash).await?;
|
||||
println!("Transaction data is {transfer_tx:?}");
|
||||
let (tx, block_id) = self.poller.poll_tx(tx_hash).await?;
|
||||
println!("Transaction is included in block {block_id}");
|
||||
println!("Transaction data is {tx:?}");
|
||||
self.store_persistent_data()?;
|
||||
Ok(cli::SubcommandReturnValue::Empty)
|
||||
Ok(cli::SubcommandReturnValue::TransactionExecuted { tx_hash })
|
||||
}
|
||||
|
||||
/// Pass an empty slice when the recipient is foreign and no accounts need decoding.
|
||||
@ -571,12 +566,17 @@ impl WalletCore {
|
||||
acc_decode_data: &[AccDecodeData],
|
||||
) -> Result<cli::SubcommandReturnValue> {
|
||||
println!("Transaction hash is {tx_hash}");
|
||||
let transfer_tx = self.poll_native_token_transfer(tx_hash).await?;
|
||||
if let common::transaction::LeeTransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
self.decode_insert_privacy_preserving_transaction_results(&tx, acc_decode_data)?;
|
||||
let (tx, block_id) = self.poller.poll_tx(tx_hash).await?;
|
||||
println!("Transaction is included in block {block_id}");
|
||||
println!("Transaction data is {tx:?}");
|
||||
if let common::transaction::LeeTransaction::PrivacyPreserving(private_tx) = tx {
|
||||
self.decode_insert_privacy_preserving_transaction_results(
|
||||
&private_tx,
|
||||
acc_decode_data,
|
||||
)?;
|
||||
}
|
||||
self.store_persistent_data()?;
|
||||
Ok(cli::SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||
Ok(cli::SubcommandReturnValue::TransactionExecuted { tx_hash })
|
||||
}
|
||||
|
||||
pub async fn send_privacy_preserving_tx(
|
||||
|
||||
@ -2,6 +2,7 @@ use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use common::{HashType, block::Block, transaction::LeeTransaction};
|
||||
use lee_core::BlockId;
|
||||
use log::{info, warn};
|
||||
use sequencer_service_rpc::{RpcClient as _, SequencerClient};
|
||||
|
||||
@ -30,7 +31,7 @@ impl TxPoller {
|
||||
}
|
||||
|
||||
// TODO: this polling is not based on blocks, but on timeouts, need to fix this.
|
||||
pub async fn poll_tx(&self, tx_hash: HashType) -> Result<LeeTransaction> {
|
||||
pub async fn poll_tx(&self, tx_hash: HashType) -> Result<(LeeTransaction, BlockId)> {
|
||||
let max_blocks_to_query = self.polling_max_blocks_to_query;
|
||||
|
||||
info!("Starting poll for transaction {tx_hash}");
|
||||
@ -41,7 +42,7 @@ impl TxPoller {
|
||||
|
||||
loop {
|
||||
match self.client.get_transaction(tx_hash).await {
|
||||
Ok(Some(tx)) => return Ok(tx),
|
||||
Ok(Some((tx, block_id))) => return Ok((tx, block_id)),
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}");
|
||||
|
||||
@ -16,7 +16,10 @@ use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuil
|
||||
use serde::Serialize;
|
||||
use tempfile::TempDir;
|
||||
use testcontainers::compose::DockerCompose;
|
||||
use wallet::{WalletCore, account::AccountIdWithPrivacy, cli::CliAccountMention};
|
||||
use wallet::{
|
||||
WalletCore, account::AccountIdWithPrivacy, cli::CliAccountMention,
|
||||
config::WalletConfigOverrides,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
indexer_client::IndexerClient,
|
||||
@ -92,7 +95,7 @@ impl TestContext {
|
||||
|
||||
/// Get a builder for the test context to customize its configuration.
|
||||
#[must_use]
|
||||
pub const fn builder() -> TestContextBuilder {
|
||||
pub fn builder() -> TestContextBuilder {
|
||||
TestContextBuilder::new()
|
||||
}
|
||||
|
||||
@ -250,17 +253,29 @@ pub struct TestContextBuilder {
|
||||
genesis_transactions: Option<Vec<GenesisAction>>,
|
||||
sequencer_partial_config: Option<config::SequencerPartialConfig>,
|
||||
enable_indexer: bool,
|
||||
wallet_config_overrides: WalletConfigOverrides,
|
||||
}
|
||||
|
||||
impl TestContextBuilder {
|
||||
const fn new() -> Self {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
genesis_transactions: None,
|
||||
sequencer_partial_config: None,
|
||||
enable_indexer: true,
|
||||
wallet_config_overrides: WalletConfigOverrides::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Override wallet config fields (e.g. polling timeouts) for the wallet built by this context.
|
||||
#[must_use]
|
||||
pub fn with_wallet_config_overrides(
|
||||
mut self,
|
||||
wallet_config_overrides: WalletConfigOverrides,
|
||||
) -> Self {
|
||||
self.wallet_config_overrides = wallet_config_overrides;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_genesis(mut self, genesis_transactions: Vec<GenesisAction>) -> Self {
|
||||
self.genesis_transactions = Some(genesis_transactions);
|
||||
@ -292,6 +307,7 @@ impl TestContextBuilder {
|
||||
genesis_transactions,
|
||||
sequencer_partial_config,
|
||||
enable_indexer,
|
||||
wallet_config_overrides,
|
||||
} = self;
|
||||
|
||||
// Ensure logger is initialized only once
|
||||
@ -347,6 +363,7 @@ impl TestContextBuilder {
|
||||
sequencer_handle.addr(),
|
||||
&initial_public_accounts,
|
||||
&initial_private_accounts,
|
||||
wallet_config_overrides,
|
||||
)
|
||||
.context("Failed to setup wallet")?;
|
||||
|
||||
@ -459,7 +476,7 @@ pub async fn fetch_privacy_preserving_tx(
|
||||
seq_client: &SequencerClient,
|
||||
tx_hash: HashType,
|
||||
) -> PrivacyPreservingTransaction {
|
||||
let tx = seq_client.get_transaction(tx_hash).await.unwrap().unwrap();
|
||||
let (tx, _block_id) = seq_client.get_transaction(tx_hash).await.unwrap().unwrap();
|
||||
|
||||
match tx {
|
||||
LeeTransaction::PrivacyPreserving(privacy_preserving_transaction) => {
|
||||
|
||||
@ -137,6 +137,7 @@ pub fn setup_wallet(
|
||||
sequencer_addr: 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_serialized =
|
||||
@ -150,7 +151,6 @@ pub fn setup_wallet(
|
||||
.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 (mut wallet, _mnemonic) = WalletCore::new_init_storage(
|
||||
@ -192,10 +192,13 @@ pub async fn setup_public_accounts_with_initial_supply(
|
||||
initial_public_accounts: &[(PrivateKey, u128)],
|
||||
) -> Result<()> {
|
||||
for (private_key, amount) in initial_public_accounts {
|
||||
claim_funds_from_vault(
|
||||
let account_id = AccountId::from(&PublicKey::new_from_private_key(private_key));
|
||||
wallet::cli::execute_subcommand(
|
||||
wallet,
|
||||
AccountId::from(&PublicKey::new_from_private_key(private_key)),
|
||||
*amount,
|
||||
Command::Vault(VaultSubcommand::Claim {
|
||||
account_id: public_mention(account_id),
|
||||
amount: *amount,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.context("Failed to claim funds from vault into public account")?;
|
||||
@ -221,28 +224,6 @@ pub async fn setup_private_accounts_with_initial_supply(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn claim_funds_from_vault(
|
||||
wallet: &mut WalletCore,
|
||||
owner_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<()> {
|
||||
let result = wallet::cli::execute_subcommand(
|
||||
wallet,
|
||||
Command::Vault(VaultSubcommand::Claim {
|
||||
account_id: public_mention(owner_id),
|
||||
amount,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.context("Failed to execute public vault claim command")?;
|
||||
|
||||
let SubcommandReturnValue::Empty = result else {
|
||||
bail!("Expected Empty return value for public vault claim");
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn claim_funds_from_vault_to_private(
|
||||
wallet: &mut WalletCore,
|
||||
owner_id: AccountId,
|
||||
@ -262,8 +243,8 @@ async fn claim_funds_from_vault_to_private(
|
||||
.await
|
||||
.context("Failed to execute private vault claim command")?;
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { .. } = result else {
|
||||
bail!("Expected PrivacyPreservingTransfer return value for private vault claim");
|
||||
let SubcommandReturnValue::TransactionExecuted { .. } = result else {
|
||||
bail!("Expected TransactionExecuted return value for private vault claim");
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -108,7 +108,7 @@ async fn begin_step(ctx: &TestContext) -> Result<u64> {
|
||||
|
||||
/// Finish a timed wallet step. Records submit (the time between `started`
|
||||
/// being captured and `ret` being received) and, if `ret` is a
|
||||
/// [`SubcommandReturnValue::PrivacyPreservingTransfer`], polls the sequencer
|
||||
/// [`SubcommandReturnValue::TransactionExecuted`], polls the sequencer
|
||||
/// for inclusion and records the inclusion latency. Returns a [`StepResult`].
|
||||
async fn finalize_step(
|
||||
label: impl Into<String>,
|
||||
@ -132,7 +132,7 @@ async fn finalize_step(
|
||||
// recorded" signal.
|
||||
let should_wait_for_chain = !matches!(ret, SubcommandReturnValue::RegisterAccount { .. });
|
||||
if should_wait_for_chain {
|
||||
if let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = ret {
|
||||
if let SubcommandReturnValue::TransactionExecuted { tx_hash } = ret {
|
||||
tx_hash_str = Some(format!("{tx_hash}"));
|
||||
}
|
||||
let started_inclusion = Instant::now();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user