Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
<pre> | ||
DIP: 0008 | ||
Title: ChainLocks | ||
Author(s): Alexander Block | ||
Special-Thanks: Andy Freer, Samuel Westrich, Thephez, Udjinm6 | ||
Comments-Summary: No comments yet. | ||
Status: Proposed | ||
Type: Standard | ||
Created: 2018-11-16 | ||
License: MIT License | ||
</pre> | ||
|
||
## Table of Contents | ||
|
||
1. [Abstract](#abstract) | ||
1. [Motivation](#motivation) | ||
1. [Prior Work](#prior-work) | ||
1. [Signing attempts](#signing-attempts) | ||
1. [Finalization of signed blocks](#finalization-of-signed-blocks) | ||
1. [Handling of signed blocks](#handling-of-signed-blocks) | ||
1. [Conflicting successful signing attempts](#conflicting-successful-signing-attempts) | ||
1. [Implications of a signed block](#implications-of-a-signed-block) | ||
1. [Network partitions](#network-partitions) | ||
1. [Initial Block Download](#initial-block-download) | ||
1. [Copyright](#copyright) | ||
|
||
## Abstract | ||
|
||
This DIP introduces ChainLocks, a technology for near-instant confirmation | ||
of blocks and finding near-instant consensus on the longest valid/accepted | ||
chain. ChainLocks leverages LLMQ Signing Requests/Sessions to accomplish | ||
this. | ||
|
||
## Motivation | ||
|
||
When a node encounters multiple valid chains, it sets the local "active" chain | ||
by selecting the one that has the most accumulated work. This is generally | ||
known as the “longest-chain” rule as in most cases it is equivalent to | ||
choosing the chain with the most blocks. | ||
|
||
If both chains have the same amount of accumulated work (and in most cases the | ||
same block count), a decision can’t be made solely based on the longest-chain | ||
rule. In that case, the first chain received by the node is chosen to be the | ||
active one and the other chain is put aside. If another block is then received | ||
which extends the non-active chain so that it has the most accumulated work, it | ||
becomes the active one. For example, even if a chain is currently 6 blocks | ||
longer than any other chain, it’s still possible that a shorter chain becomes | ||
longer and thus the active one. This is generally known as a chain | ||
reorganization. | ||
|
||
The most common situation where this happens is if two miners find a block at | ||
approximately the same time. Such a block would race in the network and one | ||
part of the network would accept one block as the new active chain while | ||
another part of the network would accept the other block. In most cases, | ||
whoever finds the next block also indirectly resolves the situation as the new | ||
block’s parent block determines which of the chains will be the longest one. | ||
This is generally known as orphaning of blocks. | ||
|
||
It might also happen by accident. For example, if parts of the network with a | ||
high hashrate are partitioned and miners are unaware of other miners mining on | ||
another chain. When the network becomes healthy again, multiple chains will | ||
exist that all branch from a common ancestor. While these chains are | ||
propagated, one side of the previously partitioned network will have to | ||
reorganize their local chain to the chain of the other side. | ||
|
||
It can also happen on purpose if a miner with more hashrate than all other | ||
miners combined decides to ignore other miner’s blocks and only mine on top | ||
of their own blocks. This is generally known as the 51% mining attack. A miner | ||
can even go as far as not publishing any blocks for some time so the remainder | ||
of the network is not aware of the attack until they suddenly publish the | ||
longer secret chain. | ||
|
||
In all these cases, uncertainty arises for individual recipients of funds. When | ||
a reorganization happens, it is not necessary for the new chain to include the | ||
same transactions as the old chain. In addition to including new transactions | ||
and excluding old transactions, it is possible to include transactions in the | ||
new chain which are in conflict with the old chain. This means that a new chain | ||
might send funds from the same inputs to another address. This results in the | ||
only valid form of double spending possible in Dash (InstantSend is not | ||
double-spendable even for this case) and most other Bitcoin based | ||
cryptocurrencies. | ||
|
||
This DIP proposes a new method, called ChainLocks, for reducing uncertainty | ||
when receiving funds and removing the possibility of 51% mining attacks. | ||
|
||
## Prior work | ||
|
||
- [DIP 006: Long Living Masternode Quorums](https://github.com/dashpay/dips/blob/master/dip-0006.md) | ||
- [DIP 007: LLMQ Signing Requests / Sessions](https://github.com/dashpay/dips/blob/master/dip-0007.md) | ||
|
||
## Signing attempts | ||
|
||
When a new valid block is received by a masternode, it must invoke the [DIP007 | ||
`SignIfMember` operation](https://github.com/dashpay/dips/blob/master/dip-0007.md#void-signifmemberuint256-id-uint256-msghash-int-activellmqs). | ||
|
||
The request id for the operation is `hash(prevBlockHash, attemptNum)` and the | ||
message hash is the hash of the new block (`newBlockHash`). The first time this | ||
is attempted, `attemptNum` must be set to `0`. | ||
|
||
In most cases, the majority of the LLMQ will sign the same message hash in the | ||
first attempt and thus find consensus. This can be checked with the [DIP007 | ||
`HasRecoveredSig` operation](https://github.com/dashpay/dips/blob/master/dip-0007.md#bool-hasrecoveredsiguint256-id-uint256-msghash-int-activellmqs). | ||
This will even hold true in most cases where 2 competing blocks are being | ||
propagated inside the network, as only one is able to reach more LLMQ members | ||
faster than the other and thus gain a majority in the signing request. | ||
|
||
In some cases however, it is possible that no majority can be reached in the | ||
first attempt. This could happen if too many members of the LLMQ are | ||
malfunctioning or if more than two blocks are competing. If this happens, a | ||
second signing request with an incremented `attemptNum` value must be | ||
initiated. To check for a failed attempt, the [DIP007 `IsMajorityPossible` | ||
operation](https://github.com/dashpay/dips/blob/master/dip-0007.md#bool-ismajoritypossibleuint256-id-uint256-msghash-int-activellmqs) must be used. An attempt | ||
is also considered as failed when it did not succeed after some timeout. | ||
|
||
On failure, another signing request with an incremented `attemptNum` value | ||
should be initiated. The new request should use the message hash returned by | ||
the [DIP007 `GetMostSignedSession` operation](https://github.com/dashpay/dips/blob/master/dip-0007.md#uint256-getmostsignedsessionuint256-id-int-activellmqs), which is the hash of the block | ||
which had the most signatures in the last attempt. After a few attempts, a | ||
request should result in a recovered threshold signature which indicates | ||
consensus has been reached. | ||
|
||
## Finalization of signed blocks | ||
|
||
After a signing attempt has succeeded, another LLMQ must sign the successful | ||
attempt. This is only performed once for each `prevBlockHash` and thus either | ||
succeeds or fails without performing additional attempts. | ||
|
||
The request id is `prevBlockHash` and the message hash is the block hash of the | ||
previously successful attempt. | ||
|
||
After a LLMQ member has successfully recovered the final ChainLocks | ||
signature, it must create a P2P message and propagate it to all nodes. The | ||
message is called `CLSIG` and has the following structure: | ||
|
||
| Field | Type | Size | Description | | ||
|--|--|--|--| | ||
| prevBlockHash | uint256 | 32 | Hash of the previous block | | ||
| blockHash | uint256 | 32 | Hash of the signed block from the successful attempt | | ||
| attemptNum | uint16 | 2 | The attempt number | | ||
| sig | BLSSig | 96 | Recovered signature | | ||
|
||
This message is propagated through the inventory system. | ||
|
||
Upon receipt, each node must perform the following verification before | ||
announcing it to other nodes: | ||
|
||
1. `prevBlockHash` must refer to a block that is part of any locally known | ||
chain | ||
2. Based on the deterministic masternode list at the chain height of | ||
`prevBlockHash`, a quorum must be selected that was active at the time this | ||
block was mined | ||
3. The signature must verify against the quorum public key and | ||
`hash(blockHash, attemptNum)`. | ||
|
||
## Handling of signed blocks | ||
|
||
When a new block has been successfully signed by a LLMQ and the `CLSIG` message | ||
is received by a node, it should ensure that only this block is locally | ||
accepted as the next block. | ||
|
||
If an alternative block for the same height is received, it must be invalidated | ||
and removed from the currently active chain since a signed block has already | ||
been received. If the correct block is already present locally, its chain | ||
should be activated as the new active chain. If the correct block is not known | ||
locally, it must wait for this block to arrive and request it from other nodes | ||
if necessary. | ||
|
||
If a block has been received locally and no `CLSIG` message has been received | ||
yet, it should be handled the same way it was handled before the introduction | ||
of ChainLocks. This means the longest-chain and first-seen rules must be | ||
applied. When the `CLSIG` message for this (or another) block is later | ||
received, the above logic must be applied. | ||
|
||
## Conflicting successful signing attempts | ||
|
||
While the network is operating as expected, it’s not possible to encounter | ||
two conflicting recovered signatures for two signing attempts of the same | ||
parent block. It is possible for a malicious masternode operator to manually | ||
double-sign two different attempts when a close race between two competing | ||
blocks occurs. If one of the conflicting signature shares is withheld until the | ||
second attempt succeeds and the conflicting signature is then propagated to the | ||
network, the two attempts will result in two valid recovered signatures. | ||
|
||
When performing the finalization of successful attempts, the LLMQ members will | ||
only try to finalize a single attempt, which is usually the first one to | ||
succeed. Only a single attempt will be able to gain a majority during | ||
finalization, which removes the possibility of conflicts. In the worst case, | ||
finalization completely fails, no `CLSIG` message is created and nodes must | ||
fall back to the first-seen and longest-chain rules. | ||
|
||
## Implications of a signed block | ||
|
||
If a block was successfully signed, it can be safely assumed that no chain | ||
reorganization before this block can happen, as all nodes would agree to reject | ||
blocks with a lower height. This means that each transaction in this block and | ||
all previous blocks can be considered irreversibly and instantly confirmed. | ||
|
||
For InstantSend, this also means that the minimum of 6 confirmations of the | ||
parent transaction can be removed if the parent transaction is inside or below | ||
a signed block. | ||
|
||
## Network partitions | ||
|
||
If there is a network partition, the most likely thing to happen is that just | ||
one side is able to mine a signed chain. The other side will encounter | ||
non-signed blocks building on top of the last signed block. Miners who observe | ||
this must assume that another currently unobserved chain is being built in | ||
parallel. Since the parallel chain might be signed and could possibly overtake | ||
their own chain after the network is healthy again, miners should act | ||
accordingly (e.g. reduce hash power to reduce costs). | ||
|
||
If the network is partitioned to a degree that makes a majority in the | ||
responsible LLMQ impossible, all partitions in the network will be unable to | ||
produce a signed chain. After the network is healthy again, one part of the | ||
network will reorganize itself to the other’s chain after which the | ||
responsible LLMQ will sign the new chain tip. | ||
|
||
## Initial Block Download | ||
|
||
While fully synced, nodes will usually receive `CLSIG` messages for new blocks | ||
shortly after they are mined. If a node was offline for some time or has to | ||
perform an initial block download, the signatures for old blocks will not be | ||
present in the initial implementation. | ||
|
||
Nodes should fall back to the plain “longest-chain” and “first-seen” | ||
rules in this case until the first block signature for a new block is received. | ||
|
||
We assume that old blocks are secure enough to not encounter any significant | ||
forks which could lead to a different chain tip after initial block download is | ||
finished. When the chain tip is reached, the first received signature will | ||
resolve any ambiguities which might occur in the last few blocks. | ||
|
||
If the need arises to include block signatures in initial block download, we | ||
will update this DIP and implementations accordingly. | ||
|
||
## Copyright | ||
|
||
Copyright (c) 2018 Dash Core Group, Inc. [Licensed under the MIT | ||
License](https://opensource.org/licenses/MIT) |