Fix invariant checks for Permissioned Domains#6134
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #6134 +/- ##
=========================================
- Coverage 79.9% 79.9% -0.0%
=========================================
Files 840 840
Lines 65483 65514 +31
Branches 7251 7256 +5
=========================================
+ Hits 52332 52343 +11
- Misses 13151 13171 +20
🚀 New features to boost your workflow:
|
|
Does this need an amendment? |
No it didn't change anything. I can't imagine situation where before is different from after (except where before is null) |
ximinez
left a comment
There was a problem hiding this comment.
This invariant has a few problems in general:
sleStatus_is anoptional. It should be avector, in case more than one permissioned domain is affected by a transaction. If that is supposed to be impossible, then that can be one of the first things thatfinalizechecks.if (selStatus_.size() > 1) { JLOG...; return false; }- The conditions in
finalizeare only checked for successfulPermissionedDomainSettransactions. If no other transaction should be able to modify a permisioned domain object, then it should check that. That probably means adding a check forPermissionedDomainDelete, too. If it's not one of those two types, or not successful, andselStatus_is not empty,finalizeshould fail. If it is one of those two types, andselStatus_.size() != 1,finalizedshould also fail. Maybe add an_isDeletedflag toSleStatusand check that it's false forSet, and true forDelete. - Because you're checking the integrity of the object, and not checking any of the changes between
beforeandafter, you probably should ignorebeforeentirely. If it's messed up, there's nothing you can do about it, and ifafteris correct, then you've fixed whatever problem might have existed.
All that said, that's not what this PR is about, though maybe it should be. The changes above would obviously require an amendment.
As for what the PR is about, I can't convince myself that it's impossible for this change to result in a different ledger. The main reason is that if, somehow, a bad object had ever been written to the ledger, this check will now catch it, whereas it wouldn't have caught it before the change. That will result in the transaction succeeding on some nodes, and failing on others.
modified and added check for size() > 1 (which is actually impossible as there is no such transaction)
removed check for "before"
I don't think it is possible. Invariant checks are all called for every tx, and I don't see a way to figure out that this particular PermissiondDomain sle object is modified by this particular tx. We just assumed that if there is "after" then it was
Don't think that we need to add check for PermissionedDomainDelete. Do we actually care if the delete incorrect object ?
This is not true. Currently (without this PR) invariants check only "after" object for both cases ("before" and "after"), and only for PermissionedDomainSet transaction. Which mean "after" always will be present (no crash) and verified. And "before" check is not so important (as you mention early, and I agree). Also this fix is related to verification logic, not to the creation/modification logic. Correct me if I'm wrong somewhere. |
e586813 to
34ea901
Compare
EVERY failure case in an Invariant should be impossible. The intention is less "double-check that the transaction did the right thing", and more "if something goes extremely wrong, or an attacker finds an exploit, what are some reasonable checks we can do to stop it?" That's why invariant unit tests have to modify the open ledger directly. The things they're testing for are, as far as we know, impossible to do with a transaction.
👍
We don't care if the object is malformed if it's deleted, but what if it isn't deleted? What if it's deleted incorrectly? Basic outline of how to check all of the above conditions in
Ironically, I realized that removing the
"I don't see a way to create invalid object" is exactly what Invariants are for. You may not see a way to create an invalid object, or two objects, or to delete an object that shouldn't be deleted, but that doesn't mean that there isn't one. Back to what I said earlier, the intention of Invariants is to catch those impossible situations that end up happening despite all our best efforts. Maybe you made a mistake. Maybe there's some subtle exploit that nobody can predict. Or maybe an inexperienced developer makes a change five years from now without understanding all the implications and consequences. The questions to ask yourself are
For example, let's assume your implementation of the transactors is perfect. Great. Down the road, there's a new feature that has nothing to do with those transactions. Product, design, or the developer decides it would be cool to automatically create a Permissioned Domain automatically as part of the new Oh, and they don't look at the Invariants either. Maybe they figure "Hey, if the invariants don't complain, then it must be ok." As currently written, the Invariants won't complain. And to add icing to the cake, the code review doesn't catch it. And testing maybe doesn't even know it exists, or they don't thoroughly exercise all the possible edge cases. "Oh, that can't happen..."
Despite a very good developer implementing the feature, and a boatload of time spent on the code reviews, including onr by me, that issue was discovered and reported by external contributors (including a former Rippler, but we can't count on that). I don't remember the exact timeline, but I think it was before QA got their hands on it, Even so, I don't think they would have caught it, because they're not in the habit of checking the entire object tree for stray objects. (Maybe they should?) |
ximinez
left a comment
There was a problem hiding this comment.
This is so much better and safer! Thank you for making the changes. I left a couple of suggestions, but they're all pretty minor, and easy to fix.
ximinez
left a comment
There was a problem hiding this comment.
Apologies for the absurdly long delay getting back to this. Thanks for making the changes.

High Level Overview of Change
Fixed typo in invariant checks, found by Immunefi
Type of Change
.gitignore, formatting, dropping support for older tooling)