Skip to content
Sandip Patel edited this page Nov 19, 2019 · 10 revisions

Introduction

A hardfork in a blockchain is a change in which an older version of the code cannot process blocks generated by the newer version. However, the new version still has to be able to process the entire blockchain, so it needs to handle blocks generated by both versions.

In Peerplays, hardforks are defined only by their name (in most cases a number) and a timestamp. The timestamp is after a new version of the software was released, so that users have time to upgrade. Up to this timestamp, blocks are generated according to the old version, and after the timestamp the new version kicks in.

On the block processing side, the hardfork timestamps are used in the same way: If the block was generated before a certain hardfork's timestamp, the old parsing rules are used. If it was generated later, the new rules are used.

Defining a hardfork

Peerplays stores a list of hardforks and their timestamps in the libraries/chain/hardfork.d directory. To add a hardfork called myhf in the code, create a new file in that directory with the filename of myhf.hf with contents like

#ifndef HARDFORK_MYHF_TIME
#define HARDFORK_MYHF_TIME (fc::time_point_sec( 1540000000 ))
#endif

where MYHF should be replaced with the uppercase hardfork name and 1540000000 with the Unix timestamp of your desired hardfork time.

Making backwards-incompatible changes to the code

After the hardfork is defined, you can use its defined timestamp to perform runtime checks.

If the hardfork includes introducing new operations to the blockchain, all the code dealing with these operations can safely assert that the current time is later the hardfork timestamp

FC_ASSERT(db().head_block_time() >= HARDFORK_MYHF_TIME);
FC_ASSERT(block_time >= HARDFORK_MYHF_TIME, "my_new_cool_operation not allowed yet!" );

Or you can use it in conditionals to run extra code before or after the hardfork

if (block_time < HARDFORK_MYHF_TIME) {
    // do whatever
}

This includes both code for creating/manipulating such operations and for parsing/applying them.

Git flow

Since changes requiring hardforks are by definition incompatible, they should be kept in the hardfork/hf-<hf_number> branch. While in this branch, the hardfork timestamp can still be edited, so that it always remains in the future. The main develop branch is then regularly merged into the hardfork/hf-<hf_number> branch. For hardfork related changes, Contributors can create new branch feature/<Jira-ID> from specific hardfork/hf-<hf_number>. Once the development is done, contributors can raise PR to merge their changes back to hardfork/hf-<hf_number>. We can handle multiple hardforks in parallel this way.

QA Deployment of hardfork:

  • Validate all required PRs are merged into hardfork/hf-<hf_number>
  • Set GRAPHENE_SYMBOL and GRAPHENE_ADDRESS_PREFIX value as "PPY" in file libraries/chain/include/graphene/chain/config.hpp
  • Rebase hardfork/hf-<hf_number> onto develop and push the changes to github
  • Ensure CI is passed
  • Deploy binaries into QA environment

Once the hardfork/hf-<hf_number> is QA verified, Special care must be taken to keep the hardfork timestamp far enough in the future for the release. Merge hardfork/hf-<hf_number> into master. A release Tag is made from the master branch. It follows the normal rules for release, including merging back into both develop and hardfork/hf-<hf_number> once the release it made.

Hardfork release checklist

  • Merge hardfork/hf-<hf_number> into master
  • Ensure CI is passed.
  • Goto release tab and create new release.
  • Add release note and upload all required binaries.
  • Delete hardfork/hf-<hf_number> branch