Skip to content
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

The case of the missing ada #1598

Merged
merged 5 commits into from
Jun 30, 2020
Merged

The case of the missing ada #1598

merged 5 commits into from
Jun 30, 2020

Conversation

nc6
Copy link
Contributor

@nc6 nc6 commented Jun 30, 2020

A fun one, this.

The scenario:

In one of our tests, 163,000 ADA vanished, violating the preservation of ADA property. How did this happen? The sequence of events was something like this:

  1. Key 24583f7b is registered, and is set as the reward account for a pool.
  2. The pool produces a number of blocks.
  3. A reward update is created which includes a payment of 163765411781 lovelace to 24583f7b.
  4. Key 24583f7b is deregistered.
  5. The reward update created in 3 is applied. This has the effect of adding 24583f7b back into the _rewards map, but not the _stkCreds map.
  6. Key 24583f7b is re-registered. Since it is not in the _stkCreds map, this is allowed. However, the registration zeros its rewards, resulting in the destruction of those 163,000 ADA.

Why did we not spot this sooner? Well, because previously we had:

_rewards = _rewards ds ∪ Map.singleton (RewardAcnt network hk) (Coin 0)

during certificate registration. But during the performance upgrades (in d716ad) this was changes to

_rewards = addpair (RewardAcnt network hk) (Coin 0) (_rewards ds),

Union is left-biased, and hence will not overwrite. addpair is implemented to ignore the old value and overwrite it with the new. Hence before d716ad, the reward account still contained funds, albeit inaccessible ones.

This PR does a number of things:

  • It expands the test for ADA preservation to be more helpful.
  • It adds an additional check to the ADA preservation that verifies a more local preservation property - that outside the epoch boundary, the change in rewards must be equal to the sum of the withdrawls.
  • It adds another test which verifies that the stkCreds and rewards maps stay in sync (e.g. that they have the same domain).
  • It adds a sanity check during key registration that the key is not already in rewards.
  • It fixes applyRUpd by checking whether the keys are still registered. Any funds allocated to deregistered keys are now returned to the reserves.

nc6 added 4 commits June 30, 2020 12:28
This commit reworks the "preservation of ADA" test to more accurately
reflect what it's testing (CHAIN level rather than NEWEPOCH). In
addition, it adds an extra ada preservation property, which confirms
that outside of an epoch boundary, the change in rewards is equal to the
sum of withdrawls.
This will fix the problem, but does not reveal the underlying cause.
This commit fixes the underlying issue behind the missing ADA.

When we create a reward update, we only grant rewards to registered
stake keys. However, it's possible to deregister them after the update
is created but before it's applied. In such a case, `applyRUpd` was
adding them to a reward map anyway. When the key got re-registered, the
reward account was being reset to 0, and hence money was being
destroyed.

This commit adds a check to `applyRUpd` that verifies whether a key is
still registered and, if not, returns the funds to the reserves.
@nc6 nc6 requested a review from JaredCorduan June 30, 2020 10:39
@nc6 nc6 requested a review from uroboros as a code owner June 30, 2020 10:39
Copy link
Contributor

@uroboros uroboros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BRAVO!

@@ -222,6 +232,7 @@ delegationTransition = do
-- note that pattern match is used instead of regCred, as in the spec
-- hk ∉ dom (_stkCreds ds) -- Specification code translates below
not (haskey hk (_stkCreds ds)) ?! StakeKeyAlreadyRegisteredDELEG hk
not (haskey (RewardAcnt network hk) (_rewards ds)) ?! StakeKeyInRewardsDELEG hk
Copy link
Contributor

@JaredCorduan JaredCorduan Jun 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want to add this change to the spec too? I can do it if that would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change isn't too important (it's a sanity check), but if you felt like adding the applyRUpd changes to the spec that would be great!

Copy link
Contributor

@JaredCorduan JaredCorduan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 👏 🕵️

@nc6 nc6 merged commit 179bfd3 into master Jun 30, 2020
@iohk-bors iohk-bors bot deleted the nc/the-case-of-the-missing-ada branch June 30, 2020 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants