Skip to content

Commit c4f060b

Browse files
author
DogLooksGood
committed
Improve the retry logic for players reg query
1 parent 8b254db commit c4f060b

3 files changed

Lines changed: 70 additions & 60 deletions

File tree

transactor-components/src/wrapped_transport.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,24 +72,29 @@ impl TransportT for WrappedTransport {
7272
) -> Result<Pin<Box<dyn Stream<Item = Result<GameAccount>> + Send + 'a>>> {
7373
let interval = self.resub_interval;
7474
Ok(Box::pin(stream! {
75-
let sub = self.inner.subscribe_game_account(addr).await;
75+
let mut sub;
7676

77-
let mut sub = match sub {
78-
Ok(sub) => sub,
79-
Err(e) => {
80-
yield Err(e);
81-
return;
77+
loop {
78+
match self.inner.subscribe_game_account(addr).await {
79+
Ok(s) => {
80+
sub = s;
81+
break;
82+
}
83+
Err(e) => {
84+
error!("An error occurred when initializing websocket: {}", e);
85+
continue;
86+
}
8287
}
83-
};
88+
}
8489

8590
loop {
8691
let item = sub.next().await;
8792
match item {
8893
Some(Ok(item)) => {
8994
yield Ok(item);
90-
},
95+
}
9196
Some(Err(e)) => {
92-
error!("An error occurred in game account subscription, quit sub loop");
97+
error!("An error occured in subscription, quit loop");
9398
yield Err(e);
9499
return;
95100
}

transport/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ pub enum TransportError {
186186

187187
#[error("Failed to deserialize players reg")]
188188
PlayersRegDeserializationError,
189+
190+
#[error("Failed to get account from RPC: {0}")]
191+
GetAccountError(String),
192+
193+
#[error("The version of game state mismatches the version of players reg")]
194+
GameStatePlayersRegVersionMismatch,
189195
}
190196

191197
pub type TransportResult<T> = std::result::Result<T, TransportError>;

transport/src/solana.rs

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ const FEE_CAP: u64 = 20000;
6868
const PLAYERS_REG_HEAD_LEN: usize = 152;
6969
const PLAYERS_REG_INIT_LEN: usize = PLAYERS_REG_HEAD_LEN + 4;
7070

71-
const MAX_RETRIES_FOR_GET_PLAYERS_REG: usize = 5;
72-
7371
fn read_keypair(path: PathBuf) -> TransportResult<Keypair> {
7472
let keypair = solana_sdk::signature::read_keypair_file(path)
7573
.map_err(|e| TransportError::InvalidKeyfile(e.to_string()))?;
@@ -646,14 +644,15 @@ impl TransportT for SolanaTransport {
646644
let (payer, payer_pubkey) = self.payer()?;
647645
let game_account_pubkey = Self::parse_pubkey(&addr)?;
648646
let game_state = self.internal_get_game_state(&game_account_pubkey).await?;
649-
let players = self
650-
.internal_get_players_reg_state(
647+
let (game_state, players_reg) = self
648+
.internal_get_game_state_and_players_reg_state(
649+
&game_account_pubkey,
651650
&game_state.players_reg_account,
652651
game_state.access_version,
653652
game_state.settle_version,
654653
)
655-
.await?
656-
.players;
654+
.await?;
655+
let players = players_reg.players;
657656

658657
if game_state.settle_version != params.settle_version {
659658
return Err(Error::SettleVersionMismatch(
@@ -803,16 +802,16 @@ impl TransportT for SolanaTransport {
803802
tx.sign(&[payer], blockhash);
804803
let sig = self.send_transaction(tx)?;
805804

806-
let game_state = self.internal_get_game_state(&game_account_pubkey).await?;
807-
808-
let players = self
809-
.internal_get_players_reg_state(
805+
let (game_state, players_reg) = self
806+
.internal_get_game_state_and_players_reg_state(
807+
&game_account_pubkey,
810808
&game_state.players_reg_account,
811809
game_state.access_version,
812810
game_state.settle_version,
813811
)
814-
.await?
815-
.players;
812+
.await?;
813+
814+
let players = players_reg.players;
816815

817816
Ok(SettleResult {
818817
signature: sig.to_string(),
@@ -1303,27 +1302,28 @@ impl TransportT for SolanaTransport {
13031302
Ok(x) => x,
13041303
Err(e) => {
13051304
error!("Game state deserialization error: {}", e.to_string());
1306-
yield(Err(Error::TransportError(e.to_string())));
13071305
unsub().await;
13081306
return;
13091307
}
13101308
};
13111309

1312-
let players = match self.internal_get_players_reg_state(
1310+
let (game_state, players_reg) = match self.internal_get_game_state_and_players_reg_state(
1311+
&game_account_pubkey,
13131312
&state.players_reg_account,
13141313
state.access_version,
13151314
state.settle_version,
13161315
).await {
1317-
Ok(players_reg) => players_reg.players,
1316+
Ok((game_state, players_reg)) => (game_state, players_reg),
13181317
Err(e) => {
13191318
error!("Get players reg error: {}", e.to_string());
13201319
unsub().await;
1321-
yield Err(Error::TransportError(e.to_string()));
13221320
return;
13231321
}
13241322
};
13251323

1326-
let acc = match state.into_account(addr.clone(), players) {
1324+
let players = players_reg.players;
1325+
1326+
let acc = match game_state.into_account(addr.clone(), players) {
13271327
Ok(x) => x,
13281328
Err(e) => {
13291329
error!("Game account parsing error: {}", e.to_string());
@@ -1340,11 +1340,13 @@ impl TransportT for SolanaTransport {
13401340
async fn get_game_account(&self, addr: &str) -> Result<Option<GameAccount>> {
13411341
let game_account_pubkey = Self::parse_pubkey(addr)?;
13421342
let game_state = self.internal_get_game_state(&game_account_pubkey).await?;
1343-
let players = self.internal_get_players_reg_state(
1343+
let (game_state, players_reg) = self.internal_get_game_state_and_players_reg_state(
1344+
&game_account_pubkey,
13441345
&game_state.players_reg_account,
13451346
game_state.access_version,
13461347
game_state.settle_version
1347-
).await?.players;
1348+
).await?;
1349+
let players = players_reg.players;
13481350
Ok(Some(game_state.into_account(addr, players)?))
13491351
}
13501352

@@ -1688,47 +1690,44 @@ impl SolanaTransport {
16881690

16891691
/// Get the state of on-chain players registrations of a game
16901692
/// Not for public API usage
1691-
async fn internal_get_players_reg_state(
1693+
async fn internal_get_game_state_and_players_reg_state(
16921694
&self,
1695+
game_account_pubkey: &Pubkey,
16931696
players_reg_account_pubkey: &Pubkey,
16941697
access_version: u64,
16951698
settle_version: u64,
1696-
) -> TransportResult<PlayersReg> {
1697-
let mut retries = 0;
1698-
loop {
1699-
if retries == MAX_RETRIES_FOR_GET_PLAYERS_REG {
1700-
break;
1701-
}
1702-
let players_reg_account = self
1703-
.client
1704-
.get_account_with_commitment(
1705-
players_reg_account_pubkey,
1706-
CommitmentConfig::finalized(),
1707-
)
1708-
.map_err(|e| TransportError::AccountNotFound(e.to_string()))?
1709-
.value
1710-
.ok_or(TransportError::AccountNotFound(players_reg_account_pubkey.to_string()))?;
1699+
) -> TransportResult<(GameState, PlayersReg)> {
1700+
1701+
let accounts_result = self.client.get_multiple_accounts_with_commitment(&[
1702+
*game_account_pubkey,
1703+
*players_reg_account_pubkey,
1704+
], CommitmentConfig::finalized())
1705+
.map_err(|e| TransportError::GetAccountError(e.to_string()))?
1706+
.value;
1707+
1708+
let game_account_data = accounts_result[0]
1709+
.as_ref()
1710+
.map(|acc| &acc.data)
1711+
.ok_or(TransportError::GameAccountNotFound)?;
17111712

1712-
let mut players_reg = PlayersReg::try_from_slice(&players_reg_account.data.as_slice())
1713+
let players_reg_data = accounts_result[1]
1714+
.as_ref()
1715+
.map(|acc| &acc.data)
1716+
.ok_or(TransportError::GameAccountPlayersNotFound)?;
1717+
1718+
let game_state = GameState::deserialize(&mut game_account_data.as_slice())
1719+
.map_err(|_| TransportError::GameStateDeserializeError)?;
1720+
1721+
let mut players_reg = PlayersReg::try_from_slice(&players_reg_data.as_slice())
17131722
.map_err(|_| TransportError::PlayersRegDeserializationError)?;
17141723

1715-
if players_reg.access_version == access_version
1716-
&& players_reg.settle_version == settle_version
1717-
{
1718-
players_reg.players.retain(|p| p.access_version != 0);
1724+
if players_reg.access_version == access_version && players_reg.settle_version == settle_version {
1725+
players_reg.players.retain(|p| p.access_version != 0);
17191726

1720-
return Ok(players_reg);
1721-
}
1722-
println!("Versions mismatches, PlayersReg: A {} S {}, GameAccount: A {} S {}",
1723-
players_reg.access_version, players_reg.settle_version,
1724-
access_version, settle_version);
1725-
retries += 1;
1727+
return Ok((game_state, players_reg));
17261728
}
1727-
error!(
1728-
"Failed to get players_reg_account for {}",
1729-
players_reg_account_pubkey
1730-
);
1731-
Err(TransportError::GameAccountPlayersNotFound)
1729+
1730+
Err(TransportError::GameStatePlayersRegVersionMismatch)
17321731
}
17331732

17341733
/// Get the state of an on-chain game account by its public key

0 commit comments

Comments
 (0)