Aegis 0.32.3: WizardConnect waits between relay reconnects
When the relays were unreachable (after a sleep, or a relay offline) the relay client reconnected with no delay at all, re-signing the queued wallet_ready on every lap. On Theseus's main thread that spun a core for an hour, grew the process to 2.5 GB and froze the browser. connect() now waits 2 s, 4 s ... up to 60 s between tries, and starts over once a connection has held for a minute.
This commit is contained in:
parent
a33854a926
commit
eac7020820
2 changed files with 40 additions and 1 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "aegis",
|
||||
"name": "Aegis Wallet",
|
||||
"version": "0.32.2",
|
||||
"version": "0.32.3",
|
||||
"category": "plugin",
|
||||
"description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash and window.wizardconnect on any site; window.tronWeb / window.tronLink / window.ethereum / window.solana too. Every call needs your approval.",
|
||||
"author": "Silent Mode",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,44 @@ const WALLET_ICON = "data:image/svg+xml;utf8," + encodeURIComponent(
|
|||
</svg>`
|
||||
);
|
||||
|
||||
// Reconnect backoff for WizardConnect relays.
|
||||
//
|
||||
// RelayClient.connect() resolves as soon as the subscription is created, before
|
||||
// any socket opens. When every relay is unreachable (DNS down after a sleep, a
|
||||
// relay offline) the pool closes the subscription at once, the connection
|
||||
// manager hears "disconnected" and calls connect() again with no delay — its
|
||||
// reconnectInterval only applies when connect() throws, which it never does.
|
||||
// Every lap also re-wraps the queued wallet_ready (two Schnorr signatures and
|
||||
// two ECDH per relay), all on Theseus's main thread: on 2026-10-07 that spun
|
||||
// one core flat out for an hour, grew the process to 2.5 GB and froze the
|
||||
// browser. Delaying connect() itself throttles the loop, whoever calls it: the
|
||||
// first try is immediate, then 2 s, 4 s ... up to 60 s; a connection that has
|
||||
// held for a minute starts the count over.
|
||||
const RECONNECT_FIRST_MS = 2000;
|
||||
const RECONNECT_MAX_MS = 60_000;
|
||||
const RECONNECT_HEALTHY_MS = 60_000;
|
||||
function throttleRelayReconnects(wcCore, { now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
|
||||
const proto = wcCore?.RelayClient?.prototype;
|
||||
if (!proto || typeof proto.connect !== "function" || proto.__aegisThrottled) return false;
|
||||
const connect = proto.connect;
|
||||
proto.connect = async function throttledConnect(...args) {
|
||||
const st = this.__aegisReconnect || (this.__aegisReconnect = { last: 0, n: 0 });
|
||||
if (now() - st.last > RECONNECT_HEALTHY_MS) st.n = 0;
|
||||
if (st.n > 0) {
|
||||
const gap = Math.min(RECONNECT_MAX_MS, RECONNECT_FIRST_MS * 2 ** (st.n - 1));
|
||||
const wait = st.last + gap - now();
|
||||
if (wait > 0) await sleep(wait);
|
||||
}
|
||||
st.n++;
|
||||
st.last = now();
|
||||
return connect.apply(this, args);
|
||||
};
|
||||
proto.__aegisThrottled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = function makeWc({ HDKey, secp256k1, sha256, hkdf, WalletConnectionManager, wcCore, libauth, log = () => {}, api, approvalRequest }) {
|
||||
throttleRelayReconnects(wcCore);
|
||||
|
||||
// ---- WalletAdapter --------------------------------------------------------
|
||||
//
|
||||
|
|
@ -265,3 +302,5 @@ module.exports = function makeWc({ HDKey, secp256k1, sha256, hkdf, WalletConnect
|
|||
|
||||
return { startForWallet, stopForWallet, connectUri, disconnect, disconnectOrigin, snapshot, onStateChange };
|
||||
};
|
||||
|
||||
module.exports.throttleRelayReconnects = throttleRelayReconnects;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue