Smithing - zoobc/zoobc-core GitHub Wiki

Smithing

  • Description

    Smithing is a process by which a node produces a block to be offered to the network as the next state of the blockchain. There are various types of consensus mechanisms to decide whose block should be accepted as the next blocks. A few of the popular ones are: Proof of Work, Proof of Stake, Proof of Authority etc. In case of ZooBc, we are using a different consensus mechanism of our very own called Proof of Participation.
  • Process

    The smithing turn in Proof of Participation is adjusted in such a way that all the participants of the network have same and equal opportunity to smith/produce a block. The process are as follows:

    1. Every constant time, a thread will run a calculation (in each individual nodes) to know whether it's time for it to create a block.

    2. Time to create block for a blocksmith is calculated as follow:

      if previousBlock.SkippedBlocksmith < 1:

      blocksmith[0] = previousBlock.Timestamp + smithingPeriod
      blocksmith[n] = blocksmith[0] + (blocksmithTimeGap * n)
      

      if previousBlock.SkippedBlocksmiths > 0, we'll set the start time to lastSkippedBlocksmith.ExpireTime

      lastSkippedBlocksmithExpireTime = previousBlock.Timestamp - blocksmithTimeGap + SmithingBlockCreationTime + SmithingNetworkTolerance
      blocksmith[0] = lastSkippedBlocksmithExpireTime + smithingPeriod
      
      blocksmith[n] = blocksmith[0] + (blocksmithTimeGap * n)
      

      We can see that from above calculation, the smith time of blocksmiths will look something like:

      blocksmiht smith time

      The smith time of blocksmith will be repeated, meaning if all blocksmiths has pass their expiration time of creating a block, we'll go back to the very first blocksmith again and repeat the same order (given the same previous block). note:

      blocksmithTimeGap = 10 seconds
      smithingPeriod = 15 seconds
      SmithingBlockCreationTime = 30 seconds
      
  1. When it's the node time to create block, it will generate block, and push it into the block pool.

  2. BlockPool

    BlockPool is the temporary place to store pending blocks. Any block that is not produced by the first place blocksmith, will be pushed to BlockPool. Block in the BlockPool is valid and have been run on PushBlock() function without commiting to the database. Every 5 seconds the node will run a check to see if any block in it is legal to be persisted to the chain (call PushBlock()). The conditions are:

    // beginTime will be calculated in point (1).
    expireTime = beginTime + SmithingBlockCreationTime + SmithingNetworkTolerance
    
    // valid condition
    beginTime < currentTime < expireTime
    

    However for the non-first blocksmith block, the valid condition for the block to be persisted is:

    previousBlocksmithExpireTime < currentTime < currentBlocksmithExpireTime
    

    The time window for block to be persisted is their blocksmithTimeGap (10 seconds).

    In the case where every blocksmith have expired we'll choose the block with highest cummulative difficulty in the BlockPool to be persisted.

    example:

    blockA {
      begin: 15,
      expire: 60,
    }
    blockB {
      begin: 25,
      expire: 70,
    }
    blockC {
      begin: 35,
      expire: 80,
    }
    
    The valid persist time for blockB (in case blockA expire) is 60 - 70 second window.
    
    If we are running 3 nodes network, and currentTime = 81 (meaning every block has expired), But we got blockA in the blockPool, we'll persist blockA.
    

    blocksmiht persist time visual

    The dark block represent a valid persist time for that blocksmith. Valid persist time will always be the previous blocksmith's expired + blocksmith gap time, except for the first blocksmith, that'll have its whole smith time to persist.

  • Block Push

    BlockPush is a generalized operation that will push a block as a new state for the blockchain. The operations that it performs is as follows:

    1. It fetches all of the mempool transactions to be placed inside a block, and sort them ascending order based on their FeePerByte then their ArrivalTimestamp, and place them inside the block instance.
    2. It fetches the Receipt that are to be included to the block, and place them inside the block instance.
    3. It starts a DB transaction.
    4. It adds the block data into DB.
    5. It executes the transactions's UndoApplyUnconfirmed and ApplyConfirmed to make sure the effect of each transactions is added to the DB.
    6. It process the receipts of the block to calculate the change of the current node.
    7. It calculates the skipped blocksmiths. The skipped blocksmiths will have their scores reduced.
    8. It distributes the coinbase to a constant number of nodes evenly.
    9. It checks whether any node satisfies the condition to be expelled (his score reaches 0), if yes kick them from the node registry.
    10. It builds the ScrambledNodes if needed.
    11. It finalizes the data and commit the DB transaction, making it written to the DB.
    12. It emits event observer.BlockPushed that will broadcast the block to its peers.
    13. It emits event observer.ExpiringEscrowTransactions that will mark expired escrow transactions in the
  • Block Broadcast

    "Block broadcast" is a process where a block produced/accepted by a node is re-transmitted to other participants in the network, which would result synchronized state of all the participants (nodes) accross the network.

    • Block Broadcast Process

      The process of broadcast of a block is started by a node smithing a block or accepting a block broadcasted by other nodes. The Block broadcasted would not have the transactions, but just the Ids of the transactions. This mechanism to lighten the transmission of a block, because (another) node upon receiving a block will do basic validation of the block, and if that node thinks that the block is not valid he does not need to fetch the transcations of the block. This will save quite some amount of bandwith.

    The process graphically can be drawn as the flow diagram below:

    /images/blockbroadcast.png

    It can be explained as this:

    • Imagine there are 2 nodes in this case. Node A as the block receiver, and Node B as the sender of the block.

    • 1.1. Node A receives a block broadcast from Node B

      1. The block is validated to see whether it's a valid block for Node A's blockchain state.
      2. If it's valid, it will check whther the recipient node (Node A) has all the transactions of the incoming block. If yes, the block is sent to the Completed Block Pool which then to be processed to be included to the blockchain. If no, it will be sent to the Waiting-transaction Block Pool.
    • 1.2. Node A send a request for the transactions needed to complete the blocks in the Waiting-transaction Block Pool asynchronously.

      1. Node B upon receiving the request will get the transactions required from his: transactions table, mempool, and blocks in the Completed Block Pool.
      2. When they all are ready, Node B will send the transactions to Node A.
    • 1.3. Node A receives the transactions from Node B

      1. Node A validates all of the transactions from B.
      2. Node A will send receipts to Node B for all of the transactions that he thinks are valid.
      3. With the tranactions Node A got from Node B, Node A then tries to complete the blocks in his Waiting-transaction Block Pool.
      4. If any of the blocks from Waiting-transaction Block Pool is completed, it will be sent to the Completed Block Pool.
    • 2.1. There's a thread running every constant time that push the blocks inside Completed Block Pool to the blockchain

      1. It iterates the blocks inside of the Completed Block Pool.
      2. If a block is found is to be pushed in the current time window, Block Push will be performed on the block.
      3. Upon the the successful pushing of the block, the Completed Block Pool will be cleared.