|
@@ -0,0 +1,85 @@
|
|
|
+<pre>
|
|
|
+ PIP: PIP-0013
|
|
|
+ Title: Allow nodes to pull pending operations
|
|
|
+ Type: Protocol
|
|
|
+ Impact: Soft-Fork
|
|
|
+ Author: Herman Schoenfeld <i><[email protected]></i>
|
|
|
+ Comments-URI: https://discord.gg/sJqcgtD (channel #pip-0013)
|
|
|
+ Status: Proposed
|
|
|
+ Created: 2018-01-03
|
|
|
+</pre>
|
|
|
+
|
|
|
+## Summary
|
|
|
+
|
|
|
+A new network operation called NET_OP_PULL_PENDING is proposed that allows nodes to pull some or all of the pending operations from other connected peers.
|
|
|
+
|
|
|
+## Motivation
|
|
|
+
|
|
|
+Currently a node receives new operations as they flood-fill the network when created and during block propagation. Whilst this is extremely efficient, if a node restarts it loses the current pending pool and only receives it when the next block is minted. This situation can lead to out-of-sequence N_OPERATION errors since a node forgets the correct N_OPERATION of accounts due to pending operations it no longer knows about. This has led to withdrawal failures at exchanges from Poloniex, a serious user-experience issue. Whilst this can be mitigated by persisting the pending pool, a comprehensive solution is proposed here that allows a node to download relevant (or all) of the pending pool on startup. This also benefits mobile and light-client nodes.
|
|
|
+
|
|
|
+## Specification
|
|
|
+
|
|
|
+The proposal here is to add a new network operation
|
|
|
+
|
|
|
+### NET_OP_PULL_PENDING
|
|
|
+
|
|
|
+**Arguments**
|
|
|
+- N : DWord - the number of parameter keys in parameters
|
|
|
+- KeyHash_1 : Bytes[20] - the RIPEMD160 of the first key
|
|
|
+
|
|
|
+ .
|
|
|
+ .
|
|
|
+ .
|
|
|
+
|
|
|
+- KeyHash_N : Bytes[20] - the RIPEMD160 hash of the N'th key
|
|
|
+
|
|
|
+**Output**
|
|
|
+- M : DWord - the number of pending operations being returned
|
|
|
+- OP_1_SIZE : DWord - the byte length of OP_1
|
|
|
+- OP_1 - ByteArray[OP_1_SIZE] - the first pending operation
|
|
|
+
|
|
|
+ .
|
|
|
+ .
|
|
|
+ .
|
|
|
+
|
|
|
+- OP_M_SIZE : DWord - the byte length of OP_M
|
|
|
+- OP_M - ByteArray[OP_M_SIZE] - the M'th pending operation
|
|
|
+
|
|
|
+**PSEUDO-CODE**
|
|
|
+```pascal
|
|
|
+let output = list of operations
|
|
|
+if N = 0 then
|
|
|
+ output = PendingPool
|
|
|
+else
|
|
|
+ for all O in PendingPool
|
|
|
+ for all k in (Argument Keys)
|
|
|
+ let senderAccount = SafeBox.Accounts[O.Sender]
|
|
|
+ let receiverAccount = SafeBox.Accounts[O.Receiver]
|
|
|
+ let feePayerAccount = SafeBox.Accounts[O.Signer]
|
|
|
+
|
|
|
+ if senderAccount.Key = k OR receiverAccount.Key = k OR feePayerAccount.Key = k then
|
|
|
+ output.Add(O)
|
|
|
+ else
|
|
|
+ if O is ChangeKeyOperation AND O.NewKey = k then
|
|
|
+ output.Add(O)
|
|
|
+ else if O is BuyAccountOperation and O.NewKey = k then
|
|
|
+ output.Add(O)
|
|
|
+ else ....
|
|
|
+
|
|
|
+return FORMAT(output)
|
|
|
+```
|
|
|
+
|
|
|
+**NOTE** the above pseudo-code is only a guide and actual implementation will more scenarios. It is left to the implementor to determine all the scenarios correctly. Errors in implementation will never result in out-of-consensus issues, since this is a non-critical network operation.
|
|
|
+
|
|
|
+### DoS Protection
|
|
|
+
|
|
|
+Since this network operation could be used to DoS a peer, peers should include the following protection:
|
|
|
+- If 2 NET_OP_PULL_PENDING is received from the **same peer** within 5 seconds, blacklist that peer.
|
|
|
+
|
|
|
+## Rationale
|
|
|
+
|
|
|
+Other approaches were considered involving Bloom Filtering and bit-vectors, but these changes cannot be introduced within the V3 timeline. The above proposal is elegant and simple to implement, and achieves the job until later date.
|
|
|
+
|
|
|
+## Backwards Compatibility
|
|
|
+
|
|
|
+This proposal is backwards compatible and can be introduced as a soft-fork.
|