-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Allow NFT to be burned when number of offers is greater than 500 (part of NonFungibleTokensV1_2
amendment)
#4346
Changes from 12 commits
52f044d
9f6eac3
2a496c6
534dbc2
a05e1f6
ffae342
afe0e85
9912b7b
6b7cfb0
ad4df75
410e0b9
6d37bce
cc8d763
4cc0dfb
576d85c
f367420
414d454
7768ad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -520,34 +520,52 @@ findTokenAndPage( | |
} | ||
return std::nullopt; | ||
} | ||
void | ||
removeAllTokenOffers(ApplyView& view, Keylet const& directory) | ||
{ | ||
view.dirDelete(directory, [&view](uint256 const& id) { | ||
auto offer = view.peek(Keylet{ltNFTOKEN_OFFER, id}); | ||
|
||
if (!offer) | ||
Throw<std::runtime_error>( | ||
"Offer " + to_string(id) + " not found in ledger!"); | ||
int | ||
shawnxie999 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
removeTokenOffersWithLimit( | ||
ApplyView& view, | ||
Keylet const& directory, | ||
int maxDeletableOffers) | ||
{ | ||
if (maxDeletableOffers == 0) | ||
return 0; | ||
|
||
auto const owner = (*offer)[sfOwner]; | ||
std::optional<std::uint64_t> pageIndex{0}; | ||
int deletedOffersCount = 0; | ||
|
||
if (!view.dirRemove( | ||
keylet::ownerDir(owner), | ||
(*offer)[sfOwnerNode], | ||
offer->key(), | ||
false)) | ||
Throw<std::runtime_error>( | ||
"Offer " + to_string(id) + " not found in owner directory!"); | ||
do | ||
{ | ||
auto const page = view.peek(keylet::page(directory, *pageIndex)); | ||
if (!page) | ||
break; | ||
|
||
auto offerIndexes = page->getFieldV256(sfIndexes); | ||
|
||
// We reverse-iterate the offer directory page to delete all entries. | ||
// Deleting an entry in a NFTokenOffer directory page won't cause | ||
// entries from other pages to move to the current, so, it is safe to | ||
// delete entries one by one in the page. It is required to iterate | ||
// backwards to handle iterator invalidation for vector, as we are | ||
// deleting during iteration. | ||
shawnxie999 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (int i = offerIndexes.size() - 1; i >= 0; --i) | ||
shawnxie999 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (auto const offer = view.peek(keylet::nftoffer(offerIndexes[i]))) | ||
{ | ||
if (deleteTokenOffer(view, offer)) | ||
++deletedOffersCount; | ||
else | ||
Throw<std::runtime_error>( | ||
"Offer " + to_string(offerIndexes[i]) + | ||
" cannot be deleted!"); | ||
} | ||
|
||
adjustOwnerCount( | ||
view, | ||
view.peek(keylet::account(owner)), | ||
-1, | ||
beast::Journal{beast::Journal::getNullSink()}); | ||
if (maxDeletableOffers == deletedOffersCount) | ||
break; | ||
} | ||
pageIndex = (*page)[~sfIndexNext]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to move this update of
My concern if that if you delete the last offer out of the directory page, then The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting point, ill update my code. But weirdly I have never ran into this problem throughout all my time doing testing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to clarify, this situation is a problem because the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you didn't see a problem, but that still doesn't mean it was a good idea.
Yes, but it's better to take a larger view on this. For every C++ value you can either have a copy or a reference. The That's a generalization. There are specifics to lifetime rules using As it turns out, the |
||
} while (pageIndex.value_or(0) && maxDeletableOffers != deletedOffersCount); | ||
|
||
view.erase(offer); | ||
}); | ||
return deletedOffersCount; | ||
} | ||
|
||
TER | ||
|
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'm curious why buy offers for an NFToken are preferred over sell offers.
In my mind there should be a lot fewer sell offers for an NFT than there might be buy offers. I would expect there to almost always be fewer than 500 sell offers. If that's the case, then if we prefer sell offers then we will almost always remove the entire directory of sell
NFTokenSellOffers
.The buy offers seem like the ones that might exceed 500. If they do exceed 500, and we delete them first, then we'll be leaving two directory structures behind at the end of this:
It feels like we should design this to at least minimize the amount of ledger trash it leaves behind.
Am I correct that there are probably more buy offers than sell offers? Does the motivation for changing the preference make sense?
At the very least, the comment should explain why we prefer to delete buy offers. That way, if the reason stays important, it's less likely to be changed when someone is maintaining the code in the future.
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.
Yeah, it is more likely to have more buy offers than sell offers. That's why I tried to when delete buy offers, because I had the impression that buy offer is the root of the problem, and should be deleted first. On the other hand, sell offers are created by the owner and are less of a problem. Obviously I haven't taken optimization into account, and it does make sense to reduce ledge space to delete sell offers first.
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.
But I think it also may be more ideal to delete buy offers from user's perspective, because there would be less hassle for the buyer to delete their offers (if their offer was amongst the deleted ones). Buyers may not be aware of their outstanding buy offers when the NFT was burned, and take up unnecessary reserves for them. On the other hand, the owner of the NFT can delete his/her sell offer themself
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.
There is a accumulated effort when factoring how every buyer needs to manually cancel their buy offer, so it would probably be favourable to delete buy offers first.
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.
team would like to discuss with @ledhed2222
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'm not sure what how severe it is to having the extra directory on the ledger. Down the line, we are looking to implement (from Scott D.)
With this upcoming implementation, the sell directory is unlikely to hang on the ledger forever. As soon as someone submits a transaction to delete one of their orphaned offers, all the orphaned offers from the burnt NFT will be removed. So I don't think it would be a big problem then.
And I think it might be preferable to help the buyers first, because buyers are less aware of the orphaned offers. While the owner of the NFT who created sell offers is much more aware of his/her orphaned offers, and is more likely to delete them in batches themselves.
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'm curious - if i have an NFT with 600 buy offers, which I burn, there are now 100 orphaned offers. what parties are able to cancel the orphaned offers at that point, other than the person who owns the offer (and if they are expired, anyone)? presumably I should still be able to cancel them since I am listed as the "owner" on the offer.
but generally, I don't think i have a huge POV/opinion on which offers get cancelled with higher priority. what scott is saying makes sense. i might go with that.
however, one thing i'm wondering is whether we can included a
warning
if the token burn did not successfully cancel all offers. something likeNot all offers for this NFT could be cancelled. You should immediately cancel any remaining offers
.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.
Currently there are two parties that have permission to cancel NFTokenOffers, whether those offers are orphaned or not:
Owner
of the offer can always cancel the offer.Destination
, then theDestination
can cancel the offer.That's assuming that the offer has not expired, in which case the offer can be canceled by anybody.
Here's the code: https://github.com/XRPLF/rippled/blob/develop/src/ripple/app/tx/impl/NFTokenCancelOffer.cpp#L77-L87
Regarding a
warning
, that's not really something that the ledger internals can provide. There are three types of responses:tesSUCCESS
is what you get if the transaction succeeded. If theNFTokenBurn
succeeds, whether it leaves orphan offers or not, the appropriate response istesSUCCESS
.tec*
is the range of responses where the ledger did not do what you asked, but burned your fee anyway. That's not what is happening here, since the burn was successful.ter
,ter
, and so forth) to indicate other kinds of failures. But they all mean that your transaction did not change the ledger in any way.At any rate, such a warning would be returned to the wrong person.
The person who is leaving the orphaned offers is the issuer burning the token. They really don't care whether there are left over offers in the ledger. The only folks who care are the offer owners. And they only care once they want to recover the reserve on their offers. So they may not be motivated to cancel their offers for a long time.
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.
@seelabs' suggestion may help, but I have doubts about its effectiveness in a larger scale. Here's why.
Offers on the DEX are encountered whenever someone wants to trade a currency pair. There are some currency pairs that are very popular, so their order books get a lot of traffic. There are other currency pairs that see a lot less traffic. For those low-traffic currencies, dead offers can sit around for a long time before the DEX stumbles across them and removes them.
Compared to currency pairs, there are lots of NFTs on the ledger. And there are up to two order books for every individual NFT in the ledger. I would be astonished if any NFTs are traded frequently. The bulk of NFTs, and offers for them, will just sit on the ledger. Any single NFToken will probably be traded relatively infrequently.
So I doubt that suggestion will help much.
But at a more meta level, what I hear you saying is that the patch you are providing for this problem is insufficient. We need yet another patch to clean up what is left behind by this patch. Amendments are not free. We should get everything that we think is needed into one amendment.
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.
@scottschurr (cc. @seelabs )
Our team's idea is try to get this change into the next release(1.10), so that we can get voting and hear community's voice as early as possible. The voting may or may not be in our favor, but we want to get it into next release to get a feel what the community likes, and perhaps make more adjustments from there.
While I do agree that it feels more robust to include the patch of cleaning orphaned offers into the existing one, but unfortunately this was not considered in scoping, and including it would push back the timeline even further.