From 6c2bdb1b20c438316fa8f0ae478e42dd7ee13afc Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:04:43 +0100 Subject: [PATCH 1/5] feat: add `--label` option to `wallet account new` sub command Following the work done in https://github.com/logos-blockchain/lssa/pull/292 and the comment on extending the work https://github.com/logos-blockchain/lssa/pull/292#pullrequestreview-3672282664, this commit introduces a new `--label` option to the `wallet account new` sub command. **Usage**: ``` wallet account new public --label "Public test account" wallet account new private --label "Private test account" ``` Labels have to be unique across all accounts in the wallet storage. The commit also adds tests, which make use of the `WalletSubCommand` trait functions (hence the change to make it a `pub trait`). --- .gitignore | 1 + examples/program_deployment/README.md | 6 ++ integration_tests/tests/account.rs | 102 ++++++++++++++++++ integration_tests/tests/amm.rs | 35 ++++-- .../tests/auth_transfer/private.rs | 15 ++- .../tests/auth_transfer/public.rs | 10 +- integration_tests/tests/keys_restoration.rs | 4 + integration_tests/tests/pinata.rs | 5 +- integration_tests/tests/token.rs | 102 ++++++++++++++---- wallet/src/cli/account.rs | 58 +++++++++- 10 files changed, 303 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 40be2daa..e4898102 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ storage.json result wallet-ffi/wallet_ffi.h bedrock_signing_key +integration_tests/configs/debug/ diff --git a/examples/program_deployment/README.md b/examples/program_deployment/README.md index b0d59151..63a14db7 100644 --- a/examples/program_deployment/README.md +++ b/examples/program_deployment/README.md @@ -93,6 +93,9 @@ Generated new account with account_id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1 ``` The relevant part is the account id `BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9` +> [!NOTE] +> You can optionally assign a label to the account for easier identification using the `--label` option: `wallet account new public --label "my-account"`. Labels must be unique across all accounts. + ## Check the account state New accounts are always Uninitialized. Verify: ```bash @@ -269,6 +272,9 @@ Generated new account with account_id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8 ``` The relevant part for this tutorial is the account id `7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr` +> [!NOTE] +> As with public accounts, you can use the `--label` option to assign a label: `wallet account new private --label "my-private-account"`. + You can check it's uninitialized with ```bash diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index ec53da78..36dcca5e 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -3,6 +3,11 @@ use integration_tests::TestContext; use log::info; use nssa::program::Program; use tokio::test; +use wallet::cli::{ + Command, + account::{AccountSubcommand, NewSubcommand}, + execute_subcommand, +}; #[test] async fn get_existing_account() -> Result<()> { @@ -26,3 +31,100 @@ async fn get_existing_account() -> Result<()> { Ok(()) } + +#[test] +async fn new_public_account_with_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let label = "my-test-public-account".to_string(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: Some(label.clone()), + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify the label was stored + let stored_label = ctx + .wallet() + .storage() + .labels + .get(&account_id.to_string()) + .expect("Label should be stored for the new account"); + + assert_eq!(stored_label.to_string(), label); + + info!("Successfully created public account with label"); + + Ok(()) +} + +#[test] +async fn new_private_account_with_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let label = "my-test-private-account".to_string(); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: Some(label.clone()), + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify the label was stored + let stored_label = ctx + .wallet() + .storage() + .labels + .get(&account_id.to_string()) + .expect("Label should be stored for the new account"); + + assert_eq!(stored_label.to_string(), label); + + info!("Successfully created private account with label"); + + Ok(()) +} + +#[test] +async fn new_public_account_without_label() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); + + let result = execute_subcommand(ctx.wallet_mut(), command).await?; + + // Extract the account_id from the result + let account_id = match result { + wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, + _ => panic!("Expected RegisterAccount return value"), + }; + + // Verify no label was stored + assert!( + !ctx.wallet() + .storage() + .labels + .contains_key(&account_id.to_string()), + "No label should be stored when not provided" + ); + + info!("Successfully created public account without label"); + + Ok(()) +} diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 3f513d70..ecea91b3 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -19,7 +19,10 @@ async fn amm_public() -> Result<()> { account_id: definition_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -31,7 +34,10 @@ async fn amm_public() -> Result<()> { account_id: supply_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -43,7 +49,10 @@ async fn amm_public() -> Result<()> { account_id: recipient_account_id_1, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -55,7 +64,10 @@ async fn amm_public() -> Result<()> { account_id: definition_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -67,7 +79,10 @@ async fn amm_public() -> Result<()> { account_id: supply_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -79,7 +94,10 @@ async fn amm_public() -> Result<()> { account_id: recipient_account_id_2, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { @@ -144,7 +162,10 @@ async fn amm_public() -> Result<()> { account_id: user_holding_lp, } = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await? else { diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index bf2ed8b1..aa8ca180 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -149,7 +149,10 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { let from: AccountId = ctx.existing_private_accounts()[0]; // Create a new private account - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -306,7 +309,10 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { let from: AccountId = ctx.existing_private_accounts()[0]; // Create a new private account - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -366,7 +372,10 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { async fn initialize_private_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { account_id } = result else { anyhow::bail!("Expected RegisterAccount return value"); diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index da30fe5a..ed8296ec 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -51,7 +51,10 @@ async fn successful_transfer_to_existing_account() -> Result<()> { pub async fn successful_transfer_to_new_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); wallet::cli::execute_subcommand(ctx.wallet_mut(), command) .await @@ -212,7 +215,10 @@ async fn two_consecutive_successful_transfers() -> Result<()> { async fn initialize_public_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })); + let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { account_id } = result else { anyhow::bail!("Expected RegisterAccount return value"); diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index b1d9edcb..24299a56 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -24,6 +24,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create first private account at root let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::root()), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -36,6 +37,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create second private account at /0 let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::from_str("/0")?), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -70,6 +72,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create first public account at root let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::root()), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { @@ -82,6 +85,7 @@ async fn restore_keys_from_seed() -> Result<()> { // Create second public account at /0 let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::from_str("/0")?), + label: None, })); let result = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; let SubcommandReturnValue::RegisterAccount { diff --git a/integration_tests/tests/pinata.rs b/integration_tests/tests/pinata.rs index bf88536c..002dd2c7 100644 --- a/integration_tests/tests/pinata.rs +++ b/integration_tests/tests/pinata.rs @@ -112,7 +112,10 @@ async fn claim_pinata_to_new_private_account() -> Result<()> { // Create new private account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 506c250f..0ff6eee5 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -23,7 +23,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for the token definition let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -36,7 +39,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for the token supply holder let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -49,7 +55,10 @@ async fn create_and_transfer_public_token() -> Result<()> { // Create new account for receiving a token transaction let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -262,7 +271,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for the token definition (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -275,7 +287,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for the token supply holder (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -288,7 +303,10 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { // Create new account for receiving a token transaction (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -429,6 +447,7 @@ async fn create_token_with_private_definition() -> Result<()> { ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: Some(ChainIndex::root()), + label: None, })), ) .await?; @@ -444,6 +463,7 @@ async fn create_token_with_private_definition() -> Result<()> { ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: Some(ChainIndex::root()), + label: None, })), ) .await?; @@ -496,7 +516,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Create private recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -509,7 +532,10 @@ async fn create_token_with_private_definition() -> Result<()> { // Create public recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -615,7 +641,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create token definition account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -628,7 +657,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -685,7 +717,10 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { // Create recipient account let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -762,7 +797,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create token definition account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -775,7 +813,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create supply account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -788,7 +829,10 @@ async fn shielded_token_transfer() -> Result<()> { // Create recipient account (private) for shielded transfer let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -876,7 +920,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create token definition account (public) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -889,7 +936,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -902,7 +952,10 @@ async fn deshielded_token_transfer() -> Result<()> { // Create recipient account (public) for deshielded transfer let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Public { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -990,7 +1043,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create token definition account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -1003,7 +1059,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create supply account (private) let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { @@ -1031,7 +1090,10 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { // Create new private account for claiming path let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), - Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: None })), + Command::Account(AccountSubcommand::New(NewSubcommand::Private { + cci: None, + label: None, + })), ) .await?; let SubcommandReturnValue::RegisterAccount { diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 8ef45c29..7f936284 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -58,12 +58,18 @@ pub enum NewSubcommand { #[arg(long)] /// Chain index of a parent node cci: Option, + #[arg(short, long)] + /// Label to assign to the new account + label: Option, }, /// Register new private account Private { #[arg(long)] /// Chain index of a parent node cci: Option, + #[arg(short, long)] + /// Label to assign to the new account + label: Option, }, } @@ -73,7 +79,17 @@ impl WalletSubcommand for NewSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - NewSubcommand::Public { cci } => { + NewSubcommand::Public { cci, label } => { + if let Some(ref label) = label + && wallet_core + .storage + .labels + .values() + .any(|l| l.to_string() == *label) + { + anyhow::bail!("Label '{label}' is already in use by another account"); + } + let (account_id, chain_index) = wallet_core.create_new_account_public(cci); let private_key = wallet_core @@ -84,6 +100,13 @@ impl WalletSubcommand for NewSubcommand { let public_key = PublicKey::new_from_private_key(private_key); + if let Some(label) = label { + wallet_core + .storage + .labels + .insert(account_id.to_string(), Label::new(label)); + } + println!( "Generated new account with account_id Public/{account_id} at path {chain_index}" ); @@ -93,9 +116,26 @@ impl WalletSubcommand for NewSubcommand { Ok(SubcommandReturnValue::RegisterAccount { account_id }) } - NewSubcommand::Private { cci } => { + NewSubcommand::Private { cci, label } => { + if let Some(ref label) = label + && wallet_core + .storage + .labels + .values() + .any(|l| l.to_string() == *label) + { + anyhow::bail!("Label '{label}' is already in use by another account"); + } + let (account_id, chain_index) = wallet_core.create_new_account_private(cci); + if let Some(label) = label { + wallet_core + .storage + .labels + .insert(account_id.to_string(), Label::new(label)); + } + let (key, _) = wallet_core .storage .user_data @@ -379,6 +419,20 @@ impl WalletSubcommand for AccountSubcommand { AccountSubcommand::Label { account_id, label } => { let (account_id_str, _) = parse_addr_with_privacy_prefix(&account_id)?; + // Check if label is already used by a different account + if let Some(existing_account) = wallet_core + .storage + .labels + .iter() + .find(|(_, l)| l.to_string() == label) + .map(|(a, _)| a.clone()) + && existing_account != account_id_str + { + anyhow::bail!( + "Label '{label}' is already in use by account {existing_account}" + ); + } + let old_label = wallet_core .storage .labels From 80c0356fac504c35a98d8efe99a523f380254566 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 17 Feb 2026 20:57:05 -0300 Subject: [PATCH 2/5] wip --- sequencer_core/src/block_settlement_client.rs | 5 ++++ .../configs/debug/sequencer_config.json | 4 +-- sequencer_runner/src/lib.rs | 28 +++++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 16afa9c1..c6822e0c 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -28,6 +28,11 @@ pub trait BlockSettlementClientTrait: Clone { /// Create and sign a transaction for inscribing data. fn create_inscribe_tx(&self, block: &Block) -> Result<(SignedMantleTx, MsgId)> { let inscription_data = borsh::to_vec(block)?; + log::info!( + "The size of the block {} is {} bytes", + block.header.block_id, + inscription_data.len() + ); let verifying_key_bytes = self.bedrock_signing_key().public_key().to_bytes(); let verifying_key = Ed25519PublicKey::from_bytes(&verifying_key_bytes).expect("valid ed25519 public key"); diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 4ac8e15b..aee66f42 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -5,8 +5,8 @@ "is_genesis_random": true, "max_num_tx_in_block": 20, "mempool_max_size": 1000, - "block_create_timeout_millis": 12000, - "retry_pending_blocks_timeout_millis": 6000, + "block_create_timeout_millis": 2000, + "retry_pending_blocks_timeout_millis": 500, "port": 3040, "bedrock_config": { "backoff": { diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 74ebae49..358bd37f 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -1,4 +1,9 @@ -use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; +use std::{ + net::SocketAddr, + path::PathBuf, + sync::Arc, + time::{Duration, Instant}, +}; use actix_web::dev::ServerHandle; use anyhow::{Context as _, Result}; @@ -7,12 +12,15 @@ use common::rpc_primitives::RpcConfig; use futures::{FutureExt as _, never::Never}; #[cfg(not(feature = "standalone"))] use log::warn; -use log::{error, info}; +use log::{debug, error, info, warn}; #[cfg(feature = "standalone")] use sequencer_core::SequencerCoreWithMockClients as SequencerCore; -use sequencer_core::config::SequencerConfig; #[cfg(not(feature = "standalone"))] use sequencer_core::{SequencerCore, block_settlement_client::BlockSettlementClientTrait as _}; +use sequencer_core::{ + SequencerCore, block_settlement_client::BlockSettlementClientTrait as _, + config::SequencerConfig, +}; use sequencer_rpc::new_http_server; use tokio::{sync::Mutex, task::JoinHandle}; @@ -176,20 +184,21 @@ async fn retry_pending_blocks_loop( (pending_blocks, client) }; - if let Some(block) = pending_blocks - .iter() - .min_by_key(|block| block.header.block_id) - { + for block in &pending_blocks { info!( "Resubmitting pending block with id {}", block.header.block_id ); - // TODO: We could cache the inscribe tx for each pending block to avoid re-creating - // it on every retry. + // TODO: We could cache the inscribe tx for each pending block to avoid re-creating it + // on every retry. + let now = Instant::now(); let (tx, _msg_id) = block_settlement_client .create_inscribe_tx(block) .context("Failed to create inscribe tx for pending block")?; + debug!(">>>> Create inscribe: {:?}", now.elapsed()); + + let now = Instant::now(); if let Err(e) = block_settlement_client .submit_inscribe_tx_to_bedrock(tx) .await @@ -199,6 +208,7 @@ async fn retry_pending_blocks_loop( block.header.block_id ); } + debug!(">>>> Post: {:?}", now.elapsed()); } } } From c2d4e717e4493253a995946e10c381434187b12d Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 18 Feb 2026 12:21:58 -0300 Subject: [PATCH 3/5] small changes --- indexer/core/src/lib.rs | 4 +++- sequencer_runner/configs/debug/sequencer_config.json | 2 +- sequencer_runner/src/lib.rs | 8 ++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/indexer/core/src/lib.rs b/indexer/core/src/lib.rs index 283842b8..e81faf9a 100644 --- a/indexer/core/src/lib.rs +++ b/indexer/core/src/lib.rs @@ -65,7 +65,9 @@ impl IndexerCore { &self.config.channel_id, ).collect::>(); - info!("Parsed {} L2 blocks", l2_blocks_parsed.len()); + let mut l2_blocks_parsed_ids: Vec<_> = l2_blocks_parsed.iter().map(|block| block.header.block_id).collect(); + l2_blocks_parsed_ids.sort(); + info!("Parsed {} L2 blocks with ids {:?}", l2_blocks_parsed.len(), l2_blocks_parsed_ids); for l2_block in l2_blocks_parsed { // State modification, will be updated in future diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index aee66f42..8974790c 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -5,7 +5,7 @@ "is_genesis_random": true, "max_num_tx_in_block": 20, "mempool_max_size": 1000, - "block_create_timeout_millis": 2000, + "block_create_timeout_millis": 15000, "retry_pending_blocks_timeout_millis": 500, "port": 3040, "bedrock_config": { diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 358bd37f..4975ec01 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -175,7 +175,7 @@ async fn retry_pending_blocks_loop( loop { tokio::time::sleep(retry_pending_blocks_timeout).await; - let (pending_blocks, block_settlement_client) = { + let (mut pending_blocks, block_settlement_client) = { let sequencer_core = seq_core.lock().await; let client = sequencer_core.block_settlement_client(); let pending_blocks = sequencer_core @@ -184,7 +184,11 @@ async fn retry_pending_blocks_loop( (pending_blocks, client) }; - for block in &pending_blocks { + let k = 50; + if pending_blocks.len() > k { + pending_blocks.select_nth_unstable_by_key(k, |b| b.header.block_id); + } + for block in pending_blocks.iter().take(k) { info!( "Resubmitting pending block with id {}", block.header.block_id From 78eaac59f673dc7c79d4100d6b26ab1784f9e878 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 18 Feb 2026 15:43:54 -0300 Subject: [PATCH 4/5] wip --- sequencer_core/src/block_settlement_client.rs | 9 ++ sequencer_core/src/lib.rs | 12 ++- .../configs/debug/sequencer_config.json | 4 +- sequencer_runner/src/lib.rs | 90 ++++++++++--------- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index c6822e0c..04a3740c 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -95,6 +95,15 @@ impl BlockSettlementClientTrait for BlockSettlementClient { } async fn submit_inscribe_tx_to_bedrock(&self, tx: SignedMantleTx) -> Result<()> { + let (parent_id, msg_id) = match tx.mantle_tx.ops.first() { + Some(Op::ChannelInscribe(inscribe)) => (inscribe.parent, inscribe.id()), + _ => panic!("Expected ChannelInscribe op"), + }; + log::info!(">>>>>>>>>>>>>>>>>>>>>>"); + log::info!("Posted block to Bedrock"); + log::info!(">>>>>> parent id: {parent_id:?}"); + log::info!(">>>>>> msg id: {msg_id:?}"); + log::info!(">>>>>>>>>>>>>>>>>>>>>>"); self.bedrock_client .post_transaction(tx) .await diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index cad7e20e..bfcfd01c 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -177,9 +177,19 @@ impl SequencerCore Result { - let (_tx, _msg_id) = self + let (tx, _msg_id) = self .produce_new_block_with_mempool_transactions() .context("Failed to produce new block with mempool transactions")?; + match self + .block_settlement_client + .submit_inscribe_tx_to_bedrock(tx) + .await + { + Ok(()) => {} + Err(err) => { + error!("Failed to post block data to Bedrock with error: {err:#}"); + } + } Ok(self.chain_height) } diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 8974790c..8e8275b9 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -5,8 +5,8 @@ "is_genesis_random": true, "max_num_tx_in_block": 20, "mempool_max_size": 1000, - "block_create_timeout_millis": 15000, - "retry_pending_blocks_timeout_millis": 500, + "block_create_timeout_millis": 2000, + "retry_pending_blocks_timeout_millis": 200000, "port": 3040, "bedrock_config": { "backoff": { diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 4975ec01..f50d6736 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -127,6 +127,11 @@ pub async fn startup_sequencer(app_config: SequencerConfig) -> Result>, block_timeout: Duration) } } +#[cfg(not(feature = "standalone"))] +async fn retry_pending_blocks(seq_core: &Arc>) -> Result<()> { + let (mut pending_blocks, block_settlement_client) = { + let sequencer_core = seq_core.lock().await; + let client = sequencer_core.block_settlement_client(); + let pending_blocks = sequencer_core + .get_pending_blocks() + .expect("Sequencer should be able to retrieve pending blocks"); + (pending_blocks, client) + }; + + let k = 25; + if pending_blocks.len() > k { + pending_blocks.select_nth_unstable_by_key(k, |b| b.header.block_id); + } + for block in pending_blocks.iter().take(k) { + info!( + "Resubmitting pending block with id {}", + block.header.block_id + ); + // TODO: We could cache the inscribe tx for each pending block to avoid re-creating it + // on every retry. + let now = Instant::now(); + let (tx, _msg_id) = block_settlement_client + .create_inscribe_tx(block) + .context("Failed to create inscribe tx for pending block")?; + + debug!(">>>> Create inscribe: {:?}", now.elapsed()); + + let now = Instant::now(); + if let Err(e) = block_settlement_client + .submit_inscribe_tx_to_bedrock(tx) + .await + { + warn!( + "Failed to resubmit block with id {} with error {e:#}", + block.header.block_id + ); + } + debug!(">>>> Post: {:?}", now.elapsed()); + } + Ok(()) +} + #[cfg(not(feature = "standalone"))] async fn retry_pending_blocks_loop( seq_core: Arc>, @@ -174,46 +223,7 @@ async fn retry_pending_blocks_loop( ) -> Result { loop { tokio::time::sleep(retry_pending_blocks_timeout).await; - - let (mut pending_blocks, block_settlement_client) = { - let sequencer_core = seq_core.lock().await; - let client = sequencer_core.block_settlement_client(); - let pending_blocks = sequencer_core - .get_pending_blocks() - .expect("Sequencer should be able to retrieve pending blocks"); - (pending_blocks, client) - }; - - let k = 50; - if pending_blocks.len() > k { - pending_blocks.select_nth_unstable_by_key(k, |b| b.header.block_id); - } - for block in pending_blocks.iter().take(k) { - info!( - "Resubmitting pending block with id {}", - block.header.block_id - ); - // TODO: We could cache the inscribe tx for each pending block to avoid re-creating it - // on every retry. - let now = Instant::now(); - let (tx, _msg_id) = block_settlement_client - .create_inscribe_tx(block) - .context("Failed to create inscribe tx for pending block")?; - - debug!(">>>> Create inscribe: {:?}", now.elapsed()); - - let now = Instant::now(); - if let Err(e) = block_settlement_client - .submit_inscribe_tx_to_bedrock(tx) - .await - { - warn!( - "Failed to resubmit block with id {} with error {e:#}", - block.header.block_id - ); - } - debug!(">>>> Post: {:?}", now.elapsed()); - } + retry_pending_blocks(&seq_core).await?; } } From 0194376fe2baa84bd432fcf5025e3d7a9058d8c9 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Fri, 20 Feb 2026 14:38:30 +0300 Subject: [PATCH 5/5] chore: remove k parameter for resubmitting blocks & adjust config --- sequencer_runner/configs/debug/sequencer_config.json | 4 ++-- sequencer_runner/src/lib.rs | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 8e8275b9..23600311 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -5,8 +5,8 @@ "is_genesis_random": true, "max_num_tx_in_block": 20, "mempool_max_size": 1000, - "block_create_timeout_millis": 2000, - "retry_pending_blocks_timeout_millis": 200000, + "block_create_timeout_millis": 15000, + "retry_pending_blocks_timeout_millis": 5000, "port": 3040, "bedrock_config": { "backoff": { diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index f50d6736..b4dafd56 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -183,11 +183,7 @@ async fn retry_pending_blocks(seq_core: &Arc>) -> Result<() (pending_blocks, client) }; - let k = 25; - if pending_blocks.len() > k { - pending_blocks.select_nth_unstable_by_key(k, |b| b.header.block_id); - } - for block in pending_blocks.iter().take(k) { + for block in pending_blocks.iter() { info!( "Resubmitting pending block with id {}", block.header.block_id