Skip to content

Commit cc67b2a

Browse files
authored
Merge of #4019
2 parents b8dabb2 + 33dd44f commit cc67b2a

File tree

8 files changed

+389
-25
lines changed

8 files changed

+389
-25
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- The speculative shielded context now avoids updating its
2+
state if the transaction failed. Added a test for it.
3+
([\#4019](https://github.com/anoma/namada/pull/4019))

crates/apps_lib/src/client/rpc.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::{BTreeMap, BTreeSet};
44
use std::io;
55

66
use borsh::BorshDeserialize;
7+
use color_eyre::owo_colors::OwoColorize;
78
use data_encoding::HEXLOWER;
89
use either::Either;
910
use masp_primitives::asset_type::AssetType;
@@ -395,6 +396,15 @@ async fn query_shielded_balance(
395396
context: &impl Namada,
396397
args: args::QueryBalance,
397398
) {
399+
display_line!(
400+
context.io(),
401+
"{}: {}\n",
402+
"WARNING".bold().underline().yellow(),
403+
"The resulting balance could be outdated, make sure to run `namadac \
404+
shielded-sync` before querying the balance to get the most recent \
405+
value."
406+
);
407+
398408
let args::QueryBalance {
399409
// Token owner (needs to be a viewing key)
400410
owner,

crates/apps_lib/src/client/tx.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use std::io::Write;
33

44
use borsh::BorshDeserialize;
55
use borsh_ext::BorshSerializeExt;
6+
use color_eyre::owo_colors::OwoColorize;
67
use ledger_namada_rs::{BIP44Path, NamadaApp};
8+
use namada_core::masp::MaspTransaction;
79
use namada_sdk::address::{Address, ImplicitAddress};
810
use namada_sdk::args::TxBecomeValidator;
911
use namada_sdk::collections::HashSet;
@@ -829,13 +831,33 @@ pub async fn submit_shielded_transfer(
829831
namada: &impl Namada,
830832
args: args::TxShieldedTransfer,
831833
) -> Result<(), error::Error> {
834+
display_line!(
835+
namada.io(),
836+
"{}: {}\n",
837+
"WARNING".bold().underline().yellow(),
838+
"Some information might be leaked if your shielded wallet is not up \
839+
to date, make sure to run `namadac shielded-sync` before running \
840+
this command.",
841+
);
842+
832843
let (mut tx, signing_data) = args.clone().build(namada).await?;
833844

845+
let masp_section = tx
846+
.sections
847+
.iter()
848+
.find_map(|section| section.masp_tx())
849+
.ok_or_else(|| {
850+
error::Error::Other(
851+
"Missing MASP section in shielded transaction".to_string(),
852+
)
853+
})?;
834854
if args.tx.dump_tx || args.tx.dump_wrapper_tx {
835855
tx::dump_tx(namada.io(), &args.tx, tx)?;
856+
pre_cache_masp_data(namada, &masp_section).await;
836857
} else {
837858
sign(namada, &mut tx, &args.tx, signing_data).await?;
838-
namada.submit(tx, &args.tx).await?;
859+
let res = namada.submit(tx, &args.tx).await?;
860+
pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await;
839861
}
840862
Ok(())
841863
}
@@ -900,13 +922,33 @@ pub async fn submit_unshielding_transfer(
900922
namada: &impl Namada,
901923
args: args::TxUnshieldingTransfer,
902924
) -> Result<(), error::Error> {
925+
display_line!(
926+
namada.io(),
927+
"{}: {}\n",
928+
"WARNING".bold().underline().yellow(),
929+
"Some information might be leaked if your shielded wallet is not up \
930+
to date, make sure to run `namadac shielded-sync` before running \
931+
this command.",
932+
);
933+
903934
let (mut tx, signing_data) = args.clone().build(namada).await?;
904935

936+
let masp_section = tx
937+
.sections
938+
.iter()
939+
.find_map(|section| section.masp_tx())
940+
.ok_or_else(|| {
941+
error::Error::Other(
942+
"Missing MASP section in shielded transaction".to_string(),
943+
)
944+
})?;
905945
if args.tx.dump_tx || args.tx.dump_wrapper_tx {
906946
tx::dump_tx(namada.io(), &args.tx, tx)?;
947+
pre_cache_masp_data(namada, &masp_section).await;
907948
} else {
908949
sign(namada, &mut tx, &args.tx, signing_data).await?;
909-
namada.submit(tx, &args.tx).await?;
950+
let res = namada.submit(tx, &args.tx).await?;
951+
pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await;
910952
}
911953
Ok(())
912954
}
@@ -920,16 +962,25 @@ where
920962
{
921963
let (tx, signing_data, _) = args.build(namada).await?;
922964

965+
let opt_masp_section =
966+
tx.sections.iter().find_map(|section| section.masp_tx());
923967
if args.tx.dump_tx || args.tx.dump_wrapper_tx {
924968
tx::dump_tx(namada.io(), &args.tx, tx)?;
969+
if let Some(masp_section) = opt_masp_section {
970+
pre_cache_masp_data(namada, &masp_section).await;
971+
}
925972
} else {
926-
batch_opt_reveal_pk_and_submit(
973+
let res = batch_opt_reveal_pk_and_submit(
927974
namada,
928975
&args.tx,
929976
&[&args.source.effective_address()],
930977
(tx, signing_data),
931978
)
932979
.await?;
980+
981+
if let Some(masp_section) = opt_masp_section {
982+
pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await;
983+
}
933984
}
934985
// NOTE that the tx could fail when its submission epoch doesn't match
935986
// construction epoch
@@ -1482,3 +1533,42 @@ pub async fn gen_ibc_shielding_transfer(
14821533
}
14831534
Ok(())
14841535
}
1536+
1537+
// Pre-cache the data for the provided MASP transaction. Log an error on
1538+
// failure.
1539+
async fn pre_cache_masp_data(namada: &impl Namada, masp_tx: &MaspTransaction) {
1540+
if let Err(e) = namada
1541+
.shielded_mut()
1542+
.await
1543+
.pre_cache_transaction(masp_tx)
1544+
.await
1545+
{
1546+
// Just display the error but do not propagate it
1547+
edisplay_line!(namada.io(), "Failed to pre-cache masp data: {}.", e);
1548+
}
1549+
}
1550+
1551+
// Check the result of a transaction and pre-cache the masp data accordingly
1552+
async fn pre_cache_masp_data_on_tx_result(
1553+
namada: &impl Namada,
1554+
tx_result: &ProcessTxResponse,
1555+
masp_tx: &MaspTransaction,
1556+
) {
1557+
match tx_result {
1558+
ProcessTxResponse::Applied(resp) => {
1559+
if let Some(InnerTxResult::Success(_)) =
1560+
// If we have the masp data in an ibc transfer it
1561+
// means we are unshielding, so there's no reveal pk
1562+
// tx in the batch which contains only the ibc tx
1563+
resp.batch_result().first().map(|(_, res)| res)
1564+
{
1565+
pre_cache_masp_data(namada, masp_tx).await;
1566+
}
1567+
}
1568+
ProcessTxResponse::Broadcast(_) => {
1569+
pre_cache_masp_data(namada, masp_tx).await;
1570+
}
1571+
// Do not pre-cache when dry-running
1572+
ProcessTxResponse::DryRun(_) => {}
1573+
}
1574+
}

crates/node/src/bench_utils.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,6 @@ impl BenchShieldedCtx {
12231223
vec![masp_transfer_data],
12241224
None,
12251225
expiration,
1226-
true,
12271226
)
12281227
.await
12291228
})

crates/sdk/src/tx.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,6 @@ pub async fn build_ibc_transfer(
26482648
context,
26492649
masp_transfer_data,
26502650
masp_fee_data,
2651-
!(args.tx.dry_run || args.tx.dry_run_wrapper),
26522651
args.tx.expiration.to_datetime(),
26532652
)
26542653
.await?;
@@ -3113,7 +3112,6 @@ pub async fn build_shielded_transfer<N: Namada>(
31133112
context,
31143113
transfer_data,
31153114
masp_fee_data,
3116-
!(args.tx.dry_run || args.tx.dry_run_wrapper),
31173115
args.tx.expiration.to_datetime(),
31183116
)
31193117
.await?
@@ -3280,7 +3278,6 @@ pub async fn build_shielding_transfer<N: Namada>(
32803278
context,
32813279
transfer_data,
32823280
None,
3283-
!(args.tx.dry_run || args.tx.dry_run_wrapper),
32843281
args.tx.expiration.to_datetime(),
32853282
)
32863283
.await?
@@ -3402,7 +3399,6 @@ pub async fn build_unshielding_transfer<N: Namada>(
34023399
context,
34033400
transfer_data,
34043401
masp_fee_data,
3405-
!(args.tx.dry_run || args.tx.dry_run_wrapper),
34063402
args.tx.expiration.to_datetime(),
34073403
)
34083404
.await?
@@ -3455,7 +3451,6 @@ async fn construct_shielded_parts<N: Namada>(
34553451
context: &N,
34563452
data: Vec<MaspTransferData>,
34573453
fee_data: Option<MaspFeeData>,
3458-
update_ctx: bool,
34593454
expiration: Option<DateTimeUtc>,
34603455
) -> Result<Option<(ShieldedTransfer, HashSet<AssetData>)>> {
34613456
// Precompute asset types to increase chances of success in decoding
@@ -3469,9 +3464,7 @@ async fn construct_shielded_parts<N: Namada>(
34693464
.await;
34703465

34713466
shielded
3472-
.gen_shielded_transfer(
3473-
context, data, fee_data, expiration, update_ctx,
3474-
)
3467+
.gen_shielded_transfer(context, data, fee_data, expiration)
34753468
.await
34763469
};
34773470

@@ -3852,7 +3845,6 @@ pub async fn gen_ibc_shielding_transfer<N: Namada>(
38523845
// Fees are paid from the transparent balance of the relayer
38533846
None,
38543847
args.expiration.to_datetime(),
3855-
true,
38563848
)
38573849
.await
38583850
.map_err(|err| TxSubmitError::MaspError(err.to_string()))?

crates/shielded_token/src/masp.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,10 @@ pub type WitnessMap = HashMap<usize, IncrementalWitness<Node>>;
320320
#[derive(BorshSerialize, BorshDeserialize, Debug)]
321321
/// The possible sync states of the shielded context
322322
pub enum ContextSyncStatus {
323-
/// The context contains only data that has been confirmed by the protocol
323+
/// The context contains data that has been confirmed by the protocol
324324
Confirmed,
325-
/// The context contains that that has not yet been confirmed by the
326-
/// protocol and could end up being invalid
325+
/// The context possibly contains that that has not yet been confirmed by
326+
/// the protocol and could be incomplete or invalid
327327
Speculative,
328328
}
329329

crates/shielded_token/src/masp/shielded_wallet.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,9 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedWallet<U> {
359359
/// Updates the internal state with the data of the newly generated
360360
/// transaction. More specifically invalidate the spent notes, but do not
361361
/// cache the newly produced output descriptions and therefore the merkle
362-
/// tree
363-
async fn pre_cache_transaction(
362+
/// tree (this is because we don't know the exact position in the tree where
363+
/// the new notes will be appended)
364+
pub async fn pre_cache_transaction(
364365
&mut self,
365366
masp_tx: &Transaction,
366367
) -> Result<(), eyre::Error> {
@@ -1018,7 +1019,6 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
10181019
data: Vec<MaspTransferData>,
10191020
fee_data: Option<MaspFeeData>,
10201021
expiration: Option<DateTimeUtc>,
1021-
update_ctx: bool,
10221022
) -> Result<Option<ShieldedTransfer>, TransferErr> {
10231023
// Determine epoch in which to submit potential shielded transaction
10241024
let epoch = Self::query_masp_epoch(context.client())
@@ -1212,12 +1212,6 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
12121212
)
12131213
.map_err(|error| TransferErr::Build { error })?;
12141214

1215-
if update_ctx {
1216-
self.pre_cache_transaction(&masp_tx)
1217-
.await
1218-
.map_err(|e| TransferErr::General(e.to_string()))?;
1219-
}
1220-
12211215
Ok(Some(ShieldedTransfer {
12221216
builder: builder_clone,
12231217
masp_tx,

0 commit comments

Comments
 (0)