mirror of
https://github.com/seigler/dips
synced 2025-07-27 01:36:14 +00:00
Add DIP8 - ChainLocks (#32)
This commit is contained in:
parent
0afc096282
commit
283c6c9938
1 changed files with 239 additions and 0 deletions
239
dip-0008.md
Normal file
239
dip-0008.md
Normal file
|
@ -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)
|
Loading…
Add table
Add a link
Reference in a new issue