From ab90cc5b06865c055ba63ba920ccde37a0429e63 Mon Sep 17 00:00:00 2001 From: Aere Network Date: Thu, 24 Sep 2026 00:03:31 +0300 Subject: [PATCH] verify-anchor: a certificate is a NON-EMPTY item 6 (AIP-22 stage 5 headers carry an empty certificate slot between anchors) --- tools/verify-anchor.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/verify-anchor.mjs b/tools/verify-anchor.mjs index f288b4e..20bb70e 100644 --- a/tools/verify-anchor.mjs +++ b/tools/verify-anchor.mjs @@ -268,7 +268,9 @@ async function carriesCertificate(h) { if (h < ANCHOR_FROM) return false; const b = await rpc('eth_getBlockByNumber', ['0x' + h.toString(16), false]); if (!b || !b.extraData) return false; - try { return rlpRead(hex(b.extraData), 0).item.length >= 6; } catch (e) { return false; } + // AIP-22 stage 5: from H_hdr every header has seven elements and the certificate slot (item 6) is an EMPTY list between + // anchors, so a certificate is a NON-EMPTY item 6, never just the count of elements + try { const it = rlpRead(hex(b.extraData), 0).item; return it.length >= 6 && it[5].list && it[5].item.length > 0; } catch (e) { return false; } } let DERIVED_INTERVAL = 0; @@ -416,7 +418,7 @@ for (let i = 0; i < COUNT; i++) { const parent = await rpc('eth_getBlockByNumber', ['0x' + (h - 1).toString(16), false]); const items = rlpRead(hex(b.extraData), 0).item; const vanity = Buffer.from(items[0].item); - if (items.length < 6) { console.log(h + ' FAIL: no certificate element'); bad++; continue; } + if (items.length < 6 || !items[5].list || items[5].item.length === 0) { console.log(h + ' FAIL: no certificate element'); bad++; continue; } const cert = items[5]; const toNested = (node) => (node.list ? node.item.map(toNested) : Buffer.from(node.item)); // v1 opens with a LIST ([idx, sig]); v2 opens with the SCALAR 2. Nothing else is accepted.