Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 4dbb4a5

Browse files
authored
stake-pool-py: Add more waits to solidify tests (#2882)
1 parent 37a6db8 commit 4dbb4a5

File tree

3 files changed

+92
-19
lines changed

3 files changed

+92
-19
lines changed

stake-pool/py/stake/state.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
from enum import IntEnum
44
from typing import NamedTuple, Dict
5-
from construct import Container, Struct, Int64ul # type: ignore
5+
from construct import Container, Struct, Float64l, Int32ul, Int64ul # type: ignore
66

77
from solana.publickey import PublicKey
8+
from solana.utils.helpers import decode_byte_string
89
from solana._layouts.shared import PUBLIC_KEY_LAYOUT
910

1011

@@ -46,6 +47,29 @@ class StakeAuthorize(IntEnum):
4647
WITHDRAWER = 1
4748

4849

50+
class StakeStateType(IntEnum):
51+
"""Stake State Types."""
52+
UNINITIALIZED = 0
53+
INITIALIZED = 1
54+
STAKE = 2
55+
REWARDS_POOL = 3
56+
57+
58+
class StakeState(NamedTuple):
59+
state_type: StakeStateType
60+
state: Container
61+
62+
"""Stake state."""
63+
@classmethod
64+
def decode(cls, data: str, encoding: str):
65+
data_bytes = decode_byte_string(data, encoding)
66+
parsed = STAKE_STATE_LAYOUT.parse(data_bytes)
67+
return StakeState(
68+
state_type=parsed['state_type'],
69+
state=parsed['state'],
70+
)
71+
72+
4973
LOCKUP_LAYOUT = Struct(
5074
"unix_timestamp" / Int64ul,
5175
"epoch" / Int64ul,
@@ -57,3 +81,51 @@ class StakeAuthorize(IntEnum):
5781
"staker" / PUBLIC_KEY_LAYOUT,
5882
"withdrawer" / PUBLIC_KEY_LAYOUT,
5983
)
84+
85+
META_LAYOUT = Struct(
86+
"rent_exempt_reserve" / Int64ul,
87+
"authorized" / AUTHORIZED_LAYOUT,
88+
"lockup" / LOCKUP_LAYOUT,
89+
)
90+
91+
META_LAYOUT = Struct(
92+
"rent_exempt_reserve" / Int64ul,
93+
"authorized" / AUTHORIZED_LAYOUT,
94+
"lockup" / LOCKUP_LAYOUT,
95+
)
96+
97+
DELEGATION_LAYOUT = Struct(
98+
"voter_pubkey" / PUBLIC_KEY_LAYOUT,
99+
"stake" / Int64ul,
100+
"activation_epoch" / Int64ul,
101+
"deactivation_epoch" / Int64ul,
102+
"warmup_cooldown_rate" / Float64l,
103+
)
104+
105+
STAKE_LAYOUT = Struct(
106+
"delegation" / DELEGATION_LAYOUT,
107+
"credits_observed" / Int64ul,
108+
)
109+
110+
STAKE_AND_META_LAYOUT = Struct(
111+
"meta" / META_LAYOUT,
112+
"stake" / STAKE_LAYOUT,
113+
)
114+
115+
STAKE_STATE_LAYOUT = Struct(
116+
"state_type" / Int32ul,
117+
"state" / STAKE_AND_META_LAYOUT,
118+
# NOTE: This can be done better, but was mainly needed for testing. Ideally,
119+
# we would have something like:
120+
#
121+
# Switch(
122+
# lambda this: this.state,
123+
# {
124+
# StakeStateType.UNINITIALIZED: Pass,
125+
# StakeStateType.INITIALIZED: META_LAYOUT,
126+
# StakeStateType.STAKE: STAKE_AND_META_LAYOUT,
127+
# }
128+
# ),
129+
#
130+
# Unfortunately, it didn't work.
131+
)

stake-pool/py/tests/conftest.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,28 +42,28 @@ def solana_test_validator():
4242
def validators(event_loop, async_client, payer) -> List[PublicKey]:
4343
num_validators = 3
4444
validators = []
45-
futures = []
4645
for i in range(num_validators):
4746
vote = Keypair()
4847
node = Keypair()
49-
futures.append(create_vote(async_client, payer, vote, node, payer.public_key, payer.public_key, 10))
48+
event_loop.run_until_complete(
49+
create_vote(async_client, payer, vote, node, payer.public_key, payer.public_key, 10)
50+
)
5051
validators.append(vote.public_key)
51-
event_loop.run_until_complete(asyncio.gather(*futures))
5252
return validators
5353

5454

5555
@pytest.fixture
56-
def stake_pool_addresses(event_loop, async_client, payer, validators) -> Tuple[PublicKey, PublicKey]:
56+
def stake_pool_addresses(event_loop, async_client, payer, validators, waiter) -> Tuple[PublicKey, PublicKey]:
5757
fee = Fee(numerator=1, denominator=1000)
5858
referral_fee = 20
59+
event_loop.run_until_complete(waiter.wait_for_next_epoch_if_soon(async_client))
5960
stake_pool_addresses = event_loop.run_until_complete(
6061
create_all(async_client, payer, fee, referral_fee)
6162
)
62-
futures = [
63-
add_validator_to_pool(async_client, payer, stake_pool_addresses[0], validator)
64-
for validator in validators
65-
]
66-
event_loop.run_until_complete(asyncio.gather(*futures))
63+
for validator in validators:
64+
event_loop.run_until_complete(
65+
add_validator_to_pool(async_client, payer, stake_pool_addresses[0], validator)
66+
)
6767
return stake_pool_addresses
6868

6969

stake-pool/py/tests/test_deposit_withdraw_stake.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from stake.actions import create_stake, delegate_stake
77
from stake.constants import STAKE_LEN
8+
from stake.state import StakeState
89
from stake_pool.actions import deposit_stake, withdraw_stake, update_stake_pool
910
from stake_pool.state import StakePool
1011

@@ -15,26 +16,26 @@ async def test_deposit_withdraw_stake(async_client, validators, payer, stake_poo
1516
resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed)
1617
data = resp['result']['value']['data']
1718
stake_pool = StakePool.decode(data[0], data[1])
18-
token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint)
19-
20-
resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN)
21-
stake_rent_exemption = resp['result']
22-
waited = await waiter.wait_for_next_epoch_if_soon(async_client)
23-
if waited:
24-
await update_stake_pool(async_client, payer, stake_pool_address)
25-
2619
validator = next(iter(validators))
2720
stake_amount = 1_000_000
2821
stake = Keypair()
2922
await create_stake(async_client, payer, stake, payer.public_key, stake_amount)
3023
stake = stake.public_key
3124
await delegate_stake(async_client, payer, payer, stake, validator)
25+
resp = await async_client.get_account_info(stake, commitment=Confirmed)
26+
data = resp['result']['value']['data']
27+
stake_state = StakeState.decode(data[0], data[1])
28+
print(stake_state)
29+
3230
await waiter.wait_for_next_epoch(async_client)
31+
3332
await update_stake_pool(async_client, payer, stake_pool_address)
33+
token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint)
3434
await deposit_stake(async_client, payer, stake_pool_address, validator, stake, token_account)
35-
3635
pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed)
3736
pool_token_balance = pool_token_balance['result']['value']['amount']
37+
resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN)
38+
stake_rent_exemption = resp['result']
3839
assert pool_token_balance == str(stake_amount + stake_rent_exemption)
3940

4041
destination_stake = Keypair()

0 commit comments

Comments
 (0)