Do not insert into accounts lt hash cache if freeze has started#6307
Do not insert into accounts lt hash cache if freeze has started#6307brooksprumo merged 3 commits intoanza-xyz:masterfrom
Conversation
e4c73cb to
ba98c82
Compare
|
Backports to the beta branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule. Exceptions include CI/metrics changes, CLI improvements and documentation updates on a case by case basis. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6307 +/- ##
=======================================
Coverage 82.7% 82.7%
=======================================
Files 845 845
Lines 377824 377847 +23
=======================================
+ Hits 312782 312824 +42
+ Misses 65042 65023 -19 🚀 New features to boost your workflow:
|
| if self | ||
| .freeze_started_for_accounts_lt_hash | ||
| .load(Ordering::Acquire) | ||
| { |
There was a problem hiding this comment.
As discussed offline, checking here isn't sufficient to guarantee freeze hasn't started before we modify the lt hash cache.
|
since we don't do rent anymore, the buggy account is always |
|
The above patch can still have a race with TX when we compute the lthash. Another idea is to blacklist |
Not a bad idea but some future SIMD's that allow customizing where block fees are distributed will make this approach too complicated in my opinion |
I'm not confident to say that |
Correct. Fixed in 013298a. |
Yeah, I think it should be fine grabbing the read lock here. We only ever grab the write lock during Bank::freeze(), so during |
jstarry
left a comment
There was a problem hiding this comment.
Looks correct to me as is, but we can do without the extra atomic
| let has_freeze_started = self | ||
| .freeze_started_for_accounts_lt_hash | ||
| .load(Ordering::Relaxed); |
There was a problem hiding this comment.
We don't need freeze_started_for_accounts_lt_hash if we are using self.freeze_lock() because we can check if the hash is not equal to Hash::default() to know if we read locked before or after freezing.
There was a problem hiding this comment.
Yeah, you're right. I could use freeze_started_for_accounts_lt_hash as an optimization: e.g. check the atomic bool first, and if true we can bail early, else grab the read lock and check again. I don't think that'll be a common case, so I don't think the added complexity is necessary.
I've removed freeze_started_for_accounts_lt_hash in 532b547.
HaoranYi
left a comment
There was a problem hiding this comment.
Nice. The change is much simipler now. Change is contained in only one file. It should be much easier to backport.
(cherry picked from commit 273f713)
… (backport of anza-xyz#6307) (anza-xyz#6320) * Do not insert into accounts lt hash cache if freeze has started (anza-xyz#6307) (cherry picked from commit 273f713) * fix build due to sdk dependency renames --------- Co-authored-by: Brooks <brooks@anza.xyz>

Problem
When activating the accounts lt hash feature (SIMD-215) on testnet, there was a bank hash mismatch caused by a bad lt hash.
After investigating with @jstarry1, it was concluded this is possible when the leader is still executing transactions after bank freeze has started. This would allow putting an entry into the accounts lt hash cache that was not the initial value of the account, and instead the value after bank freeze finishes up any deferred changes to account state. Then, then calculating the lt hash for the slot, we'd compute the wrong final lt hash value, since the initial state of this account was incorrect in the cache.
Here's an example:
freeze()and begins finishing up deferred changes to account state.A.Tis executing that includes an instruction that modifies accountA.TloadsA, and as part of loadingA, we callinspect_account(). The value ofAthat gets loaded is after step (2). The modifiedAis added to the accounts lt hash cache.Tfinished executing and sees it is past the end of the block so it does not commit.Ais a modified account in this slot because of step (2). As part of subtracting out the old state of accountA, we look at the accounts lt hash cache and see there is an entry forA. However, this version ofAis the same as the modified version, and not the old version ofA. Thus, we calculate the accounts lt hash value.Summary of Changes
Disallow adding entries to the accounts lt hash cache if freeze has started.
Note, I intend to backport this to v2.2.
Footnotes
https://discord.com/channels/428295358100013066/838890116386521088/1375339076370300958 ↩