Producer

Introduction

This document defines the protocol used to setup and teardown connections for the Producer.

Constants

Name Type Value
PRODUCER_STAKING_CONTRACT_ADDRESS bytes32 TBD
PRODUCER_STAKE_THRESHOLD uint TBD
PRODUCER_EXIT_WAIT_TIME uint TBD

Data Structures

Producer

struct Producer {
    uint stake
    bytes32 withdrawalAddress
}

Storage

exitBlock

uint exitBlock

Operations

Producer Staking Contract

Producer Staking contract is used to lock stake of the producer. Relayer will only trasmit messages if producer already has stake locked with the contract and there are no exit requests for the stake. There is a waiting period of PRODUCER_EXIT_WAIT_TIME to exit before which stake cannot be withdrawn after the exit request.

Data Structures

struct Producer {
    uint256 stake;
    address withdrawalAddress;
    bytes32 minerAddress;
}
Storage
mapping(address => Producer) lockedStake;
mapping(address => uint256) unlockRequests;
Methods
function lockStake(address withdrawalAddress, uint256 stake, bytes32 minerAddress, bytes[] minerSignedMessage, uint256 minerAddressType):
    require(!lockedStake[msg.sender]);
    require(stake >= PRODUCER_STAKE_THRESHOLD);
    require(verifySignature(bytes32 minerAddress, bytes[] minerSignedMessage, uint256 minerAddressType)); // find a random message such that same signature cannot be reused by others or can be frontrun
    // message can contain the address of producer then all problems will be solved
    require(LINTokenContract.transferFrom(msg.sender, address(this), stake));
    lockedStake[msg.sender] = Producer(stake, withdrawalAddress, minerAddress); 
    emit ProducerStakeLocked(msg.sender, withdrawalAddress, stake)
function requestStakeUnlock():
    require(lockedStake[msg.sender]);
    require(!unlockRequests[msg.sender]);
    unlockRequests[msg.sender] = block.number;
    emit ProducerStakeUnlockRequested(msg.sender, block.number);
function unlockStake():
    require(unlockRequests[msg.sender] + PRODUCER_EXIT_WAIT_TIME >= block.number);
    uint stake = lockedStake[msg.sender].stake;
    delete lockedStake[msg.sender];
    delete unlockRequests[msg.sender];
    require(LINTokenContract.transfer(msg.sender, stake));
    emit ProducerExited(msg.sender, stake);

Setup

Allocate Stake

Producer of message stakes LIN with the network before joining. This stake is used to slash the producer in case the messages are spam. Stake should be allocated in the LIN contract for ProducerStakingContract to lock stake.

func allocateStake(bytes32 stake):
    LINTokenContract::approve(PRODUCER_STAKING_CONTRACT_ADDRESS, stake).send(self.privKey)

Stake LIN

As the stake is allocated to the ProducerStakingContract, producer can send a transaction to the lockStake method of ProducerStakingContract.

func lockStake(bytes32 stakerAddress, uint stake):
    ProducerStakingContract::lockStake(stakerAddress, stake).send(self.privKey)
func onProducerStakeLocked():
    ChildManagement::findChildren()
    self.acceptConnections = true

Teardown

Propose Exit

Producer can propose an exit by sending a transaction to ProducerStakingContract.

func proposeExit():
    ProducerStakingContract::proposeExit().send(self.privKey)

Wait and Exit

Producer should then wait for PRODUCER_EXIT_WAIT_TIME before the stake can be released. Proposer can send a transaction to ProducerStakingContract once the wait time is passed to collect the stake to the withdrawal address mentioned when registering.

func onProducerStakeUnlockRequested(bytes32 producer):
    if producer == self.pubKey:
        exitBlock = event.block + RELAYER_EXIT_WAIT_TIME
        ChildManagement::disconnectChildren()
func onExitWaitCompleted():
    ProducerStakingContract::exit().send(self.privKey)