Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_bip68_sequence.py
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | class BIP68Test(BitcoinTestFramework): | ||||
# the first sequence bit is set. | # the first sequence bit is set. | ||||
def test_disable_flag(self): | def test_disable_flag(self): | ||||
# Create some unconfirmed inputs | # Create some unconfirmed inputs | ||||
new_addr = self.nodes[0].getnewaddress() | new_addr = self.nodes[0].getnewaddress() | ||||
# send 2 BCH | # send 2 BCH | ||||
self.nodes[0].sendtoaddress(new_addr, 2) | self.nodes[0].sendtoaddress(new_addr, 2) | ||||
utxos = self.nodes[0].listunspent(0, 0) | utxos = self.nodes[0].listunspent(0, 0) | ||||
assert(len(utxos) > 0) | assert len(utxos) > 0 | ||||
utxo = utxos[0] | utxo = utxos[0] | ||||
tx1 = CTransaction() | tx1 = CTransaction() | ||||
value = int(satoshi_round(utxo["amount"] - self.relayfee) * COIN) | value = int(satoshi_round(utxo["amount"] - self.relayfee) * COIN) | ||||
# Check that the disable flag disables relative locktime. | # Check that the disable flag disables relative locktime. | ||||
# If sequence locks were used, this would require 1 block for the | # If sequence locks were used, this would require 1 block for the | ||||
▲ Show 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | def test_sequence_lock_unconfirmed_inputs(self): | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
tx2.hash, -1e15, -fee_multiplier * self.nodes[0].calculate_fee(tx2)) | tx2.hash, -1e15, -fee_multiplier * self.nodes[0].calculate_fee(tx2)) | ||||
cur_time = int(time.time()) | cur_time = int(time.time()) | ||||
for i in range(10): | for i in range(10): | ||||
self.nodes[0].setmocktime(cur_time + 600) | self.nodes[0].setmocktime(cur_time + 600) | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
cur_time += 600 | cur_time += 600 | ||||
assert(tx2.hash in self.nodes[0].getrawmempool()) | assert tx2.hash in self.nodes[0].getrawmempool() | ||||
test_nonzero_locks( | test_nonzero_locks( | ||||
tx2, self.nodes[0], use_height_lock=True) | tx2, self.nodes[0], use_height_lock=True) | ||||
test_nonzero_locks( | test_nonzero_locks( | ||||
tx2, self.nodes[0], use_height_lock=False) | tx2, self.nodes[0], use_height_lock=False) | ||||
# Mine tx2, and then try again | # Mine tx2, and then try again | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
tx2.hash, 1e15, fee_multiplier * self.nodes[0].calculate_fee(tx2)) | tx2.hash, 1e15, fee_multiplier * self.nodes[0].calculate_fee(tx2)) | ||||
# Advance the time on the node so that we can test timelocks | # Advance the time on the node so that we can test timelocks | ||||
self.nodes[0].setmocktime(cur_time + 600) | self.nodes[0].setmocktime(cur_time + 600) | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
assert(tx2.hash not in self.nodes[0].getrawmempool()) | assert tx2.hash not in self.nodes[0].getrawmempool() | ||||
# Now that tx2 is not in the mempool, a sequence locked spend should | # Now that tx2 is not in the mempool, a sequence locked spend should | ||||
# succeed | # succeed | ||||
tx3 = test_nonzero_locks( | tx3 = test_nonzero_locks( | ||||
tx2, self.nodes[0], use_height_lock=False) | tx2, self.nodes[0], use_height_lock=False) | ||||
assert(tx3.hash in self.nodes[0].getrawmempool()) | assert tx3.hash in self.nodes[0].getrawmempool() | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
assert(tx3.hash not in self.nodes[0].getrawmempool()) | assert tx3.hash not in self.nodes[0].getrawmempool() | ||||
# One more test, this time using height locks | # One more test, this time using height locks | ||||
tx4 = test_nonzero_locks( | tx4 = test_nonzero_locks( | ||||
tx3, self.nodes[0], use_height_lock=True) | tx3, self.nodes[0], use_height_lock=True) | ||||
assert(tx4.hash in self.nodes[0].getrawmempool()) | assert tx4.hash in self.nodes[0].getrawmempool() | ||||
# Now try combining confirmed and unconfirmed inputs | # Now try combining confirmed and unconfirmed inputs | ||||
tx5 = test_nonzero_locks( | tx5 = test_nonzero_locks( | ||||
tx4, self.nodes[0], use_height_lock=True) | tx4, self.nodes[0], use_height_lock=True) | ||||
assert(tx5.hash not in self.nodes[0].getrawmempool()) | assert tx5.hash not in self.nodes[0].getrawmempool() | ||||
utxos = self.nodes[0].listunspent() | utxos = self.nodes[0].listunspent() | ||||
tx5.vin.append( | tx5.vin.append( | ||||
CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1)) | CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1)) | ||||
tx5.vout[0].nValue += int(utxos[0]["amount"] * COIN) | tx5.vout[0].nValue += int(utxos[0]["amount"] * COIN) | ||||
raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"] | raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"] | ||||
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, | assert_raises_rpc_error(-26, NOT_FINAL_ERROR, | ||||
self.nodes[0].sendrawtransaction, raw_tx5) | self.nodes[0].sendrawtransaction, raw_tx5) | ||||
# Test mempool-BIP68 consistency after reorg | # Test mempool-BIP68 consistency after reorg | ||||
# | # | ||||
# State of the transactions in the last blocks: | # State of the transactions in the last blocks: | ||||
# ... -> [ tx2 ] -> [ tx3 ] | # ... -> [ tx2 ] -> [ tx3 ] | ||||
# tip-1 tip | # tip-1 tip | ||||
# And currently tx4 is in the mempool. | # And currently tx4 is in the mempool. | ||||
# | # | ||||
# If we invalidate the tip, tx3 should get added to the mempool, causing | # If we invalidate the tip, tx3 should get added to the mempool, causing | ||||
# tx4 to be removed (fails sequence-lock). | # tx4 to be removed (fails sequence-lock). | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
assert(tx4.hash not in self.nodes[0].getrawmempool()) | assert tx4.hash not in self.nodes[0].getrawmempool() | ||||
assert(tx3.hash in self.nodes[0].getrawmempool()) | assert tx3.hash in self.nodes[0].getrawmempool() | ||||
# Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in | # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in | ||||
# diagram above). | # diagram above). | ||||
# This would cause tx2 to be added back to the mempool, which in turn causes | # This would cause tx2 to be added back to the mempool, which in turn causes | ||||
# tx3 to be removed. | # tx3 to be removed. | ||||
tip = int(self.nodes[0].getblockhash( | tip = int(self.nodes[0].getblockhash( | ||||
self.nodes[0].getblockcount() - 1), 16) | self.nodes[0].getblockcount() - 1), 16) | ||||
height = self.nodes[0].getblockcount() | height = self.nodes[0].getblockcount() | ||||
for i in range(2): | for i in range(2): | ||||
block = create_block(tip, create_coinbase(height), cur_time) | block = create_block(tip, create_coinbase(height), cur_time) | ||||
block.nVersion = 3 | block.nVersion = 3 | ||||
block.rehash() | block.rehash() | ||||
block.solve() | block.solve() | ||||
tip = block.sha256 | tip = block.sha256 | ||||
height += 1 | height += 1 | ||||
self.nodes[0].submitblock(ToHex(block)) | self.nodes[0].submitblock(ToHex(block)) | ||||
cur_time += 1 | cur_time += 1 | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
assert(tx3.hash not in mempool) | assert tx3.hash not in mempool | ||||
assert(tx2.hash in mempool) | assert tx2.hash in mempool | ||||
# Reset the chain and get rid of the mocktimed-blocks | # Reset the chain and get rid of the mocktimed-blocks | ||||
self.nodes[0].setmocktime(0) | self.nodes[0].setmocktime(0) | ||||
self.nodes[0].invalidateblock( | self.nodes[0].invalidateblock( | ||||
self.nodes[0].getblockhash(cur_height + 1)) | self.nodes[0].getblockhash(cur_height + 1)) | ||||
self.nodes[0].generate(10) | self.nodes[0].generate(10) | ||||
def get_csv_status(self): | def get_csv_status(self): | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | def test_version2_relay(self, before_activation): | ||||
rawtx = self.nodes[1].createrawtransaction(inputs, outputs) | rawtx = self.nodes[1].createrawtransaction(inputs, outputs) | ||||
rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] | rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] | ||||
tx = FromHex(CTransaction(), rawtxfund) | tx = FromHex(CTransaction(), rawtxfund) | ||||
tx.nVersion = 2 | tx.nVersion = 2 | ||||
tx_signed = self.nodes[1].signrawtransactionwithwallet(ToHex(tx))[ | tx_signed = self.nodes[1].signrawtransactionwithwallet(ToHex(tx))[ | ||||
"hex"] | "hex"] | ||||
try: | try: | ||||
self.nodes[1].sendrawtransaction(tx_signed) | self.nodes[1].sendrawtransaction(tx_signed) | ||||
assert(before_activation == False) | assert before_activation == False | ||||
except: | except: | ||||
assert(before_activation) | assert before_activation | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
BIP68Test().main() | BIP68Test().main() |