-
Notifications
You must be signed in to change notification settings - Fork 109
Replace service date by numbered forks #2272
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
Draft
larskuhtz
wants to merge
1
commit into
master
Choose a base branch
from
lars/replace-service-date-by-forknumbers
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| {-# LANGUAGE ImportQualifiedPost #-} | ||
|
|
||
| -- | | ||
| -- Module: Chainweb.ForkNumber | ||
| -- Copyright: Copyright © 2025 Kadena LLC. | ||
| -- License: MIT | ||
| -- Maintainer: Lars Kuhtz <[email protected]> | ||
| -- Stability: experimental | ||
| -- | ||
| module Chainweb.ForkState | ||
| ( | ||
| ) where | ||
|
|
||
| -- | Starting with Chainweb 2.33, forks are identified by a monotonically | ||
| -- increasing fork number. Each block is created according to a specific fork | ||
| -- number. | ||
| -- | ||
| -- Each fork number is associated with a specific block height at which it | ||
| -- becomes active. This number is also called the "fork height" for the | ||
| -- respective fork. Forks are either activated on a per chain or a per network | ||
| -- basis. The former are triggered as soon as the specific chain reaches the | ||
| -- block height for the respective fork. The latter are triggered when all | ||
| -- chains in the network have reached the respective block height. | ||
| -- | ||
| -- The Fork height of a fork is determined by miners, usually via upgrading to | ||
| -- a new software version that includes the fork activation logic, but it is | ||
| -- also possible that a new software version allows miners to configure whether | ||
| -- they want to support a specific fork or not. | ||
| -- | ||
| -- For the purpose of fork activation the feature flags field in the block | ||
| -- header is renamed into the "fork state" field. | ||
| -- | ||
| -- The support for a fork by a miner is signaled by increasing the vote count | ||
| -- for the fork in a newly mined block by one. Votes are accumulated over | ||
| -- 120 epochs (5 days), which is called a "fork epoch". I.e. a fork epoch | ||
| -- consists of 12 * 120 block heights. | ||
| -- | ||
| -- A fork is activated in an epoch when at least 2/3 of all blocks for the | ||
| -- previous 120 epochs have signaled for the respective fork number. Once a fork | ||
| -- is activated it can not be deactivated again. The fork number is | ||
| -- monontonically increasing. | ||
| -- | ||
| -- A block that is signalling a fork number that is larger than the current fork | ||
| -- number plus one is considered invalid. In other words forks can only be | ||
| -- activated successively, one at a time. There will always be at least 120 | ||
| -- epochs between the activation of two successive forks. | ||
| -- | ||
| -- Starting with chainweb-node version 2.33, a node must accept blocks that have | ||
| -- either the fork number of the block height of the block or the respetive fork | ||
| -- number plus one. It must reject all other blocks. The fork number at the time | ||
| -- that chainweb node version 2.33 is released is zero. | ||
| -- | ||
| newtype ForkState = ForkState { _forkState :: Word64 } | ||
| deriving (Eq, Ord, Generic) | ||
| deriving anyclass (NFData) | ||
|
|
||
| _forkNumber' :: ForkState -> Word32 | ||
| _forkNumber' (ForkState w) = int $ w .&. 0xFFFFFFFF | ||
|
|
||
| _forkVotes' :: ForkState -> Word32 | ||
| _forkVotes' (ForkState w) = int $ (w `shiftR` 32) .&. 0xFFFFFFFF | ||
|
|
||
| forkNumber' :: Lens' ForkState Word32 | ||
| forkNumber' = lens _forkNumber $ \(ForkState w) v -> ForkState | ||
| $ (w .&. 0xFFFFFFFF00000000) | ||
| .|. (fromIntegral v .&. 0xFFFFFFFF) | ||
|
|
||
| forkVotes' :: Lens' ForkState Word32 | ||
| forkVotes' = lens _forkVotes $ \(ForkState w) v -> ForkState | ||
| $ (w .&. 0x00000000FFFFFFFF) | ||
| .|. ((fromIntegral v .&. 0xFFFFFFFF) `shiftL` 32) | ||
|
|
||
| -- -------------------------------------------------------------------------- -- | ||
| -- Fork State Validation in Block Headers | ||
|
|
||
| _forkNumber :: BlockHeader -> Word32 | ||
| _forkNumber = view (forkState . forkNumber') | ||
|
|
||
| _forkVotes :: BlockHeader -> Word32 | ||
| _forkVotes = view (forkState . forkVotes') | ||
|
|
||
| forkNumber :: Lens' BlockHeader Word32 | ||
| forkNumber = forkState . forkNumber' | ||
|
|
||
| forkVotes :: Lens' BlockHeader Word32 | ||
| forkVotes = forkState . forkVotes' | ||
|
|
||
| forkEpochLength :: Natural | ||
| forkEpochLength = 120 * 120 -- 5 days | ||
|
|
||
| isForkEpoch :: BlockHeader -> Bool | ||
| isForkEpoch hdr = mod (view blockHeight hdr) forkEpochLength == 0 | ||
|
|
||
| getForkNumber :: BlockHeader -> Word32 | ||
| getForkNumber = view signaledForkNumber . view forkState | ||
|
|
||
| getForkNumberVotes :: BlockHeader -> Word32 | ||
| getForkNumberVotes = view signaledNumber . view forkState | ||
|
|
||
| validateForkNumber :: Parent BlockHeader -> BlockHeader -> Bool | ||
| validateForkNumber (Parent parent) hdr | ||
| | isForkEpoch hdr = | ||
| if view getForkNumberVotes parent >= (forkEpochLength * 2 `div 3) | ||
| then | ||
| view getForkNumber hdr == view getForkNumber parent + 1 | ||
| && view getForkNumberVotes hdr <= 1 | ||
| else | ||
| view getForkNumber hdr == view getForkNumber parent | ||
| && view getForkNumberVotes hdr <= 1 | ||
| | otherwise = | ||
| view getForkNumber hdr == view getForkNumber (parent hdr) | ||
| && view getForkNumberVotes hdr <= view getForkNumberVotes (parent hdr) + 1 | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
syntax error, missing back tick
and is this 3 supposed to be graph diameter? if so we need to get the graph diameter from the blockheader, not hardcode
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 the idea here is to allow fork votes to pass given that 2/3 of the blocks vote in favor.
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.
yes, the PR proposes that a super-majority is required.
The idea is that a forking changes only triggers when there is already sufficient support for it such the two branches of the network growth at different rates. The forking branch would establish itself is the clear winner, preventing inefficiencies and potential load spikes due to intermittent reorgs.
It probably also is generally a good idea to be conservative. In the "code is law" paradigm of a decentralized blockchain, a forking protocol change is a kind of constitutional change.