diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 211f347942..0a738b835e 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -195,11 +195,11 @@ pub async fn sign( // Build a transaction to reveal the signer of the given transaction. pub async fn submit_reveal_aux( context: &impl Namada, - args: args::Tx, + args: &args::Tx, address: &Address, -) -> Result<(), error::Error> { +) -> Result, error::Error> { if args.dump_tx { - return Ok(()); + return Ok(None); } if let Address::Implicit(ImplicitAddress(pkh)) = address { @@ -210,20 +210,42 @@ pub async fn submit_reveal_aux( .map_err(|e| error::Error::Other(e.to_string()))?; if tx::is_reveal_pk_needed(context.client(), address).await? { + // FIXME: rework this message? yes slightly display_line!( context.io(), "Submitting a tx to reveal the public key for address \ {address}..." ); - let (mut tx, signing_data) = - tx::build_reveal_pk(context, &args, &public_key).await?; + return Ok(Some( + tx::build_reveal_pk(context, args, &public_key).await?, + )); + } + } - sign(context, &mut tx, &args, signing_data).await?; + Ok(None) +} - context.submit(tx, &args).await?; - } +async fn batch_opt_reveal_pk_and_submit( + namada: &N, + args: &args::Tx, + owner: &Address, + tx_data: (Tx, SigningTxData), +) -> Result<(), error::Error> +where + ::Error: std::fmt::Display, +{ + let submit_pk_tx_data = submit_reveal_aux(namada, args, owner).await?; + let mut batched_tx_data = + submit_pk_tx_data.map_or_else(Default::default, |data| vec![data]); + batched_tx_data.push(tx_data); + let (mut batched_tx, batched_signing_data) = + namada_sdk::tx::build_batch(batched_tx_data)?; + + for sig_data in batched_signing_data { + sign(namada, &mut batched_tx, args, sig_data).await?; } + namada.submit(batched_tx, args).await?; Ok(()) } @@ -231,17 +253,18 @@ pub async fn submit_bridge_pool_tx( namada: &N, args: args::EthereumBridgePool, ) -> Result<(), error::Error> { - let tx_args = args.tx.clone(); - let (mut tx, signing_data) = args.clone().build(namada).await?; + let bridge_pool_tx_data = args.clone().build(namada).await?; if args.tx.dump_tx { - tx::dump_tx(namada.io(), &args.tx, tx); + tx::dump_tx(namada.io(), &args.tx, bridge_pool_tx_data.0); } else { - submit_reveal_aux(namada, tx_args.clone(), &args.sender).await?; - - sign(namada, &mut tx, &tx_args, signing_data).await?; - - namada.submit(tx, &tx_args).await?; + batch_opt_reveal_pk_and_submit( + namada, + &args.tx, + &args.sender, + bridge_pool_tx_data, + ) + .await?; } Ok(()) @@ -254,16 +277,18 @@ pub async fn submit_custom( where ::Error: std::fmt::Display, { - submit_reveal_aux(namada, args.tx.clone(), &args.owner).await?; - - let (mut tx, signing_data) = args.build(namada).await?; + let custom_tx_data = args.build(namada).await?; if args.tx.dump_tx { - tx::dump_tx(namada.io(), &args.tx, tx); + tx::dump_tx(namada.io(), &args.tx, custom_tx_data.0); } else { - sign(namada, &mut tx, &args.tx, signing_data).await?; - - namada.submit(tx, &args.tx).await?; + batch_opt_reveal_pk_and_submit( + namada, + &args.tx, + &args.owner, + custom_tx_data, + ) + .await?; } Ok(()) @@ -768,15 +793,17 @@ pub async fn submit_transparent_transfer( )); } - for datum in args.data.iter() { - submit_reveal_aux(namada, args.tx.clone(), &datum.source).await?; - } - let (mut tx, signing_data) = args.clone().build(namada).await?; if args.tx.dump_tx { tx::dump_tx(namada.io(), &args.tx, tx); } else { + // FIXME: need to extend batch_opt_revel for this to support multiple + // reveal pkls + for datum in args.data.iter() { + submit_reveal_aux(namada, &args.tx, &datum.source).await?; + } + sign(namada, &mut tx, &args.tx, signing_data).await?; namada.submit(tx, &args.tx).await?; } @@ -803,8 +830,9 @@ pub async fn submit_shielding_transfer( namada: &impl Namada, args: args::TxShieldingTransfer, ) -> Result<(), error::Error> { + // FIXME: same here, extend for datum in args.data.iter() { - submit_reveal_aux(namada, args.tx.clone(), &datum.source).await?; + submit_reveal_aux(namada, &args.tx, &datum.source).await?; } // Repeat once if the tx fails on a crossover of an epoch @@ -873,20 +901,18 @@ pub async fn submit_ibc_transfer( where ::Error: std::fmt::Display, { - submit_reveal_aux( - namada, - args.tx.clone(), - &args.source.effective_address(), - ) - .await?; - let (mut tx, signing_data, _) = args.build(namada).await?; + let (tx, signing_data, _) = args.build(namada).await?; if args.tx.dump_tx { tx::dump_tx(namada.io(), &args.tx, tx); } else { - sign(namada, &mut tx, &args.tx, signing_data).await?; - - namada.submit(tx, &args.tx).await?; + batch_opt_reveal_pk_and_submit( + namada, + &args.tx, + &args.source.effective_address(), + (tx, signing_data), + ) + .await?; } // NOTE that the tx could fail when its submission epoch doesn't match // construction epoch @@ -904,7 +930,7 @@ where let current_epoch = rpc::query_and_print_epoch(namada).await; let governance_parameters = rpc::query_governance_parameters(namada.client()).await; - let (mut tx_builder, signing_data) = if args.is_pgf_funding { + let (proposal_tx_data, proposal_author) = if args.is_pgf_funding { let proposal = PgfFundingProposal::try_from(args.proposal_data.as_ref()) .map_err(|e| { @@ -916,11 +942,12 @@ where .map_err(|e| { error::TxSubmitError::InvalidProposal(e.to_string()) })?; + let proposal_author = proposal.proposal.author.clone(); - submit_reveal_aux(namada, args.tx.clone(), &proposal.proposal.author) - .await?; - - tx::build_pgf_funding_proposal(namada, &args, proposal).await? + ( + tx::build_pgf_funding_proposal(namada, &args, proposal).await?, + proposal_author, + ) } else if args.is_pgf_stewards { let proposal = PgfStewardProposal::try_from( args.proposal_data.as_ref(), @@ -947,11 +974,12 @@ where .map_err(|e| { error::TxSubmitError::InvalidProposal(e.to_string()) })?; + let proposal_author = proposal.proposal.author.clone(); - submit_reveal_aux(namada, args.tx.clone(), &proposal.proposal.author) - .await?; - - tx::build_pgf_stewards_proposal(namada, &args, proposal).await? + ( + tx::build_pgf_stewards_proposal(namada, &args, proposal).await?, + proposal_author, + ) } else { let proposal = DefaultProposal::try_from(args.proposal_data.as_ref()) .map_err(|e| { @@ -976,19 +1004,24 @@ where .map_err(|e| { error::TxSubmitError::InvalidProposal(e.to_string()) })?; + let proposal_author = proposal.proposal.author.clone(); - submit_reveal_aux(namada, args.tx.clone(), &proposal.proposal.author) - .await?; - - tx::build_default_proposal(namada, &args, proposal).await? + ( + tx::build_default_proposal(namada, &args, proposal).await?, + proposal_author, + ) }; if args.tx.dump_tx { - tx::dump_tx(namada.io(), &args.tx, tx_builder); + tx::dump_tx(namada.io(), &args.tx, proposal_tx_data.0); } else { - sign(namada, &mut tx_builder, &args.tx, signing_data).await?; - - namada.submit(tx_builder, &args.tx).await?; + batch_opt_reveal_pk_and_submit( + namada, + &args.tx, + &proposal_author, + proposal_tx_data, + ) + .await?; } Ok(()) @@ -1096,7 +1129,13 @@ pub async fn submit_reveal_pk( where ::Error: std::fmt::Display, { - submit_reveal_aux(namada, args.tx, &(&args.public_key).into()).await?; + let tx_data = + submit_reveal_aux(namada, &args.tx, &(&args.public_key).into()).await?; + + if let Some((mut tx, signing_data)) = tx_data { + sign(namada, &mut tx, &args.tx, signing_data).await?; + namada.submit(tx, &args.tx).await?; + } Ok(()) } @@ -1108,17 +1147,20 @@ pub async fn submit_bond( where ::Error: std::fmt::Display, { - let default_address = args.source.clone().unwrap_or(args.validator.clone()); - submit_reveal_aux(namada, args.tx.clone(), &default_address).await?; - - let (mut tx, signing_data) = args.build(namada).await?; + let submit_bond_tx_data = args.build(namada).await?; if args.tx.dump_tx { - tx::dump_tx(namada.io(), &args.tx, tx); + tx::dump_tx(namada.io(), &args.tx, submit_bond_tx_data.0); } else { - sign(namada, &mut tx, &args.tx, signing_data).await?; - - namada.submit(tx, &args.tx).await?; + let default_address = + args.source.clone().unwrap_or(args.validator.clone()); + batch_opt_reveal_pk_and_submit( + namada, + &args.tx, + &default_address, + submit_bond_tx_data, + ) + .await?; } Ok(())