-
Notifications
You must be signed in to change notification settings - Fork 35
Ethereum Validation Clique PoA
The Ion interoperability framework uses modular validation to allow interoperability with blockchains of any consensus protocol. This document describes the design and implemenntation of a validation contract for the Clique consensus mechanism.
A sequence diagram for the Clique Proof of Authority validation module is given below:
The latest contract can be found here.
The core functions and other properties are identical to those found in the generic validation module specifications - see here. However to support the functionality of the Clique block validation a number of changes are made to the implementation of the validation module.
Array containing all active validators, which is referenced whenever a block is verified.
Function: RegisterChain
Purpose: Registers a new chain to the Ion contract, creating a specific connection between the validation contract and Ion hub contract.
Arguments:
* id (bytes32 Unique id of another chain to interoperate with )
* validators (address[] Array containing the validators at the genesis block )
* genesisHash (bytes32 Hash of the genesis block for the chain being registered with Ion )
Function: SubmitBlock
Purpose: Validates a submitted block, needs to recreate the signed hash using the submitted block then perform a verification of the signature used.
Arguments:
* id (bytes32: the identification hash of the chain being interoperated with )
* rlpBlockHeader (bytes: rlp encoded blockheader without validator signatures )
* rlpSignerBlockHeader (bytes: rlp encoded signed block as defined by Clique, including the validator signature )
Unsigned blocks should be submitted RLP encoded in the following ordering:
{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-65],
header.MixDigest,
header.Nonce
}
In order to extract both the block hash and the hash that is signed by the PoA validators this RLP encoded signed block header must be submitted. Hashing this gives the blockhash:
{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra,
header.MixDigest,
header.Nonce
}
Creating v, r, and s from the hash of the above block data a recovery against the hashed unsigned block can be performed. The public key recovered should exist within the list of validators. However for a given round the validator can only submit once.
Submitted blocks should be rejected if:
- The signature recovered does not belong to a validator in the whitelist
- The signatory has exceed their limit of blocks signed for a given round
- ParentHash is not found in the BlockHeader mappings
If a block is successfully validated two things should happen:
- Block is appended to the state history of the foreign chain
- The vote for addition or removal of validators should be tallied
Therefore the list of validators for subsequent epochs will be known prior to the subsequent epochs beginning.
Votes for addition or removals are carried out using repurposed fields in the header. The address of the validator would be contained in the miner block and the indication whether they are to be added or removed indicated through setting the nonce field to 0 or 0xFFFF to add or remove respectively. This should be submitted to the countVotes() function.
Listed are a number of issues when using clique.
Clique sacrifices consistency over availability. During any given round block sealers can propose a block in any given order it is possible that two separate proposers submit a block at the same time. This would create a small fork in the chain which should be solved using the GHOST protocol, however this would not prevent somebody from submitting an 'incorrect' block to the Ion contract.
PBFT/Istanbul should not suffer from this issue.
Clique allows additional validators to be added or removed from the validator set using a voting system. Validator sets are valid for a prescribed epoch, the start of an epoch does not require any knowledge of previous state. Validators active during the epoch are able to propose an addition or removal from the validator set, requiring floor((SIGNER_COUNT/2) + 1) of the set to agree.
Given N validators and M rounds, giving an epoch of length M*N blocks, validators can vote each time they propose a block. Changes to the set are conducted at the start of every new epoch.
However an edge case whereby removing a validator reduces the threshold which spurs a cascade of removals.
To verify a block it is passed RLP encoded into solidity as a bytes. Given a standard clique block we can be assured it has the form [prefix, length, payload]. The payload is of the form:
| Field | Type | Length | Prefix | Example |
|---|---|---|---|---|
| ParentHash | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a0cc97e24be8f595ece94c345c88b178e395befbdf4590d861f85fad856630f5e9 |
| UncleHash | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 |
| Coinbase | String | 20 bytes | 0x80 + 0x14 = 0x94 |
940000000000000000000000000000000000000000 |
| Root | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a0db37435caa1fca7e1aa5b4da1c69fdf1d127232519eb3b1b5069825e6c62f5dc |
| TxHash | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 |
| ReceiptHash | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 |
| LogsBloom | String | 256 bytes |
0xb7 + 0x02 = 0xb9, 0x01\0x00
|
b90100000000000000000000000000...000000000000000000000000000000000 |
| Difficulty | Single Byte | 1 byte | 0x02 |
02 |
| Number | Single Byte | 1 byte | 0x0a |
0a |
| GasLimit | String | 3 bytes | 0x80 + 0x03 = 0x83 |
8347e7c4 |
| GasUsed | String | 1 bytes | 0x80 + 0x00 = 0x80 |
80 |
| TimeStamp | String | 4 bytes | 0x80 + 0x04 = 0x84 |
845b2228cb |
| ExtraData | String | 97 bytes |
0xb7 + 0x01 = 0xb8, 0x67
|
b861d78301080a846765746887676f31...ebcaba778c634132e5771f19c1e7f00 |
| MixHash | String | 32 bytes | 0x80 + 0x20 = 0xa0 |
a00000000000000000000000000000000000000000000000000000000000000000 |
| Nonce | String | 8 bytes | 0x80 + 0x08 = 0x88 |
880000000000000000 |
| Total | N/A | 15, 583 bytes [Prefixes, Payload] |
0xf7 + 0x02 = 0xf9, 0x02\0x56
|
f90256[payload] |
Hashing this gives the block hash, in order to verify the signed hash the signature(s) must be extracted from extraData field. Modifing the RLP encoded header however requires recalculating the overall RLP prefix and that of the extraData field.
Removing the
| Field | Type | Length | Prefix | Example |
|---|---|---|---|---|
| ExtraData | String | 32 bytes | 0xc0 + 0x20 = 0xe0 |
e0d78301080a846765746887676f312e392e33856c696e75780000000000000000 |
| Total | N/A | 14, 518 bytes [Prefixes, Payload] |
0xf7 + 0x02 = 0xf9, 0x02\0x14
|
f90214[payload] |
Given any block header the RLP encoding is dependent upon the length of the arguments within each field. A number of fields are of a static length, meaning no matter what data is held it is encoded at the same length for each block. However there are five fields which cannot be expected to always have the same length in bytes:
- Difficulty [PoW or PoS only]
- Number
- GasLimit
- GasUsed
- Timestamp
- ExtraData [Istanbul Only]
Clearmatics :D