fix: init guard in noncemanager (#2227)

This commit is contained in:
James Prestwich 2023-03-04 17:37:50 -08:00 committed by GitHub
parent 1c90e1b76a
commit e54666b467
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 29 additions and 14 deletions

View File

@ -9,6 +9,7 @@ use thiserror::Error;
/// consecutive transactions without waiting for them to hit the mempool /// consecutive transactions without waiting for them to hit the mempool
pub struct NonceManagerMiddleware<M> { pub struct NonceManagerMiddleware<M> {
inner: M, inner: M,
init_guard: futures_locks::Mutex<()>,
initialized: AtomicBool, initialized: AtomicBool,
nonce: AtomicU64, nonce: AtomicU64,
address: Address, address: Address,
@ -21,7 +22,13 @@ where
/// Instantiates the nonce manager with a 0 nonce. The `address` should be the /// Instantiates the nonce manager with a 0 nonce. The `address` should be the
/// address which you'll be sending transactions from /// address which you'll be sending transactions from
pub fn new(inner: M, address: Address) -> Self { pub fn new(inner: M, address: Address) -> Self {
Self { initialized: false.into(), nonce: 0.into(), inner, address } Self {
inner,
init_guard: Default::default(),
initialized: Default::default(),
nonce: Default::default(),
address,
}
} }
/// Returns the next nonce to be used /// Returns the next nonce to be used
@ -34,21 +41,29 @@ where
&self, &self,
block: Option<BlockId>, block: Option<BlockId>,
) -> Result<U256, NonceManagerError<M>> { ) -> Result<U256, NonceManagerError<M>> {
// initialize the nonce the first time the manager is called if self.initialized.load(Ordering::SeqCst) {
if !self.initialized.load(Ordering::SeqCst) {
let nonce = self
.inner
.get_transaction_count(self.address, block)
.await
.map_err(MiddlewareError::from_err)?;
self.nonce.store(nonce.as_u64(), Ordering::SeqCst);
self.initialized.store(true, Ordering::SeqCst);
Ok(nonce)
} else {
// return current nonce // return current nonce
Ok(self.nonce.load(Ordering::SeqCst).into()) return Ok(self.nonce.load(Ordering::SeqCst).into())
} }
}
let _guard = self.init_guard.lock().await;
// do this again in case multiple tasks enter this codepath
if self.initialized.load(Ordering::SeqCst) {
// return current nonce
return Ok(self.nonce.load(Ordering::SeqCst).into())
}
// initialize the nonce the first time the manager is called
let nonce = self
.inner
.get_transaction_count(self.address, block)
.await
.map_err(MiddlewareError::from_err)?;
self.nonce.store(nonce.as_u64(), Ordering::SeqCst);
self.initialized.store(true, Ordering::SeqCst);
Ok(nonce)
} // guard dropped here
async fn get_transaction_count_with_manager( async fn get_transaction_count_with_manager(
&self, &self,