From a984d416e3c562787f825b634560d31ff629c761 Mon Sep 17 00:00:00 2001 From: thephez Date: Tue, 21 May 2019 11:16:50 -0400 Subject: [PATCH] DIP10 - Add DIP and update Readme (#49) LLMQ InstantSend --- README.md | 1 + dip-0010.md | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 dip-0010.md diff --git a/README.md b/README.md index f39ab2e..b10721b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Number | Layer | Title | Owner | Type | Status [6](dip-0006.md) | Consensus | Long-Living Masternode Quorums | Alexander Block | Standard | Active [7](dip-0007.md) | Consensus | LLMQ Signing Requests / Sessions | Alexander Block | Standard | Active [8](dip-0008.md) | Consensus | ChainLocks | Alexander Block | Standard | Active +[10](dip-0010.md) | Consensus | LLMQ InstantSend | Alexander Block | Standard | Proposed ## License diff --git a/dip-0010.md b/dip-0010.md new file mode 100644 index 0000000..dad957e --- /dev/null +++ b/dip-0010.md @@ -0,0 +1,249 @@ +
+  DIP: 0010
+  Title: LLMQ InstantSend
+  Author(s): Alexander Block
+  Special-Thanks:
+  Status: Proposed
+  Type: Standard
+  Created: 2019-05-16
+  License: MIT License
+
+ +## Table of Contents + +1. [Abstract](#abstract) +1. [Motivation](#motivation) +1. [Prior Work](#prior-work) +1. [Making all transactions instant](#making-all-transactions-instant) +1. [Used LLMQ type](#used-llmq-type) +1. [Eligible transactions for InstantSend](#eligible-transactions-for-instantsend) +1. [Locking Transaction Inputs](#locking-transaction-inputs) +1. [Finalization and creation of ISLOCK messages](#finalization-and-creation-of-islock-messages) +1. [Detecting and handling double-spend attempts](#detecting-and-handling-double-spend-attempts) +1. [Conflicts between ChainLocks and InstantSend](#conflicts-between-chainlocks-and-instantsend) +1. [Retroactive signing of transactions in blocks](#retroactive-signing-of-transactions-in-blocks) +1. [Dangling Partial Locks](#dangling-partial-locks) +1. [Persistence of InstantSend locks](#persistence-of-instantsend-locks) +1. [Copyright](#copyright) + +## Abstract + +This DIP defines a new implementation for InstantSend based on DIP0006 LLMQs +and DIP0007 LLMQ Signing Requests/Sessions. + +## Motivation + +InstantSend is a feature to allow instant confirmations of payments. It works +by locking transaction inputs through masternode quorums. It has been present +in Dash for a few years and been proven to work. Nevertheless, there are some +limitations which could theoretically be fixed in the old system. However, +fixing these limits in the old system (i.e. before LLMQs) would have created +risks in terms of scalability and security. + +With LLMQs, these limitations can be lifted to enable more scaling and a better +user experience. + +## Prior work + +- [DIP 0006: Long Living Masternode Quorums](https://github.com/dashpay/dips/blob/master/dip-0006.md) +- [DIP 0007: LLMQ Signing Requests / Sessions](https://github.com/dashpay/dips/blob/master/dip-0007.md) +- [DIP 0008: LLMQ based ChainLocks](https://github.com/dashpay/dips/blob/master/dip-0008.md) +- [Transaction Locking and masternode Consensus: A Mechanism for Mitigating Double Spending Attacks](https://github.com/dashpay/docs/blob/master/binary/Dash%20Whitepaper%20-%20Transaction%20Locking%20and%20Masternode%20Consensus.pdf) + +## Making all transactions instant + +LLMQ-based InstantSend allows all transactions to be treated as InstantSend +transactions. The old system differentiated transactions as InstantSend +transactions by using the P2P message `ix` instead of `tx`. In the new system, +such distinction is not required anymore as LLMQs will try to lock every valid +transaction by default. If an `ix` P2P message is received from an older +client, nodes should convert these to simple `tx` messages and treat them as +such (including processing and propagating as `tx`). + +## Used LLMQ type + +All signing sessions/requests involved in InstantSend must use the LLMQ_50_60 +LLMQ type. + +## Eligible transactions for InstantSend + +When a transaction is received and successfully added to the mempool (which +means it also passes the usual validation checks), each masternode should check +if the transaction is eligible for InstantSend. + +A transaction is eligible for InstantSend when each of its inputs is considered +confirmed. This is the case when the previous transaction referred to by the +input is confirmed with 6 blocks, confirmed through an older InstantSend lock +or the block containing it is ChainLocked. When checking the previous +transaction for an InstantSend lock, it is important to also do this on mempool +(non-mined) transactions. This allows chained InstantSend locking. + +## Locking Transaction Inputs + +When a transaction is eligible for InstantSend, each masternode should try to +initiate a signing request for each of the transaction’s inputs. The request +id is: + + hash("inlock", prevTxHash, prevTxOut) + +`"inlock"` is a static string, prepended with the length (6, as a compact int, +which is a single byte) of the string. The message hash of the signing request +is the txid/hash of the transaction to be locked. + +The [DIP0007 LLMQ Signing Request/Sessions](https://github.com/dashpay/dips/blob/master/dip-0007.md) +subsystem should handle the signing and recovery of signatures afterwards. It +will also automatically determine if the local masternode has to sign a share +or if it should skip it. In case of conflicts between transactions which are +not fully locked yet, the DIP0007 subsystem will handle this as well by +skipping signing of conflicting inputs. + +Each masternode should then wait for the recovered signatures for each input to +appear. When all recovered signatures have appeared, each masternode should +initiate the finalization phase. + +## Finalization and creation of ISLOCK messages + +When a masternode has observed all recovered signatures for each input of a +transaction, it should initiate the finalization and creation of an `ISLOCK` +message. + +Finalization is simply another signing request, performed on a (potentially) +different LLMQ than used before. The request id of the new signing request is: + + hash("islock", inputCount, prevTxHash1, prevTxOut1, prevTxHash2, +prevTxOut2, ...) + +`"islock"` is a static string, prepended with the length (6, as a compact int, +which is a single byte) of the string. `inputCount` is a compact int, +comparable to what is typically used in serialized arrays/vectors to serialize +the size. After `inputCount`, multiple pairs of <`prevTxHash`, `prevTxOut`> +follow, which are corresponding to the individual inputs of the transaction to +be locked. The message hash of the signing request is the txid/hash of the +transaction to be locked. + +The LLMQ Signing Request/Sessions subsystem will handle this the same way as in +the previous section. + +When a masternode receives the recovered signature for this signing request, it +should use the signature to create a new p2p message, which is the `ISLOCK` +message. It has the following structure: + +| Field | Type | Size | Description | +|--|--|--|--| +| inputCount | compactSize uint | 1 - 9 | Number of inputs in the transaction | +| inputs | COutpoint[] | `inputCount` * 36 | Inputs of the transaction. COutpoint is a uint256 (hash of previous transaction) and a uint32 (output index) | +| txid | uint256 | 32 | txid/hash of the transaction | +| sig | BLSSig | 96 | Recovered signature from the signing request/session | + +This p2p message should be propagated to all full nodes, including +non-masternodes. This is done using the `INV`/`GETDATA` subsystem. It should +also be propagated to SPV nodes if the transaction referred to by the txid +matches the bloom filter of the SPV node. Receiving nodes should verify the +message by checking the signature against the responsible LLMQ’s public key. +The responsible LLMQ can be determined by re-calculating the request id from +the data found in the `ISLOCK` message and then choosing the responsible LLMQ +with the help of the LLMQ Signing Requests/Sessions subsystem. If the `ISLOCK` +message is determined to be valid, it should be propagated further. + +All full nodes and SPV nodes should only consider a transaction to be locked +when a valid `ISLOCK` for the transaction is available. The individual inputs +previously locked and their corresponding recovered signatures should not be +used when it comes to `ISLOCK` validation. + +## Detecting and handling double-spend attempts + +When an `ISLOCK` message is present, it can be used to easily detect +conflicting transactions which try to double spend the locked transaction +inputs. This is even possible when the original transaction is not present and +only the `ISLOCK` message is present (which might be the case due to the +first-seen rule). + +Each time an `ISLOCK` message is received, nodes should check the mempool and +recent non-ChainLocked blocks for conflicting transactions. A transaction is +considered conflicting when it spends an outpoint found in the `ISLOCK` message +but its txid/hash does not match the txid from the `ISLOCK` message. + +The same checks should be performed when a transaction is received before the +corresponding (or conflicting) `ISLOCKs` are received. This includes +transactions received through normal transaction propagation or through mined +blocks. + +If a conflict is found in the mempool, the conflicting transaction +should be removed from the mempool. The originally locked transaction will +naturally not be present in this situation, as the first-seen rule would have +already filtered it. Thus the transaction referenced in the `ISLOCK` message +should be re-requested from one of the nodes that had previously announced it. + +If a conflict is found in a recently mined block, conflict resolution depends +on the ChainLock state of the block. If the block is not ChainLocked, the whole +block must be invalidated. This might result in a reorganization of the chain +and re-acceptance of non-conflicting transactions in the local mempool. If the +block (or one of its descendants) has a ChainLock, the `ISLOCK` (and all +chained descendants) must be ignored and pruned from memory (including +persistent memory). + +## Conflicts between ChainLocks and InstantSend + +The latter case with a conflicting block receiving a ChainLock is very unlikely +to happen. The ChainLocks system usually does not try to lock blocks which +contain non-InstantSend locked transactions. This means that even if a miner +manages to include a conflicting TX into a block, masternodes following normal +consensus rules will not create a ChainLock for this block. Consequently the +block would be invalidated on all nodes when the `ISLOCK` appears. + +Only in the case of an attack, where an attacker managed to get control over +large parts of the masternode network, would this situation becomes a +possibility. In this situation, ChainLocks have a higher priority when it comes +to consensus. Please see [DIP0008 - ChainLocks](https://github.com/dashpay/dips/blob/master/dip-0008.md) +for more details. + +## Retroactive signing of transactions in blocks + +When a block is received that contains transactions which were previously +unknown to the receiving masternode, the masternode should try to lock these +transactions the same way as those received through normal transaction +propagation. + +In most cases, this will be a no-op as the `ISLOCK` will already be present +locally and thus the locking attempt can be skipped. Retroactive signing +however becomes important when miners include transactions in new blocks which +are not known by the remainder of the network. As it is desirable to lock all +transactions, retroactive signing ensures that even these transactions get +locked. + +This also allows the ChainLocks system to retroactively lock blocks which +include unsafe transactions, as these transactions will become safe after a +short delay. + +## Dangling Partial Locks + +In rare cases, a transaction input may not be locked. This could result in a +transaction where only some of the inputs are successfully locked. + +This would happen if a LLMQ becomes inactive in the middle of a signing session +due to a fresh LLMQ pushing an old LLMQ out of the active list. In this case, +some members of the old LLMQ may not receive the transaction in a timely manner +and thus do not perform the threshold signing. It might also happen if a LLMQ +becomes dysfunctional, e.g. due to too many members being offline or +unresponsive. + +In the initial implementation, we will ignore this unlikely scenario and simply +consider the transaction as not locked, which also means that the `ISLOCK` +message is never created. Such a transaction reverts to being a normal +transaction and will be mined with a delay of a few minutes. See +["Safe Transactions” in DIP0008 - ChainLocks](https://github.com/dashpay/dips/blob/master/dip-0008.md#safe-transactions) +for more details. + +## Persistence of InstantSend locks + +An InstantSend lock should be persistent until the corresponding transaction is +mined on-chain and either confirmed by 24 blocks or a ChainLock. InstantSend +locks for non-mined transaction should never expire or time out. + +Persistency is meant to be persistent on-disk and able to survive restarts of +the node. Storing InstantSend locks in RAM only is not enough. + +## Copyright + +Copyright (c) 2019 Dash Core Group, Inc. [Licensed under the MIT +License](https://opensource.org/licenses/MIT)