1414from test_framework .blocktools import (
1515 create_block ,
1616 create_coinbase ,
17+ add_witness_commitment ,
1718)
1819
1920from test_framework .test_framework import BitcoinTestFramework
2425
2526from test_framework .messages import (
2627 BLOCK_HEADER_SIZE ,
28+ uint256_from_compact ,
29+ )
30+
31+ from test_framework .wallet import (
32+ MiniWallet ,
2733)
2834
2935def assert_template (node , block , expect , * , rehash = True , submit = True , solve = True , expect_submit = None ):
@@ -118,6 +124,11 @@ def nbits_test(self, node, block):
118124 bad_block .nBits = 469762303 # impossible in the real world
119125 assert_template (node , bad_block , "bad-diffbits" , solve = False , expect_submit = "high-hash" )
120126
127+ self .log .info ("Lowering nBits should make the block invalid" )
128+ bad_block = copy .deepcopy (block )
129+ bad_block .nBits -= 1
130+ assert_template (node , bad_block , "bad-diffbits" )
131+
121132 def merkle_root_test (self , node , block ):
122133 self .log .info ("Bad merkle root" )
123134 bad_block = copy .deepcopy (block )
@@ -140,6 +151,117 @@ def current_tip_test(self, node, block):
140151
141152 assert_template (node , bad_block , "inconclusive-not-best-prevblk" , expect_submit = "prev-blk-not-found" )
142153
154+ def pow_test (self , node , block ):
155+ '''Modifies block with the generated PoW'''
156+ self .log .info ("Generate a block" )
157+ target = uint256_from_compact (block .nBits )
158+ # Ensure that it doesn't meet the target by coincidence
159+ while block .sha256 <= target :
160+ block .nNonce += 1
161+ block .rehash ()
162+ self .log .debug ("Found a nonce" )
163+
164+ self .log .info ("A block template doesn't need PoW" )
165+ assert_template (node , block , None )
166+
167+ self .log .info ("Add proof of work" )
168+ block .solve ()
169+ assert_template (node , block , None )
170+
171+ def submit_test (self , node , block_0_height , block ):
172+ self .log .info ("getblocktemplate call in previous tests did not submit the block" )
173+ assert_equal (node .getblockcount (), block_0_height + 1 )
174+
175+ self .log .info ("Submitting this block should succeed" )
176+ assert_equal (node .submitblock (block .serialize ().hex ()), None )
177+ node .waitforblockheight (2 )
178+
179+ def transaction_test (self , node , block_0_height , tx ):
180+ self .log .info ("make block template with a transaction" )
181+
182+ block_1 = node .getblock (node .getblockhash (block_0_height + 1 ))
183+ block_2_hash = node .getblockhash (block_0_height + 2 )
184+
185+ block_3 = create_block (
186+ int (block_2_hash , 16 ),
187+ create_coinbase (block_0_height + 3 ),
188+ block_1 ["mediantime" ] + 1 ,
189+ txlist = [tx ["hex" ]],
190+ )
191+ assert_equal (len (block_3 .vtx ), 2 )
192+ add_witness_commitment (block_3 )
193+ block_3 .solve ()
194+ assert_template (node , block_3 , None )
195+
196+ self .log .info ("checking block validity did not update the UTXO set" )
197+ # Call again to ensure the UTXO set wasn't updated
198+ assert_template (node , block_3 , None )
199+
200+ def overspending_transaction_test (self , node , block_0_height , tx ):
201+ self .log .info ("Add an transaction that spends too much" )
202+
203+ block_1 = node .getblock (node .getblockhash (block_0_height + 1 ))
204+ block_2_hash = node .getblockhash (block_0_height + 2 )
205+
206+ bad_tx = copy .deepcopy (tx )
207+ bad_tx ["tx" ].vout [0 ].nValue = 10000000000
208+ bad_tx_hex = bad_tx ["tx" ].serialize ().hex ()
209+ assert_equal (
210+ node .testmempoolaccept ([bad_tx_hex ])[0 ]["reject-reason" ],
211+ "bad-txns-in-belowout" ,
212+ )
213+ block_3 = create_block (
214+ int (block_2_hash , 16 ),
215+ create_coinbase (block_0_height + 3 ),
216+ block_1 ["mediantime" ] + 1 ,
217+ txlist = [bad_tx_hex ],
218+ )
219+ assert_equal (len (block_3 .vtx ), 2 )
220+ add_witness_commitment (block_3 )
221+ block_3 .solve ()
222+
223+ assert_template (node , block_3 , "bad-txns-in-belowout" )
224+
225+ def spend_twice_test (self , node , block_0_height , tx ):
226+ block_1 = node .getblock (node .getblockhash (block_0_height + 1 ))
227+ block_2_hash = node .getblockhash (block_0_height + 2 )
228+
229+ self .log .info ("Can't spend coins twice" )
230+ tx_hex = tx ["tx" ].serialize ().hex ()
231+ tx_2 = copy .deepcopy (tx )
232+ tx_2_hex = tx_2 ["tx" ].serialize ().hex ()
233+ # Nothing wrong with these transactions individually
234+ assert_equal (node .testmempoolaccept ([tx_hex ])[0 ]["allowed" ], True )
235+ assert_equal (node .testmempoolaccept ([tx_2_hex ])[0 ]["allowed" ], True )
236+ # But can't be combined
237+ assert_equal (
238+ node .testmempoolaccept ([tx_hex , tx_2_hex ])[0 ]["package-error" ],
239+ "package-contains-duplicates" ,
240+ )
241+ block_3 = create_block (
242+ int (block_2_hash , 16 ),
243+ create_coinbase (block_0_height + 3 ),
244+ block_1 ["mediantime" ] + 1 ,
245+ txlist = [tx_hex , tx_2_hex ],
246+ )
247+ assert_equal (len (block_3 .vtx ), 3 )
248+ add_witness_commitment (block_3 )
249+
250+ assert_template (node , block_3 , "bad-txns-inputs-missingorspent" , submit = False )
251+
252+ return block_3
253+
254+ def parallel_test (self , node , block_3 ):
255+ # Ensure that getblocktemplate can be called concurrently by many threads.
256+ self .log .info ("Check blocks in parallel" )
257+ check_50_blocks = lambda n : [
258+ assert_template (n , block_3 , "bad-txns-inputs-missingorspent" , submit = False )
259+ for _ in range (50 )
260+ ]
261+ rpcs = [node .cli for _ in range (6 )]
262+ with ThreadPoolExecutor (max_workers = len (rpcs )) as threads :
263+ list (threads .map (check_50_blocks , rpcs ))
264+
143265 def run_test (self ):
144266 node = self .nodes [0 ]
145267
@@ -164,6 +286,17 @@ def run_test(self):
164286 self .merkle_root_test (node , block_2 )
165287 self .bad_timestamp_test (node , block_2 )
166288 self .current_tip_test (node , block_2 )
289+ # This sets the PoW for the next test
290+ self .pow_test (node , block_2 )
291+ self .submit_test (node , block_0_height , block_2 )
292+
293+ self .log .info ("Generate a transaction" )
294+ tx = MiniWallet (node ).create_self_transfer ()
295+
296+ self .transaction_test (node , block_0_height , tx )
297+ self .overspending_transaction_test (node , block_0_height , tx )
298+ block_3 = self .spend_twice_test (node , block_0_height , tx )
299+ self .parallel_test (node , block_3 )
167300
168301if __name__ == "__main__" :
169302 MiningTemplateVerificationTest (__file__ ).main ()
0 commit comments