diff --git a/chain.js b/chain.js
index a394b01..11a72cf 100644
--- a/chain.js
+++ b/chain.js
@@ -189,15 +189,36 @@ function saveState() {
fs.renameSync(tmp, STATE_FILE);
} catch (e) { console.error('chain state save failed', e.message); }
}
+// Most-synced tip across the RPC pool. Public load-balanced nodes (publicnode)
+// sometimes answer eth_blockNumber from a replica lagging thousands of blocks
+// behind — which stalls the scan (latest < lastBlock) and, worse, could let a
+// getLogs from a lagging node skip freshly-mined events for good. Take the MAX
+// height and remember which node reported it, so we scan against a node we know
+// is synced to that height.
+async function bestTip() {
+ const urls = getConfig().rpcs;
+ let best = { block: 0, url: urls[0] };
+ await Promise.all(urls.map(async u => {
+ try { const b = parseInt(await rpcOnce(u, 'eth_blockNumber', []), 16);
+ if (b > best.block) best = { block: b, url: u }; } catch (e) {}
+ }));
+ return best;
+}
async function tail() {
if (busy) return; busy = true;
try {
- const latest = parseInt(await rpc('eth_blockNumber', []), 16);
+ const tip = await bestTip();
+ const latest = tip.block;
while (state.lastBlock < latest) {
const from = state.lastBlock + 1;
const to = Math.min(from + CHUNK - 1, latest);
- const logs = await rpc('eth_getLogs', [{ address: getConfig().contract,
- fromBlock: '0x' + from.toString(16), toBlock: '0x' + to.toString(16) }]);
+ // scan against the node we confirmed is synced to `latest`; fall back to
+ // the rotating pool only if that specific node errors on this range.
+ let logs;
+ try { logs = await rpcOnce(tip.url, 'eth_getLogs', [{ address: getConfig().contract,
+ fromBlock: '0x' + from.toString(16), toBlock: '0x' + to.toString(16) }]); }
+ catch (e) { logs = await rpc('eth_getLogs', [{ address: getConfig().contract,
+ fromBlock: '0x' + from.toString(16), toBlock: '0x' + to.toString(16) }]); }
for (const lg of logs) {
const ev = decodeLog(lg);
if (!ev) continue;
diff --git a/public/assets/contract.js b/public/assets/contract.js
index 2993aac..c984a47 100644
--- a/public/assets/contract.js
+++ b/public/assets/contract.js
@@ -12,8 +12,8 @@
$('lnkSource').href = src;
$('lnkSource2').href = src;
} else {
- // private rehearsal chain: point at the audited Amoy verification instead
- const src = 'https://repo.sourcify.dev/contracts/full_match/80002/0xaF47EC401A9B0D570a553b1A1c95D6079083636e/';
+ // fallback if explorer unset: point straight at the Sourcify-verified source
+ const src = 'https://repo.sourcify.dev/contracts/full_match/137/0xBE1ECA72AFF47d13D8E907e523F55eB9e2d365E0/';
$('lnkExplorer').href = src;
$('lnkSource').href = src;
$('lnkSource2').href = src;
diff --git a/public/contract.html b/public/contract.html
index 6720abb..8dd465c 100644
--- a/public/contract.html
+++ b/public/contract.html
@@ -142,7 +142,7 @@
-
+