2
2
# Copyright (c) 2019 The Unit-e Core developers
3
3
# Distributed under the MIT software license, see the accompanying
4
4
# 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
+ )
6
17
from 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
+ )
10
35
11
36
12
37
def stake_p2wsh (node , staking_node , amount ):
@@ -18,23 +43,49 @@ def stake_p2wsh(node, staking_node, amount):
18
43
staking_node: the node which will be able to stake nodes
19
44
amount: the amount to send
20
45
"""
21
- multisig = node .addmultisigaddress (2 , [node .getnewaddress (), node .getnewaddress ()])
46
+ multisig = node .addmultisigaddress (
47
+ 2 , [node .getnewaddress (), node .getnewaddress ()])
22
48
bare = CScript (hex_str_to_bytes (multisig ['redeemScript' ]))
23
49
spending_script_hash = sha256 (bare )
24
50
25
- addr_info = staking_node .validateaddress (staking_node .getnewaddress ('' , 'legacy' ))
51
+ addr_info = staking_node .validateaddress (
52
+ staking_node .getnewaddress ('' , 'legacy' ))
26
53
staking_key_hash = hash160 (hex_str_to_bytes (addr_info ['pubkey' ]))
27
54
28
55
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 )
31
82
32
83
33
84
class RemoteStakingTest (UnitETestFramework ):
34
85
def set_test_params (self ):
35
86
self .num_nodes = 2
36
87
self .setup_clean_chain = True
37
- self .extra_args = [
88
+ self .extra_args = [
38
89
[],
39
90
['-minimumchainwork=0' , '-maxtipage=1000000000' ]
40
91
]
@@ -43,8 +94,13 @@ def run_test(self):
43
94
alice , bob = self .nodes
44
95
alice .importmasterkey (regtest_mnemonics [0 ]['mnemonics' ])
45
96
97
+ bob .add_p2p_connection (P2PInterface ())
98
+ network_thread_start ()
99
+ bob .p2p .wait_for_verack ()
100
+
46
101
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 )
48
104
49
105
alices_addr = alice .getnewaddress ()
50
106
@@ -60,21 +116,50 @@ def run_test(self):
60
116
assert_equal (ps ['wallets' ][0 ]['stakeable_balance' ], 0 )
61
117
62
118
# 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 )
65
121
alice .generatetoaddress (1 , alices_addr )
66
122
self .sync_all ()
67
123
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
+
68
129
wi = alice .getwalletinfo ()
69
130
assert_equal (wi ['remote_staking_balance' ], 2 )
131
+ assert_equal (wi ['balance' ], alice_balance )
70
132
71
133
def bob_is_staking_the_new_coin ():
72
134
ps = bob .proposerstatus ()
73
135
return ps ['wallets' ][0 ]['stakeable_balance' ] == 2
74
136
wait_until (bob_is_staking_the_new_coin , timeout = 10 )
75
137
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
+
76
149
# 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 )
78
163
79
164
80
165
if __name__ == '__main__' :
0 commit comments