PIP: PIP-0013 Title: Allow nodes to pull pending operations Type: Protocol Impact: Soft-Fork Author: Herman Schoenfeld <firstname.lastname@example.org> Comments-URI: https://discord.gg/sJqcgtD (channel #pip-0013) Status: Active Created: 2018-01-03
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.
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 is required to wait until the next block in order to become aware of pending/minted operations. This situation can lead to out-of-sequence N_OPERATION errors since a node can forget the correct N_OPERATION of an owned account due to recent pending operations it lost during the resetart. This has led to withdrawal failures at exchanges from Poloniex, a serious user-experience issue. Whilst this can be mitigated client-side by persisting the pending pool, a comprehensive solution is proposed here. The proposal also benefits mobile and light-clients by allowing them to poll peers for pending operations, as well as other layer-2 scenarios.
The proposal here is to add a new network operation.
N : DWord - the number of parameter keys in parameters
KeyHash_1 : Bytes - the RIPEMD160 of the first key
. . .
KeyHash_N : Bytes - the RIPEMD160 hash of the N'th key
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
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 RIPEMD160(senderAccount.Key) = k OR RIPEMD160(receiverAccount.Key) = k OR RIPEMD160(feePayerAccount.Key) = k then output.Add(O) else if O is ChangeKeyOperation AND RIPEMD160(O.NewKey) = k then output.Add(O) else if O is BuyAccountOperation and RIPEMD160(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.
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.
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. Argument keys are hashed for network efficiency, which is paid for client-side computationally. This is why DoS protection is necessary for this network operation.
This proposal is backwards compatible and can be introduced as a soft-fork.