2017.04.07

Parity: Proof of Authority Network

次世代システム研究室のN.M.です。今回はParity PoAを利用してprivate blockchainの実施について話したいです。

Parity Proof of Authority

Parity is a fast and lightweight Ethereum client programmed in the Rust language made by Ethcore. It has some advantages over the most widely used Ethereum client, Geth, such as consuming around half the memory and being considerably faster. The image below taken from ethcore.io illustrates this.

parity-perf

Another advantage is the capability to use various different consensus algorithms in addition to Proof of Work. PoW requires competing miners to submit their proofs of work. The first accepted proof with a valid block wins and that miner’s block is appended to the chain. The computation difficulty is dynamically calculated to maintain a steady predefined block generation rate. The difficulty is sufficient to make mining attacks prohibitively expensive.

PoW is great for public chains because unknown and untrusted miners exist on the network. To get the block reward and transaction fees a miner must play by the rules. But for private blockchains where we know and trust the miners PoW is not so desirable, and the computing overhead of PoW becomes wasteful.

This is where parity helps by offering two alternative mining algorithms tailored for private networks, Authority Round (Aura) and Tendermint. At the time of writing Tendermint is still experimental so they recommend using Aura. Aura is the parity implementation of the Proof of Authority algorithm. PoA is tailor made for private blockchains and requires much less processing power than using Proof of Work. Aura has various configuration options which we will discuss below.

Validators

PoA requires validators (miners) to sign a hash of the blocks they submit. Other nodes then verify the signer is the expected validator. Expected validators are calculated from a list of accepted validators and the current time slice. Using time slices across the network requires system times to be synchronized closely between parity nodes. The synchronization accuracy effects how quickly blocks may be generated.

The block generation rate is configurable, we found 5 seconds to work well. This is much faster than the public Ethereum generation rate of 15 seconds. When discussing PoA this 5 second period is called a step. Validators take turns to generate blocks within their allotted steps.

Parity offers multiple ways to configure the list of validators. Configuration can be via a static list or can be done using a contract on the blockchain. Also, the contract can be one of two types, non-reporting or reporting. The parity client interacts with the contract to get the list of validators. When we use a reporting contract the parity client also reports bad behavior. The ABI’s differ in that both types are required to provide a getValidators method, but the reporting contract must also provide additional methods that enable reporting of bad behavior.

At the time of writing the MajorityList.sol implementation of a reporting contract contains bugs that are currently being fixed, so you may need to create your own reporting contract. Parity itself should be Parity/v1.6.5 or above.

The configuration of the mining engine is done inside the chain specification JSON file.

Here is the relevant configuration for a static list of validators.
"validators": {
	"list": [
		"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e",
		"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"
	]
}
Here we see there are two accounts configured that may act as validators. Validator accounts should be assigned separate parity nodes. Obviously, the parity node acting as a validating node should also be configured to mine. Below is the relevant configuration from the parity node configuration .toml file.
[mining]
engine_signer = "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e"
Here we see that the validator address 0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e will be used for signing the blocks generated and submitted to the network.

A non-reporting contract

Now let’s look at the relevant part of the chain spec configuration JSON for a non-reporting contract configured parity PoA setup.
"validators": {
    "safeContract": "0x0000000000000000000000000000000000000005"
}
Here we see the address of the non-reporting validator contract: 0x0000000000000000000000000000000000000005. This address can be configured inside the accounts configuration in the chain spec file as shown below:
    "accounts": {
        "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
        "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
        "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
        "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
        "0x0000000000000000000000000000000000000005": {
            "balance": "1",
            "constructor": "{{ parity_contract_constructor }}"
        },
        ...
      }
The first 4 addresses are required and must be present in the parity chain spec for normal operation. Next we see the non-reporting contract configuration. The {{ parity_contract_constructor }} represents the hex byte-code for the contract constructor. The constructor byte-code may be obtained from the solidity browser in the Bytecode text field shown below.

browser-solidity

 

A reporting contract

A reporting contract provides two additional methods reportBenign, and reportMalicious. These two methods are called by the parity client when detecting benign or malicious block generation problems. An example of a malicious block generation problem would be more than one block generated for a given step. An example of a benign problem would be generating a block outside the validator’s allotted step.
Below is a simple example reporting contract which I used for testing PoA configuration.
pragma solidity ^0.4.6;

/*
 * Simple contract fullfilling abi of 'Reporting Contract' at https://github.com/paritytech/parity/wiki/Validator-Set#reporting-contract
 */
contract Validators {
	// Accounts used for testing: "0".sha3() and "1".sha3()
	address[] public validators = [0xca35b7d915458ef540ade6068dfe2f44e8fa733c, 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c];
	mapping(address => uint) indices;
	address public disliked;

    modifier onlyByProvider() {
        if (msg.sender != 0xdd870fa1b7c4700f2bd7f44238821c26f7392148) throw;
        _;
    }
	function Validators() {
	    for (uint i = 0; i < validators.length; i++) {
	        indices[validators[i]] = i;
	    }
	}
    
	// Called on every block to update node validator list.
    function getValidators() constant returns (address[]) {
		return validators;
	}
 
	// Expand the list of validators.
	function addValidator(address validator) onlyByProvider {
	    if (validators.length != 0 && indices[validator] != 0) {
	        return;
	    }
	    indices[validator] = validators.length;
	    validators.push(validator);
	}

	// Remove a validator from the list.
	function reportMalicious(address validator) onlyByProvider {
	    validators[indices[validator]] = validators[validators.length-1];
		delete indices[validator];
		delete validators[validators.length-1];
		validators.length--;
	}
	
	function reportBenign(address validator) onlyByProvider {
	    disliked = validator;
	}
}
In the code above we see the three required methods of a reporting contract as specified by the reporting contract ABI: getValidators, reportMalicious, and reportBenign. Additionally there is a method that gets called to add a validator, addValidator. In this implementation adding a validator can only be done by the ‘provider’ address. You can see that reportMalicious actually removes the offending address and reportBenign just sets the variable disliked. Of course how these reporting methods are implemented is up to the implementor of the contract. You may prefer to have the reporting methods simply fire an event, and monitor such events and removing validators manually. Also only having one ‘provider’ address that can add validators introduces a single point of failure. If the ‘provider’ account is compromised there is the possibility of losing control of the PoA network. The original reporting contract provided by Ethcore attempted to implement a majority voting scheme for adding providers.
For easy testing within browser-solidity, all three addresses (the two validators and the ‘provider’) are simply hardcoded to addresses initially created by browser solidity. However when you wish to run this contract as a reporting contract from within a parity PoA network you will need to create parity accounts. For this you may use the JSON-RPC api as shown below:
curl --data '{"method":"parity_newAccountFromPhrase","params":["this is your passphrase","your_password"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545
The above command connects to the parity default RPC port 8545 and calls the parity_newAccountFromPhrase method to create a new account with the passphrase and password supplied. After successful execution the key-store file will be created under the parity data directory.

Full configuration samples

Chain Spec

Below is a full sample configuration for the chain spec:
{
    "name": "MyPrivateChain",
    "engine": {
        "authorityRound": {
            "params": {
                "gasLimitBoundDivisor": "0x400",
                "stepDuration": "5",
                "validators" : { "contract": "0x0000000000000000000000000000000000000005" },
                "blockReward": "0x4563918244F40000"
            }
        }
    },
    "params": {
        "maximumExtraDataSize": "0x20",
        "minGasLimit": "0x1388",
        "networkID" : "54321"
    },
    "genesis": {
        "seal": {
            "authorityRound": {
                "step": "0x0",
                "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
            }
        },
        "difficulty": "0x20000",
        "gasLimit": "0x5B8D80"
    },
    "accounts": {
        "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
        "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
        "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
        "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
        "0x0000000000000000000000000000000000000005": {
            "balance": "1",
            "constructor": "{{ parity_contract_constructor }}"
        },
        "{{ account_with_lots_of_money }}": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
    }
}
This creates a chain called ‘MyPrivateChain’ using PoA. PoA validator configuration is done using a reporting contract. the {{ parity_contract_constructor }} will need to be filled in appropriately using a tool such as browser-solidity as explained above. Because we don’t want to run out of ether, the {{ account_with_lots_of_money }} has 2 to the power of 200 wei. This account will need to be created as explained above and the address entered here. Although running out of ether is not likely since we have a blockReward configured to 5 ether. Given the stepDuration of 5 seconds this means 1 new ether will be created every second and awarded to the validators as they create new blocks.

This chain spec file should be saved as chain-spec.json in a location referenced by the parity config as below.

Parity Configuration

Parity has many configuration options that dictate how a parity node will behave. Generally these configurations may be supplied on the command line or written to a config file as show below:
[parity]
chain = "./chain-spec.json"
base_path = "./"
[network]
port = 30303
id = 54321
[rpc]
port = 8545
apis = ['web3','eth','net','personal','parity','parity_set','traces','rpc','parity_accounts']
[ui]
port = 8180
[dapps]
port = 8080
[account]
password = ["./passwords"]
unlock = []
[mining]
engine_signer = "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e"
reseal_on_txs = "none"
Above we see that all external files referenced (chain-spec.json, base_path directory, passwords) are pointing to the current directory. This may or may not be desirable for you so edit as you see fit.
This file should be saved as parity-node.toml.

Summary

We discussed how to setup a private network using Parity’s Proof of Authority implementation. We explained why Proof of Work is not the best solution for a private blockchain and why Proof of Authority may be preferred.
We explained some considerations and some of the more important configurations.
If your desire is just to get a simple PoA network up and running quickly your best option is to use the hard-coded validator list configuration. If need a more scalable configuration, so that you may add validator nodes after the genesis block is created you should use one of the contract options: reporting or non-reporting. If you desire the added ability to detect misbehaving validators and to respond automatically you should go for the reporting contract option otherwise use the non-reporting contract. Remember that if you implement a contract that is deployed in the genesis block it will be difficult to fix any bugs. So you need to get it right first time! There are a couple of options in the parity development pipeline which should be available soon after this writing (Mar 29) however:
  • You can hard fork using a recently introduced Multi validator set
  • Or use the soon to be introduced validator set based on name registry
So if you need a PoA solution for production and you are worried about deploying a 100% bug free validator contract, it may be best to wait for these features to be fully implemented.

For information on the z.com blockchain service please visit: guide.blockchain.z.com

次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆さんのご応募をお待ちしています。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ

関連記事