-
Notifications
You must be signed in to change notification settings - Fork 956
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
MASP vp multiple txs #2690
MASP vp multiple txs #2690
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2690 +/- ##
==========================================
- Coverage 53.95% 53.93% -0.03%
==========================================
Files 308 308
Lines 100018 100054 +36
==========================================
- Hits 53967 53963 -4
- Misses 46051 46091 +40 ☔ View full report in Codecov by Sentry. |
d7fe472
to
4629aba
Compare
token, | ||
amount, | ||
}) | ||
if let ShieldedActionOwner::Minted = counterpart { |
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 this could be removed if we only validated the absolute value of the balance changes instead of the value and the sign. I'm not sure though if this is completely safe to do
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.
Can I just clarify the following?: When receiving a simple IBC transfer, the Transaction
will have a vin
from the IBC account's transparent address and no vout
s (because the amount will be in the shielded outputs)? And because of this, validate_transparent_bundle
computes a negative delta? Is this the reason why we negate diff
here?
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 my understating when we receive a shielded action two things happen:
- We mint the token amount in the
#Multitoken/{token_addr}/balance/minted
balance (this should be the case only if we are receiving a foreign token, if we are receiving back the native token than we should unescrow from#Multitoken/{token_addr}/balance/#Ibc
) - The amount is shielded, thus increasing the transparent balance of the MASP, but this does not reduce the amount of the minted balance, so in this case the sum of the amounts does not collapse to 0, leading to the need to mock an opposite balance change for the minted balance to make the computation work
0e2cc89
to
143fbae
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.
Nice, I like the way you have structured the MASP VP. I just think that perhaps some of the logic could maybe be simplified and made less verbose. I also think we should take advantage of Transaction::sapling_value_balance()
in the MASP VP checks somehow since that value tells us how much is flowing into/out of the shielded pool for a given Transaction
.
I've sketched some of my ideas here: https://github.com/anoma/namada/tree/murisi/multi-tx-masp-vp-experiments .
let mut token_bundle_balances = BTreeMap::default(); | ||
|
||
// To help recognize asset types not in the conversion tree | ||
let unepoched_tokens = unepoched_tokens(token, denom)?; |
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.
It might be easier to compute and accumulate all unepoched_tokens
corresponding to ChangedBalance::masp
's elements in the loop in validate_state_and_get_transfer_data
. Doing that would remove this loop body's direct dependence on token
, and hence potentially allow us to remove the for token in changed_balances.masp {
loop in this function. Doing that might allows us to reduce the loop nesting in this function.
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.
Actually we still depend on the token
binding in two more places inside this loop:
- When checking the conversion
- When matching the transparent bundle agains the changed keys in storage
For the second point we could simply iterate on the entire token_bundle_balances
but for the first point I suspect we'd need to iterate anyway, so we'll end up just moving the for loop to a different place instead of removing it
|
||
match delta_balance { | ||
Some(delta_balance) | ||
if delta_balance == &delta_bundle => {} |
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.
It seems that we check here that the transparent account balance changes recorded in the MASP transaction reflect the transparent account balance changes reflected in the keys. So if the key changes indicate that Bertha's balance has increased by +1 BTC, a transaction with a vin
from Bertha of 5 BTC and a vout
of 6 BTC TO Bertha would pass, right? Do we have any checks to prevent the VP from accepting a vin
from Bertha of (5+x) BTC
and a vout of (6+x) BTC
(where x is large enough to exceed relevant source account balances)? If not, does anything in the client depend on the vin
s and vout
s correctness (and not just the correctness of the delta)?
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 good point. We don't have such a check, so it's possible for a transparent address to withdraw more than it owns if in the same transaction it also receives an amount great enough to compensate for this difference. To my understanding though, this is also the logic used in the multitoken
vp. The client seems to be working only with the deltas implied by the transparent bundle (atm we use the changed balance keys only to determine who's the sender and who's the receiver but we can perhaps rework that)
|
||
// Iterate over the delta balances described by the transparent | ||
// bundle and verify that these match the actual modifications | ||
// in storage NOTE: this effectively prevent the |
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 this restriction (of not allowing the same addresses/tokens to be involved in other transparent transfers in the same tx) conceptually necessary? Or is it just an accidental consequence of our current design?
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.
No this is an unfortunate consequence of this logic, I'd be very happy if we could lift this constraint
token, | ||
amount, | ||
}) | ||
if let ShieldedActionOwner::Minted = counterpart { |
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.
Can I just clarify the following?: When receiving a simple IBC transfer, the Transaction
will have a vin
from the IBC account's transparent address and no vout
s (because the amount will be in the shielded outputs)? And because of this, validate_transparent_bundle
computes a negative delta? Is this the reason why we negate diff
here?
); | ||
return Ok(false); | ||
} | ||
} else if !changed_balances.masp.is_empty() { |
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 it possible for the MASP transparent balance to be incorrectly changed when transparent bundles are there? Like imagine a situation where a single Tx
causes 5 BTC to be (legitimately) unshielded to Bertha (in the usual way with Transaction
- Transfer
pair) and simultaneously 10 ETH is transferred from MASP
transparent address to Christel
(with no corresponding vin
s or vout
s). In this situation shielded_tx.transparent_bundle()
would contain only BTC denominated vin
s and vout
s, and changed_balances.masp
would contain ETH and BTC. In this situation, which code prevents a positive change in changed_balances.other.get(ETH)
?
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 for
loop at line 361 should iterate over all the masp changed balances and then checks the transparent bundle. If the bundle does not contain any data for ETH than token_bundle_balances
should not be updated and therefore fail the test at line 579 where we check that the modifications implied by the transparent bundle effectively match to changes in storage. token_bundle_balances
is instantiated for every token based on the modifications in the balance keys in storage so it should cover the case you illustrated
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.
Correction, you're right, the token_bundle_balances
would be empty in this case and so this is a bug 👍🏻
… sapling bundle anymore
…oves unchecked operation.
91405df
to
01b7a8b
Compare
Closed in favor of #3186 |
* origin/murisi+grarco/multi-tx-masp-vp-rebased2: Enable governance to change MASP token map. Moved SignedAmount into core and removed use of unchecked arithmetic. Use try_fold to build the ChangedBalances object. Created a structure for representing conversion leafs. Factored the accumulation code out of verify_sapling_balancing_value. Updated the WASM binaries. Extend SignedAmount to hold MASP value balance. Use a MASP crate that guarantees ValueSums. Make MASP VP accept IBC transactions. Ensure that all implied transfers have been authorized by the relevant party. Split validate_transparent_bundle into 3 functions. Now check that the diff between pre and post is the value balance. Now decode AssetTypes separately. Unifies `DeltaBalance` and `SignedAmount` Fix transparent bundle validation bug Fixes balances check in masp vp to allow non-masp transfers Fixes balance owner when token is minted Changelog #2690 Refactors transparent bundle validation into a separate function. Removes unchecked operation. `valid_spend_descriptions_anchor` does not expect the presence of the sapling bundle anymore Refactors balances split Fixes unrecognized assets Refactors transparent bundle check to just compare maps Reworks masp vp to accept multiple transfers in a single tx
* origin/murisi+grarco/multi-tx-masp-vp-rebased2: Enable governance to change MASP token map. Moved SignedAmount into core and removed use of unchecked arithmetic. Use try_fold to build the ChangedBalances object. Created a structure for representing conversion leafs. Factored the accumulation code out of verify_sapling_balancing_value. Updated the WASM binaries. Extend SignedAmount to hold MASP value balance. Use a MASP crate that guarantees ValueSums. Make MASP VP accept IBC transactions. Ensure that all implied transfers have been authorized by the relevant party. Split validate_transparent_bundle into 3 functions. Now check that the diff between pre and post is the value balance. Now decode AssetTypes separately. Unifies `DeltaBalance` and `SignedAmount` Fix transparent bundle validation bug Fixes balances check in masp vp to allow non-masp transfers Fixes balance owner when token is minted Changelog #2690 Refactors transparent bundle validation into a separate function. Removes unchecked operation. `valid_spend_descriptions_anchor` does not expect the presence of the sapling bundle anymore Refactors balances split Fixes unrecognized assets Refactors transparent bundle check to just compare maps Reworks masp vp to accept multiple transfers in a single tx
Describe your changes
Closes #2595.
Modifies the MASP vp to allow multiple transfers in a single transaction. To achieve this, some constraints had to be removes (like the checks on the presence/absence of the transparent bundle, transparent inputs and outputs). Since we cannot expect a singles source/target anymore some changes were made, most importantly:
No changes to the SDK have been done in this PR because, at least for the moment, we still rely on the
Transfer
object to recover theTransaction
, and so othertx_data
types won't work, leading to an impossibility to effectively take advantage of these vp updates.Indicate on which release or other PRs this topic is based on
#2621
Checklist before merging to
draft