Added timeout to waitForTransaction (#477).

This commit is contained in:
Richard Moore 2020-02-03 23:05:04 -05:00
parent 8eb0190d5e
commit bacc440397
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
4 changed files with 40 additions and 9 deletions

@ -259,7 +259,7 @@ export abstract class Provider implements OnceBlockable {
}
// @TODO: This *could* be implemented here, but would pull in events...
abstract waitForTransaction(transactionHash: string, timeout?: number): Promise<TransactionReceipt>;
abstract waitForTransaction(transactionHash: string, confirmations?: number, timeout?: number): Promise<TransactionReceipt>;
readonly _isProvider: boolean;

@ -193,7 +193,8 @@ export class Logger {
messageDetails.push(key + "=" + JSON.stringify(params[key].toString()));
}
});
messageDetails.push("version=" + this.version);
messageDetails.push(`code=${ code }`);
messageDetails.push(`version=${ this.version }`);
const reason = message;
if (messageDetails.length) {

@ -444,22 +444,42 @@ export class BaseProvider extends Provider {
// @TODO: Add .poller which must be an event emitter with a 'start', 'stop' and 'block' event;
// this will be used once we move to the WebSocket or other alternatives to polling
async waitForTransaction(transactionHash: string, confirmations?: number): Promise<TransactionReceipt> {
async waitForTransaction(transactionHash: string, confirmations?: number, timeout?: number): Promise<TransactionReceipt> {
if (confirmations == null) { confirmations = 1; }
const receipt = await this.getTransactionReceipt(transactionHash);
// Receipt is already good
if (receipt.confirmations >= confirmations) { return receipt; }
if ((receipt ? receipt.confirmations: 0) >= confirmations) { return receipt; }
// Poll until the receipt is good...
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
let timer: NodeJS.Timer = null;
let done = false;
const handler = (receipt: TransactionReceipt) => {
if (receipt.confirmations < confirmations) { return; }
if (timer) { clearTimeout(timer); }
if (done) { return; }
done = true;
this.removeListener(transactionHash, handler);
resolve(receipt);
}
this.on(transactionHash, handler);
if (typeof(timeout) === "number" && timeout > 0) {
timer = setTimeout(() => {
if (done) { return; }
timer = null;
done = true;
this.removeListener(transactionHash, handler);
reject(logger.makeError("timeout exceeded", Logger.errors.TIMEOUT, { timeout: timeout }));
}, timeout);
if (timer.unref) { timer.unref(); }
}
});
}

@ -1,7 +1,7 @@
"use strict";
import { Network } from "@ethersproject/networks";
import { BlockWithTransactions, Provider } from "@ethersproject/abstract-provider";
import { Block, BlockWithTransactions, Provider } from "@ethersproject/abstract-provider";
import { shuffled } from "@ethersproject/random";
import { deepCopy, defineReadOnly, shallowCopy } from "@ethersproject/properties";
import { BigNumber } from "@ethersproject/bignumber";
@ -56,7 +56,7 @@ function median(values: Array<number>): number {
function serialize(value: any): string {
if (value === null) {
return null;
return "null";
} else if (typeof(value) === "number" || typeof(value) === "boolean") {
return JSON.stringify(value);
} else if (typeof(value) === "string") {
@ -222,6 +222,8 @@ function getProcessFunc(provider: FallbackProvider, method: string, params: { [
case "getTransaction":
case "getTransactionReceipt":
normalize = function(tx: any): string {
if (tx == null) { return null; }
tx = shallowCopy(tx);
tx.confirmations = -1;
return serialize(tx);
@ -233,6 +235,8 @@ function getProcessFunc(provider: FallbackProvider, method: string, params: { [
// We drop the confirmations from transactions as it is approximate
if (params.includeTransactions) {
normalize = function(block: BlockWithTransactions): string {
if (block == null) { return null; }
block = shallowCopy(block);
block.transactions = block.transactions.map((tx) => {
tx = shallowCopy(tx);
@ -241,6 +245,11 @@ function getProcessFunc(provider: FallbackProvider, method: string, params: { [
});
return serialize(block);
};
} else {
normalize = function(block: Block): string {
if (block == null) { return null; }
return serialize(block);
}
}
break;
@ -460,7 +469,7 @@ export class FallbackProvider extends BaseProvider {
const results = configs.filter((c) => (c.done && c.error == null));
if (results.length >= this.quorum) {
const result = processFunc(results);
if (result != undefined) { return result; }
if (result !== undefined) { return result; }
}
// All configs have run to completion; we will never get more data
@ -470,8 +479,9 @@ export class FallbackProvider extends BaseProvider {
return logger.throwError("failed to meet quorum", Logger.errors.SERVER_ERROR, {
method: method,
params: params,
results: configs.map((c) => exposeDebugConfig(c)),
//results: configs.map((c) => c.result),
//errors: configs.map((c) => c.error),
results: configs.map((c) => exposeDebugConfig(c)),
provider: this
});
}