namada
namada copied to clipboard
Embed masp transactions inside fee payment
The masp client has some intrinsics limitations when it comes to producing transactions which derives from previous txs' output descriptions for which it has not queried a node. More specifically, given the missing notes coming from other txs not produced by this very wallet, it's impossible to construct a merkle tree matching one of those seen by the protocol: the result is that (almost) all txs built as such will be rejected because of an invalid commitment anchor.
To get around this, for shielding and unshielding operations (the ones affected by this), as proposed by @murisi, we could embed them directly inside the fee unshielding Transaction
object, so that the client can use the same, confirmed notes to produce a single transaction, avoiding the issue altogether.
To achieve this, we need to modify the client to produce a single Transaction
object in such cases and attach an empty tx as the inner to mock a no-op. We could also support another custom tx as the inner to allow running multiple transactions (the ones embedded in the fee payment and the actual inner).
For safety reasons this depends on #2592 so that the fee unshielding operation cannot be exploited to perform free transactions. It also depends on #2595 and #2596 for the unshielding case to support different tokens between the actual fee unshielding and the proper unshielding txs and also to avoid an extra transparent transfer from the fee payer to the actual recipient.
Finally, we need to review the logic in run_fee_unshielding
in terms of error management to see if needs to be changed to support this feature.
@grarco This will change the transaction format, right? Only for MASP transactions or also for all transactions?
Haven't thought too much about it but since we'll need to unshield to more than one recipient this should require modifying the structure of WrapperTx
, which would affect all transactions
@grarco Would it be possible to do a special case analysis of an inner transaction with an output from a MASP transfer that pays the fee? Would that be simpler or more complicated? Would that allow us to not break wrapper transactions?
New logic discussed 2024.04.26:
- When we analyze for "sufficient fee or not", we should first look at the wrapper, and in the special case where the wrapper fee paying address doesn't have enough balance, check if the inner contains a valid unshield to that address. Reject immediately if the inner does not contain an unshield.
Note with batching: first inner tx in a batch must pay for the fees.
Order of operations here:
- Remove fee unshielding bit in wrapper tx (#3217)
- Vectorize/refactor the transfer struct & inner tx (@grarco is working on this)
- Add in support for the first inner tx unshielding a fee (@grarco will work on this)