fix: one transaction approval at a time, and honest copy for a nonce collision (closes #271)
All checks were successful
check / check (push) Successful in 28s
All checks were successful
check / check (push) Successful in 28s
This commit was merged in pull request #284.
This commit is contained in:
@@ -14,8 +14,10 @@ const {
|
||||
assertWithinCeilings,
|
||||
sameAddress,
|
||||
failureIsRetryable,
|
||||
isNonceCollision,
|
||||
describeTxFailure,
|
||||
describeSigningFailure,
|
||||
NONCE_COLLISION_MESSAGE,
|
||||
ALLOWED_TX_TYPES,
|
||||
SERIALIZED_FIELDS,
|
||||
FORBIDDEN_FIELDS,
|
||||
@@ -23,6 +25,7 @@ const {
|
||||
TX_STAGE_SIGN,
|
||||
TX_STAGE_VERIFY,
|
||||
TX_STAGE_BROADCAST,
|
||||
TX_STAGE_NONCE,
|
||||
MAX_GAS_LIMIT,
|
||||
MAX_FEE_PER_GAS,
|
||||
} = require("../src/shared/approvalVerify");
|
||||
@@ -1191,7 +1194,6 @@ describe("signing failure and retry", () => {
|
||||
"already known",
|
||||
"timeout of 30000ms exceeded",
|
||||
"could not coalesce error",
|
||||
"replacement transaction underpriced",
|
||||
]) {
|
||||
const outcome = describeTxFailure(
|
||||
TX_STAGE_BROADCAST,
|
||||
@@ -1199,10 +1201,76 @@ describe("signing failure and retry", () => {
|
||||
);
|
||||
expect(outcome.retryable).toBe(false);
|
||||
expect(outcome.spendApproval).toBe(true);
|
||||
expect(outcome.stage).toBe(TX_STAGE_BROADCAST);
|
||||
expect(outcome.error).toBe(message);
|
||||
}
|
||||
});
|
||||
|
||||
// The one broadcast failure that is not ambiguous. The node answered, and
|
||||
// its answer was that the nonce was already spoken for, so this
|
||||
// transaction is not in a mempool anywhere.
|
||||
test("a nonce the node refused is classified however it was worded", () => {
|
||||
for (const err of [
|
||||
new Error("nonce too low"),
|
||||
new Error("replacement transaction underpriced"),
|
||||
Object.assign(new Error("could not coalesce error"), {
|
||||
code: "NONCE_EXPIRED",
|
||||
}),
|
||||
Object.assign(new Error("could not coalesce error"), {
|
||||
code: "REPLACEMENT_UNDERPRICED",
|
||||
}),
|
||||
// The shape ethers hands up when it could not classify the node's
|
||||
// error itself: the node's own words are nested underneath.
|
||||
Object.assign(new Error("could not coalesce error"), {
|
||||
info: { error: { code: -32000, message: "OldNonce" } },
|
||||
}),
|
||||
]) {
|
||||
const outcome = describeTxFailure(TX_STAGE_BROADCAST, err);
|
||||
expect(
|
||||
describeSigningFailure(
|
||||
outcome,
|
||||
"The transaction could not be sent.",
|
||||
).message,
|
||||
).toMatch(/did not reach the network/);
|
||||
expect(outcome.retryable).toBe(false);
|
||||
expect(outcome.spendApproval).toBe(true);
|
||||
expect(outcome.error).toBe(NONCE_COLLISION_MESSAGE);
|
||||
expect(outcome.stage).toBe(TX_STAGE_NONCE);
|
||||
expect(isNonceCollision(err)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
// A node that says it knows the transaction has it, so it did reach the
|
||||
// network and the ambiguous wording is the correct one.
|
||||
test("already known is not a nonce collision", () => {
|
||||
const err = new Error("already known");
|
||||
const outcome = describeTxFailure(TX_STAGE_BROADCAST, err);
|
||||
expect(
|
||||
describeSigningFailure(
|
||||
outcome,
|
||||
"The transaction could not be sent.",
|
||||
).message,
|
||||
).toMatch(/may still have reached the network/);
|
||||
expect(outcome.stage).toBe(TX_STAGE_BROADCAST);
|
||||
expect(isNonceCollision(err)).toBe(false);
|
||||
});
|
||||
|
||||
test("a nonce collision says the transaction did not reach the network", () => {
|
||||
const outcome = describeTxFailure(
|
||||
TX_STAGE_BROADCAST,
|
||||
new Error("nonce too low"),
|
||||
);
|
||||
const copy = describeSigningFailure(
|
||||
outcome,
|
||||
"The transaction could not be sent.",
|
||||
);
|
||||
expect(copy.retryable).toBe(false);
|
||||
expect(copy.message).toMatch(/did not reach the network/);
|
||||
expect(copy.message).not.toMatch(/may still have reached the network/);
|
||||
expect(copy.message).toMatch(/Please send it again from the site\.$/);
|
||||
expect(copy.message).toMatch(/^[A-Z].*\.$/);
|
||||
});
|
||||
|
||||
test("a failed broadcast does not tell the user to send it again", () => {
|
||||
const outcome = describeSigningFailure(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user