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
):
51 def set_test_params(self
):
53 self
.extra_args
= [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
54 self
.setup_clean_chain
= True
59 connections
.append(NodeConn('127.0.0.1', p2p_port(0), self
.nodes
[0], node0
))
60 node0
.add_connection(connections
[0])
61 NetworkThread().start() # Start up network handling in another thread
63 # wait_for_verack ensures that the P2P connection is fully up.
64 node0
.wait_for_verack()
66 self
.log
.info("Mining %d blocks", DERSIG_HEIGHT
- 2)
67 self
.coinbase_blocks
= self
.nodes
[0].generate(DERSIG_HEIGHT
- 2)
68 self
.nodeaddress
= self
.nodes
[0].getnewaddress()
70 self
.log
.info("Test that a transaction with non-DER signature can still appear in a block")
72 spendtx
= create_transaction(self
.nodes
[0], self
.coinbase_blocks
[0],
73 self
.nodeaddress
, 1.0)
77 tip
= self
.nodes
[0].getbestblockhash()
78 block_time
= self
.nodes
[0].getblockheader(tip
)['mediantime'] + 1
79 block
= create_block(int(tip
, 16), create_coinbase(DERSIG_HEIGHT
- 1), block_time
)
81 block
.vtx
.append(spendtx
)
82 block
.hashMerkleRoot
= block
.calc_merkle_root()
86 node0
.send_and_ping(msg_block(block
))
87 assert_equal(self
.nodes
[0].getbestblockhash(), block
.hash)
89 self
.log
.info("Test that blocks must now be at least version 3")
92 block
= create_block(tip
, create_coinbase(DERSIG_HEIGHT
), block_time
)
96 node0
.send_and_ping(msg_block(block
))
97 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), tip
)
99 wait_until(lambda: "reject" in node0
.last_message
.keys(), lock
=mininode_lock
)
101 assert_equal(node0
.last_message
["reject"].code
, REJECT_OBSOLETE
)
102 assert_equal(node0
.last_message
["reject"].reason
, b
'bad-version(0x00000002)')
103 assert_equal(node0
.last_message
["reject"].data
, block
.sha256
)
104 del node0
.last_message
["reject"]
106 self
.log
.info("Test that transactions with non-DER signatures cannot appear in a block")
109 spendtx
= create_transaction(self
.nodes
[0], self
.coinbase_blocks
[1],
110 self
.nodeaddress
, 1.0)
114 # First we show that this tx is valid except for DERSIG by getting it
115 # accepted to the mempool (which we can achieve with
116 # -promiscuousmempoolflags).
117 node0
.send_and_ping(msg_tx(spendtx
))
118 assert spendtx
.hash in self
.nodes
[0].getrawmempool()
120 # Now we verify that a block with this transaction is invalid.
121 block
.vtx
.append(spendtx
)
122 block
.hashMerkleRoot
= block
.calc_merkle_root()
126 node0
.send_and_ping(msg_block(block
))
127 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), tip
)
129 wait_until(lambda: "reject" in node0
.last_message
.keys(), lock
=mininode_lock
)
131 # We can receive different reject messages depending on whether
132 # bitcoind is running with multiple script check threads. If script
133 # check threads are not in use, then transaction script validation
134 # happens sequentially, and bitcoind produces more specific reject
136 assert node0
.last_message
["reject"].code
in [REJECT_INVALID
, REJECT_NONSTANDARD
]
137 assert_equal(node0
.last_message
["reject"].data
, block
.sha256
)
138 if node0
.last_message
["reject"].code
== REJECT_INVALID
:
139 # Generic rejection when a block is invalid
140 assert_equal(node0
.last_message
["reject"].reason
, b
'block-validation-failed')
142 assert b
'Non-canonical DER signature' in node0
.last_message
["reject"].reason
144 self
.log
.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
145 block
.vtx
[1] = create_transaction(self
.nodes
[0],
146 self
.coinbase_blocks
[1], self
.nodeaddress
, 1.0)
147 block
.hashMerkleRoot
= block
.calc_merkle_root()
151 node0
.send_and_ping(msg_block(block
))
152 assert_equal(int(self
.nodes
[0].getbestblockhash(), 16), block
.sha256
)
154 if __name__
== '__main__':