A blockchain “hard fork” is a change to the block producing software such that any new blocks produced would be invalid according to the old unchanged software. Therefore, the unchanged software would not accept these blocks into its chain. If nodes running the new and modified software continue to produce blocks on top of their chain, a “fork” will result, starting at the parent block of the first incompatible block.
Cardano manages hard forks by gating the new block generation code behind a feature flag. The network agrees upon a slot at which all nodes will enable the new block generation code. After that slot, the network is said to be operating in a new “era.”
Agreement on the slot number (epoch really) to switch to the new era happens by an on-chain voting protocol. If the voting proposal is carried, operators of nodes must ensure that their software version will be compatible with the new era, before the hard fork occurs.
The roadmap is actually divided into phases, under which one or more eras (hard forks) may occur.
The Hard Fork Combinator
The mechanism whereby the Cardano Node operates in different modes - depending on which slot it is up to - is called the “Hard Fork Combinator”.
The following seminars (company internal use only) are a good introduction:
|2020/05/15||Hardfork Combinator I: Reconciling The Eras||This session will explain the technology behind the fabled hardfork combinator for Cardano. As this is quite a bit of machinery, and central to Shelley, we will take the time to talk about it in two sessions, to give enough background that everyone can follow along. This first session will focus on the combinator itself, and how advanced Haskell features allow us to travel from one typed world to another. In a future session, which yet needs to be scheduled, he will present on the subtleties of treating time in the presence of a hardfork.|
|2020/06/05||Hard Fork Combinator II: Time for a Hard Fork||As any computer scientist, physicist, or cross-timezone remote worker can testify, time is a tricky and unforgiving beast. Cardano, as a slot-based Proof of Stake system, is inherently time-driven, so it is vital to get time right. Across the hardfork from Byron to Shelley, the way in which time is divided into slots will change, which turned out to be a massive complicating factor. In this presentation, Edsko will show us how the hard fork combinator handles time across the fork point.|
In a nutshell, pretty much all types in
Cardano.Api are indexed by the
Era. The node will provide a
TimeInterpreter object by the
LocalStateQuery protocol, which allows
cardano-wallet to calculate what time a certain slot occurs at. Calculating the time of a given slot number is more complicated than it sounds.
cardano-wallet have command-line parameters and/or configuration options for the hard-fork combinator.
Nodes must be initialised with a genesis config. The genesis config defines the initial state of the chain. There is the Byron era genesis obviously, and some subsequent eras (Shelley and Alonzo, at the time of writing) also have their own genesis.
Only the hash of a genesis config is stored on-chain. For mainnet, the genesis hash is used as the previous block header hash for the Epoch Boundary Block of epoch 0.
cardano-wallet connects to its local
cardano-node, it must provide the Byron genesis config hash. Hashes for subsequent genesis configs are contained on-chain within the voting system update proposals.
For mainnet, we have hardcoded the genesis hash. It will never change. For testnet, users must supply a genesis config to the Command-Line Interface, so that its hash may be used when connecting to the local node.
Epoch Boundary Blocks
Epoch Boundary Blocks (EBBs) only existed in the Byron era, prior to their abolition with the Shelley hard fork. Confusingly, they were also referred to as “genesis” blocks. The EBB is the previous block of the first block in a Byron epoch. EBBs were calculated locally on each full node of mainnet, and were never transmitted across the network between nodes.
Hard forking to Alonzo (the latest era, at the time of writing) by natural methods requires several epochs’ worth of network operation time to take effect. For disposable local testnets, this would delay startup and make our integration tests slower.
cardano-node can be configured to hard fork itself at the start of any given epoch number, without an update proposal. It’s also possible to hard fork directly into all the eras at epoch 0. This is what we use for the integration tests
cardano-node configuration for this is:
TestShelleyHardForkAtEpoch: 0 TestAllegraHardForkAtEpoch: 0 TestMaryHardForkAtEpoch: 0 TestAlonzoHardForkAtEpoch: 0
Historical note: “Cardano Mode”
In theory, it is possible to run
cardano-node in a single-era mode, where the Hard Fork Combinator is completely disabled. This is called running in Byron-only or Shelley-only mode. Then there is full “Cardano Mode”, which enables the Hard Fork Combinator, thereby allowing the software to pass through eras.
cardano-cli, there are
--cardano-mode switches, to tell the network client which mode the local node is using.
Cardano Mode is the default. I’m not aware of too many people using single-era modes for anything much.
Formal specifications (and the actual implementations!) for each Cardano era exist in the input-output-hk/cardano-ledger repo. These documents are surprisingly readable, and are our go-to source for answers about how the node operates. See the
README.md for links to PDFs and/or build instructions.
Decentralized Update Proposals
The input-output-hk/decentralized-software-updates repo contains research materials for a future implementation of decentralized software updates.