fix: answer the page when a background handler throws (closes #280)
This commit was merged in pull request #282.
This commit is contained in:
@@ -170,6 +170,16 @@ function approvedNonce(approvedTx) {
|
||||
}
|
||||
}
|
||||
|
||||
// What the page is told when a request failed in a way the wallet has no
|
||||
// specific answer for. -32603 is the JSON-RPC internal error EIP-1474 defines
|
||||
// and EIP-1193 defers to for RPC-layer failures; no EIP-1193 4xxx code
|
||||
// describes "the wallet broke", and one is not invented here. The cause is
|
||||
// logged rather than put in the message: the page gets a stable sentence, the
|
||||
// background console gets the throw.
|
||||
const INTERNAL_ERROR_CODE = -32603;
|
||||
const INTERNAL_ERROR_MESSAGE =
|
||||
"AutistMask could not complete this request because of an internal error.";
|
||||
|
||||
async function getState() {
|
||||
const result = await storageGet("autistmask");
|
||||
return (
|
||||
@@ -1093,9 +1103,26 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
// keep fallback
|
||||
}
|
||||
}
|
||||
handleRpc(msg.method, msg.params, trustedOrigin).then((response) => {
|
||||
sendResponse(response);
|
||||
});
|
||||
handleRpc(msg.method, msg.params, trustedOrigin)
|
||||
.then((response) => {
|
||||
sendResponse(response);
|
||||
})
|
||||
.catch((err) => {
|
||||
// Without this the page's window.ethereum.request() promise
|
||||
// stays pending forever: no response is sent, the content
|
||||
// script posts nothing back, and the dApp cannot tell the
|
||||
// failure from a slow wallet. handleRpc does real work —
|
||||
// state loads, provider calls, transaction population — so
|
||||
// "it does not throw today" is not a property anyone is
|
||||
// maintaining.
|
||||
log.errorf("RPC request failed:", msg.method, err);
|
||||
sendResponse({
|
||||
error: {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
message: INTERNAL_ERROR_MESSAGE,
|
||||
},
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1202,6 +1229,10 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Which phase the last-resort .catch() below reports. Everything up to
|
||||
// the broadcastTransaction() call provably never reached the network,
|
||||
// so an escape from there must not tell the user it might have.
|
||||
let lastResortStage = TX_STAGE_VERIFY;
|
||||
(async () => {
|
||||
// The chain this attempt is on, read once. Verification below
|
||||
// refuses an artifact signed for any other chain, and the nonce
|
||||
@@ -1285,6 +1316,7 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
|
||||
try {
|
||||
const provider = getProvider(state.rpcUrl);
|
||||
lastResortStage = TX_STAGE_BROADCAST;
|
||||
const tx = await provider.broadcastTransaction(msg.rawSignedTx);
|
||||
if (nonce !== null) spent.add(nonce);
|
||||
settleApproval(
|
||||
@@ -1316,7 +1348,28 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
stage: outcome.stage,
|
||||
});
|
||||
}
|
||||
})();
|
||||
})().catch((e) => {
|
||||
// Every statement above is inside a try, but a throw from one of
|
||||
// the catch blocks escapes as an unhandled rejection and neither
|
||||
// the popup nor the page is ever answered. Settle both, through
|
||||
// the same chokepoint as every other retirement.
|
||||
log.errorf("transaction approval response failed:", e);
|
||||
settleApproval(
|
||||
msg.id,
|
||||
{
|
||||
error: {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
message: INTERNAL_ERROR_MESSAGE,
|
||||
},
|
||||
},
|
||||
{ holdsClaim: true },
|
||||
);
|
||||
sendResponse({
|
||||
error: INTERNAL_ERROR_MESSAGE,
|
||||
retryable: false,
|
||||
stage: lastResortStage,
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1400,7 +1453,25 @@ runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
}
|
||||
sendResponse({ error: errMsg, retryable });
|
||||
}
|
||||
})();
|
||||
})().catch((e) => {
|
||||
// Same shape as the transaction path: a throw out of the catch
|
||||
// block above would leave the popup and the page both waiting.
|
||||
log.errorf("sign approval response failed:", e);
|
||||
settleApproval(
|
||||
msg.id,
|
||||
{
|
||||
error: {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
message: INTERNAL_ERROR_MESSAGE,
|
||||
},
|
||||
},
|
||||
{ holdsClaim: true },
|
||||
);
|
||||
sendResponse({
|
||||
error: INTERNAL_ERROR_MESSAGE,
|
||||
retryable: false,
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user