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

Introduce the P7 to P8 update. #1301

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased changes

- Add P7 -> P8 update.
- Automatically suspend validators from the consensus that missed too many
rounds in the previous payday.
- Add support for suspend/resume to validator configuration updates.
Expand Down
12 changes: 9 additions & 3 deletions concordium-consensus/src/Concordium/ProtocolUpdate/P7.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,33 @@ module Concordium.ProtocolUpdate.P7 (
updateNextProtocolVersion,
) where

import Control.Monad.State
import Control.Monad.State hiding (get)
import qualified Data.HashMap.Strict as HM
import Data.Serialize

import qualified Concordium.Crypto.SHA256 as SHA256
import Concordium.Types
import Concordium.Types.Updates

import qualified Concordium.Genesis.Data.P8 as P8
import Concordium.GlobalState.BlockState
import qualified Concordium.GlobalState.Persistent.BlockState as PBS
import Concordium.GlobalState.Types
import qualified Concordium.GlobalState.Types as GSTypes
import Concordium.KonsensusV1.TreeState.Implementation
import Concordium.KonsensusV1.TreeState.Types
import qualified Concordium.ProtocolUpdate.P7.ProtocolP8 as ProtocolP8
import qualified Concordium.ProtocolUpdate.P7.Reboot as Reboot

-- | Updates that are supported from protocol version P7.
data Update = Reboot
data Update
= Reboot
| ProtocolP8 P8.ProtocolUpdateData
deriving (Show)

-- | Hash map for resolving updates from their specification hash.
updates :: HM.HashMap SHA256.Hash (Get Update)
updates = HM.fromList [(Reboot.updateHash, return Reboot)]
updates = HM.fromList [(Reboot.updateHash, return Reboot), (ProtocolP8.updateHash, ProtocolP8 <$> get)]

-- | Determine if a 'ProtocolUpdate' corresponds to a supported update type.
checkUpdate :: ProtocolUpdate -> Either String Update
Expand All @@ -53,9 +57,11 @@ updateRegenesis ::
BlockPointer (MPV m) ->
m (PVInit m)
updateRegenesis Reboot = Reboot.updateRegenesis
updateRegenesis (ProtocolP8 protocolUpdateData) = ProtocolP8.updateRegenesis protocolUpdateData

-- | Determine the protocol version the update will update to.
updateNextProtocolVersion ::
Update ->
SomeProtocolVersion
updateNextProtocolVersion Reboot{} = SomeProtocolVersion SP7
updateNextProtocolVersion ProtocolP8{} = SomeProtocolVersion SP8
120 changes: 120 additions & 0 deletions concordium-consensus/src/Concordium/ProtocolUpdate/P7/ProtocolP8.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

-- | This module implements the P7.ProtocolP8 protocol update.
-- This protocol update is valid at protocol version P7, and updates
-- to protocol version P8.
--
-- This produces a new 'RegenesisDataP8' using the 'GDP8RegenesisFromP7' constructor,
-- as follows:
--
-- * 'genesisCore':
--
-- * 'genesisTime' is the timestamp of the last finalized block of the previous chain.
-- * 'genesisEpochDuration' is taken from the previous genesis.
-- * 'genesisSignatureThreshold' is taken from the previous genesis.
--
-- * 'genesisFirstGenesis' is either:
--
-- * the hash of the genesis block of the previous chain, if it is a 'GDP7Initial'; or
-- * the 'genesisFirstGenesis' value of the genesis block of the previous chain, if it
-- is a 'GDP7Regenesis'.
--
-- * 'genesisPreviousGenesis' is the hash of the previous genesis block.
--
-- * 'genesisTerminalBlock' is the hash of the last finalized block of the previous chain.
--
-- * 'genesisStateHash' is the state hash of the last finalized block of the previous chain.
--
-- * 'genesisMigration' is derived from the data provided to the protocol update, which is the
-- validator score parameters
--
-- The block state is taken from the last finalized block of the previous chain. It is updated
-- as part of the state migration, which makes the following changes:
--
-- * The seed state is migrated as follows:
--
-- * The current epoch is reset to zero.
-- * The current and updated leadership election nonce are set to the hash of
-- @"Regenesis" <> encode oldUpdatedNonce@.
-- * The trigger block time is kept the same, meaning that the epoch will transition as soon
-- as possible.
-- * The epoch transition triggered flag is set.
-- * The shutdown triggered flag is cleared.
--
-- * The old current epoch is subtracted from the next payday epoch.
--
-- * The protocol update queue is emptied during the migration.
--
-- Note that, the initial epoch of the new chain is not considered
-- a new epoch for the purposes of block rewards and baker/finalization committee determination.
-- In particular, the timing of the next payday will be the same as if the protocol update
-- had not happened. (For instance, if it would have happened at the start of the next epoch
-- prior to the protocol update, after the update it will happen at the start of epoch 1.
-- The trigger block time in epoch 0 of the new consensus is the same as the trigger block
-- time in the final epoch of the old consensus.)
-- Furthermore, the bakers from the final epoch of the previous chain are also the bakers for the
-- initial epoch of the new chain.
module Concordium.ProtocolUpdate.P7.ProtocolP8 where

import Control.Monad.State
import Lens.Micro.Platform

import qualified Concordium.Crypto.SHA256 as SHA256
import qualified Concordium.Genesis.Data as GenesisData
import qualified Concordium.Genesis.Data.BaseV1 as BaseV1
import qualified Concordium.Genesis.Data.P8 as P8
import Concordium.GlobalState.BlockState
import qualified Concordium.GlobalState.Persistent.BlockState as PBS
import Concordium.GlobalState.Types
import qualified Concordium.GlobalState.Types as GSTypes
import qualified Concordium.KonsensusV1.TreeState.Implementation as TreeState
import Concordium.KonsensusV1.TreeState.Types
import Concordium.KonsensusV1.Types
import Concordium.Types.HashableTo (getHash)
import Concordium.Types.ProtocolVersion

-- | The hash that identifies a update from P7 to P8 protocol.
-- This is the hash of the published specification document.
updateHash :: SHA256.Hash
updateHash = read "f12e20b6936a6b1b736e95715e1654b92adb4226ef7601b4183895bee563f9da"

-- | Construct the genesis data for a P7.ProtocolP8 update.
-- This takes the terminal block of the old chain which is used as the basis for constructing
-- the new genesis block.
updateRegenesis ::
( MPV m ~ 'P7,
BlockStateStorage m,
MonadState (TreeState.SkovData (MPV m)) m,
GSTypes.BlockState m ~ PBS.HashedPersistentBlockState (MPV m)
) =>
P8.ProtocolUpdateData ->
-- | The terminal block of the old chain.
BlockPointer 'P7 ->
m (PVInit m)
updateRegenesis protocolUpdateData terminalBlock = do
-- Genesis time is the timestamp of the terminal block
let regenesisTime = blockTimestamp terminalBlock
-- Core parameters are derived from the old genesis, apart from genesis time which is set for
-- the time of the terminal block.
gMetadata <- use TreeState.genesisMetadata
BaseV1.CoreGenesisParametersV1{..} <- gmParameters <$> use TreeState.genesisMetadata
let core =
BaseV1.CoreGenesisParametersV1
{ BaseV1.genesisTime = regenesisTime,
..
}
-- genesisFirstGenesis is the block hash of the previous genesis, if it is initial,
-- or the genesisFirstGenesis of the previous genesis otherwise.
let genesisFirstGenesis = gmFirstGenesisHash gMetadata
genesisPreviousGenesis = gmCurrentGenesisHash gMetadata
genesisTerminalBlock = getHash terminalBlock
let regenesisBlockState = bpState terminalBlock
genesisStateHash <- getStateHash regenesisBlockState
let genesisMigration =
P8.StateMigrationData
{ migrationProtocolUpdateData = protocolUpdateData
}
let newGenesis = GenesisData.RGDP8 $ P8.GDP8RegenesisFromP7{genesisRegenesis = BaseV1.RegenesisDataV1{genesisCore = core, ..}, ..}
return (PVInit newGenesis (GenesisData.StateMigrationParametersP7ToP8 genesisMigration) (bmHeight $ bpInfo terminalBlock))
Loading