forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Track transaction packages in CTxMemPoolEntry
Associate with each CTxMemPoolEntry all the size/fees of descendant mempool transactions. Sort mempool by max(feerate of entry, feerate of descendants). Update statistics on-the-fly as transactions enter or leave the mempool. Also add ancestor and descendant limiting, so that transactions can be rejected if the number or size of unconfirmed ancestors exceeds a target, or if adding a transaction would cause some other mempool entry to have too many (or too large) a set of unconfirmed in- mempool descendants.
- Loading branch information
Showing
10 changed files
with
993 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#!/usr/bin/env python2 | ||
# Copyright (c) 2014-2015 The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
# Test descendant package tracking code | ||
|
||
from test_framework.test_framework import BitcoinTestFramework | ||
from test_framework.util import * | ||
|
||
def satoshi_round(amount): | ||
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) | ||
|
||
class MempoolPackagesTest(BitcoinTestFramework): | ||
|
||
def setup_network(self): | ||
self.nodes = [] | ||
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0"])) | ||
self.is_network_split = False | ||
self.sync_all() | ||
|
||
# Build a transaction that spends parent_txid:vout | ||
# Return amount sent | ||
def chain_transaction(self, parent_txid, vout, value, fee, num_outputs): | ||
send_value = satoshi_round((value - fee)/num_outputs) | ||
inputs = [ {'txid' : parent_txid, 'vout' : vout} ] | ||
outputs = {} | ||
for i in xrange(num_outputs): | ||
outputs[self.nodes[0].getnewaddress()] = send_value | ||
rawtx = self.nodes[0].createrawtransaction(inputs, outputs) | ||
signedtx = self.nodes[0].signrawtransaction(rawtx) | ||
txid = self.nodes[0].sendrawtransaction(signedtx['hex']) | ||
fulltx = self.nodes[0].getrawtransaction(txid, 1) | ||
assert(len(fulltx['vout']) == num_outputs) # make sure we didn't generate a change output | ||
return (txid, send_value) | ||
|
||
def run_test(self): | ||
''' Mine some blocks and have them mature. ''' | ||
self.nodes[0].generate(101) | ||
utxo = self.nodes[0].listunspent(10) | ||
txid = utxo[0]['txid'] | ||
vout = utxo[0]['vout'] | ||
value = utxo[0]['amount'] | ||
|
||
fee = Decimal("0.0001") | ||
# 100 transactions off a confirmed tx should be fine | ||
chain = [] | ||
for i in xrange(100): | ||
(txid, sent_value) = self.chain_transaction(txid, 0, value, fee, 1) | ||
value = sent_value | ||
chain.append(txid) | ||
|
||
# Check mempool has 100 transactions in it, and descendant | ||
# count and fees should look correct | ||
mempool = self.nodes[0].getrawmempool(True) | ||
assert_equal(len(mempool), 100) | ||
descendant_count = 1 | ||
descendant_fees = 0 | ||
descendant_size = 0 | ||
SATOSHIS = 100000000 | ||
|
||
for x in reversed(chain): | ||
assert_equal(mempool[x]['descendantcount'], descendant_count) | ||
descendant_fees += mempool[x]['fee'] | ||
assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees) | ||
descendant_size += mempool[x]['size'] | ||
assert_equal(mempool[x]['descendantsize'], descendant_size) | ||
descendant_count += 1 | ||
|
||
# Adding one more transaction on to the chain should fail. | ||
try: | ||
self.chain_transaction(txid, vout, value, fee, 1) | ||
except JSONRPCException as e: | ||
print "too-long-ancestor-chain successfully rejected" | ||
|
||
# TODO: test ancestor size limits | ||
|
||
# Now test descendant chain limits | ||
txid = utxo[1]['txid'] | ||
value = utxo[1]['amount'] | ||
vout = utxo[1]['vout'] | ||
|
||
transaction_package = [] | ||
# First create one parent tx with 10 children | ||
(txid, sent_value) = self.chain_transaction(txid, vout, value, fee, 10) | ||
parent_transaction = txid | ||
for i in xrange(10): | ||
transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) | ||
|
||
for i in xrange(1000): | ||
utxo = transaction_package.pop(0) | ||
try: | ||
(txid, sent_value) = self.chain_transaction(utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) | ||
for j in xrange(10): | ||
transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) | ||
if i == 998: | ||
mempool = self.nodes[0].getrawmempool(True) | ||
assert_equal(mempool[parent_transaction]['descendantcount'], 1000) | ||
except JSONRPCException as e: | ||
print e.error['message'] | ||
assert_equal(i, 999) | ||
print "tx that would create too large descendant package successfully rejected" | ||
|
||
# TODO: test descendant size limits | ||
|
||
if __name__ == '__main__': | ||
MempoolPackagesTest().main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.