-
Notifications
You must be signed in to change notification settings - Fork 217
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
Fix for the listAssets
API which shows assets unrelated to a wallet
#3132
Conversation
listAssets
API which shows assets unrelated to a walletlistAssets
API which shows assets unrelated to a wallet
I implemented what we discussed today: instead of filtering "foreign" assets at "query" time we instead filter them at wallet restore time, omitting "foreign" TX outputs. Please take a look 👀 |
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.
Great
then | ||
let updatedTx = tx | ||
{ fee = actualFee dir | ||
, outputs = filter (ours s . address) (outputs tx) |
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.
Yes this looks like it will work for listAssets
.
If everything breaks due to this change, then perhaps we could annotate the TxOut address about whether it belongs to the wallet.
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.
Uhh, this does indeed look like it could break everything. 😅 I think the original idea for the Tx
type was to represent a transaction exactly as it appears on the chain — no modifications. (I believe that the adjustment to the fee
field is a hack, as this field did not exist in Byron, but is added for clarity.) Changing this assumption has several implications:
- The
/v2/wallets/{walletId}/transactions
endpoint changes in a backwards-incompatible way and no longer presents transactions as they appear on-chain. For example,cardano-node
will return a different result than this endpoint if you give it the same transaction hash. Tx
are stored in the database viaputTxHistory
. If we change the contents ofTx
, we would have to add a migration for the database as well.- The
inputIx
field of theTxIn
refers to an index in the listoutputs
. If we filter the list, the indices get rearranged. 😱 We are safe in thatourNextUTxO
uses the originaltx
, not theupdatedTx
to compute theUTxO
set. Users of the/v2/…/transactions
endpoint are not so lucky. If we really want to filter outputs from theTx
, we should at least record their indices as well.
In light of these implications, my preference would be to keep the original idea of Tx
representing a complete transaction, and do the filtering in listAssets
a posteriori.
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 Tx
type in cardano-wallet has never been a transaction exactly as it appears on the chain. Multiple fields are missing!
It can be whatever we want or need it to be. We can compute info about the transaction once during restoration, then cache it in the db. An example of such info is the transaction amount.
I ask, do users really need to see TxOuts which don't concern their wallet?
If they do, perhaps the wallet should store the original serialized transaction in the database for this purpose.
Although, if our code is making assumptions all over the place that the TxOuts aren't filtered -- you raise a very good point about numbering -- then it's probably easiest to not filter, but instead annotate the TxOut address with a flag indicating whether the address belongs to this wallet.
Yes this will probably need database migrations; we can do migrations.
Also users will not see a propertly filtered listAssets unless they restore from genesis. This is also fine.
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.
@HeinrichApfelmus appreciate your input!
I've added Solution #2 to the issue description that takes your input into account as described by @rvl
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.
@HeinrichApfelmus finally I finished covering discussed implementation with property tests. Please take another look and if there are no obstacles - I'll merge it.
41a7bf2
to
35e453b
Compare
25c6952
to
d3f58cb
Compare
@@ -770,6 +773,24 @@ prop_applyOurTxToUTxO_allOurs slotNo blockHeight tx utxo = | |||
shouldHaveResult :: Bool | |||
shouldHaveResult = evalState (isOurTx tx utxo) AllOurs | |||
|
|||
-- Verifies that UTxO set can't grow when there are no "our" transactions. | |||
-- Hint: UTxO set shrinks when foreign transaction uses it as collateral. |
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 don't think that the hint is correct. "Collateral" has a very specific meaning and the UTxO can shrink even when no "collateral" inputs are used. Also, a transaction cannot be "foreign" if it spends an output belonging to the wallet!
I think the underlying issue is that there are two ways to recognize whether a transaction creates or spends an output belonging to our wallet: a) checking whether the address of a transaction output belongs to us and b) looking up a transaction input in our UTxO
. (isOurTx
gives a complete list of ways). In particular, transaction inputs cannot be recognized by their address — transaction inputs are stored as references and are not resolved. The only way to recognize a TxIn
is to have a current UTxO
set as reference — this is a subtle, but important point. In turn, this implies that the utxo
arguments from all the tests are, in fact, transaction outputs that have once been recognized as "ours".
In that light, I recommend to remove the prop_applyOurTxToUTxO_noneOurs
test — the assumption that no outputs ever belong to the test wallet logically implies that the argument utxo
should empty. The logic that the test was trying to cover is probably already covered by prop_applyOurTxToUTxO_someOurs
.
ce1c5c0
to
9d9a10f
Compare
…problematic test
9840105
to
329335b
Compare
329335b
to
1a93496
Compare
Issue Number
ADP-710
Problematic current state:
list of wallet assets
WAs
derived like this:Solution №1(unfoldable, superseded by the Solution №2, see below)When restoring wallet state from blocks of transactions all transaction outputs that are not related to wallet address are omitted;
Consequences
Wallet states collected before the fix contain transactions with all outputs (including unrelated) In order for the unrelated assets (those found in unrelated outputs) to disappear wallet state needs to be restored from scratch.
Modified transactions
T'
are no longer valid as some of their outputs were omitted;Solution №2(unfoldable, superseded by the Solution №3, see below)Solution №2
Solution №3
Ad-hoc improvements
Cardano.Wallet
module