Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.

Commit 9c47353

Browse files
committed
Fork state header validation
1 parent e5a9226 commit 9c47353

File tree

6 files changed

+362
-62
lines changed

6 files changed

+362
-62
lines changed

cabal.project

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ package yet-another-logger
9595
source-repository-package
9696
type: git
9797
location: https://github.com/kadena-io/pact.git
98-
tag: d4f03045df6ba5178a76e534d619b6233ad1c659
99-
--sha256: 1q4b3i606davn6iyk6az2q7cw5f7llxjhkbqyzw4bsxhrkah7fch
98+
tag: 4208012e3f2fdf1721c24cdcb97de5f64fd5f58a
99+
--sha256: 1al11csqr291avfwbb7hcrfxapz9sx0iclv3j5ipnli287h52cvs
100100

101101
source-repository-package
102102
type: git
103103
location: https://github.com/kadena-io/pact-5.git
104-
tag: 6c81f4cf0631a4087f8350230bd9b7c3714f9751
105-
--sha256: sha256-7SttW6Aexh+sQLdT1JZ4sZIhRXJ5G4q23aBvRh0sEK0=
104+
tag: bfc5310c462aaefabe7c512407ac6dab87fc8c42
105+
--sha256: 05xp1vwxkvjxrn8pij9z4g1hadbkb8hrgziwzs408yxxxmkcv6kq
106106

107107
source-repository-package
108108
type: git

chainweb.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ library
194194
, Chainweb.CutDB.RestAPI.Server
195195
, Chainweb.CutDB.Sync
196196
, Chainweb.Difficulty
197+
, Chainweb.ForkState
197198
, Chainweb.Graph
198199
, Chainweb.HostAddress
199200
, Chainweb.Logger

src/Chainweb/BlockHeader.hs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module Chainweb.BlockHeader
4747

4848
-- * BlockHeader
4949
, I.BlockHeader
50+
5051
-- ** Getters
5152
, blockFlags
5253
, blockCreationTime
@@ -61,6 +62,10 @@ module Chainweb.BlockHeader
6162
, blockEpochStart
6263
, blockNonce
6364
, blockHash
65+
, blockForkState
66+
, blockForkVotes
67+
, blockForkNumber
68+
6469
-- ** Utilities
6570
, I._blockPow
6671
, I.blockPow
@@ -85,6 +90,12 @@ module Chainweb.BlockHeader
8590
, I.adjacentChainIds
8691
, I.absBlockHeightDiff
8792

93+
-- ** Fork State
94+
, I.isForkEpochStart
95+
, I.forkEpochLength
96+
, I.isForkCountBlock
97+
, I.isForkVoteBlock
98+
8899
-- * IsBlockHeader
89100
, I.IsBlockHeader(..)
90101

@@ -107,15 +118,16 @@ module Chainweb.BlockHeader
107118
)
108119
where
109120

110-
import Chainweb.ChainId (ChainId)
111-
import Chainweb.BlockWeight (BlockWeight)
112-
import Chainweb.BlockHeight (BlockHeight)
113-
import Chainweb.Version (ChainwebVersionCode)
114-
import Chainweb.Payload (BlockPayloadHash)
115-
import Chainweb.Difficulty (HashTarget)
121+
import Chainweb.ForkState (ForkState, ForkVotes, ForkNumber)
122+
import Chainweb.BlockCreationTime (BlockCreationTime)
116123
import Chainweb.BlockHash (BlockHash, BlockHashRecord)
117124
import Chainweb.BlockHeader.Internal qualified as I
118-
import Chainweb.BlockCreationTime (BlockCreationTime)
125+
import Chainweb.BlockHeight (BlockHeight)
126+
import Chainweb.BlockWeight (BlockWeight)
127+
import Chainweb.ChainId (ChainId)
128+
import Chainweb.Difficulty (HashTarget)
129+
import Chainweb.Payload (BlockPayloadHash)
130+
import Chainweb.Version (ChainwebVersionCode)
119131
import Control.Lens (Getter)
120132

121133
blockFlags :: Getter I.BlockHeader I.FeatureFlags
@@ -156,3 +168,12 @@ blockNonce = I.blockNonce
156168

157169
blockHash :: Getter I.BlockHeader BlockHash
158170
blockHash = I.blockHash
171+
172+
blockForkState :: Getter I.BlockHeader ForkState
173+
blockForkState = I.blockForkState
174+
175+
blockForkVotes :: Getter I.BlockHeader ForkVotes
176+
blockForkVotes = I.blockForkVotes
177+
178+
blockForkNumber :: Getter I.BlockHeader ForkNumber
179+
blockForkNumber = I.blockForkNumber

src/Chainweb/BlockHeader/Internal.hs

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ module Chainweb.BlockHeader.Internal
9292
, blockEpochStart
9393
, blockNonce
9494
, blockHash
95+
9596
-- ** Utilities
9697
, _blockPow
9798
, blockPow
@@ -130,6 +131,19 @@ module Chainweb.BlockHeader.Internal
130131
-- * Create a new BlockHeader
131132
, newBlockHeader
132133

134+
-- * Fork State
135+
, blockForkState
136+
, _blockForkNumber
137+
, blockForkNumber
138+
, _blockForkVotes
139+
, blockForkVotes
140+
, forkEpochLength
141+
, isForkEpochStart
142+
, isForkCountBlock
143+
, isForkVoteBlock
144+
, newForkState
145+
, isLastForkEpochBlock
146+
133147
-- * CAS Constraint
134148
, BlockHeaderCas
135149

@@ -186,6 +200,7 @@ import Numeric.AffineSpace
186200
import Numeric.Natural
187201
import System.IO.Unsafe
188202
import Text.Read (readEither)
203+
import Chainweb.ForkState
189204

190205
-- -------------------------------------------------------------------------- --
191206
-- Nonce
@@ -244,6 +259,8 @@ decodeEpochStartTime = EpochStartTime <$> decodeTime
244259

245260
-- -----------------------------------------------------------------------------
246261
-- Feature Flags
262+
--
263+
-- Deprecated: renamed into 'blockForkState'
247264

248265
newtype FeatureFlags = FeatureFlags Word64
249266
deriving stock (Show, Eq, Generic)
@@ -600,7 +617,7 @@ epochStart ph@(ParentHeader p) adj (BlockCreationTime bt)
600617
--
601618
-- The result is guaranteed to be non-empty
602619
--
603-
adjCreationTimes = fmap (_blockCreationTime)
620+
adjCreationTimes = fmap _blockCreationTime
604621
$ HM.insert cid (_parentHeader ph)
605622
$ HM.filter (not . isGenesisBlockHeader)
606623
$ fmap _parentHeader adj
@@ -693,7 +710,7 @@ genesisBlockHeaders = \v ->
693710
testnetGenesisHeaders = makeGenesisBlockHeaders testnet04
694711

695712
genesisBlockHeader :: (HasCallStack, HasChainId p) => ChainwebVersion -> p -> BlockHeader
696-
genesisBlockHeader v p = genesisBlockHeaders v ^?! at (_chainId p) . _Just
713+
genesisBlockHeader v p = genesisBlockHeaders v ^?! ix (_chainId p)
697714

698715
makeGenesisBlockHeaders :: ChainwebVersion -> HashMap ChainId BlockHeader
699716
makeGenesisBlockHeaders v = HM.fromList [ (cid, makeGenesisBlockHeader v cid) | cid <- HS.toList (chainIds v)]
@@ -1049,6 +1066,87 @@ instance FromJSON (ObjectEncoded BlockHeader) where
10491066
$ fmap ObjectEncoded . parseBlockHeaderObject
10501067
{-# INLINE parseJSON #-}
10511068

1069+
-- -------------------------------------------------------------------------- --
1070+
-- Fork State
1071+
1072+
blockForkState :: Lens' BlockHeader ForkState
1073+
blockForkState = blockFlags . coerced
1074+
1075+
_blockForkNumber :: BlockHeader -> ForkNumber
1076+
_blockForkNumber = view (blockForkState . forkNumber)
1077+
1078+
_blockForkVotes :: BlockHeader -> ForkVotes
1079+
_blockForkVotes = view (blockForkState . forkVotes)
1080+
1081+
blockForkNumber :: Lens' BlockHeader ForkNumber
1082+
blockForkNumber = blockForkState . forkNumber
1083+
1084+
blockForkVotes :: Lens' BlockHeader ForkVotes
1085+
blockForkVotes = blockForkState . forkVotes
1086+
1087+
-- | Returns whether a block is the first block in a fork epoch.
1088+
--
1089+
isForkEpochStart :: BlockHeader -> Bool
1090+
isForkEpochStart hdr =
1091+
rem (int $ view blockHeight hdr) forkEpochLength == 0
1092+
1093+
isLastForkEpochBlock :: BlockHeader -> Bool
1094+
isLastForkEpochBlock hdr =
1095+
rem (1 + int (view blockHeight hdr)) forkEpochLength == 0
1096+
1097+
-- | Returns whether a block is at a height at which voting occurs.
1098+
--
1099+
isForkVoteBlock :: BlockHeader -> Bool
1100+
isForkVoteBlock hdr =
1101+
rem (int $ view blockHeight hdr) forkEpochLength < (forkEpochLength - 120)
1102+
1103+
-- | Returns whether a block is at a height at which vote couting occurs.
1104+
--
1105+
isForkCountBlock :: BlockHeader -> Bool
1106+
isForkCountBlock hdr = not (isForkVoteBlock hdr)
1107+
1108+
-- | New Fork State computation
1109+
--
1110+
-- The Boolean parameter indicates whether the block votes "yes" (True) to
1111+
-- increasing the fork number.
1112+
--
1113+
-- Callers of this function must not just unconditionally vote "yes". Instead,
1114+
-- they should vote "yes" only if the current fork number is less than the
1115+
-- maximum fork number that the version of the code supports.
1116+
--
1117+
-- TODO: replace the Boolean parameter with a 'maxSupportedForkNumber'
1118+
-- parameter.
1119+
--
1120+
-- * isForkEpochStart -> forkNumber is deterministically increased
1121+
-- * isForkEpochStart -> forkVote is nondeterministically reset to 0 or forkStep
1122+
-- * forkVoteBlock && not isForkVoteStart -> forkVotes are non-deterministically monotonicly increasing
1123+
-- * forkCountBlock -> forkVotes are deterministically set
1124+
--
1125+
newForkState
1126+
:: HM.HashMap ChainId ParentHeader
1127+
-- ^ Adjacent parent headers
1128+
-> ParentHeader
1129+
-- Parent block header
1130+
-> Bool
1131+
-- ^ Non-deterministcally selected vote (True = yes, False = no)
1132+
-> ForkState
1133+
newForkState as p vote
1134+
| isLastForkEpochBlock (view parentHeader p) = cur
1135+
-- reset votes and vote
1136+
& forkVotes .~ (if vote then addVote else id) resetVotes
1137+
-- based on current vote count decide whether to increase fork number
1138+
& forkNumber %~ (if decideVotes curVotes then succ else id)
1139+
| isForkVoteBlock (view parentHeader p) = cur
1140+
-- vote
1141+
& forkVotes %~ (if vote then addVote else id)
1142+
| otherwise = cur
1143+
-- do one vote counting step
1144+
& forkVotes .~ countVotes allParentVotes
1145+
where
1146+
cur = view (parentHeader . blockForkState) p
1147+
curVotes = view (parentHeader . blockForkVotes ) p
1148+
allParentVotes = view (parentHeader . blockForkVotes) <$> (p : HM.elems as)
1149+
10521150
-- -------------------------------------------------------------------------- --
10531151
-- IsBlockHeader
10541152

@@ -1114,7 +1212,7 @@ newBlockHeader adj pay nonce t p@(ParentHeader b) =
11141212
cid = _chainId p
11151213
v = _chainwebVersion p
11161214
target = powTarget p adj t
1117-
adjHashes = BlockHashRecord $ (_blockHash . _parentHeader) <$> adj
1215+
adjHashes = BlockHashRecord $ _blockHash . _parentHeader <$> adj
11181216

11191217
-- -------------------------------------------------------------------------- --
11201218
-- TreeDBEntry instance
@@ -1141,7 +1239,8 @@ instance TreeDbEntry BlockHeader where
11411239
-- on the graph of the parent.
11421240
--
11431241
headerSizes :: ChainwebVersion -> Rule BlockHeight Natural
1144-
headerSizes v = fmap (\g -> _versionHeaderBaseSizeBytes v + 36 * degree g + 2) $ _versionGraphs v
1242+
headerSizes v = (\g -> _versionHeaderBaseSizeBytes v + 36 * degree g + 2)
1243+
<$> _versionGraphs v
11451244

11461245
-- | The size of the serialized block header.
11471246
--

0 commit comments

Comments
 (0)