2 # Copyright (c) 2014-2016 The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Test BIP68 implementation."""
7 from test_framework
.test_framework
import BitcoinTestFramework
8 from test_framework
.util
import *
9 from test_framework
.blocktools
import *
11 SEQUENCE_LOCKTIME_DISABLE_FLAG
= (1<<31)
12 SEQUENCE_LOCKTIME_TYPE_FLAG
= (1<<22) # this means use time (0 means height)
13 SEQUENCE_LOCKTIME_GRANULARITY
= 9 # this is a bit-shift
14 SEQUENCE_LOCKTIME_MASK
= 0x0000ffff
16 # RPC error for non-BIP68 final transactions
17 NOT_FINAL_ERROR
= "64: non-BIP68-final"
19 class BIP68Test(BitcoinTestFramework
):
23 self
.setup_clean_chain
= False
24 self
.extra_args
= [[], ["-acceptnonstdtxn=0"]]
27 self
.relayfee
= self
.nodes
[0].getnetworkinfo()["relayfee"]
30 self
.nodes
[0].generate(110)
32 self
.log
.info("Running test disable flag")
33 self
.test_disable_flag()
35 self
.log
.info("Running test sequence-lock-confirmed-inputs")
36 self
.test_sequence_lock_confirmed_inputs()
38 self
.log
.info("Running test sequence-lock-unconfirmed-inputs")
39 self
.test_sequence_lock_unconfirmed_inputs()
41 self
.log
.info("Running test BIP68 not consensus before versionbits activation")
42 self
.test_bip68_not_consensus()
44 self
.log
.info("Activating BIP68 (and 112/113)")
47 self
.log
.info("Verifying nVersion=2 transactions are standard.")
48 self
.log
.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).")
49 self
.test_version2_relay()
51 self
.log
.info("Passed")
53 # Test that BIP68 is not in effect if tx version is 1, or if
54 # the first sequence bit is set.
55 def test_disable_flag(self
):
56 # Create some unconfirmed inputs
57 new_addr
= self
.nodes
[0].getnewaddress()
58 self
.nodes
[0].sendtoaddress(new_addr
, 2) # send 2 BTC
60 utxos
= self
.nodes
[0].listunspent(0, 0)
61 assert(len(utxos
) > 0)
66 value
= int(satoshi_round(utxo
["amount"] - self
.relayfee
)*COIN
)
68 # Check that the disable flag disables relative locktime.
69 # If sequence locks were used, this would require 1 block for the
71 sequence_value
= SEQUENCE_LOCKTIME_DISABLE_FLAG |
1
72 tx1
.vin
= [CTxIn(COutPoint(int(utxo
["txid"], 16), utxo
["vout"]), nSequence
=sequence_value
)]
73 tx1
.vout
= [CTxOut(value
, CScript([b
'a']))]
75 tx1_signed
= self
.nodes
[0].signrawtransaction(ToHex(tx1
))["hex"]
76 tx1_id
= self
.nodes
[0].sendrawtransaction(tx1_signed
)
77 tx1_id
= int(tx1_id
, 16)
79 # This transaction will enable sequence-locks, so this transaction should
83 sequence_value
= sequence_value
& 0x7fffffff
84 tx2
.vin
= [CTxIn(COutPoint(tx1_id
, 0), nSequence
=sequence_value
)]
85 tx2
.vout
= [CTxOut(int(value
-self
.relayfee
*COIN
), CScript([b
'a']))]
88 assert_raises_jsonrpc(-26, NOT_FINAL_ERROR
, self
.nodes
[0].sendrawtransaction
, ToHex(tx2
))
90 # Setting the version back down to 1 should disable the sequence lock,
91 # so this should be accepted.
94 self
.nodes
[0].sendrawtransaction(ToHex(tx2
))
96 # Calculate the median time past of a prior block ("confirmations" before
98 def get_median_time_past(self
, confirmations
):
99 block_hash
= self
.nodes
[0].getblockhash(self
.nodes
[0].getblockcount()-confirmations
)
100 return self
.nodes
[0].getblockheader(block_hash
)["mediantime"]
102 # Test that sequence locks are respected for transactions spending confirmed inputs.
103 def test_sequence_lock_confirmed_inputs(self
):
104 # Create lots of confirmed utxos, and use them to generate lots of random
108 while len(addresses
) < max_outputs
:
109 addresses
.append(self
.nodes
[0].getnewaddress())
110 while len(self
.nodes
[0].listunspent()) < 200:
112 random
.shuffle(addresses
)
113 num_outputs
= random
.randint(1, max_outputs
)
115 for i
in range(num_outputs
):
116 outputs
[addresses
[i
]] = random
.randint(1, 20)*0.01
117 self
.nodes
[0].sendmany("", outputs
)
118 self
.nodes
[0].generate(1)
120 utxos
= self
.nodes
[0].listunspent()
122 # Try creating a lot of random transactions.
123 # Each time, choose a random number of inputs, and randomly set
124 # some of those inputs to be sequence locked (and randomly choose
125 # between height/time locking). Small random chance of making the locks
128 # Randomly choose up to 10 inputs
129 num_inputs
= random
.randint(1, 10)
130 random
.shuffle(utxos
)
132 # Track whether any sequence locks used should fail
135 # Track whether this transaction was built with sequence locks
136 using_sequence_locks
= False
141 for j
in range(num_inputs
):
142 sequence_value
= 0xfffffffe # this disables sequence locks
144 # 50% chance we enable sequence locks
145 if random
.randint(0,1):
146 using_sequence_locks
= True
148 # 10% of the time, make the input sequence value pass
149 input_will_pass
= (random
.randint(1,10) == 1)
150 sequence_value
= utxos
[j
]["confirmations"]
151 if not input_will_pass
:
155 # Figure out what the median-time-past was for the confirmed input
156 # Note that if an input has N confirmations, we're going back N blocks
157 # from the tip so that we're looking up MTP of the block
158 # PRIOR to the one the input appears in, as per the BIP68 spec.
159 orig_time
= self
.get_median_time_past(utxos
[j
]["confirmations"])
160 cur_time
= self
.get_median_time_past(0) # MTP of the tip
162 # can only timelock this input if it's not too old -- otherwise use height
164 if ((cur_time
- orig_time
) >> SEQUENCE_LOCKTIME_GRANULARITY
) >= SEQUENCE_LOCKTIME_MASK
:
165 can_time_lock
= False
167 # if time-lockable, then 50% chance we make this a time lock
168 if random
.randint(0,1) and can_time_lock
:
169 # Find first time-lock value that fails, or latest one that succeeds
170 time_delta
= sequence_value
<< SEQUENCE_LOCKTIME_GRANULARITY
171 if input_will_pass
and time_delta
> cur_time
- orig_time
:
172 sequence_value
= ((cur_time
- orig_time
) >> SEQUENCE_LOCKTIME_GRANULARITY
)
173 elif (not input_will_pass
and time_delta
<= cur_time
- orig_time
):
174 sequence_value
= ((cur_time
- orig_time
) >> SEQUENCE_LOCKTIME_GRANULARITY
)+1
175 sequence_value |
= SEQUENCE_LOCKTIME_TYPE_FLAG
176 tx
.vin
.append(CTxIn(COutPoint(int(utxos
[j
]["txid"], 16), utxos
[j
]["vout"]), nSequence
=sequence_value
))
177 value
+= utxos
[j
]["amount"]*COIN
178 # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
179 tx_size
= len(ToHex(tx
))//2 + 120*num_inputs
+ 50
180 tx
.vout
.append(CTxOut(int(value
-self
.relayfee
*tx_size
*COIN
/1000), CScript([b
'a'])))
181 rawtx
= self
.nodes
[0].signrawtransaction(ToHex(tx
))["hex"]
183 if (using_sequence_locks
and not should_pass
):
184 # This transaction should be rejected
185 assert_raises_jsonrpc(-26, NOT_FINAL_ERROR
, self
.nodes
[0].sendrawtransaction
, rawtx
)
187 # This raw transaction should be accepted
188 self
.nodes
[0].sendrawtransaction(rawtx
)
189 utxos
= self
.nodes
[0].listunspent()
191 # Test that sequence locks on unconfirmed inputs must have nSequence
192 # height or time of 0 to be accepted.
193 # Then test that BIP68-invalid transactions are removed from the mempool
195 def test_sequence_lock_unconfirmed_inputs(self
):
196 # Store height so we can easily reset the chain at the end of the test
197 cur_height
= self
.nodes
[0].getblockcount()
199 # Create a mempool tx.
200 txid
= self
.nodes
[0].sendtoaddress(self
.nodes
[0].getnewaddress(), 2)
201 tx1
= FromHex(CTransaction(), self
.nodes
[0].getrawtransaction(txid
))
204 # Anyone-can-spend mempool tx.
205 # Sequence lock of 0 should pass.
208 tx2
.vin
= [CTxIn(COutPoint(tx1
.sha256
, 0), nSequence
=0)]
209 tx2
.vout
= [CTxOut(int(tx1
.vout
[0].nValue
- self
.relayfee
*COIN
), CScript([b
'a']))]
210 tx2_raw
= self
.nodes
[0].signrawtransaction(ToHex(tx2
))["hex"]
211 tx2
= FromHex(tx2
, tx2_raw
)
214 self
.nodes
[0].sendrawtransaction(tx2_raw
)
216 # Create a spend of the 0th output of orig_tx with a sequence lock
217 # of 1, and test what happens when submitting.
218 # orig_tx.vout[0] must be an anyone-can-spend output
219 def test_nonzero_locks(orig_tx
, node
, relayfee
, use_height_lock
):
221 if not use_height_lock
:
222 sequence_value |
= SEQUENCE_LOCKTIME_TYPE_FLAG
226 tx
.vin
= [CTxIn(COutPoint(orig_tx
.sha256
, 0), nSequence
=sequence_value
)]
227 tx
.vout
= [CTxOut(int(orig_tx
.vout
[0].nValue
- relayfee
*COIN
), CScript([b
'a']))]
230 if (orig_tx
.hash in node
.getrawmempool()):
231 # sendrawtransaction should fail if the tx is in the mempool
232 assert_raises_jsonrpc(-26, NOT_FINAL_ERROR
, node
.sendrawtransaction
, ToHex(tx
))
234 # sendrawtransaction should succeed if the tx is not in the mempool
235 node
.sendrawtransaction(ToHex(tx
))
239 test_nonzero_locks(tx2
, self
.nodes
[0], self
.relayfee
, use_height_lock
=True)
240 test_nonzero_locks(tx2
, self
.nodes
[0], self
.relayfee
, use_height_lock
=False)
242 # Now mine some blocks, but make sure tx2 doesn't get mined.
243 # Use prioritisetransaction to lower the effective feerate to 0
244 self
.nodes
[0].prioritisetransaction(txid
=tx2
.hash, fee_delta
=int(-self
.relayfee
*COIN
))
245 cur_time
= int(time
.time())
247 self
.nodes
[0].setmocktime(cur_time
+ 600)
248 self
.nodes
[0].generate(1)
251 assert(tx2
.hash in self
.nodes
[0].getrawmempool())
253 test_nonzero_locks(tx2
, self
.nodes
[0], self
.relayfee
, use_height_lock
=True)
254 test_nonzero_locks(tx2
, self
.nodes
[0], self
.relayfee
, use_height_lock
=False)
256 # Mine tx2, and then try again
257 self
.nodes
[0].prioritisetransaction(txid
=tx2
.hash, fee_delta
=int(self
.relayfee
*COIN
))
259 # Advance the time on the node so that we can test timelocks
260 self
.nodes
[0].setmocktime(cur_time
+600)
261 self
.nodes
[0].generate(1)
262 assert(tx2
.hash not in self
.nodes
[0].getrawmempool())
264 # Now that tx2 is not in the mempool, a sequence locked spend should
266 tx3
= test_nonzero_locks(tx2
, self
.nodes
[0], self
.relayfee
, use_height_lock
=False)
267 assert(tx3
.hash in self
.nodes
[0].getrawmempool())
269 self
.nodes
[0].generate(1)
270 assert(tx3
.hash not in self
.nodes
[0].getrawmempool())
272 # One more test, this time using height locks
273 tx4
= test_nonzero_locks(tx3
, self
.nodes
[0], self
.relayfee
, use_height_lock
=True)
274 assert(tx4
.hash in self
.nodes
[0].getrawmempool())
276 # Now try combining confirmed and unconfirmed inputs
277 tx5
= test_nonzero_locks(tx4
, self
.nodes
[0], self
.relayfee
, use_height_lock
=True)
278 assert(tx5
.hash not in self
.nodes
[0].getrawmempool())
280 utxos
= self
.nodes
[0].listunspent()
281 tx5
.vin
.append(CTxIn(COutPoint(int(utxos
[0]["txid"], 16), utxos
[0]["vout"]), nSequence
=1))
282 tx5
.vout
[0].nValue
+= int(utxos
[0]["amount"]*COIN
)
283 raw_tx5
= self
.nodes
[0].signrawtransaction(ToHex(tx5
))["hex"]
285 assert_raises_jsonrpc(-26, NOT_FINAL_ERROR
, self
.nodes
[0].sendrawtransaction
, raw_tx5
)
287 # Test mempool-BIP68 consistency after reorg
289 # State of the transactions in the last blocks:
290 # ... -> [ tx2 ] -> [ tx3 ]
292 # And currently tx4 is in the mempool.
294 # If we invalidate the tip, tx3 should get added to the mempool, causing
295 # tx4 to be removed (fails sequence-lock).
296 self
.nodes
[0].invalidateblock(self
.nodes
[0].getbestblockhash())
297 assert(tx4
.hash not in self
.nodes
[0].getrawmempool())
298 assert(tx3
.hash in self
.nodes
[0].getrawmempool())
300 # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
302 # This would cause tx2 to be added back to the mempool, which in turn causes
304 tip
= int(self
.nodes
[0].getblockhash(self
.nodes
[0].getblockcount()-1), 16)
305 height
= self
.nodes
[0].getblockcount()
307 block
= create_block(tip
, create_coinbase(height
), cur_time
)
313 self
.nodes
[0].submitblock(ToHex(block
))
316 mempool
= self
.nodes
[0].getrawmempool()
317 assert(tx3
.hash not in mempool
)
318 assert(tx2
.hash in mempool
)
320 # Reset the chain and get rid of the mocktimed-blocks
321 self
.nodes
[0].setmocktime(0)
322 self
.nodes
[0].invalidateblock(self
.nodes
[0].getblockhash(cur_height
+1))
323 self
.nodes
[0].generate(10)
325 # Make sure that BIP68 isn't being used to validate blocks, prior to
326 # versionbits activation. If more blocks are mined prior to this test
327 # being run, then it's possible the test has activated the soft fork, and
328 # this test should be moved to run earlier, or deleted.
329 def test_bip68_not_consensus(self
):
330 assert(get_bip9_status(self
.nodes
[0], 'csv')['status'] != 'active')
331 txid
= self
.nodes
[0].sendtoaddress(self
.nodes
[0].getnewaddress(), 2)
333 tx1
= FromHex(CTransaction(), self
.nodes
[0].getrawtransaction(txid
))
336 # Make an anyone-can-spend transaction
339 tx2
.vin
= [CTxIn(COutPoint(tx1
.sha256
, 0), nSequence
=0)]
340 tx2
.vout
= [CTxOut(int(tx1
.vout
[0].nValue
- self
.relayfee
*COIN
), CScript([b
'a']))]
343 tx2_raw
= self
.nodes
[0].signrawtransaction(ToHex(tx2
))["hex"]
344 tx2
= FromHex(tx2
, tx2_raw
)
347 self
.nodes
[0].sendrawtransaction(ToHex(tx2
))
349 # Now make an invalid spend of tx2 according to BIP68
350 sequence_value
= 100 # 100 block relative locktime
354 tx3
.vin
= [CTxIn(COutPoint(tx2
.sha256
, 0), nSequence
=sequence_value
)]
355 tx3
.vout
= [CTxOut(int(tx2
.vout
[0].nValue
- self
.relayfee
*COIN
), CScript([b
'a']))]
358 assert_raises_jsonrpc(-26, NOT_FINAL_ERROR
, self
.nodes
[0].sendrawtransaction
, ToHex(tx3
))
360 # make a block that violates bip68; ensure that the tip updates
361 tip
= int(self
.nodes
[0].getbestblockhash(), 16)
362 block
= create_block(tip
, create_coinbase(self
.nodes
[0].getblockcount()+1))
364 block
.vtx
.extend([tx1
, tx2
, tx3
])
365 block
.hashMerkleRoot
= block
.calc_merkle_root()
369 self
.nodes
[0].submitblock(ToHex(block
))
370 assert_equal(self
.nodes
[0].getbestblockhash(), block
.hash)
372 def activateCSV(self
):
373 # activation should happen at block height 432 (3 periods)
374 min_activation_height
= 432
375 height
= self
.nodes
[0].getblockcount()
376 assert(height
< min_activation_height
)
377 self
.nodes
[0].generate(min_activation_height
-height
)
378 assert(get_bip9_status(self
.nodes
[0], 'csv')['status'] == 'active')
379 sync_blocks(self
.nodes
)
381 # Use self.nodes[1] to test that version 2 transactions are standard.
382 def test_version2_relay(self
):
384 outputs
= { self
.nodes
[1].getnewaddress() : 1.0 }
385 rawtx
= self
.nodes
[1].createrawtransaction(inputs
, outputs
)
386 rawtxfund
= self
.nodes
[1].fundrawtransaction(rawtx
)['hex']
387 tx
= FromHex(CTransaction(), rawtxfund
)
389 tx_signed
= self
.nodes
[1].signrawtransaction(ToHex(tx
))["hex"]
390 tx_id
= self
.nodes
[1].sendrawtransaction(tx_signed
)
392 if __name__
== '__main__':