22# Copyright (c) 2019 The Unit-e Core developers
33# Distributed under the MIT software license, see the accompanying
44# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5- from test_framework .mininode import sha256
5+ from test_framework .blocktools import (
6+ create_block ,
7+ create_coinbase ,
8+ get_tip_snapshot_meta ,
9+ sign_coinbase ,
10+ )
11+ from test_framework .mininode import (
12+ msg_witness_block ,
13+ network_thread_start ,
14+ P2PInterface ,
15+ sha256 ,
16+ )
617from test_framework .regtest_mnemonics import regtest_mnemonics
7- from test_framework .script import CScript , OP_2 , hash160
8- from test_framework .test_framework import UnitETestFramework , STAKE_SPLIT_THRESHOLD
9- from test_framework .util import assert_equal , assert_greater_than , bytes_to_hex_str , hex_str_to_bytes , wait_until
18+ from test_framework .script import (
19+ CScript ,
20+ OP_2 ,
21+ hash160 ,
22+ )
23+ from test_framework .test_framework import (
24+ UnitETestFramework ,
25+ PROPOSER_REWARD ,
26+ STAKE_SPLIT_THRESHOLD ,
27+ )
28+ from test_framework .util import (
29+ assert_equal ,
30+ assert_greater_than ,
31+ bytes_to_hex_str ,
32+ hex_str_to_bytes ,
33+ wait_until ,
34+ )
1035
1136
1237def stake_p2wsh (node , staking_node , amount ):
@@ -18,23 +43,49 @@ def stake_p2wsh(node, staking_node, amount):
1843 staking_node: the node which will be able to stake nodes
1944 amount: the amount to send
2045 """
21- multisig = node .addmultisigaddress (2 , [node .getnewaddress (), node .getnewaddress ()])
46+ multisig = node .addmultisigaddress (
47+ 2 , [node .getnewaddress (), node .getnewaddress ()])
2248 bare = CScript (hex_str_to_bytes (multisig ['redeemScript' ]))
2349 spending_script_hash = sha256 (bare )
2450
25- addr_info = staking_node .validateaddress (staking_node .getnewaddress ('' , 'legacy' ))
51+ addr_info = staking_node .validateaddress (
52+ staking_node .getnewaddress ('' , 'legacy' ))
2653 staking_key_hash = hash160 (hex_str_to_bytes (addr_info ['pubkey' ]))
2754
2855 rs_p2wsh = CScript ([OP_2 , staking_key_hash , spending_script_hash ])
29- outputs = [{'address' : 'script' , 'amount' : amount , 'script' : bytes_to_hex_str (rs_p2wsh )}]
30- node .sendtypeto ('unite' , 'unite' , outputs )
56+ outputs = [{'address' : 'script' , 'amount' : amount ,
57+ 'script' : bytes_to_hex_str (rs_p2wsh )}]
58+ return node .sendtypeto ('unite' , 'unite' , outputs )
59+
60+
61+ def build_block_with_remote_stake (node ):
62+ height = node .getblockcount ()
63+ snapshot_meta = get_tip_snapshot_meta (node )
64+ stakes = node .liststakeablecoins ()
65+
66+ coin = stakes ['stakeable_coins' ][0 ]['coin' ]
67+ script_pubkey = hex_str_to_bytes (coin ['script_pub_key' ]['hex' ])
68+ stake = {
69+ 'txid' : coin ['out_point' ]['txid' ],
70+ 'vout' : coin ['out_point' ]['n' ],
71+ 'amount' : coin ['amount' ],
72+ }
73+
74+ tip = int (node .getbestblockhash (), 16 )
75+ block_time = node .getblock (
76+ node .getbestblockhash ())['time' ] + 1
77+ coinbase = sign_coinbase (
78+ node , create_coinbase (
79+ height , stake , snapshot_meta .hash , raw_script_pubkey = script_pubkey ))
80+
81+ return create_block (tip , coinbase , block_time )
3182
3283
3384class RemoteStakingTest (UnitETestFramework ):
3485 def set_test_params (self ):
3586 self .num_nodes = 2
3687 self .setup_clean_chain = True
37- self .extra_args = [
88+ self .extra_args = [
3889 [],
3990 ['-minimumchainwork=0' , '-maxtipage=1000000000' ]
4091 ]
@@ -43,8 +94,13 @@ def run_test(self):
4394 alice , bob = self .nodes
4495 alice .importmasterkey (regtest_mnemonics [0 ]['mnemonics' ])
4596
97+ bob .add_p2p_connection (P2PInterface ())
98+ network_thread_start ()
99+ bob .p2p .wait_for_verack ()
100+
46101 alice .generate (1 )
47- assert_equal (len (alice .listunspent ()), regtest_mnemonics [0 ]['balance' ] / STAKE_SPLIT_THRESHOLD )
102+ assert_equal (len (alice .listunspent ()),
103+ regtest_mnemonics [0 ]['balance' ] / STAKE_SPLIT_THRESHOLD )
48104
49105 alices_addr = alice .getnewaddress ()
50106
@@ -60,21 +116,50 @@ def run_test(self):
60116 assert_equal (ps ['wallets' ][0 ]['stakeable_balance' ], 0 )
61117
62118 # Stake the funds
63- result = alice .stakeat (recipient )
64- stake_p2wsh (alice , staking_node = bob , amount = 1 )
119+ tx1_hash = alice .stakeat (recipient )
120+ tx2_hash = stake_p2wsh (alice , staking_node = bob , amount = 1 )
65121 alice .generatetoaddress (1 , alices_addr )
66122 self .sync_all ()
67123
124+ # Estimate Alice balance
125+ tx1_fee = alice .gettransaction (tx1_hash )['fee' ]
126+ tx2_fee = alice .gettransaction (tx2_hash )['fee' ]
127+ alice_balance = regtest_mnemonics [0 ]['balance' ] + tx1_fee + tx2_fee
128+
68129 wi = alice .getwalletinfo ()
69130 assert_equal (wi ['remote_staking_balance' ], 2 )
131+ assert_equal (wi ['balance' ], alice_balance )
70132
71133 def bob_is_staking_the_new_coin ():
72134 ps = bob .proposerstatus ()
73135 return ps ['wallets' ][0 ]['stakeable_balance' ] == 2
74136 wait_until (bob_is_staking_the_new_coin , timeout = 10 )
75137
138+ # Bob generates a new block with remote stake of Alice
139+ block = build_block_with_remote_stake (bob )
140+ bob .p2p .send_and_ping (msg_witness_block (block ))
141+ self .sync_all ()
142+
143+ # Reward from the Bob's block comes to remote staking balance of Alice
144+ # Actual spendable balance shouldn't change because the reward is not yet mature
145+ wi = alice .getwalletinfo ()
146+ assert_equal (wi ['remote_staking_balance' ], 2 + PROPOSER_REWARD )
147+ assert_equal (wi ['balance' ], alice_balance )
148+
76149 # Change outputs for both staked coins, and the balance staked remotely
77- assert_equal (len (alice .listunspent ()), 2 + (regtest_mnemonics [0 ]['balance' ] // STAKE_SPLIT_THRESHOLD ))
150+ assert_equal (len (alice .listunspent ()), 2 +
151+ (regtest_mnemonics [0 ]['balance' ] // STAKE_SPLIT_THRESHOLD ))
152+
153+ # Chech that Alice can spend remotely staked coins
154+ inputs = []
155+ for coin in bob .liststakeablecoins ()['stakeable_coins' ]:
156+ out_point = coin ['coin' ]['out_point' ]
157+ inputs .append ({'tx' : out_point ['txid' ], 'n' : out_point ['n' ]})
158+ alice .sendtypeto ('' , '' , [{'address' : alices_addr , 'amount' : 1.9 }], '' , '' , False ,
159+ {'changeaddress' : alices_addr , 'inputs' : inputs })
160+
161+ wi = alice .getwalletinfo ()
162+ assert_equal (wi ['remote_staking_balance' ], PROPOSER_REWARD )
78163
79164
80165if __name__ == '__main__' :
0 commit comments