77from io import BytesIO
88from time import sleep
99
10- from test_framework .authproxy import JSONRPCException
1110from test_framework .messages import CTransaction , CTxIn , CTxOut , COIN , COutPoint
1211from test_framework .mininode import network_thread_start
1312from test_framework .pivx_node import PivxTestNode
1413from test_framework .script import CScript , OP_CHECKSIG
1514from test_framework .test_framework import PivxTestFramework
16- from test_framework .util import connect_nodes_bi , p2p_port , bytes_to_hex_str , \
17- assert_equal , assert_greater_than , sync_blocks , assert_raises_rpc_error
15+ from test_framework .util import connect_nodes_bi , p2p_port , bytes_to_hex_str , set_node_times , \
16+ assert_equal , assert_greater_than , sync_blocks , sync_mempools , assert_raises_rpc_error
1817
1918# filter utxos based on first 5 bytes of scriptPubKey
2019def getDelegatedUtxos (utxos ):
@@ -24,11 +23,15 @@ def getDelegatedUtxos(utxos):
2423class PIVX_ColdStakingTest (PivxTestFramework ):
2524
2625 def set_test_params (self ):
27- self .setup_clean_chain = True
2826 self .num_nodes = 3
2927 self .extra_args = [['-staking=1' ]] * self .num_nodes
3028 self .extra_args [0 ].append ('-sporkkey=932HEevBSujW2ud7RfB1YF91AFygbBRQj3de3LyaCRqNzKKgWXi' )
3129
30+ def setup_chain (self ):
31+ # Start with PoW cache: 200 blocks
32+ self ._initialize_chain ()
33+ self .enable_mocktime ()
34+
3235
3336 def setup_network (self ):
3437 ''' Can't rely on syncing all the nodes when staking=1
@@ -79,40 +82,53 @@ def isColdStakingEnforced(self):
7982 def run_test (self ):
8083 self .description = "Performs tests on the Cold Staking P2CS implementation"
8184 self .init_test ()
82- LAST_POW_BLOCK = 250
8385 NUM_OF_INPUTS = 20
84- INPUT_VALUE = 50
85- INITAL_MINED_BLOCKS = LAST_POW_BLOCK + 1
86+ INPUT_VALUE = 249
8687
8788 # nodes[0] - coin-owner
8889 # nodes[1] - cold-staker
8990
90- # 1) nodes[0] mines 20 blocks. nodes[2] mines 231 blocks.
91- # -----------------------------------------------------------
92- # Check that SPORK 17 is disabled
93- assert (not self .isColdStakingEnforced ())
91+ # 1) nodes[0] and nodes[2] mine 25 blocks each
92+ # --------------------------------------------
9493 print ("*** 1 ***" )
95- self .log .info ("Mining %d blocks..." % INITAL_MINED_BLOCKS )
96- self .generateBlock (20 , 0 )
97- sync_blocks (self .nodes )
98- self .log .info ("20 Blocks mined." )
99- self .generateBlock (INITAL_MINED_BLOCKS - 20 )
94+ self .log .info ("Mining 50 Blocks..." )
95+ for peer in [0 , 2 ]:
96+ for j in range (25 ):
97+ self .mocktime = self .generate_pow (peer , self .mocktime )
98+ sync_blocks (self .nodes )
99+
100+ # 2) node[1] sends his entire balance (50 mature rewards) to node[2]
101+ # - node[2] stakes a block - node[1] locks the change
102+ print ("*** 2 ***" )
103+ self .log .info ("Emptying node1 balance" )
104+ assert_equal (self .nodes [1 ].getbalance (), 50 * 250 )
105+ txid = self .nodes [1 ].sendtoaddress (self .nodes [2 ].getnewaddress (), (50 * 250 - 0.01 ))
106+ assert (txid is not None )
107+ sync_mempools (self .nodes )
108+ self .mocktime = self .generate_pos (2 , self .mocktime )
100109 sync_blocks (self .nodes )
101- self .log .info ("251 Blocks mined." )
110+ # lock the change output (so it's not used as stake input in generate_pos)
111+ for x in self .nodes [1 ].listunspent ():
112+ assert (self .nodes [1 ].lockunspent (False , [{"txid" : x ['txid' ], "vout" : x ['vout' ]}]))
113+ # check that it cannot stake
114+ sleep (1 )
115+ assert_equal (self .nodes [1 ].getstakingstatus ()["stakeablecoins" ], False )
102116
103- # 2 ) nodes[0] generates a owner address
117+ # 3 ) nodes[0] generates a owner address
104118 # nodes[1] generates a cold-staking address.
105119 # ---------------------------------------------
106- print ("*** 2 ***" )
120+ print ("*** 3 ***" )
107121 owner_address = self .nodes [0 ].getnewaddress ()
108122 self .log .info ("Owner Address: %s" % owner_address )
109123 staker_address = self .nodes [1 ].getnewstakingaddress ()
110124 staker_privkey = self .nodes [1 ].dumpprivkey (staker_address )
111125 self .log .info ("Staking Address: %s" % staker_address )
112126
113- # 3 ) Check enforcement.
127+ # 4 ) Check enforcement.
114128 # ---------------------
115- print ("*** 3 ***" )
129+ print ("*** 4 ***" )
130+ # Check that SPORK 17 is disabled
131+ assert (not self .isColdStakingEnforced ())
116132 self .log .info ("Creating a stake-delegation tx before cold staking enforcement..." )
117133 assert_raises_rpc_error (- 4 , "The transaction was rejected!" ,
118134 self .nodes [0 ].delegatestake , staker_address , INPUT_VALUE , owner_address , False , False , True )
@@ -123,9 +139,9 @@ def run_test(self):
123139 # double check
124140 assert (self .isColdStakingEnforced ())
125141
126- # 4 ) nodes[0] delegates a number of inputs for nodes[1] to stake em.
142+ # 5 ) nodes[0] delegates a number of inputs for nodes[1] to stake em.
127143 # ------------------------------------------------------------------
128- print ("*** 4 ***" )
144+ print ("*** 5 ***" )
129145 self .log .info ("First check warning when using external addresses..." )
130146 assert_raises_rpc_error (- 5 , "Only the owner of the key to owneraddress will be allowed to spend these coins" ,
131147 self .nodes [0 ].delegatestake , staker_address , INPUT_VALUE , "yCgCXC8N5VThhfiaVuKaNLkNnrWduzVnoT" )
@@ -152,38 +168,39 @@ def run_test(self):
152168 assert (res != None and res ["txid" ] != None and res ["txid" ] != "" )
153169 assert_equal (res ["owner_address" ], owner_address )
154170 assert_equal (res ["staker_address" ], staker_address )
155- self .generateBlock ()
171+ sync_mempools (self .nodes )
172+ self .mocktime = self .generate_pos (2 , self .mocktime )
156173 sync_blocks (self .nodes )
157174 self .log .info ("%d Txes created." % NUM_OF_INPUTS )
158175 # check balances:
159176 self .expected_balance = NUM_OF_INPUTS * INPUT_VALUE
160177 self .expected_immature_balance = 0
161178 self .checkBalances ()
162179
163- # 5 ) check that the owner (nodes[0]) can spend the coins.
180+ # 6 ) check that the owner (nodes[0]) can spend the coins.
164181 # -------------------------------------------------------
165- print ("*** 5 ***" )
182+ print ("*** 6 ***" )
166183 self .log .info ("Spending back one of the delegated UTXOs..." )
167184 delegated_utxos = getDelegatedUtxos (self .nodes [0 ].listunspent ())
168- assert_equal (20 , len (delegated_utxos ))
185+ assert_equal (NUM_OF_INPUTS , len (delegated_utxos ))
169186 assert_equal (len (delegated_utxos ), len (self .nodes [0 ].listcoldutxos ()))
170187 u = delegated_utxos [0 ]
171188 txhash = self .spendUTXOwithNode (u , 0 )
172189 assert (txhash != None )
173190 self .log .info ("Good. Owner was able to spend - tx: %s" % str (txhash ))
174191
175- self .generateBlock ( )
192+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
176193 sync_blocks (self .nodes )
177194 # check balances after spend.
178195 self .expected_balance -= float (u ["amount" ])
179196 self .checkBalances ()
180197 self .log .info ("Balances check out after spend" )
181- assert_equal (19 , len (self .nodes [0 ].listcoldutxos ()))
198+ assert_equal (NUM_OF_INPUTS - 1 , len (self .nodes [0 ].listcoldutxos ()))
182199
183- # 6 ) check that the staker CANNOT use the coins to stake yet.
200+ # 7 ) check that the staker CANNOT use the coins to stake yet.
184201 # He needs to whitelist the owner first.
185202 # -----------------------------------------------------------
186- print ("*** 6 ***" )
203+ print ("*** 7 ***" )
187204 self .log .info ("Trying to generate a cold-stake block before whitelisting the owner..." )
188205 assert_equal (self .nodes [1 ].getstakingstatus ()["stakeablecoins" ], False )
189206 self .log .info ("Nice. Cold staker was NOT able to create the block yet." )
@@ -193,25 +210,25 @@ def run_test(self):
193210 assert (ret )
194211 self .log .info ("Delegator address %s whitelisted" % owner_address )
195212
196- # 7 ) check that the staker CANNOT spend the coins.
213+ # 8 ) check that the staker CANNOT spend the coins.
197214 # ------------------------------------------------
198- print ("*** 7 ***" )
215+ print ("*** 8 ***" )
199216 self .log .info ("Trying to spend one of the delegated UTXOs with the cold-staking key..." )
200217 delegated_utxos = getDelegatedUtxos (self .nodes [0 ].listunspent ())
201218 assert_greater_than (len (delegated_utxos ), 0 )
202219 u = delegated_utxos [0 ]
203220 assert_raises_rpc_error (- 26 , "mandatory-script-verify-flag-failed (Script failed an OP_CHECKCOLDSTAKEVERIFY operation" ,
204221 self .spendUTXOwithNode , u , 1 )
205222 self .log .info ("Good. Cold staker was NOT able to spend (failed OP_CHECKCOLDSTAKEVERIFY)" )
206- self .generateBlock ( )
223+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
207224 sync_blocks (self .nodes )
208225
209- # 8 ) check that the staker can use the coins to stake a block with internal miner.
226+ # 9 ) check that the staker can use the coins to stake a block with internal miner.
210227 # --------------------------------------------------------------------------------
211- print ("*** 8 ***" )
228+ print ("*** 9 ***" )
212229 assert_equal (self .nodes [1 ].getstakingstatus ()["stakeablecoins" ], True )
213230 self .log .info ("Generating one valid cold-stake block..." )
214- self .generateBlock (1 , 1 )
231+ self .mocktime = self . generate_pos (1 , self . mocktime )
215232 self .log .info ("New block created by cold-staking. Trying to submit..." )
216233 newblockhash = self .nodes [1 ].getbestblockhash ()
217234 self .log .info ("Block %s submitted" % newblockhash )
@@ -223,20 +240,20 @@ def run_test(self):
223240 self .log .info ("Great. Cold-staked block was accepted!" )
224241
225242 # check balances after staked block.
226- self .expected_balance -= 50
227- self .expected_immature_balance += 300
243+ self .expected_balance -= INPUT_VALUE
244+ self .expected_immature_balance += ( INPUT_VALUE + 250 )
228245 self .checkBalances ()
229246 self .log .info ("Balances check out after staked block" )
230247
231- # 9 ) check that the staker can use the coins to stake a block with a rawtransaction.
248+ # 10 ) check that the staker can use the coins to stake a block with a rawtransaction.
232249 # ----------------------------------------------------------------------------------
233- print ("*** 9 ***" )
250+ print ("*** 10 ***" )
234251 self .log .info ("Generating another valid cold-stake block..." )
235252 stakeable_coins = getDelegatedUtxos (self .nodes [0 ].listunspent ())
236253 stakeInputs = self .get_prevouts (1 , stakeable_coins )
237254 assert_greater_than (len (stakeInputs ), 0 )
238255 # Create the block
239- new_block = self .stake_next_block (1 , stakeInputs , None , staker_privkey )
256+ new_block = self .stake_next_block (1 , stakeInputs , self . mocktime , staker_privkey )
240257 self .log .info ("New block created (rawtx) by cold-staking. Trying to submit..." )
241258 # Try to submit the block
242259 ret = self .nodes [1 ].submitblock (bytes_to_hex_str (new_block .serialize ()))
@@ -248,22 +265,24 @@ def run_test(self):
248265 assert_equal (self .nodes [0 ].getblockcount (), self .nodes [1 ].getblockcount ())
249266 assert_equal (new_block .hash , self .nodes [0 ].getbestblockhash ())
250267 self .log .info ("Great. Cold-staked block was accepted!" )
268+ self .mocktime += 60
269+ set_node_times (self .nodes , self .mocktime )
251270
252271 # check balances after staked block.
253- self .expected_balance -= 50
254- self .expected_immature_balance += 300
272+ self .expected_balance -= INPUT_VALUE
273+ self .expected_immature_balance += ( INPUT_VALUE + 250 )
255274 self .checkBalances ()
256275 self .log .info ("Balances check out after staked block" )
257276
258- # 10 ) check that the staker cannot stake a block changing the coinstake scriptPubkey.
277+ # 11 ) check that the staker cannot stake a block changing the coinstake scriptPubkey.
259278 # ----------------------------------------------------------------------------------
260- print ("*** 10 ***" )
279+ print ("*** 11 ***" )
261280 self .log .info ("Generating one invalid cold-stake block (changing first coinstake output)..." )
262281 stakeable_coins = getDelegatedUtxos (self .nodes [0 ].listunspent ())
263282 stakeInputs = self .get_prevouts (1 , stakeable_coins )
264283 assert_greater_than (len (stakeInputs ), 0 )
265284 # Create the block (with dummy key)
266- new_block = self .stake_next_block (1 , stakeInputs , None , "" )
285+ new_block = self .stake_next_block (1 , stakeInputs , self . mocktime , "" )
267286 self .log .info ("New block created (rawtx) by cold-staking. Trying to submit..." )
268287 # Try to submit the block
269288 ret = self .nodes [1 ].submitblock (bytes_to_hex_str (new_block .serialize ()))
@@ -277,15 +296,15 @@ def run_test(self):
277296 self .checkBalances ()
278297 self .log .info ("Balances check out after (non) staked block" )
279298
280- # 11 ) neither adding different outputs to the coinstake.
299+ # 12 ) neither adding different outputs to the coinstake.
281300 # ------------------------------------------------------
282- print ("*** 11 ***" )
301+ print ("*** 12 ***" )
283302 self .log .info ("Generating another invalid cold-stake block (adding coinstake output)..." )
284303 stakeable_coins = getDelegatedUtxos (self .nodes [0 ].listunspent ())
285304 stakeInputs = self .get_prevouts (1 , stakeable_coins )
286305 assert_greater_than (len (stakeInputs ), 0 )
287306 # Create the block
288- new_block = self .stake_next_block (1 , stakeInputs , None , staker_privkey )
307+ new_block = self .stake_next_block (1 , stakeInputs , self . mocktime , staker_privkey )
289308 # Add output (dummy key address) to coinstake (taking 100 PIV from the pot)
290309 self .add_output_to_coinstake (new_block , 100 )
291310 self .log .info ("New block created (rawtx) by cold-staking. Trying to submit..." )
@@ -301,20 +320,20 @@ def run_test(self):
301320 self .checkBalances ()
302321 self .log .info ("Balances check out after (non) staked block" )
303322
304- # 12 ) Now node[0] gets mad and spends all the delegated coins, voiding the P2CS contracts.
323+ # 13 ) Now node[0] gets mad and spends all the delegated coins, voiding the P2CS contracts.
305324 # ----------------------------------------------------------------------------------------
306325 self .log .info ("Let's void the contracts." )
307- self .generateBlock ( )
326+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
308327 sync_blocks (self .nodes )
309- print ("*** 12 ***" )
328+ print ("*** 13 ***" )
310329 self .log .info ("Cancel the stake delegation spending the delegated utxos..." )
311330 delegated_utxos = getDelegatedUtxos (self .nodes [0 ].listunspent ())
312331 # remove one utxo to spend later
313332 final_spend = delegated_utxos .pop ()
314333 txhash = self .spendUTXOsWithNode (delegated_utxos , 0 )
315334 assert (txhash != None )
316335 self .log .info ("Good. Owner was able to void the stake delegations - tx: %s" % str (txhash ))
317- self .generateBlock ( )
336+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
318337 sync_blocks (self .nodes )
319338
320339 # deactivate SPORK 17 and check that the owner can still spend the last utxo
@@ -323,7 +342,7 @@ def run_test(self):
323342 txhash = self .spendUTXOsWithNode ([final_spend ], 0 )
324343 assert (txhash != None )
325344 self .log .info ("Good. Owner was able to void a stake delegation (with SPORK 17 disabled) - tx: %s" % str (txhash ))
326- self .generateBlock ( )
345+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
327346 sync_blocks (self .nodes )
328347
329348 # check balances after big spend.
@@ -334,42 +353,34 @@ def run_test(self):
334353 self .setColdStakingEnforcement ()
335354 assert (self .isColdStakingEnforced ())
336355
337- # 13 ) check that coinstaker is empty and can no longer stake.
356+ # 14 ) check that coinstaker is empty and can no longer stake.
338357 # -----------------------------------------------------------
339- print ("*** 13 ***" )
358+ print ("*** 14 ***" )
340359 self .log .info ("Trying to generate one cold-stake block again..." )
341360 assert_equal (self .nodes [1 ].getstakingstatus ()["stakeablecoins" ], False )
342361 self .log .info ("Cigar. Cold staker was NOT able to create any more blocks." )
343362
344- # 14 ) check balances when mature.
363+ # 15 ) check balances when mature.
345364 # -----------------------------------------------------------
346- print ("*** 14 ***" )
365+ print ("*** 15 ***" )
347366 self .log .info ("Staking 100 blocks to mature the cold stakes..." )
348- self .generateBlock (100 )
367+ for i in range (2 ):
368+ for peer in [0 , 2 ]:
369+ for j in range (25 ):
370+ self .mocktime = self .generate_pos (peer , self .mocktime )
371+ sync_blocks (self .nodes )
349372 self .expected_balance = self .expected_immature_balance
350373 self .expected_immature_balance = 0
351374 self .checkBalances ()
352375 delegated_utxos = getDelegatedUtxos (self .nodes [0 ].listunspent ())
353376 txhash = self .spendUTXOsWithNode (delegated_utxos , 0 )
354377 assert (txhash != None )
355378 self .log .info ("Good. Owner was able to spend the cold staked coins - tx: %s" % str (txhash ))
356- self .generateBlock ( )
379+ self .mocktime = self . generate_pos ( 2 , self . mocktime )
357380 sync_blocks (self .nodes )
358381 self .expected_balance = 0
359382 self .checkBalances ()
360383
361- def generateBlock (self , n = 1 , nodeid = 2 ):
362- fStaked = False
363- while (not fStaked ):
364- try :
365- self .nodes [nodeid ].generate (n )
366- fStaked = True
367- except JSONRPCException as e :
368- if ("Couldn't create new block" in str (e )):
369- # Sleep two seconds and retry
370- sleep (2 )
371- else :
372- raise e
373384
374385 def checkBalances (self ):
375386 w_info = self .nodes [0 ].getwalletinfo ()
0 commit comments