Skip to content

Commit

Permalink
Fixing possible race condition (#406)
Browse files Browse the repository at this point in the history
If two transactions use `getNonce()` at the same time, they'll get
basically the same promise instance, which resolves to the same nonce.
With this change, all consecutive `getNonce()` calls will return
different promise instances, with the increment preformed.
  • Loading branch information
mutantcornholio authored May 15, 2024
1 parent a22b714 commit 7062ef5
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions src/dripper/polkadot/PolkadotActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const rpcTimeout = (service: string) => {
}, timeout);
};

const NONCE_SYNC_INTERVAL = 5 * 60 * 1000;
const NONCE_SYNC_INTERVAL = 10_000;

const encodeAccount = AccountId().enc;

Expand Down Expand Up @@ -51,7 +51,16 @@ export class PolkadotActions {
this.#pendingTransactions = new Set();
setInterval(() => {
if (this.#pendingTransactions.size === 0) {
const oldNoncePromise = this.#nonce;
this.#nonce = networkData.api.getNonce(this.address, client);

// In cases of nonce mismatch, it might be useful to have nonce change in logs
this.#nonce.then(async (newNonce) => {
const oldNonce = await oldNoncePromise;
if (newNonce !== oldNonce) {
logger.debug(`Nonce updated from ${oldNonce} to ${newNonce}`);
}
});
}
}, NONCE_SYNC_INTERVAL);

Expand All @@ -70,9 +79,10 @@ export class PolkadotActions {
});
}

private async getNonce(): Promise<number> {
const currentNonce = await this.#nonce;
this.#nonce = Promise.resolve(currentNonce + 1);
// Synchronously queues nonce increment
private getNonce(): Promise<number> {
const currentNonce = this.#nonce;
this.#nonce = this.#nonce.then((nonce) => nonce + 1);
return currentNonce;
}

Expand Down Expand Up @@ -123,15 +133,16 @@ export class PolkadotActions {

const addressBinary = Binary.fromBytes(encodeAccount(address));

const nonce = await this.getNonce();
const tx = await networkData.api.getTeleportTx({
dripAmount,
address: addressBinary,
parachain_id,
client,
nonce: await this.getNonce(),
nonce,
});

logger.debug(`Teleporting to ${address}: ${parachain_id}. Transaction ${tx}`);
logger.debug(`Teleporting to ${address}: ${parachain_id}. Transaction ${tx}; nonce: ${nonce}`);

const hash = await this.sendTx(tx);

Expand All @@ -141,13 +152,14 @@ export class PolkadotActions {

async transferTokens(dripAmount: bigint, address: string): Promise<DripResponse> {
logger.info(`💸 sending tokens to ${address}`);
const nonce = await this.getNonce();
const tx = await networkData.api.getTransferTokensTx({
dripAmount,
address,
client,
nonce: await this.getNonce(),
nonce,
});
logger.debug(`Dripping to ${address}. Transaction ${tx}`);
logger.debug(`Dripping to ${address}. Transaction ${tx}; nonce: ${nonce}`);

const hash = await this.sendTx(tx);

Expand Down

0 comments on commit 7062ef5

Please sign in to comment.