The transparency issue
Public blockchains like the Ethereum mainnet keep an immutable record of transactions, but the issue is that the ledger is 100% transparent and anybody with access to an Ethereum node has access to all of the data on the blockchain.
When discussing potential projects with clients recently, whenever I explained to them this aspect of public blockchains, most of the time it is not exactly what they had in mind. Few businesses actually want to make their data public and there are many reasons for this: Competition, intellectual property, consumer privacy …
This is when permissioned blockchains come into play:
Permissioned Blockchains & Quorum
[A permissioned blockchain] places restrictions on who is allowed to participate in the network, and only in certain transactions. Participants need to obtain an invitation or permission to join — IBM Blockchain explained blog
There are many existing implementations of permissioned blockchains such as IBM Hyperledger Fabric, R3 Corda and J.P. Morgan’s Quorum.
Quorum is based on Ethereum, allows building Smart Contracts with Solidity and shares some core development tools with Ethereum such as Truffle so it’s rather straightforward to learn for an Ethereum Developer.
Let’s explore some of the concepts behind Quorum and build a quick proof of concept:
Private Contracts and Private Transactions
Quorum allows deploying 2 types of contracts to the network :
Public contracts are similar to regular Ethereum Smart Contracts
Private contracts allow specifying which nodes in the network have access to the contract and can execute it. The other nodes cannot see the contract’s code or data and cannot query or execute it
Quorum also specifies 2 types of transactions :
Public transactions, transparent for the entire network
Private transactions, which payload is only visible to the authorised network participants
Secret Ballot example with Quorum
To illustrate these concepts, I’ve built a simple and contrived example of a potential use case for Quorum, Secret Ballot voting (the public repository is on github). In our example, Companies A, B and C must vote for a decision by selecting a number: 1 or 2. But each company does not want the other companies to know what they voted. Only the Regulator can see the results and count the votes.
We will use a network architecture with 5 nodes :
Node 1 : Regulator
Node 2 : Company A
Node 3: Company B
Node 4: Company C
Node 5: Observer (not privy to the contract nor to any transactions)
To this end, the regulator will deploy a private Smart Contract Vote which is accessible to all 4 active participants (Regulator and Companies A, B and C), but each company will vote via a single private transaction.
pragma solidity ^0.4.15;
contract SecretBallot {
/*
* Storage
*/
// votes per company
mapping(address => uint) private votes;
// totals per option
mapping(uint => uint) private totals;
// company A Address
address companyA;
// company B Address
address companyB;
// company C Address
address companyC;
/**
* @dev Contract constructor
*/
function SecretBallot(address _companyA, address _companyB, address _companyC){
companyA = _companyA;
companyB = _companyB;
companyC = _companyC;
}
/*
* Public functions
*/
/**
* @dev Register vote and update totals
* @param _option Voting option
*/
function vote(uint _option) public {
// Only allow the registered companies to vote
require(msg.sender == companyA || msg.sender == companyB || msg.sender == companyC);
// Only allow voting once
require(votes[msg.sender] == 0);
// Only allow 1 or 2 as options
require(_option == 1 || _option == 2);
// save vote
votes[msg.sender] = _option;
// update totals
totals[_option] = totals[_option] + 1;
}
/**
* @dev Get total votes for option
* @param _option Voting option
*/
function getTotalVotes(uint _option) constant public returns (uint total) {
return totals[_option];
}
}
We deploy this contract from Node 1 (Regulator)
$ truffle migrate
Then we will use the truffle console to make each company vote. (A and B vote “1” and C votes “2”)
# network names are set in the truffle config
$ truffle console --network=a
# company A votes, while making the transaction private and only visible by the regulator, "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=" is the Regulator Node's key in our setup
truffle(a)> SecretBallot.deployed().then((instance) => instance.vote(1, {privateFor: ["BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo="]}))
# Check vote count for option 1
truffle(a)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(1)).then((result) => result.toNumber())
1
# Check vote count for option 2
truffle(a)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(2)).then((result) => result.toNumber())
0
$ truffle console --network=b
# company B votes, while making the transaction private and only visible by the regulator, "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=" is the Regulator Node's key in our setup
truffle(b)> SecretBallot.deployed().then((instance) => instance.vote(1, {privateFor: ["BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo="]}))
# Check vote count for option 1
truffle(b)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(1)).then((result) => result.toNumber())
1
# Check vote count for option 2
truffle(b)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(2)).then((result) => result.toNumber())
0
$ truffle console --network=c
# company C votes, while making the transaction private and only visible by the regulator, "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=" is the Regulator Node's key in our setup
truffle(c)> SecretBallot.deployed().then((instance) => instance.vote(2, {privateFor: ["BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo="]}))
# Check vote count for option 1
truffle(c)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(1)).then((result) => result.toNumber())
0
# Check vote count for option 2
truffle(c)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(2)).then((result) => result.toNumber())
1
Then we check the totals from the Regulator node
$ truffle console
truffle(regulator)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(1)).then((result) => result.toNumber())
2
truffle(regulator)> SecretBallot.deployed().then((instance) => instance.getTotalVotes(2)).then((result) => result.toNumber())
1
I’ve summarised the results in the following table
The interesting part is that depending on who is querying the contract via getTotalVotes, they see different results. Thanks to the private transactions, each company can only see it’s own vote, while the regulator can see all the votes. So we end up with a final result of “Option 1” winning the vote by 2 to 1, all without revealing each voter’s choice to the others. Thanks Quorum !
Thanks for reading and let me know in the comments if you have any questions or remarks :)
P.S.: To make our example work we’ve had to reveal the full details of the individual votes to the regulator. There are ongoing initiatives to take the privacy a step further, for example the ZCash team’s work on ZSL for Quorum. Hopefully a production ready and practical solution will emerge soon