-
Notifications
You must be signed in to change notification settings - Fork 948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Murisi/masp ibc replay protection using txdata on 0.39.0 #3409
Murisi/masp ibc replay protection using txdata on 0.39.0 #3409
Conversation
…ncodings are consistent.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3409 +/- ##
==========================================
- Coverage 53.92% 53.77% -0.16%
==========================================
Files 317 317
Lines 107575 107807 +232
==========================================
- Hits 58011 57970 -41
- Misses 49564 49837 +273 ☔ View full report in Codecov by Sentry. |
41d4415
to
438a4ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concept makes sense; I'm wondering if we can clean up the ChangedBalances
calculation somewhat - it's very hard to follow.
@@ -279,66 +295,343 @@ where | |||
Ok(()) | |||
} | |||
|
|||
/// Look up the IBC denomination from a IbcToken. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this function be defined in the ibc
crate instead, and imported here? Seems like we might want to use it in multiple places (and I wonder if it is in fact already defined somewhere...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, this function is already implemented in the client (where the queries are sent to an RPC node). I'll investigate whether the protocol version here (which reads storage directly) can somehow reuse this logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've discussed turning this function into an RPC endpoint with @tzemanovic . Doing so seems suboptimal because this function is a essentially a heuristic for guessing IBC denominations from IbcToken
hashes based on the results the protocol has cached so far. Also it seems to me that somehow using generics to share this logic would be overkill for this limited issue. Do you think there's a way to eliminate the use of this function in the MASP VP @yito88 ?
} | ||
|
||
// Apply the balance change to the changed balances structure | ||
fn apply_balance_change( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could all these functions simply be exported by the ibc
crate? Also, could they be combined into one which takes all the state changes and returns the ChangedBalances
for this transaction which the MASP VP needs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving the ChangedBalances
functions into the namada_ibc
crate is problematic because those functions depend on the namada_vp_env
crate (which itself depends on the namada_ibc
crate). The latter dependency is due to those functions doing pre and post balance reads as well as IBC trace reads and packet commitment reads from storage. I suspect I'd have to restructure these functions in order to reduce their dependence on validity predicate functions first. Should I attempt restructuring those functions in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(discussed offline - let's do this separately)
let receiver = msg.message.packet_data.receiver.to_string(); | ||
let addr = TAddrData::Ibc(receiver.clone()); | ||
acc.decoder.insert(ibc_taddr(receiver), addr); | ||
self.apply_send_packet(&mut acc, msg, keys_changed)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could generalize apply_send_packet
for Transfer
and NftTransfer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I was just a bit reluctant to do this now because the NFT E2E tests are not a part of the tests crate in the Namada repo and require some additional setup which I've not done yet. Do you think you could get this done more quickly/efficiently than me and open up a separate PR to generalize Transfer
to NftTransfer
? If not, then I can start working on this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope this could be helpful: #3422
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brilliant, thanks! Did you manage to run the NFT E2E tests on this? Just want to clarify #3409 (comment) , then I'll merge this in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I didn't try the NFT E2E test. I will test it after testing fungible token transfers in this PR.
Also, I'll release the updated Hermes for this PR to test in CI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see thanks. I've partially applied #3422 where it pertains to determining a token Address
from a packet denom
. However I just wanted to clarify whether or not logic to receive NFT messages is missing before applying the rest of the PR. See https://github.com/anoma/namada/pull/3422/files#r1645836855 . Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yito88 For lack of time could we include this NFT support in the next release after the one today? If so, did you get a chance to test the fungible token transfers in this PR? Were there any issues that need urgent addressing?
aacbe26
to
80fc75d
Compare
80fc75d
to
08e5664
Compare
Ok(Address::Internal(InternalAddress::IbcToken(hash))) => { | ||
hash.to_string() | ||
} | ||
_ => return Ok(token.as_ref().to_string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that the token
in this case is really the denom
that we're looking for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #3409 (comment) .
_ => return Ok(token.as_ref().to_string()), | ||
}; | ||
|
||
if let Some(owner) = owner { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to know the owner to query the IBC denomination at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to investigate this. For the purposes of validation, this function almost exactly mirrors the computation done during the construction of IBC transactions in the client. Compare this to
Line 1406 in 08e5664
/// Look up the IBC denomination from a IbcToken. |
Line 2583 in 08e5664
rpc::query_ibc_denom(context, &args.token.to_string(), Some(&source)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yito88 can you clarify here? I'm quite confused about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query_ibc_denom
is for looking for readable IBC denom with IbcToken
hash.
Using an owner was to avoid looking all IBC denoms up when the balance query didn't require --token
. (Now the query requires both the token and the owner. The RPC function is left for now.)
I think we don't need the query in MASP VP because the IBC denom should be in the packet and the token address can be calculated from it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For context, the token address for a receive packet is computed here in the MASP VP: https://github.com/anoma/namada/blob/4de6577c73e223504b0fcb226257ef7b85e248a7/crates/namada/src/ledger/native_vp/masp.rs#L483C25-L483C55 . This computation was designed to produce the same shielded token as the one produced by Hermes, which can be found at
Line 3505 in 5cc23b4
// Need to check the prefix |
I think we don't need the query in MASP VP because the IBC denom should be in the packet and the token address can be calculated from it.
Thanks for the clarification @yito88 . Would this same reasoning apply to how Hermes derives the token from the IBC denom (also using query_ibc_denom
and received_ibc_token
)? Or is the context of the Hermes computation somehow different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query_ibc_denom
looks stored IBC denoms up. received_ibc_token
returns the IBC denom to be minted/unescrowed. Hermes doesn't derive the token. I think you meant gen_ibc_shielding_transfer
. It uses received_ibc_token
because Hermes will attach the shielding transfer for the receiving token.
&message.timeout_height_on_b, | ||
&message.timeout_timestamp_on_b, | ||
); | ||
// Try to find a key change with the same port, channel, and commitment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we can't just construct the path directly and read from it (instead of iterating)? What data are we missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're missing the sequence number. Also, Yuji suggested a different approach:
packet sequence can be obtained from the state with read_pre and the key next_sequence_*_key because the transaction has only one IBC message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could make it a bit simpler because we can assume that the validated transaction has only one IBC transfer.
.or_insert(ValueSum::zero()); | ||
// Enable funds to be received by the receiver in the | ||
// IBC packet | ||
*post_entry = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the idea here is to mock a balance change to an address that we are not aware of on this chain (based on the ibc msg) so that then we can verify the matching between this ibc msg packet and masp transparent output with validate_transparent_output
, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, are we validating the optional ShieldingTransfer
that the receiving chain gets? I see that this message is built in build_ibc_transfer
and we also link the hash of the unshielding masp section of the source chain. The method execute
called by the ibc native vp returns this data but it seems like we never use it. This is probably a question for @yito88
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the idea here is to mock a balance change to an address that we are not aware of on this chain (based on the ibc msg) so that then we can verify the matching between this ibc msg packet and masp transparent output with
validate_transparent_output
, correct?
Yes, exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method execute called by the ibc native vp returns this data but it seems like we never use it.
Right, IBC actions never use ShieldingTransfer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yito88 is this ok? Do we have a way to verify that the relayer is indeed forwarding the correct ShieldingTransfer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the IBC VP has to validate the ShieldingTransfer
for the given IBC message.
I'll open another PR.
…ts no longer used.
…f the success acknowledgement.
439e5a9
to
fb0ed6f
Compare
fb0ed6f
to
0c999bd
Compare
_ => return Ok(token.as_ref().to_string()), | ||
}; | ||
|
||
if let Some(owner) = owner { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yito88 can you clarify here? I'm quite confused about this
&message.timeout_height_on_b, | ||
&message.timeout_timestamp_on_b, | ||
); | ||
// Try to find a key change with the same port, channel, and commitment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see.
} | ||
|
||
// Apply the balance change to the changed balances structure | ||
fn apply_balance_change( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(discussed offline - let's do this separately)
4de6577
to
0a5d480
Compare
…0' (#3409) * origin/murisi/masp-ibc-replay-protection-using-txdata-on-0.39.0: Added changelog entry. Update balances in the MASP using a non-mutating style. Now charge gas in IBC denom query. Start using IBC ports to determine message formats. Added more comments and improved function naming. Simplify checking packet acknowledgement by assuming the uniqueness of the success acknowledgement. Removed is_any_shielded_action_balance_key and related code since thats no longer used. Now map denominations to tokens using ibc_token instead of reverse_query_denom. Subdivided some functions involved in processing IBC packets. Reduced the dependence on IBC events. Ensure that native tokens can always be decoded. Handle the is_sender_chain_source case in the MASP VP. Centralized the construction of TransparentAddresses to ensure that encodings are consistent. Split up the IBC validation logic in MASP. Now check that the IBC events are valid with respect to storage changes. Created a separate type that is either an Address or IBC receiver. Modified the MASP VP to check the IBC receivers. Now hash the TransferTarget into Transaction transparent outputs.
Describe your changes
An attempt to address issue #3300. The approach taken is to include the IBC receiver in the pre-image of shielded
Transaction
outputs. More specifically, the following changes have been made:Address
indicating a non-IBC recipientAddress
that corresponds to an transferPacketData
and checking that the transparent inputs and outputs use thatTransaction
go to thereceiver
stated inPacketData
in the case of an outgoing shielded actionTransaction
are the IBC internal address in the case of a refund or an incoming shielded actionThis PR was derived from merging Namada 0.39.0 into #3406 .
Closes #3300
Indicate on which release or other PRs this topic is based on
Namada v0.39.0
Patched Hermes 1.8.2: heliaxdev/hermes#34
Checklist before merging to
draft