Hard Forks

Monero makes use of hard-forks to update its protocol. Although it has never been used, Monero has a system in it's codebase to allow voting for activation of a hard-fork1. It works by using the blocks minor version field as a voting field, when enough blocks vote for a hard fork the fork is activated.

Because Monero has never used hard fork voting, you don't need to implement it but as it's included in the codebase, an explanation is included here.

Blocks version and vote

Monero uses the block's major version field as an indicator of hard-fork and the minor version field as an indicator of the blocks vote. A minor version of 0 is treated as a vote for 1 as legacy blocks use to just set this field to 02.

The block's vote must be greater than or equal to the version, a vote higher than the maximum known hard-fork is interpreted as a vote for the latest hard-fork3. So if a block is at V2 then the vote must be V2 or higher.

Accepting a fork

When a hard-fork is added to Monero's protocol it must specify a threshold, a number between 0 and 100, this is the proportion of blocks in the window that must vote for this fork (or a later one) for it to activate. For all current forks the threshold is 0 meaning that no votes are needed for the fork to activate.

Monero keeps track of a week (10,080 blocks) worth of votes4, when a new block is added Monero works backwards through the list of hard-forks (latest to oldest) tallying the votes and checking if the number of votes is bigger than the amount needed5, votes for later hardforks are also votes for previous hard-forks. The amount needed is calculated:

\( amountNeeded = \frac{windowSize * threshold + 99}{100} \)

If the amount of votes is greater than or equal to the amount needed and the current blockchain height is greater than or equal to the hard-fork height the HF is activated5.

Mainnet Hard-Forks 6

VersionHeightThresholdFinalized (timestamp)
1070Jul 04 2012 (1341378000)
210098270Sep 20 2015 (1442763710)
311413170Mar 21 2016 (1458558528)
412205160Jan 05 2017 (1483574400)
512886160Mar 14 2017 (1489520158)
614000000Aug 18 2017 (1503046577)
715460000Mar 17 2018 (1521303150)
816855550Sep 02 2018 (1535889547)
916862750Sep 02 2018 (1535889548)
1017880000Feb 10 2019 (1549792439)
1117887200Feb 15 2019 (1550225678)
1219784330Oct 18 2019 (1571419280)
1322100000Aug 23 2020 (1598180817)
1422107200Aug 24 2020 (1598180818)
1526888880Jun 30 2022 (1656629117)
1626896080Jun 30 2022 (1656629118)

Testnet Hard-Forks 8

VersionHeightThresholdFinalized (timestamp)
1070Jul 04 2012 (1341378000)
26246340Oct 20 2015 (1445355000)
38005000Aug 28 2016 (1472415034)
48012190Aug 28 2016 (1472415035)
58026600Aug 28 2016 (1472415036 + 86400*180)
69714000Aug 02 2017 (1501709789)
710570270Dec 02 2017 (1512211236)
810570580Aug 02 2018 (1533211200)
910577780Aug 03 2018 (1533297600)
1011543180Feb 14 2019 (1550153694)
1111550380Feb 15 2019 (1550225678)
1213087370Sep 27 2019 (1569582000)
1315439390Sep 02 2020 (1599069376)
1415446590Sep 02 2020 (1599069377)
1519828000May 16 2022 (1652727000)
1619835200May 17 2022 (1652813400)

Stagenet Hard-Forks 9

VersionHeightThresholdFinalized (timestamp)
1070Jul 04 2012 (1341378000)
2320000Mar 14 2018 (1521000000)
3330000Mar 15 2018 (1521120000)
4340000Mar 16 2018 (1521240000)
5350000Mar 18 2018 (1521360000)
6360000Mar 19 2018 (1521480000)
7370000Mar 21 2018 (1521600000)
81764560Sep 24 2018 (1537821770)
91771760Sep 24 2018 (1537821771)
102690000Feb 14 2019 (1550153694)
112697200Feb 15 2019 (1550225678)
124547210Oct 18 2019 (1571419280)
136754050Aug 23 2020 (1598180817)
146761250Aug 23 2020 (1598180818)
1511510000Jun 30 2022 (1656629117)
1611517200Jun 30 2022 (1656629118)

7

Monero C++ sets this to 1 even though the genesis block has a major version of 1.