mirror of
https://github.com/seigler/dips
synced 2025-07-26 17:26:13 +00:00
* DIP2-4 Change status from Proposed to Active * DIP2-4 Change status to Final * DIP6-8 Change status from Proposed to Active
240 lines
12 KiB
Markdown
240 lines
12 KiB
Markdown
<pre>
|
||
DIP: 0008
|
||
Title: ChainLocks
|
||
Author(s): Alexander Block
|
||
Special-Thanks: Andy Freer, Samuel Westrich, Thephez, Udjinm6
|
||
Comments-Summary: No comments yet.
|
||
Status: Active
|
||
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 |
|
||
| 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(llmqType, quorumHash, prevBlockHash, blockHash)`. `llmqType` and `quorumHash`
|
||
must be taken from the quorum selected in 2.
|
||
|
||
|
||
## 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)
|