Implementing Proof of Stake Part — 6

Leader, blocks and ICO

Kashish Khullar
Coinmonks
Published in
6 min readFeb 10, 2019

--

In the previous post, we create accounts, stake model and validators. In this post, we will create an ICO and a static leader for our application. We also add a threshold to our blocks which will limit its size and also tell us when we should determine the next leader.

Transaction Threshold

Threshold, in this application, is defined as the number of transactions that can be added in a single block.

Create a constant TRANSACTION_THRESHOLD which will be used as a size of a block and add it to the config.js file

// config.js
const TRANSACTION_THRESHOLD = 5;
const TRANSACTION_FEE = 1;module.exports = {
TRANSACTION_THRESHOLD,
TRANSACTION_FEE
};

Our threshold can only reach at one place, ie p2p-server. That’s where we receive new transactions and add them to our pool. Therefore, in the p2p-server we will add some logic to check if the threshold has reached or not.

We can write some code to check the pool length in the transaction message handler.

// p2p-server.js
.
.
.
case MESSAGE_TYPE.transaction:
if (!this.transactionPool.transactionExists(data.transaction)) {
// check if pool is filled let thresholdReached = this.transactionPool.addTransaction(
data.transaction
);
this.broadcastTransaction(data.transaction);
}
break;
.
.
.

The addTransaction function must be modified to return a true value when we hit the threshold and false otherwise. Import the constant from config.js file and check the length of the pool whenever a new transaction is added.

// transaction-pool.jsaddTransaction(transaction) {
this.transactions.push(transaction);
if (this.transactions.length >= TRANSACTION_THRESHOLD) {
return true;
} else {
return false;
}
}

Leader

The validator who has staked the maximum coins will be the leader. Let’s write the code to get the leader for the given block.

In blockchain.js file we can add the function getLeader which calls the getMax of the stake class.

// blockchain.jsgetLeader() {
return this.stakes.getMax(this.validators.list);
}

getLeader returns the address of the node that has the maximum coins staked. this.validators.list is the list of addresses of nodes that have paid the validator fee and are eligible to be elected as a leader.

We will use this function in the p2p-server to check if the current node is the leader or not.

Note: We need a wallet for the above code snippet. We can pass the wallet instance while creating a p2p-server as a dependency in the index.js file.

Finally, the leader can now create a block if it is elected and broadcast the block to the network. A leader signs the block before she broadcasts it to the network. Therefore, we need to update our createBlock function and pass the wallet as an argument.

First in blockchain.js

// blockchain.jscreateBlock(transactions, wallet) {
const block = Block.createBlock(
this.chain[this.chain.length - 1],
transactions,
wallet
);
return block;
}

and in block.js

// block.jsstatic createBlock(lastBlock, data, wallet) {
let hash;
let timestamp = Date.now();
const lastHash = lastBlock.hash;
hash = Block.hash(timestamp, lastHash, data);

// get the validators public key
let validator = wallet.getPublicKey();

// Sign the block
let signature = Block.signBlockHash(hash, wallet);
return new this(timestamp, lastHash, hash, data, validator, signature);
}

Now we can use this in the p2p-server where we create the block and broadcast it.

Let implement the broadcastBlock function. It will take only one argument which is the block to be broadcasted and a sendBlock function to actually send it individually to each connected socket, similar to what we have done for transactions. Also, we need to add a new MESSAGE_TYPE for this and a corresponding message handler for the block.

const MESSAGE_TYPE = {  chain: "CHAIN",  block: "BLOCK",  transaction: "TRANSACTION"};

Broadcasting block

Message handler for blocks: (isValidBlocks is implemented later)

Validity of Blocks

A received block maybe invalid, corrupted or old and hence honest nodes should only broadcast authenticated blocks. To check the validity of blocks lets write a function in blockchain class that checks if block is authentic and should be added to the chain.

Possible reasons for an invalid block —

  1. Invalid hash
  2. Invalid lastHash
  3. Invalid Leader
  4. Invalid signature

Following sums up all the cases into a function.

Now a leader can create blocks and broadcast it. When a node does receive a valid block it must execute all the transactions within the block to have the latest state.

Lets create an executeTransactions function in the blockchain class for this job.

For each type of transaction, the transaction is handled differently. I have also added a transferFee function in accounts.js which sends the fee from the sender to the leader of the block.

Clear Pool

After we have executed the block we must clear the pool to remove the unwanted transactions from the pool.

// transaction-pool.jsclear() {  this.transactions = [];}

This function should be called after we have added and executed the block.

ICO

Our app is almost complete there is one thing left to do. Initial Coin Offering.

Proof of Stake systems cannot work without an ICO or Proof of work algorithm initially for some time until enough coins are mined.

It can be simply stated that we will need an initial leader that will hold all the coins who will transfer them to other nodes. The initial leader must be hard-coded into the classes, mappings, and lists and should have enough initial balance and stake.

To do this we will create a separate app that will solely be responsible for initial coin offering. Later we can disconnect this node from the network.

Create a folder in the root directory named ico. In this folder, create a file index.js. Update the package.json and add a script to run the ICO app.

"scripts": {"dev": "nodemon ./app","ico": "nodemon ./ico",},

ico/index.js would be almost similar to app/index.js but will have a known wallet.

Note that the wallet instance has a secret ‘i am the leader’. We can easily find the corresponding public key for this secret.

Run a node console in the same directory where wallet.js file is and create an object of wallet class for the secret key. Using this object will find the public key for the leader.

> let Wallet = require('./wallet');
> let leader = new Wallet('i am the first leader');
> leader.getPublicKey();
'5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614'

This is the public key or address of the leader and will remain same since the secret is same.

Now we can add this address into our code and give an initial balance to the leader, add stake and make it a validator.

accounts.js

class Account {
constructor() {
this.addresses = [
"5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614"
];
this.balance = {
"5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614": 1000
};
}
.
.
.
.

stake.js

class Stake {
constructor() {
this.addresses = [
"5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614"
];
this.balance = {
"5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614": 0
};
}
.
.
.
.

Zero stake is enough initially as the first leader would be the only one in the list.

validators.js

class Validators {
constructor() {
this.list = [
"5aad9b5e21f63955e8840e8b954926c60e0e2d906fdbc0ce1e3afe249a67f614"
];
}
.
.
.
.

Now the first leader can send coins to other nodes and bootstrap the system.

Once the nodes have enough balance they can become validators and add a stake to forge blocks.

Run an ICO app and the rest normal apps. Using ICO APIs transfer coins to other nodes. You can get the public key from the APIs. Make the other nodes send validator fee and stake some coins. And the next block now will be generated by the new validators.

This finally completes are Proof of Stake implementation. I have added the entire source code on github for your consideration.

Extensions:

  1. For new nodes that join the network after some time, create executeChain function
  2. Punish the fraudulent nodes for any tampering of blocks
  3. Create isValidTransaction function to validate transactions
  4. Add connection close handler to smoothly remove nodes from the network without crashing the app.

Thank you for reading. We have successfully completed our project. Hope you enjoyed coding. If you found this helpful throw a bunch of claps.

If you have any questions about blockchain, ethereum or the world in general, leave a comment. :)

Get Best Software Deals Directly In Your Inbox

--

--