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

Commit edec441

Browse files
authored
token-2022: Force refresh blockhash on no-op transaction (#2884)
1 parent 4dbb4a5 commit edec441

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

token/program-2022/tests/reallocate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ async fn reallocate() {
9393
);
9494

9595
// reallocate succeeds with noop if account is already large enough
96+
token.get_new_latest_blockhash().await.unwrap();
9697
token
9798
.reallocate(&alice_account, &alice, &[ExtensionType::ImmutableOwner])
9899
.await

token/rust/src/token.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::client::{ProgramClient, ProgramClientError, SendTransaction};
2+
use solana_program_test::tokio::time;
23
use solana_sdk::{
34
account::Account as BaseAccount,
5+
hash::Hash,
46
instruction::Instruction,
57
program_error::ProgramError,
68
pubkey::Pubkey,
@@ -18,7 +20,11 @@ use spl_token_2022::{
1820
instruction,
1921
state::{Account, AccountState, Mint},
2022
};
21-
use std::{fmt, sync::Arc};
23+
use std::{
24+
fmt, io,
25+
sync::Arc,
26+
time::{Duration, Instant},
27+
};
2228
use thiserror::Error;
2329

2430
#[derive(Error, Debug)]
@@ -165,21 +171,54 @@ where
165171
}
166172
}
167173

174+
pub async fn get_new_latest_blockhash(&self) -> TokenResult<Hash> {
175+
let blockhash = self
176+
.client
177+
.get_latest_blockhash()
178+
.await
179+
.map_err(TokenError::Client)?;
180+
let start = Instant::now();
181+
let mut num_retries = 0;
182+
while start.elapsed().as_secs() < 5 {
183+
let new_blockhash = self
184+
.client
185+
.get_latest_blockhash()
186+
.await
187+
.map_err(TokenError::Client)?;
188+
if new_blockhash != blockhash {
189+
return Ok(new_blockhash);
190+
}
191+
192+
time::sleep(Duration::from_millis(200)).await;
193+
num_retries += 1;
194+
}
195+
196+
Err(TokenError::Client(Box::new(io::Error::new(
197+
io::ErrorKind::Other,
198+
format!(
199+
"Unable to get new blockhash after {}ms (retried {} times), stuck at {}",
200+
start.elapsed().as_millis(),
201+
num_retries,
202+
blockhash
203+
),
204+
))))
205+
}
206+
168207
pub async fn process_ixs<S2: Signers>(
169208
&self,
170209
instructions: &[Instruction],
171210
signing_keypairs: &S2,
172211
) -> TokenResult<T::Output> {
173-
let recent_blockhash = self
212+
let latest_blockhash = self
174213
.client
175214
.get_latest_blockhash()
176215
.await
177216
.map_err(TokenError::Client)?;
178217

179218
let mut tx = Transaction::new_with_payer(instructions, Some(&self.payer.pubkey()));
180-
tx.try_partial_sign(&[&self.payer], recent_blockhash)
219+
tx.try_partial_sign(&[&self.payer], latest_blockhash)
181220
.map_err(|error| TokenError::Client(error.into()))?;
182-
tx.try_sign(signing_keypairs, recent_blockhash)
221+
tx.try_sign(signing_keypairs, latest_blockhash)
183222
.map_err(|error| TokenError::Client(error.into()))?;
184223

185224
self.client

0 commit comments

Comments
 (0)