15 MAX_REPLACEMENT_LIMIT = 100
20 def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
21 """Create a txout with a given amount and scriptPubKey 23 Mines coins as needed. 25 confirmed - txouts created will be confirmed in the blockchain; 26 unconfirmed otherwise. 33 new_addr = node.getnewaddress()
35 txid = node.sendtoaddress(new_addr,
satoshi_round((amount+fee)/COIN))
36 tx1 = node.getrawtransaction(txid, 1)
40 for i, txout
in enumerate(tx1[
'vout']):
42 if txout[
'scriptPubKey'][
'addresses'] == [new_addr]:
49 tx2.vout = [
CTxOut(amount, scriptPubKey)]
52 signed_tx = node.signrawtransaction(
txToHex(tx2))
54 txid = node.sendrawtransaction(signed_tx[
'hex'],
True)
58 mempool_size = len(node.getrawmempool())
59 while mempool_size > 0:
61 new_size = len(node.getrawmempool())
64 assert(new_size < mempool_size)
65 mempool_size = new_size
73 self.
nodes.append(
start_node(0, self.options.tmpdir, [
"-maxorphantx=1000",
"-debug",
74 "-relaypriority=0",
"-whitelist=127.0.0.1",
75 "-limitancestorcount=50",
76 "-limitancestorsize=101",
77 "-limitdescendantcount=200",
78 "-limitdescendantsize=101" 85 print "Running test simple doublespend..." 88 print "Running test doublespend chain..." 91 print "Running test doublespend tree..." 94 print "Running test replacement feeperkb..." 97 print "Running test spends of conflicting outputs..." 100 print "Running test new unconfirmed inputs..." 103 print "Running test too many replacements..." 106 print "Running test opt-in..." 109 print "Running test prioritised transactions..." 115 """Simple doublespend""" 119 tx1a.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
126 tx1b.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
132 except JSONRPCException
as exp:
139 tx1b.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
146 assert (tx1a_txid
not in mempool)
147 assert (tx1b_txid
in mempool)
152 """Doublespend of a long chain""" 154 initial_nValue = 50*COIN
157 prevout = tx0_outpoint
158 remaining_value = initial_nValue
160 while remaining_value > 10*COIN:
161 remaining_value -= 1*COIN
163 tx.vin = [
CTxIn(prevout, nSequence=0)]
167 chain_txids.append(txid)
173 dbl_tx.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
174 dbl_tx.vout = [
CTxOut(initial_nValue - 30*COIN,
CScript([1]))]
179 except JSONRPCException
as exp:
186 dbl_tx.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
192 for doublespent_txid
in chain_txids:
193 assert(doublespent_txid
not in mempool)
196 """Doublespend of a big tree of transactions""" 198 initial_nValue = 50*COIN
201 def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None):
202 if _total_txs
is None:
204 if _total_txs[0] >= max_txs:
207 txout_value = (initial_value - fee) // tree_width
208 if txout_value < fee:
212 for i
in range(tree_width)]
214 tx.vin = [
CTxIn(prevout, nSequence=0)]
218 assert(len(tx.serialize()) < 100000)
225 for i, txout
in enumerate(tx.vout):
226 for x
in branch(
COutPoint(txid, i), txout_value,
228 tree_width=tree_width, fee=fee,
229 _total_txs=_total_txs):
232 fee = int(0.0001*COIN)
233 n = MAX_REPLACEMENT_LIMIT
234 tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
239 dbl_tx.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
244 except JSONRPCException
as exp:
251 dbl_tx.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
252 dbl_tx.vout = [
CTxOut(initial_nValue - fee*n - 1*COIN,
CScript([1]))]
260 assert (tx.hash
not in mempool)
264 for n
in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2):
265 fee = int(0.0001*COIN)
267 tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
271 dbl_tx.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
272 dbl_tx.vout = [
CTxOut(initial_nValue - 2*fee*n,
CScript([1]))]
276 except JSONRPCException
as exp:
278 assert_equal(
"too many potential replacements" in exp.error[
'message'],
True)
287 """Replacement requires fee-per-KB to be higher""" 291 tx1a.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
299 tx1b.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
300 tx1b.vout = [
CTxOut(int(0.001*COIN),
CScript([b
'a'*999000]))]
305 except JSONRPCException
as exp:
311 """Replacements that spend conflicting tx outputs are rejected""" 316 tx1a.vin = [
CTxIn(utxo1, nSequence=0)]
321 tx1a_txid = int(tx1a_txid, 16)
325 tx2.vin = [
CTxIn(utxo1, nSequence=0),
CTxIn(utxo2, nSequence=0)]
332 except JSONRPCException
as exp:
343 tx1b_txid = int(tx1b_txid, 16)
346 tx2.vin = [
CTxIn(utxo1, nSequence=0),
CTxIn(utxo2, nSequence=0),
353 except JSONRPCException
as exp:
359 """Replacements that add new unconfirmed inputs are rejected""" 364 tx1.vin = [
CTxIn(confirmed_utxo)]
370 tx2.vin = [
CTxIn(confirmed_utxo),
CTxIn(unconfirmed_utxo)]
376 except JSONRPCException
as exp:
382 """Replacements that evict too many transactions are rejected""" 387 initial_nValue = 10*COIN
389 fee = int(0.0001*COIN)
390 split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
391 actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
394 for i
in range(MAX_REPLACEMENT_LIMIT+1):
398 splitting_tx.vin = [
CTxIn(utxo, nSequence=0)]
399 splitting_tx.vout = outputs
400 splitting_tx_hex =
txToHex(splitting_tx)
406 for i
in range(MAX_REPLACEMENT_LIMIT+1):
416 double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)
418 for i
in range(MAX_REPLACEMENT_LIMIT+1):
421 double_tx.vin = inputs
422 double_tx.vout = [
CTxOut(double_spend_value,
CScript([b
'a']))]
423 double_tx_hex =
txToHex(double_tx)
427 except JSONRPCException
as exp:
429 assert_equal(
"too many potential replacements" in exp.error[
'message'],
True)
435 double_tx.vin = inputs[0:-1]
436 double_tx.vout = [
CTxOut(double_spend_value,
CScript([b
'a']))]
437 double_tx_hex =
txToHex(double_tx)
441 """ Replacing should only work if orig tx opted in """ 446 tx1a.vin = [
CTxIn(tx0_outpoint, nSequence=0xffffffff)]
453 tx1b.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
459 except JSONRPCException
as exp:
469 tx2a.vin = [
CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
476 tx2b.vin = [
CTxIn(tx1_outpoint, nSequence=0)]
482 except JSONRPCException
as exp:
491 tx1a_txid = int(tx1a_txid, 16)
492 tx2a_txid = int(tx2a_txid, 16)
525 tx1a.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
532 tx1b.vin = [
CTxIn(tx0_outpoint, nSequence=0)]
533 tx1b.vout = [
CTxOut(int(0.001*COIN),
CScript([b
'a'*740000]))]
539 except JSONRPCException
as exp:
556 tx2a.vin = [
CTxIn(tx1_outpoint, nSequence=0)]
563 tx2b.vin = [
CTxIn(tx1_outpoint, nSequence=0)]
571 except JSONRPCException
as exp:
584 if __name__ ==
'__main__':
UniValue prioritisetransaction(const UniValue ¶ms, bool fHelp)
def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1]))
UniValue getrawtransaction(const UniValue ¶ms, bool fHelp)
def satoshi_round(amount)
def test_new_unconfirmed_inputs(self)
def test_replacement_feeperkb(self)
def test_doublespend_tree(self)
def test_spends_of_conflicting_outputs(self)
def test_prioritised_transactions(self)
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None)
UniValue sendrawtransaction(const UniValue ¶ms, bool fHelp)
def test_simple_doublespend(self)
UniValue getrawmempool(const UniValue ¶ms, bool fHelp)
def test_too_many_replacements(self)
def test_doublespend_chain(self)
def assert_equal(thing1, thing2)
def bytes_to_hex_str(byte_str)