2 # Copyright (c) 2015-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 BIP66 (DER SIG).
7 Test that the DERSIG soft-fork activates at (regtest) height 1251.
10 from test_framework
.test_framework
import BitcoinTestFramework
11 from test_framework
.util
import *
12 from test_framework
.mininode
import *
13 from test_framework
.blocktools
import create_coinbase
, create_block
14 from test_framework
.script
import CScript
15 from io
import BytesIO
19 # Reject codes that we might receive in this test
22 REJECT_NONSTANDARD
= 64
24 # A canonical signature consists of:
25 # <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
28 Make the signature in vin 0 of a tx non-DER-compliant,
29 by adding padding after the S-value.
31 scriptSig
= CScript(tx
.vin
[0].scriptSig
)
34 if (len(newscript
) == 0):
35 newscript
.append(i
[0:-1] + b
'\0' + i
[-1:])
38 tx
.vin
[0].scriptSig
= CScript(newscript
)
40 def create_transaction(node
, coinbase
, to_address
, amount
):
41 from_txid
= node
.getblock(coinbase
)['tx'][0]
42 inputs
= [{ "txid" : from_txid
, "vout" : 0}]
43 outputs
= { to_address
: amount
}
44 rawtx
= node
.createrawtransaction(inputs
, outputs
)
45 signresult
= node
.signrawtransaction(rawtx
)
47 tx
.deserialize(BytesIO(hex_str_to_bytes(signresult
['hex'])))
50 class BIP66Test(BitcoinTestFramework
):
55 self
.extra_args
= [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
56 self
.setup_clean_chain
= True
61 connections
.append(NodeConn('127.0.0.1', p2p_port(0), self
.nodes
[0], node0
))
62 node0
.add_connection(connections
[0])
63 NetworkThread().start() # Start up network handling in another thread
65 # wait_for_verack ensures that the P2P connection is fully up.
66 node0
.wait_for_verack()
68 self
.log
.info("Mining %d blocks", DERSIG_HEIGHT
- 2)
69 self
.coinbase_blocks
= self
.nodes
[0].generate(DERSIG_HEIGHT
- 2)
70 self
.nodeaddress
= self
.nodes
[0].getnewaddress()
72 self
.log
.info("Test that a transaction with non-DER signature can still appear in a block")
74 spendtx
= create_transaction(self
.nodes
[0], self
.coinbase_blocks
[0],
75 self
.nodeaddress
, 1.0)
79 tip
= self
.nodes
[0].getbestblockhash()
80 block_time
= self
.nodes
[0].getblockheader(tip
)['mediantime'] + 1
81 block
= create_block(int(tip
, 16), create_coinbase(DERSIG_HEIGHT
- 1), block_time
)
83 block
.vtx
.append(spendtx
)
84 block
.hashMerkleRoot
= block
.calc_merkle_root()
88 node0
.send_and_ping(msg_block(block
))
89 assert_equal(self
.nodes
[0].getbestblockhash(), block
.hash)
91 self
.log
.info("Test that blocks must now be at least version 3")
94 block
= create_block(tip
, create_coinbase(DERSIG_HEIGHT
), block_time
)
98 node0
.send_and_ping(msg_block(block
))
99 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), tip
)
101 wait_until(lambda: "reject" in node0
.last_message
.keys(), lock
=mininode_lock
)
103 assert_equal(node0
.last_message
["reject"].code
, REJECT_OBSOLETE
)
104 assert_equal(node0
.last_message
["reject"].reason
, b
'bad-version(0x00000002)')
105 assert_equal(node0
.last_message
["reject"].data
, block
.sha256
)
106 del node0
.last_message
["reject"]
108 self
.log
.info("Test that transactions with non-DER signatures cannot appear in a block")
111 spendtx
= create_transaction(self
.nodes
[0], self
.coinbase_blocks
[1],
112 self
.nodeaddress
, 1.0)
116 # First we show that this tx is valid except for DERSIG by getting it
117 # accepted to the mempool (which we can achieve with
118 # -promiscuousmempoolflags).
119 node0
.send_and_ping(msg_tx(spendtx
))
120 assert spendtx
.hash in self
.nodes
[0].getrawmempool()
122 # Now we verify that a block with this transaction is invalid.
123 block
.vtx
.append(spendtx
)
124 block
.hashMerkleRoot
= block
.calc_merkle_root()
128 node0
.send_and_ping(msg_block(block
))
129 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), tip
)
131 wait_until(lambda: "reject" in node0
.last_message
.keys(), lock
=mininode_lock
)
133 # We can receive different reject messages depending on whether
134 # bitcoind is running with multiple script check threads. If script
135 # check threads are not in use, then transaction script validation
136 # happens sequentially, and bitcoind produces more specific reject
138 assert node0
.last_message
["reject"].code
in [REJECT_INVALID
, REJECT_NONSTANDARD
]
139 assert_equal(node0
.last_message
["reject"].data
, block
.sha256
)
140 if node0
.last_message
["reject"].code
== REJECT_INVALID
:
141 # Generic rejection when a block is invalid
142 assert_equal(node0
.last_message
["reject"].reason
, b
'block-validation-failed')
144 assert b
'Non-canonical DER signature' in node0
.last_message
["reject"].reason
146 self
.log
.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
147 block
.vtx
[1] = create_transaction(self
.nodes
[0],
148 self
.coinbase_blocks
[1], self
.nodeaddress
, 1.0)
149 block
.hashMerkleRoot
= block
.calc_merkle_root()
153 node0
.send_and_ping(msg_block(block
))
154 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), block
.sha256
)
156 if __name__
== '__main__':