@@ -5,7 +5,15 @@ mod helpers;
5
5
6
6
use {
7
7
helpers:: * ,
8
- solana_program:: { instruction:: InstructionError , pubkey:: Pubkey , stake} ,
8
+ solana_program:: {
9
+ borsh0_10:: try_from_slice_unchecked,
10
+ instruction:: InstructionError ,
11
+ pubkey:: Pubkey ,
12
+ stake:: {
13
+ self ,
14
+ state:: { Authorized , Delegation , Lockup , Meta , Stake , StakeState } ,
15
+ } ,
16
+ } ,
9
17
solana_program_test:: * ,
10
18
solana_sdk:: {
11
19
account:: { Account , WritableAccount } ,
@@ -16,40 +24,27 @@ use {
16
24
spl_stake_pool:: {
17
25
error:: StakePoolError ,
18
26
find_stake_program_address, find_transient_stake_program_address, id,
19
- state:: { StakeStatus , ValidatorStakeInfo } ,
27
+ state:: { AccountType , StakeStatus , ValidatorList , ValidatorListHeader , ValidatorStakeInfo } ,
20
28
MINIMUM_ACTIVE_STAKE ,
21
29
} ,
22
30
std:: num:: NonZeroU32 ,
23
31
} ;
24
32
25
- async fn setup ( ) -> (
26
- ProgramTestContext ,
27
- StakePoolAccounts ,
28
- Pubkey ,
29
- Option < NonZeroU32 > ,
30
- ) {
33
+ async fn setup (
34
+ stake_pool_accounts : & StakePoolAccounts ,
35
+ forced_stake : & StakeState ,
36
+ voter_pubkey : & Pubkey ,
37
+ ) -> ( ProgramTestContext , Option < NonZeroU32 > ) {
31
38
let mut program_test = program_test ( ) ;
32
- let stake_pool_accounts = StakePoolAccounts :: default ( ) ;
33
39
34
40
let stake_pool_pubkey = stake_pool_accounts. stake_pool . pubkey ( ) ;
35
41
let ( mut stake_pool, mut validator_list) = stake_pool_accounts. state ( ) ;
36
42
37
- let voter_pubkey = add_vote_account ( & mut program_test) ;
38
- let meta = stake:: state:: Meta {
39
- rent_exempt_reserve : STAKE_ACCOUNT_RENT_EXEMPTION ,
40
- authorized : stake:: state:: Authorized {
41
- staker : stake_pool_accounts. withdraw_authority ,
42
- withdrawer : stake_pool_accounts. withdraw_authority ,
43
- } ,
44
- lockup : stake_pool. lockup ,
45
- } ;
43
+ let _ = add_vote_account_with_pubkey ( voter_pubkey, & mut program_test) ;
46
44
47
45
let stake_account = Account :: create (
48
46
TEST_STAKE_AMOUNT + STAKE_ACCOUNT_RENT_EXEMPTION ,
49
- bincode:: serialize :: < stake:: state:: StakeState > ( & stake:: state:: StakeState :: Initialized (
50
- meta,
51
- ) )
52
- . unwrap ( ) ,
47
+ bincode:: serialize :: < StakeState > ( forced_stake) . unwrap ( ) ,
53
48
stake:: program:: id ( ) ,
54
49
false ,
55
50
Epoch :: default ( ) ,
@@ -58,13 +53,13 @@ async fn setup() -> (
58
53
let raw_validator_seed = 42 ;
59
54
let validator_seed = NonZeroU32 :: new ( raw_validator_seed) ;
60
55
let ( stake_address, _) =
61
- find_stake_program_address ( & id ( ) , & voter_pubkey, & stake_pool_pubkey, validator_seed) ;
56
+ find_stake_program_address ( & id ( ) , voter_pubkey, & stake_pool_pubkey, validator_seed) ;
62
57
program_test. add_account ( stake_address, stake_account) ;
63
58
let active_stake_lamports = TEST_STAKE_AMOUNT - MINIMUM_ACTIVE_STAKE ;
64
59
// add to validator list
65
60
validator_list. validators . push ( ValidatorStakeInfo {
66
61
status : StakeStatus :: Active . into ( ) ,
67
- vote_account_address : voter_pubkey,
62
+ vote_account_address : * voter_pubkey,
68
63
active_stake_lamports : active_stake_lamports. into ( ) ,
69
64
transient_stake_lamports : 0 . into ( ) ,
70
65
last_update_epoch : 0 . into ( ) ,
@@ -110,12 +105,27 @@ async fn setup() -> (
110
105
) ;
111
106
112
107
let context = program_test. start_with_context ( ) . await ;
113
- ( context, stake_pool_accounts , voter_pubkey , validator_seed)
108
+ ( context, validator_seed)
114
109
}
115
110
116
111
#[ tokio:: test]
117
112
async fn success_update ( ) {
118
- let ( mut context, stake_pool_accounts, voter_pubkey, validator_seed) = setup ( ) . await ;
113
+ let stake_pool_accounts = StakePoolAccounts :: default ( ) ;
114
+ let meta = Meta {
115
+ rent_exempt_reserve : STAKE_ACCOUNT_RENT_EXEMPTION ,
116
+ authorized : Authorized {
117
+ staker : stake_pool_accounts. withdraw_authority ,
118
+ withdrawer : stake_pool_accounts. withdraw_authority ,
119
+ } ,
120
+ lockup : Lockup :: default ( ) ,
121
+ } ;
122
+ let voter_pubkey = Pubkey :: new_unique ( ) ;
123
+ let ( mut context, validator_seed) = setup (
124
+ & stake_pool_accounts,
125
+ & StakeState :: Initialized ( meta) ,
126
+ & voter_pubkey,
127
+ )
128
+ . await ;
119
129
let pre_reserve_lamports = context
120
130
. banks_client
121
131
. get_account ( stake_pool_accounts. reserve_stake . pubkey ( ) )
@@ -169,7 +179,22 @@ async fn success_update() {
169
179
170
180
#[ tokio:: test]
171
181
async fn fail_increase ( ) {
172
- let ( mut context, stake_pool_accounts, voter_pubkey, validator_seed) = setup ( ) . await ;
182
+ let stake_pool_accounts = StakePoolAccounts :: default ( ) ;
183
+ let meta = Meta {
184
+ rent_exempt_reserve : STAKE_ACCOUNT_RENT_EXEMPTION ,
185
+ authorized : Authorized {
186
+ staker : stake_pool_accounts. withdraw_authority ,
187
+ withdrawer : stake_pool_accounts. withdraw_authority ,
188
+ } ,
189
+ lockup : Lockup :: default ( ) ,
190
+ } ;
191
+ let voter_pubkey = Pubkey :: new_unique ( ) ;
192
+ let ( mut context, validator_seed) = setup (
193
+ & stake_pool_accounts,
194
+ & StakeState :: Initialized ( meta) ,
195
+ & voter_pubkey,
196
+ )
197
+ . await ;
173
198
let ( stake_address, _) = find_stake_program_address (
174
199
& id ( ) ,
175
200
& voter_pubkey,
@@ -206,3 +231,113 @@ async fn fail_increase() {
206
231
)
207
232
) ;
208
233
}
234
+
235
+ #[ tokio:: test]
236
+ async fn success_remove_validator ( ) {
237
+ let stake_pool_accounts = StakePoolAccounts :: default ( ) ;
238
+ let meta = Meta {
239
+ rent_exempt_reserve : STAKE_ACCOUNT_RENT_EXEMPTION ,
240
+ authorized : Authorized {
241
+ staker : stake_pool_accounts. withdraw_authority ,
242
+ withdrawer : stake_pool_accounts. withdraw_authority ,
243
+ } ,
244
+ lockup : Lockup :: default ( ) ,
245
+ } ;
246
+ let voter_pubkey = Pubkey :: new_unique ( ) ;
247
+ let stake = Stake {
248
+ delegation : Delegation {
249
+ voter_pubkey,
250
+ stake : TEST_STAKE_AMOUNT ,
251
+ activation_epoch : 0 ,
252
+ deactivation_epoch : 0 ,
253
+ ..Delegation :: default ( )
254
+ } ,
255
+ credits_observed : 1 ,
256
+ } ;
257
+ let ( mut context, validator_seed) = setup (
258
+ & stake_pool_accounts,
259
+ & StakeState :: Stake ( meta, stake) ,
260
+ & voter_pubkey,
261
+ )
262
+ . await ;
263
+
264
+ // move forward to after deactivation
265
+ let first_normal_slot = context. genesis_config ( ) . epoch_schedule . first_normal_slot ;
266
+ context. warp_to_slot ( first_normal_slot + 1 ) . unwrap ( ) ;
267
+ stake_pool_accounts
268
+ . update_all (
269
+ & mut context. banks_client ,
270
+ & context. payer ,
271
+ & context. last_blockhash ,
272
+ & [ voter_pubkey] ,
273
+ false ,
274
+ )
275
+ . await ;
276
+
277
+ let ( stake_address, _) = find_stake_program_address (
278
+ & id ( ) ,
279
+ & voter_pubkey,
280
+ & stake_pool_accounts. stake_pool . pubkey ( ) ,
281
+ validator_seed,
282
+ ) ;
283
+ let transient_stake_seed = 0 ;
284
+ let transient_stake_address = find_transient_stake_program_address (
285
+ & id ( ) ,
286
+ & voter_pubkey,
287
+ & stake_pool_accounts. stake_pool . pubkey ( ) ,
288
+ transient_stake_seed,
289
+ )
290
+ . 0 ;
291
+
292
+ let error = stake_pool_accounts
293
+ . remove_validator_from_pool (
294
+ & mut context. banks_client ,
295
+ & context. payer ,
296
+ & context. last_blockhash ,
297
+ & stake_address,
298
+ & transient_stake_address,
299
+ )
300
+ . await ;
301
+ assert ! ( error. is_none( ) , "{:?}" , error) ;
302
+
303
+ // Get a new blockhash for the next update to work
304
+ context. get_new_latest_blockhash ( ) . await . unwrap ( ) ;
305
+
306
+ let error = stake_pool_accounts
307
+ . update_all (
308
+ & mut context. banks_client ,
309
+ & context. payer ,
310
+ & context. last_blockhash ,
311
+ & [ voter_pubkey] ,
312
+ false ,
313
+ )
314
+ . await ;
315
+ assert ! ( error. is_none( ) , "{:?}" , error) ;
316
+
317
+ // Check if account was removed from the list of stake accounts
318
+ let validator_list = get_account (
319
+ & mut context. banks_client ,
320
+ & stake_pool_accounts. validator_list . pubkey ( ) ,
321
+ )
322
+ . await ;
323
+ let validator_list =
324
+ try_from_slice_unchecked :: < ValidatorList > ( validator_list. data . as_slice ( ) ) . unwrap ( ) ;
325
+ assert_eq ! (
326
+ validator_list,
327
+ ValidatorList {
328
+ header: ValidatorListHeader {
329
+ account_type: AccountType :: ValidatorList ,
330
+ max_validators: stake_pool_accounts. max_validators,
331
+ } ,
332
+ validators: vec![ ]
333
+ }
334
+ ) ;
335
+
336
+ // Check stake account no longer exists
337
+ let account = context
338
+ . banks_client
339
+ . get_account ( stake_address)
340
+ . await
341
+ . unwrap ( ) ;
342
+ assert ! ( account. is_none( ) ) ;
343
+ }
0 commit comments