I just received a a ghosted block, what can I do to prevent this?

I have been successfully writing blocks for some time now and in the last couple of epochs I’ve had a block stolen, and this time I had one of 3 ghosted. How can I prevent this from happening?

Thank you

The terminology is confusing because there is no particular standard.

Chain forks occur naturally

On the Cardano blockchain, forks naturally and commonly occur. This happens when two different stake pools build upon the same block creating a chain fork.

1S01 <-- 2S02 <-- 3S03
             ^--- 3S04

Sorry for the crap ascii art, but hopefully you can see that block 3 for slot 03 (3S03) and block 3 for slot 04 are both built upon block 2 (for slot 02). There is two block 3’s.

How nodes decide which fork to follow

Now the next block producer needs to pick one of the forks (one of the block 3’s) to build upon. On Cardano there is a chain selection algorithm run by each node to determine which chain (fork) it prefers. The algorithm is as follows:

  • If chain length differs then prefer longest (Nakamoto consensus)
  • if chains have equal length then prefer chain whose last block has the lowest VRF (verifiable random function) score.

IE: Cardano uses a VRF to settle ties, when both chain forks are equal in length.

When more than one pool becomes a leader at the same time

When blocks are produced, each stake pool on Cardano runs a leadership check every slot (1 second) to see if it is a “slot leader”. This leadership check involves applying the VRF combined with the stake pool private key and the slot number. If the leadership check calculates a value that is lower than the proportion of stake that pool controls, then it is a “slot leader” and is permitted to make a block for that slot.

Importantly, it is possible, and quite often occurs, that two or more pools are valid “slot leaders” for the same slot in time. Such a situation will always produce a chain fork because both pools will produce their block upon the same previous block. Other nodes in the network that receive both blocks will recognise this and prefer the one with the lower VRF score according to the chain selection algorithm.

Forks caused by network delays

Another cause of chain forks is due to network delays. If a slot leader doesn’t receive the previous leader’s block in time then it will naturally produce a fork too. Looking again at the crap ascii art above: Imagine that block 3 at slot 03 (3S03) was produced by pool A and pool B hadn’t receive block 3 from pool A when it came time to produce it’s block so it produced another block 3 at slot time 04 (3S04). Thus both pool A and B produced their blocks upon block 2 and created a fork. Even though the slots differ, there can still only be one block 3 preferred, so every node will apply the chain selection algorithm and the block with the lower VRF score will win. The other block will be discarded or “orphaned” and will not contribute to the valid ledger. The pool that produced this orphaned block will also not receive any rewards for producing this block because it didn’t become part of the preferred chain.

An example fork

Here is a live example from my stake pool that happened recently:

sqlite3 /var/lib/cardano/cncli.db '.headers on' '.mode column' 'select id as RecID, block_number as blockNum, slot_number as slotNum, substr(pool_id,1,8) as poolID, substr(hash,1,8) as hash, substr(prev_hash,1,8) as prevHash, substr(block_vrf_0,1,8) as VRF, orphaned from chain where slot_number between 92866484 and 92866492;'
RecID    blockNum  slotNum   poolID    hash      prevHash  VRF       orphaned
-------  --------  --------  --------  --------  --------  --------  --------
4323693  8790265   92866484  27526b2d  089dc088  ae984936  5ddbf3fb  0       
4323694  8790266   92866491  08f05bcf  c668b8f2  089dc088  88dfbdd7  1       
4323695  8790266   92866492  f76e3a11  de0668d7  089dc088  09eba57c  0

In this example the orphaned block was produced by my pool for slot xxxxxx91 but another pool produced a block for slot xxxxxx92 (1 second later) and it obviously didn’t receive my block in time. Both blocks were produced upon the same previous block (prevHash). Notice that my block had a VRF starting with 8 wheras the other pool’s block VRF started with 0. The other pool won the “fork battle” because it’s block had the lower VRF score.

Unfortunately my pool gets involved in more of these “fork battles” because it runs in Australia on the other side of the world to the majority of the Cardano network. Fork battles are like rolling the dice because although the VRF is deterministic, it effectively randomises the winner. The more “fork battles” you get involved in, the more blocks you get “orphaned”.