Skip to content

Commit

Permalink
compute_pinned_balance supports pinned masp over ibc transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
grarco committed Jan 9, 2024
1 parent 61f6a69 commit 791ce73
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 68 deletions.
197 changes: 131 additions & 66 deletions sdk/src/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,6 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
last_indexed_tx.map_or_else(|| 0, |last| last.index.0 + 1);
for height in first_height_to_query..=last_block_height.0 {
// Get the valid masp transactions at the specified height

let epoch = query_epoch_at_height(client, height.into())
.await?
.ok_or_else(|| {
Expand All @@ -786,48 +785,21 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
))
})?;

let txs_results = match client
.block_results(height)
.await
.map_err(|e| Error::from(QueryError::General(e.to_string())))?
.end_block_events
let first_index_to_query = if height == first_height_to_query {
Some(TxIndex(first_idx_to_query))
} else {
None
};

let txs_results = match get_indexed_masp_events_at_height(
client,
height.into(),
first_index_to_query,
)
.await?
{
Some(events) => events
.into_iter()
.filter_map(|event| {
// Filter only the tx events which are valid masp txs
// and that we haven't fetched yet
let tx_index =
event.attributes.iter().find_map(|attribute| {
if attribute.key == "is_valid_masp_tx" {
Some(TxIndex(
u32::from_str(&attribute.value)
.unwrap(),
))
} else {
None
}
});

match tx_index {
Some(idx) => {
if height == first_height_to_query {
if idx.0 >= first_idx_to_query {
Some((idx, event))
} else {
None
}
} else {
Some((idx, event))
}
}
None => None,
}
})
.collect::<Vec<_>>(),
None => {
continue;
}
Some(events) => events,
None => continue,
};

// Query the actual block to get the txs bytes. If we only need one
Expand Down Expand Up @@ -1546,8 +1518,6 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
// Obtain the transaction pointer at the key
// If we don't discard the error message then a test fails,
// however the error underlying this will go undetected
// FIXME: we could index the comet tx hash here so that we could just
// query it via a single rpc call to the /tx endpoint
let indexed_tx =
rpc::query_storage_value::<C, IndexedTx>(client, &pin_key)
.await
Expand All @@ -1572,29 +1542,79 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
let tx = Tx::try_from(block[indexed_tx.index.0 as usize].as_ref())
.map_err(|e| Error::Other(e.to_string()))?;

let shielded =
match Transfer::try_from_slice(&tx.data().ok_or_else(|| {
Error::Other("Missing data section".to_string())
})?) {
Ok(transfer) => tx
.get_section(&transfer.shielded.ok_or_else(|| {
Error::Other("Missing masp section hash".to_string())
})?)
.ok_or_else(|| {
Error::Other(
"Missing masp section in transaction".to_string(),
let tx_data = tx
.data()
.ok_or_else(|| Error::Other("Missing data section".to_string()))?;
let shielded = match Transfer::try_from_slice(&tx_data) {
Ok(transfer) => tx
.get_section(&transfer.shielded.ok_or_else(|| {
Error::Other("Missing masp section hash".to_string())
})?)
.ok_or_else(|| {
Error::Other(
"Missing masp section in transaction".to_string(),
)
})?
.masp_tx()
.ok_or_else(|| {
Error::Other("Missing masp transaction".to_string())
})?,
Err(_) => {
// Try Masp over IBC

let message =
namada_core::ledger::ibc::decode_message(&tx_data)
.map_err(|e| Error::Other(e.to_string()))?;

let shielded_transfer = match message {
IbcMessage::ShieldedTransfer(msg) => msg.shielded_transfer,
IbcMessage::Envelope(_) => {
// Need the tx event to extract the memo. The result is
// in the first index of the collection
let tx_events = get_indexed_masp_events_at_height(
client,
indexed_tx.height,
Some(indexed_tx.index),
)
})?
.masp_tx()
.ok_or_else(|| {
Error::Other("Missing masp transaction".to_string())
})?,
Err(_) => {
// FIXME: add support for pinned ibc masp txs, but I need to
// query tx to do this
return Err(Error::Other("IBC Masp pinned tx".to_string()));
}
};
.await?
.ok_or_else(|| {
Error::Other(format!(
"Missing required ibc event at block height {}",
indexed_tx.height
))
})?;

tx_events[0].1
.attributes
.iter()
.find_map(|attribute| {
if attribute.key == "inner_tx" {
let tx_result = TxResult::from_str(&attribute.value).unwrap();
for ibc_event in &tx_result.ibc_events {

let event = namada_core::types::ibc::get_shielded_transfer(ibc_event).ok().flatten();
if event.is_some() {
return event;
}
}
None
} else {
None
}
}).ok_or_else(|| Error::Other("Couldn't deserialize masp tx to ibc message envelope".to_string()))?
}
_ => {
return Err(Error::Other(
"Couldn't deserialize masp tx to a valid ibc \
message"
.to_string(),
));
}
};

shielded_transfer.masp_tx
}
};

// Accumulate the combined output note value into this Amount
let mut val_acc = I128Sum::zero();
Expand Down Expand Up @@ -2271,6 +2291,51 @@ fn convert_amount(
Ok((asset_types, amount))
}

// Retrieves all the indexes and tx events at the specified height which refer
// to a valid masp transaction. If an index is given, it filters only the
// transactions with an index equal or greater to the provided one.
async fn get_indexed_masp_events_at_height(
client: &impl Client,
height: BlockHeight,
first_idx_to_query: Option<TxIndex>,
) -> Result<Option<Vec<(TxIndex, crate::tendermint::abci::Event)>>, Error> {
let first_idx_to_query = first_idx_to_query.unwrap_or_default();

Ok(client
.block_results(height)
.await
.map_err(|e| Error::from(QueryError::General(e.to_string())))?
.end_block_events
.map(|events| {
events
.into_iter()
.filter_map(|event| {
let tx_index =
event.attributes.iter().find_map(|attribute| {
if attribute.key == "is_valid_masp_tx" {
Some(TxIndex(
u32::from_str(&attribute.value).unwrap(),
))
} else {
None
}
});

match tx_index {
Some(idx) => {
if idx >= first_idx_to_query {
Some((idx, event))
} else {
None
}
}
None => None,
}
})
.collect::<Vec<_>>()
}))
}

mod tests {
/// quick and dirty test. will fail on size check
#[test]
Expand Down
2 changes: 0 additions & 2 deletions shared/src/vm/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ where
pub tx: HostRef<'a, &'a Tx>,
/// The transaction index is used to identify a shielded transaction's
/// parent
// FIXME: still need this?
pub tx_index: HostRef<'a, &'a TxIndex>,
/// The verifiers whose validity predicates should be triggered.
pub verifiers: MutHostRef<'a, &'a BTreeSet<Address>>,
Expand Down Expand Up @@ -276,7 +275,6 @@ where
pub tx: HostRef<'a, &'a Tx>,
/// The transaction index is used to identify a shielded transaction's
/// parent
// FIXME: still need this?
pub tx_index: HostRef<'a, &'a TxIndex>,
/// The runner of the [`vp_eval`] function
pub eval_runner: HostRef<'a, &'a EVAL>,
Expand Down

0 comments on commit 791ce73

Please sign in to comment.