Skip to content

Commit

Permalink
fix: avoid race conditions when fetching nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddentao committed Aug 31, 2023
1 parent ff50089 commit 77d5707
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/shared/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Context } from "./context.js";
import get from "lodash.get";
import { glob } from "glob";
import path from "node:path";
import { Mutex } from "./mutex.js";


export interface Network {
Expand Down Expand Up @@ -328,19 +329,29 @@ export const execContractMethod = async (contract: OnChainContract, method: stri

const latestNonce: Record<string, number> = {}

const nonceMutex = new Mutex()

const getLatestNonce = async (signer: Signer): Promise<number> => {
const address = await signer.getAddress()
try {
await nonceMutex.lock()

trace(`Get nonce for ${address}...`)

if (!latestNonce[address]) {
latestNonce[address] = await signer.getNonce()
trace(` Live nonce: ${latestNonce[address]}`)
} else {
latestNonce[address]++
trace(` Incremented nonce: ${latestNonce[address]}`)
}
const address = await signer.getAddress()


return latestNonce[address]
trace(`Get nonce for ${address}...`)

if (!latestNonce[address]) {
latestNonce[address] = await signer.getNonce()
trace(` Live nonce: ${latestNonce[address]}`)
} else {
latestNonce[address]++
trace(` Incremented nonce: ${latestNonce[address]}`)
}

await nonceMutex.unlock()

return latestNonce[address]
} catch (err: any) {
await nonceMutex.unlock()
return error(`Failed to get nonce: ${err.message}`)
}
}
24 changes: 24 additions & 0 deletions src/shared/mutex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
type Resolver = () => void

export class Mutex {
private _lock?: Promise<void>
private _unlock?: Resolver

async lock (): Promise<void> {
if (this._lock) {
await this._lock
}

this._lock = new Promise<void>((resolve) => {
this._unlock = resolve
})
}

async unlock (): Promise<void> {
if (!this._lock) {
throw new Error('Mutex is not locked')
}
this._unlock!()
delete this._lock;
}
}

0 comments on commit 77d5707

Please sign in to comment.