Conversation
66d84da to
ac93434
Compare
27470c6 to
a5cd565
Compare
| // If `before` is empty, this means an object is being created | ||
| // If `after` is empty, this means an object is being deleted | ||
| // Otherwise it's a modification of an object. | ||
| XRPL_ASSERT( | ||
| before != nullptr || after != nullptr, | ||
| "ripple::ValidVault::visitEntry : some object is available"); |
There was a problem hiding this comment.
This comment is not true. after should never be null. Deletion is indicated by isDelete.
- If
beforeis empty, then the object is being created - If
isDeleteis true, the the object is being deleted - Otherwise it's a modification of an object.
I think the correct assert is more like
after != nullptr && (before != nullptr || !isDelete)
| if (txnType == ttVAULT_CREATE || // | ||
| txnType == ttVAULT_SET || // | ||
| txnType == ttVAULT_DEPOSIT || // | ||
| txnType == ttVAULT_WITHDRAW || // | ||
| txnType == ttVAULT_CLAWBACK) |
There was a problem hiding this comment.
This should probably be a "permission"
There was a problem hiding this comment.
Thanks, added mustModifyVault (and a TODO to add mayModifyVault which I think you will do)
| // Transactor makes this condition impossible, but since we need to | ||
| // access beforeVault_ then we also need a defensive check. | ||
| if (!beforeVault_ && txnType != ttVAULT_CREATE) | ||
| { | ||
| // LCOV_EXCL_START | ||
| UNREACHABLE( | ||
| "ripple::ValidVault::finalize : missing old vault state"); | ||
| return false; | ||
| // LCOV_EXCL_STOP | ||
| } |
There was a problem hiding this comment.
Remember, the whole purpose of the invariants are to catch things that might be wrong in transactors, so something like "Transactor makes this condition impossible" is the wrong way to look at this. All of these failure conditions should be impossible.
Also, this is absolutely testable using the framework in Invariants_test.cpp. Do a test case that manually creates, modifies, or deletes a vault, but have the transaction type be, I dunno, ttPayment.
There was a problem hiding this comment.
Thank you, you are almost right - except I have to use a transaction type which passes the if in the outer scope i.e. one of the Vault transactions.
There was a problem hiding this comment.
Thank you, you are almost right - except I have to use a transaction type which passes the
ifin the outer scope i.e. one of the Vault transactions.
In that case, you should probably check condition this outside of that scope, which it looks like you've already done. Nice!
| (tx.getTxnType() == ttVAULT_DEPOSIT || // | ||
| tx.getTxnType() == ttVAULT_WITHDRAW || // | ||
| tx.getTxnType() == ttVAULT_CLAWBACK)) |
There was a problem hiding this comment.
This could probably also be a permission.
| case ltVAULT: | ||
| beforeVault_ = Vault::make(*before); | ||
| break; |
There was a problem hiding this comment.
This whole class has a "fatal flaw". (Well, not really fatal, but very significant.)
You're assuming that only one Vault will be affected. What if there are more? You're going to, for example, overwrite befaultVault_ here.
You've got the same problem when you're looking up assets and shares in finalize, where you return the first matching item found. What if there are multiple matches?
It should be impossible, but that is what invariants are here to confirm.
All of these structures and functions should be using collections (vector, set, whatever) instead of single values. You could have a simple check after each one that's like
if (beforeVault_.size() > 1)
{
XRPL_ASSERT(enforce, ...);
return !enforce;
}
There was a problem hiding this comment.
Thanks, that's great feedback. Making it work is actually simple (since optional is basically a collection of at-most-one)
There was a problem hiding this comment.
Thanks, that's great feedback. Making it work is actually simple (since
optionalis basically a collection of at-most-one)
I figured it would be. 😄
|
@ximinez I implemented your feedback in last three commits: Incidentally, your observation that the comment (and assert) in |
| // Note, only valid case when `afterVault_` can be empty is handled above | ||
| if (afterVault_.empty()) | ||
| { | ||
| if (hasPrivilege(tx, mustModifyVault)) |
There was a problem hiding this comment.
This comment is not true anymore. There's no case above that returns success if afterVault_ is empty, and this test does.
There was a problem hiding this comment.
Thank you, I cleaned this up in c73dc5f
ximinez
left a comment
There was a problem hiding this comment.
Updates look good. I don't think I've reviewed everything, so I'll skip a full approval.
Requested changes have been made, but I haven't done a full review.
This change adds invariants for SingleAssetVault #5224 (XLS-065), which had been intentionally skipped earlier to keep the SAV PR size manageable.
This change adds invariants for SingleAssetVault #5224 (XLS-065), which had been intentionally skipped earlier to keep the SAV PR size manageable.
High Level Overview of Change
This adds invariants for SingleAssetVault #5224 XLS-065
Context of Change
Invariants were intentionally skipped from #5224 to keep the PR size manageable. This PR fills the hole.
Type of Change
.gitignore, formatting, dropping support for older tooling)