-
Notifications
You must be signed in to change notification settings - Fork 27
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
feat(consensus): eliminate block ties #673
base: master
Are you sure you want to change the base?
Conversation
5598803
to
8abec23
Compare
8abec23
to
5026f34
Compare
5026f34
to
d4dc39e
Compare
d4dc39e
to
807d778
Compare
7e4b8b8
to
e516014
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #673 +/- ##
==========================================
- Coverage 84.70% 84.61% -0.10%
==========================================
Files 313 313
Lines 24249 24256 +7
Branches 3690 3693 +3
==========================================
- Hits 20541 20525 -16
- Misses 2997 3009 +12
- Partials 711 722 +11 ☔ View full report in Codecov by Sentry. |
for tx in txs2: | ||
meta = tx.get_metadata(force_reload=True) | ||
self.assertIsNone(meta.first_block) | ||
# for tx in txs2: |
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.
Why is this part of the code commented out?
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 actually not too sure, I'll review this part.
@@ -624,6 +624,11 @@ def get_best_block_tips(self, timestamp: Optional[float] = None, *, skip_cache: | |||
elif meta.score > best_score: | |||
best_score = meta.score | |||
best_tip_blocks = [block_hash] | |||
|
|||
# XXX: if there's more than one we filter it so it's the smallest hash | |||
if len(best_tip_blocks) > 1: |
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.
Should we allow the caller to choose whether they want to get just one or all of them?
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 think that could make sense as a new method, like get_all_block_tips
, instead of get_best_block_tips
. But currently that method wouldn't be used anywhere else, and when removing the tips indexes, it would be more convenient if we didn't have to maintain that method.
@@ -624,6 +624,11 @@ def get_best_block_tips(self, timestamp: Optional[float] = None, *, skip_cache: | |||
elif meta.score > best_score: | |||
best_score = meta.score | |||
best_tip_blocks = [block_hash] | |||
|
|||
# XXX: if there's more than one we filter it so it's the smallest hash | |||
if len(best_tip_blocks) > 1: |
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.
Should we create an issue to refactor this method and simply store the current best block in the storage?
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.
#540 sort of does this by using the height-index, but because it's not using this PR as a base it does this incorrectly and hides other tips, after this PR that change would be correct
17c1ffc
to
93d9f89
Compare
e516014
to
1b93f4d
Compare
93d9f89
to
da4ac0d
Compare
da4ac0d
to
b74fa0d
Compare
1b93f4d
to
b9b2390
Compare
b74fa0d
to
45884e3
Compare
b9b2390
to
2dddd20
Compare
45884e3
to
b21d67c
Compare
2f2d7a8
to
1a3e1d0
Compare
4a182f4
to
d870605
Compare
fb35bfb
to
17eac7c
Compare
2dddd20
to
3f18210
Compare
17eac7c
to
26a36c0
Compare
3f18210
to
e7b3d46
Compare
e7b3d46
to
2aa27e6
Compare
Bencher Report
🚨 1 Alert
Click to view all benchmark results
|
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.
Approved!
2aa27e6
to
ec17e5b
Compare
Co-authored-by: Jan Segre <jan@hathor.network>
a0b589a
to
4bf80a4
Compare
Motivation
We've always supported "block ties", meaning that blocks that have the same score will tie and both void each other, while at the same time having to remain as "best block tips" (which always had to be a list). This pushes some unnecessary complexity throughout the code. There are no disadvantages to using the block hash as a tie-breaker and simplifying this complexity.
In practice there's a slight difference in the consensus of certain situations, the difference is that before some tied block chains would be voided all the way back until they weren't tied anymore, now one of them would be picked as best chain. This situation does not cause any incompatibility in how nodes sync and any new block with higher score will cause the same state on both chains.
This PR is the first step, that only focuses on removing ties at the consensus level. Subsequent PRs will focus on refactoring out the complexity of supporting multiple tips.
Acceptance criteria
update_voided_info
so when testing if a new block might be a winner, and its score is neither higher or lower than the current winner (that is, a tie), the hash is used as a tie breakerupdate_voided_info
so when a new block is not a winner, only the tip with highest score and lowest hash is stored as "best block tips" cacheget_best_block_tips
so it only ever returns a list of size 1, when the block tips index returns more than one tip with the highest score, the one if lowest hash is selectedtest_split_brain_only_blocks_different_height
so it checks the node will correctly not void everything back to the genesis and tie the two blocks (when before it used to)test_single_fork_not_best
similarly, so it checks that the best chain is considered