Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DPoS and Its Implementation in Plasma Cash

0.00/5 (No votes)
18 Jul 2019 1  
Plasma based on DPoS is a revolutionary solution providing decentralization and significantly increasing the number of transactions processed by the blockchain per second.

Introduction

Today, there are very few people who have not heard about cryptocurrencies and their counterpart, blockchain.

In the eyes of the unenlightened, blockchain is mostly associated exclusively with the financial sphere, but this innovative technology can in fact be used in a broad range of applications, for example:

  • tourism
  • logistics
  • banking
  • law
  • construction
  • insurance
  • energetics
  • medicine
  • and many other areas

What makes blockchain so useful? First of all, it prevents hackers from breaking into computerized systems and the network itself. The logic encompassing blockchain cannot be violated. The data stored there is shared among all nodes and can never be deleted.

Blockchain immutability can only be achieved through the implementation of a consensus algorithm in the distributed network. There are many algorithms of this kind, but the most common is the Proof of Work (PoW) algorithm invented by Satoshi Nakamoto in 2008 that provoked a revolution in the crypto-economy.

The Byzantine Generals’ Problem (BGP) is an allegory faced by distributed computer system networks, wherein all involved parties must agree on a single strategy to avoid complete failure, but where some of the involved parties may be corrupt and unreliable. The BGP was used to formalize consensus algorithms and has existed for some time, but the Satoshi PoW algorithm offers a more elegant solution.

The Byzantine army consisted of many distantly located legions, each with its own general, who in turn was subject to the main general. On the eve of a battle, the main general would send out a command to all other generals, to either attack or retreat. But it was suspected that some generals were traitors, and they were intentionally sent disparate commands. The idea was that:

  • if all loyal generals attacked, the army would win
  • if all loyal generals retreated, the army would remain safe
  • if any of the generals acted independently, the army would be defeated

The task of the Byzantine generals was to find traitors, exclude them from the decision-making system, and arrive at a consensus. When applied to distributed networks, the BGP ensures that all nodes in a system are in consensus.

When undertaking the challenge of searching for a block hash in Bitcoin, we can provide evidence that complex operations have been carried out, greatly increasing the importance of the solution. By accumulating chains from a sufficient number of proofs, it is possible to obtain a consistent reliable state of the system and network. This is the essence of the consensus algorithm.

Decentralized networks reach consensus using various algorithms or logic schemes. The three main blockchain consensus algorithms, in order of descending popularity, are Proof of Work (PoW), Proof of Stake (PoS), and Delegated Proof of Stake (DPoS). Proof of Work is the oldest, the most proven and the most frequently used consensus algorithm in the blockchain.

The Proof of Work algorithm has long proven its great reliability and importance. At the same time, it has a significant drawback - it requires a huge amount of electricity and resources to operate. Consequently, the profit gained from currency acquisition is not sufficient to offset losses.

Theoretically, a program that finds hashes and performs Proof of Work even faster can be invented, making it possible to crack the consensus and making the network much more centralized.

The second algorithm, Proof of Stake, requires that interested parties must vote for the next blocks to reach consensus. Users get more coins as a reward for participating in the network. This method is very similar to the way in which PoW miners get rewards for their efforts.

The Proof of Stake algorithm is still decentralized, but it does not demand a huge amount of electricity and resources. You can simply buy a certain number of tokens.

The main disadvantage of PoS can be described as “nothing at stake.“ Investments take place when energy is expended, but in the case of PoS, nothing is at stake and any number of chains can be generated.

Another problem is that more and more tokens are accumulated by the largest token holders, making centralization risk high. An algorithm could be developed for evenly selecting consensus participants, but it would be very complex.

Not long after Proof of Work and Proof of Stake were implemented in various cryptocurrencies, Delegated Proof of Stake (DPoS) was presented. With traditional PoS, anyone can act as a stake node. However, DPoS has elected delegates, chosen by their colleagues to perform a particular role. In the DPoS environment, only elected nodes are allowed to choose blocks and contribute to consensus.

The main advantage of DPoS is that this algorithm encourages users to behave honestly, simply because it benefits them to do so.

Another great advantage is that DPoS provides increased scalability. If the set of node delegates is known, many parameters can be optimized. The consensus can then be quickly achieved.

However, increased centralization is a downside.

Despite its drawbacks, DPoS provides a perfect solution for Plasma Cash implementation! A child chain is needed to increase throughput, but full decentralization is not necessary for a child chain.

Ideally, Plasma Cash can work as one massive operator, but a larger number of delegates increases the reliability of the network at times, and they can be controlled by various organizations. This significantly increases trust.

DPoS answers the question, “Who will participate in the consensus?”

For this, new transactions are introduced in the Plasma chain: to vote / to remove a vote for a delegate. This gives participants the opportunity to nominate candidates for delegate roles. Further, at the consensus stage, all delegates are sorted according to the number of votes and their stakes.

Check out the code that was written by the Opporty company for implementing Plasma and DPoS:

Each action of the DPoS consensus algorithm has its own transaction type. The following types of transactions were implemented:

  • vote - voting for a candidate validator
  • unvote - removing a vote
  • pay - transferring a token to another member
  • candidate - adding an address to the list of candidates
  • resignation - removing an address from the list of candidates

After entering the child chain, all these transactions are subject to mandatory validation:

async function validatePayTx(transaction) {
  checkTransactionFields(transaction)
  const tokenOwner = await getSignatureOwner(transaction)
  if (tokenOwner != config.plasmaNodeAddress) {
    const utxos = await getUtxosForAddress(tokenOwner)
    let tokenId = transaction.tokenId.toString()
    checkUtxoFieldsAndFindToken(utxos, tokenId, tokenOwner)
  }
  return {success: true}
}
const validateVoteTx = async (transaction) => {
  await validatePayTx(transaction)
  return {success: true}
}
const validateUnvoteTx = async (transaction) => {
  checkTransactionFields(transaction)
  let addsTransaction = await checkAndGetAddsHistoryTx(transaction)
  if (ethUtil.addHexPrefix(addsTransaction.newOwner.toString('hex'))
    != ethUtil.addHexPrefix(transaction.newOwner.toString('hex'))) {
    throw new Error(rejectCauses.failHistory)
  }
  return {success: true}
}
const validateCandidateTx = async (transaction) => {
  await validatePayTx(transaction)
  return {success: true}
}
const validateResignationTx = async (transaction) => {
  checkTransactionFields(transaction)
  await checkAndGetAddsHistoryTx(transaction)
  return {success: true}
}

When performing a transaction of the "unvote" or "resignation" type, it is necessary to check the history and the availability of a validator with a certain number of votes and a certain token. This is done by the checkAndGetAddsHistoryTx function. It verifies whether the vote from a specific user is available in the transaction history. If the vote is available, it can be removed or the user can be removed from the list of validators (transaction type "resignation").

const checkUtxoFieldsAndFindToken = (utxos, tokenId, tokenOwner) => {
  for (let i = 0; i < utxos.length; i++) {
    if (!utxos[i].owner ||
      !utxos[i].tokenId ||
      !utxos[i].amount ||
      !(utxos[i].blockNumber > -1)) {
      continue
    }
    if ((utxos[i].tokenId === tokenId) &&
      (utxos[i].owner === tokenOwner)) {
      return {success: true}
    }
  }
  throw new Error(rejectCauses.noUtxo)
}

After validation, the state changes and the validator is added to / removed from the list of validators.

const checkAndGetAddsHistoryTx = async (transaction) => {
  const faceThatRemoves = await getSignatureOwner(transaction)
  let blockKey = 'block' + transaction.prevBlock
  let block = (new Block(await redis.getAsync(Buffer.from(blockKey))))
  if (!block) {
    throw new Error(rejectCauses.failHistory)
  }
  let addsTransaction = block.getTxByTokenId(transaction.tokenId)
  if (!addsTransaction) {
    throw new Error(rejectCauses.failHistory)
  }
  let faceThatAdds = await getSignatureOwner(addsTransaction)
  if (faceThatAdds != faceThatRemoves) {
    throw new Error(rejectCauses.failHistory)
  }
  return addsTransaction
}

In the case of the "vote" transaction, a stake is added to a specific delegate on the list - stateValidators.addStake(stake).

const unvoteTxExecute = async (transaction, blockNumber) => {
  const newOwner = await getSignatureOwner(transaction)
  let oldOwner = ethUtil.addHexPrefix(transaction.newOwner.toString('hex'))
  let stake = {
    voter: newOwner,
    candidate: JSON.parse(transaction.data.toString()).candidate,
    value: 1,
  }
  await stateValidators.toLowerStake(stake)
  await utxoTransition(transaction, blockNumber, newOwner, oldOwner)
  return {success: true}
}

In the case of the "unvote" transaction, the opposite occurs - stake withdrawal awaits: stateValidators.toLowerStake(stake).

const candidateTxExecute = async (transaction, blockNumber) => {
  const oldOwner = await getSignatureOwner(transaction)
  await stateValidators.addCandidate(oldOwner)
  let newOwner = ethUtil.addHexPrefix(transaction.newOwner.toString('hex'))
  await utxoTransition(transaction, blockNumber, newOwner, oldOwner)
  return {success: true}
}

When the "candidate" transaction is executed, a delegate is simply added to the list - stateValidators.addCandidate(oldOwner).

const resignationTxExecute = async (transaction, blockNumber) => {
  const newOwner = await getSignatureOwner(transaction)
  let oldOwner = ethUtil.addHexPrefix(transaction.newOwner.toString('hex'))
  await stateValidators.removeCandidate(newOwner)
  await utxoTransition(transaction, blockNumber, newOwner, oldOwner)
  return {success: true}
}

Or they are deleted in the case of the "resignation" transaction.
In all cases, a state transition occurs and the token is spent. It goes either to the main Plasma address or back to the previous owner. The utxoTransition function is used.
It is necessary to understand that all the stages are divided into equal parts, depending on the block submission time. The order of delegates in the list changes in a pseudo-random manner at each stage.
All this happens in a strictly deterministic way:

async prepareValidators() {
    let seedData = Math.floor(Date.now()/config.roundInterval)
    this.hungValidators = Object.assign([], this.validators)
    let seedSource = crypto.createHash('sha256')
      .update(String(seedData), 'utf8').digest()
    for (let i = 0, delCount = this.hungValidators.length; i < delCount; i++) {
      for (let x = 0; x < 4 && i < delCount; i++, x++) {
        let newIndex = seedSource[x] % delCount
        let b = this.hungValidators[newIndex]
        this.hungValidators[newIndex] = this.hungValidators[i]
        this.hungValidators[i] = b
      }
    }
    return 'ok'
  }

Validator delegates are sorted, depending on the current round (rounds are calculated based on the current date). The current validator can be identified at any moment:

async getCurrentValidator() {
    let dateStamp = Date.now()
    let index = Math.floor((dateStamp / config.blockTime) %
    (this.hungValidators.length))
    return this.hungValidators[index]
  }

At any single moment, there can be only one delegate known to everyone, and that delegate is the current validator. Only this party can add a valid block. All other miners will have to wait for their turn.

If the delegate behaves improperly, they can simply be excluded from the list.

The idea of ​​delegated proof of stake is actually very simple. Nevertheless, this algorithm is quite fast and fully decentralized.

The Opporty company has introduced a new DPoS consensus, Plasma, that provides a maximum level of security with an adequate level of centralization.

In fact, the child chain is a complete implementation of the blockchain in its classic form:

  • Chain of blocks
  • Distributed database
  • DPoS consensus algorithm for coherence
  • Compressed Patricia Tree for saving the state

With Plasma, two blockchains work in complete synchronization, complementing each other.

Ethereum provides maximum stability and reliability. Plasma based on DPoS enables decentralization outside the main network, significantly increasing the number of transactions processed by the blockchain per second.

Useful Links

  1. White Paper Plasma
  2. DPoS
  3. Privacy and Scalability Solution for Ethereum Blockchain
  4. Consensus
  5. Byzantine Fault
  6. Sidechains vs Plasma vs Sharding
  7. Vitalik Buterin speaks about DPoS
  8. Slasher Ghost, and Other Developments in Proof of Stake
  9. Merkling in Ethereum

History

  • 18th July, 2019: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here