Changeset View
Changeset View
Standalone View
Standalone View
test/functional/mining_prioritisetransaction.py
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
for i in range(3): | for i in range(3): | ||||
for j in txids[i]: | for j in txids[i]: | ||||
assert j in mempool | assert j in mempool | ||||
sizes[i] += mempool[j]['size'] | sizes[i] += mempool[j]['size'] | ||||
# Fail => raise utxo_count | # Fail => raise utxo_count | ||||
assert sizes[i] > LEGACY_MAX_BLOCK_SIZE | assert sizes[i] > LEGACY_MAX_BLOCK_SIZE | ||||
# add a fee delta to something in the cheapest bucket and make sure it gets mined | # add a fee delta to something in the cheapest bucket and make sure it gets mined | ||||
# also check that a different entry in the cheapest bucket is NOT mined (lower | # also check that a different entry in the cheapest bucket is NOT mined | ||||
# the priority to ensure its not mined due to priority) | |||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
txids[0][0], 0, 100 * self.nodes[0].calculate_fee_from_txid(txids[0][0])) | txids[0][0], 100 * self.nodes[0].calculate_fee_from_txid(txids[0][0])) | ||||
self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) | |||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
self.log.info("Assert that prioritised transaction was mined") | self.log.info("Assert that prioritised transaction was mined") | ||||
assert txids[0][0] not in mempool | assert txids[0][0] not in mempool | ||||
assert txids[0][1] in mempool | assert txids[0][1] in mempool | ||||
Show All 11 Lines | def run_test(self): | ||||
# | # | ||||
# NOTE WELL: gettransaction returns the fee as a negative number and | # NOTE WELL: gettransaction returns the fee as a negative number and | ||||
# as fractional coins. However, the prioritisetransaction expects a | # as fractional coins. However, the prioritisetransaction expects a | ||||
# number of satoshi to add or subtract from the actual fee. | # number of satoshi to add or subtract from the actual fee. | ||||
# Thus the conversation here is simply int(tx_fee*COIN) to remove all fees, and then | # Thus the conversation here is simply int(tx_fee*COIN) to remove all fees, and then | ||||
# we add the minimum fee back. | # we add the minimum fee back. | ||||
tx_fee = self.nodes[0].gettransaction(high_fee_tx)['fee'] | tx_fee = self.nodes[0].gettransaction(high_fee_tx)['fee'] | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
high_fee_tx, -1e15, int(tx_fee * COIN) + self.nodes[0].calculate_fee_from_txid(high_fee_tx)) | high_fee_tx, int(tx_fee * COIN) + self.nodes[0].calculate_fee_from_txid(high_fee_tx)) | ||||
# Add everything back to mempool | # Add everything back to mempool | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
# Check to make sure our high fee rate tx is back in the mempool | # Check to make sure our high fee rate tx is back in the mempool | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
assert high_fee_tx in mempool | assert high_fee_tx in mempool | ||||
# Now verify the modified-high feerate transaction isn't mined before | # Now verify the modified-high feerate transaction isn't mined before | ||||
# the other high fee transactions. Keep mining until our mempool has | # the other high fee transactions. Keep mining until our mempool has | ||||
# decreased by all the high fee size that we calculated above. | # decreased by all the high fee size that we calculated above. | ||||
while (self.nodes[0].getmempoolinfo()['bytes'] > sizes[0] + sizes[1]): | while (self.nodes[0].getmempoolinfo()['bytes'] > sizes[0] + sizes[1]): | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
# High fee transaction should not have been mined, but other high fee rate | # High fee transaction should not have been mined, but other high fee rate | ||||
# transactions should have been. | # transactions should have been. | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
self.log.info( | self.log.info( | ||||
"Assert that de-prioritised transaction is still in mempool") | "Assert that de-prioritised transaction is still in mempool") | ||||
assert high_fee_tx in mempool | assert high_fee_tx in mempool | ||||
for x in txids[2]: | for x in txids[2]: | ||||
if (x != high_fee_tx): | if (x != high_fee_tx): | ||||
assert x not in mempool | assert x not in mempool | ||||
# Create a free, low priority transaction. Should be rejected. | # Create a free transaction. Should be rejected. | ||||
utxo_list = self.nodes[0].listunspent() | utxo_list = self.nodes[0].listunspent() | ||||
assert len(utxo_list) > 0 | assert len(utxo_list) > 0 | ||||
utxo = utxo_list[0] | utxo = utxo_list[0] | ||||
inputs = [] | inputs = [] | ||||
outputs = {} | outputs = {} | ||||
inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) | inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) | ||||
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee | outputs[self.nodes[0].getnewaddress()] = utxo["amount"] | ||||
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) | raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) | ||||
tx_hex = self.nodes[0].signrawtransactionwithwallet(raw_tx)["hex"] | tx_hex = self.nodes[0].signrawtransactionwithwallet(raw_tx)["hex"] | ||||
txid = self.nodes[0].sendrawtransaction(tx_hex) | tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"] | ||||
# A tx that spends an in-mempool tx has 0 priority, so we can use it to | |||||
# test the effect of using prioritise transaction for mempool | |||||
# acceptance | |||||
inputs = [] | |||||
inputs.append({"txid": txid, "vout": 0}) | |||||
outputs = {} | |||||
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee | |||||
raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs) | |||||
tx2_hex = self.nodes[0].signrawtransactionwithwallet(raw_tx2)["hex"] | |||||
tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"] | |||||
# This will raise an exception due to min relay fee not being met | # This will raise an exception due to min relay fee not being met | ||||
assert_raises_rpc_error(-26, "min relay fee not met (code 66)", | assert_raises_rpc_error(-26, "min relay fee not met (code 66)", | ||||
self.nodes[0].sendrawtransaction, tx2_hex) | self.nodes[0].sendrawtransaction, tx_hex) | ||||
assert tx2_id not in self.nodes[0].getrawmempool() | assert tx_id not in self.nodes[0].getrawmempool() | ||||
# This is a less than 1000-byte transaction, so just set the fee | # This is a less than 1000-byte transaction, so just set the fee | ||||
# to be the minimum for a 1000-byte transaction and check that it is | # to be the minimum for a 1000-byte transaction and check that it is | ||||
# accepted. | # accepted. | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
tx2_id, 0, int(self.relayfee * COIN)) | tx_id, int(self.relayfee * COIN)) | ||||
self.log.info( | self.log.info( | ||||
"Assert that prioritised free transaction is accepted to mempool") | "Assert that prioritised free transaction is accepted to mempool") | ||||
assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id) | assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id) | ||||
assert tx2_id in self.nodes[0].getrawmempool() | assert tx_id in self.nodes[0].getrawmempool() | ||||
# Test that calling prioritisetransaction is sufficient to trigger | # Test that calling prioritisetransaction is sufficient to trigger | ||||
# getblocktemplate to (eventually) return a new block. | # getblocktemplate to (eventually) return a new block. | ||||
mock_time = int(time.time()) | mock_time = int(time.time()) | ||||
self.nodes[0].setmocktime(mock_time) | self.nodes[0].setmocktime(mock_time) | ||||
template = self.nodes[0].getblocktemplate() | template = self.nodes[0].getblocktemplate() | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
tx2_id, 0, -int(self.relayfee * COIN)) | tx_id, -int(self.relayfee * COIN)) | ||||
self.nodes[0].setmocktime(mock_time + 10) | self.nodes[0].setmocktime(mock_time + 10) | ||||
new_template = self.nodes[0].getblocktemplate() | new_template = self.nodes[0].getblocktemplate() | ||||
assert template != new_template | assert template != new_template | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
PrioritiseTransactionTest().main() | PrioritiseTransactionTest().main() |