Bootstrap Rewards

Introduction

This document defines for the procedure for bootstrapping a Marlin network with rewards.

Concepts

Allocation of Bootstrapped Rewards

When a new network starts, it would not receive bootstrapping rewards directly. A Token weighted voting process is used to allocate rewards to an existing network.

Network Rewards

Rewards are given to original producer who publishes the correct block for the blockchain protocols used in the network. Original producer is determined by comparing the miner address of the block to the source address of the witness. The correct canonical block is determined by a voting process where the relayers can participate. Original producer can then claim the block reward by producing a witness for the transmission.

Constants

Name Type Value
BLOCK_VOTING_INTERVAL uint TBD
OPTIMISTIC_FINALITY_INTERVAL uint TBD

Data Structures

Type Aliases

Name Type Description Examples
Address bytes32 Address of a user on Blockchain

Vote

struct Vote {
    Address proposerAddress
    uint salt
    uint currentBlockHeight
}

Storage

VotesCache

mapping(bytes32 => Vote) votesCache

ProposedBlockId

bytes32 proposedBlockId

Operations

Bootstrapping rewards are provided to networks to make sure that there is enough incentive for nodes to pariticipate in the network even if the revenue due to forwarding packets is not very high.

We are evaluating multiple strategies for distributing rewards to the network. Below are some of them

1. Rewarding Voted Canonical block

The block hash of the associated blockchain and the addresses of miners who mined the blocks are agreed upon by voting on a smart contract.

Proposing a Block

The voting happends in intervals of BLOCK_VOTING_INTERVAL Blocks. Relayer can send a proposal for new block including the addresses of miners who mined blocks in the interval and the blockhash of the last block of the interval. Block can only be proposed for the next target height in the contract.

func proposeBlock(bytes32 blockHash, Address[] minerAddresses):
    if minerAddresses.length != BLOCK_VOTING_INTERVAL
        return
    BlockVotingContract::submitBlockProposal(minerAddresses, blockHash).send(this.privKey)

Create Vote for Block

Relayer can vote on any proposal for the current target height. Relayer has to create a sealed vote by hashing proposerAddress, currentBlockHeight in the contract and random salt.

func createSealedVote(Vote vote):
    sealedVoteId = Keccak256(vote.proposerAddress, vote.currentContractBlockHeight, vote.salt)
    votesCache[sealedVoteId] = vote
    return sealedVoteId

Commit Vote

Sealed vote created by the relayer can be submitted to the BlockVotingContract.

func submitVote(bytes32 sealedVote):
    BlockVotingContract::sealedVote(sealedVote).send(this.privKey)

Reveal vote

The sealed vote can be revealed by the relayer by submitting the proposerAddress, currentContractBlockHeight and salt used to create the vote which can be verified by the Block voting contract.

func revealVote(bytes32 sealedVoteId)
    vote = votesCache[sealedVoteId]
    BlockVotingContract::revealVote(vote.proposerAddress, vote.salt)

Rewarding the relayers

Relayers who provided block to the miner who mined the block can submit a witness to the contract with necessary witness to claim the reward.

func claimReward(Witness witness, Chunk chunk, uint256 blockHeight):
    BootstrapRewards::claimReward(witness, blockHeight, chunk).send(self.privKey)

2. Rewarding all blocks above current difficulty

Relayer who relayed a chunk of the previous block on top of which miner built a valid block is rewarded. To make things clear, let us assume block A was mined by producer P. Rci are the set of relayers who relayed chunk ci for i = 1,2,...,NUM_CHUNKS[message_type] to miner M. If Miner M produces a block A+1 building on top of A such that it is valid, then all Rci for i = 1,2,...,NUM_CHUNKS[message_type] will be rewarded.

Valid block is considered to be a block with difficulty above the limit specified by the protocol. Anyone submitting the block below the difficulty will be treated as spam and detected by the spam detection mechanisms.

The Block for which reward is being claimed should be submitted beforehand to the bootstrap contract.

func sendBlock(BlockHeader currentBlockHeader, Block previousBlock):
    BootstrapRewards::submitValidBlock(currentBlockHeader, previousBlock).send(self.privKey)

Once block is submitted anyone who have sent chunks corresponding to the previous block to the miner will be rewarded.

func claimReward(Witness witness, Chunk chunk, bytes32 prevBlockHash):
    if(!SpamPrevention::getReportCache(chunk.messageId)):
        return
    BoostrapRewards::claimReward(witness, chunk, blockHash).send(self.privKey)

3. Rewarding Canonical chain maintained as Light client

We maintain the canonical chain by allowing anyone to submit block hashes. We assume that network will come to consensus and single chain prevails after OPTIMISTIC_FINALITY_INTERVAL blocks.

Anyone can submit the block hashes along with the block Header to the Bootstrap Rewards contract. The contract keeps track of the chain the header belongs to based on previous block hash of the block header. Once OPTIMISTIC_FINALITY_INTERVAL blocks are passed, only one chain prevails and the chain that prevails is considered as the canonical chain. Difficulty adjustments can also be done on chain as the block headers are available.

func sendBlock(BlockHeader currentBlockHeader, Block previousBlock):
    BootstrapRewards::submitValidBlock(currentBlockHeader, previousBlock).send(self.privKey)

Rewards are distributed to relayers who have relayed the previous block to miner who has built the block that is part of canonical chain.

func claimReward(Witness witness, Chunk chunk, uint256 blockHeight):
    if(!SpamPrevention::getReportCache(chunk.messageId)):
        return
    BoostrapRewards::claimReward(witness, chunk, blockHeight).send(self.privKey)