Dovada vie a paznicului de fereastra, rulata pe punctul de productie
Paznicul StateWindowReader exista din 2026-08-01 si are 12 teste. Testele ruleaza pe un nod fals. Un nod fals dovedeste ca acel cod face ce a crezut autorul; nu dovedeste ca punctul public se mai poarta cum a masurat autorul. state-window-live.ts inchide golul. Nu e in `npm test`, fiindca o suita care cade cand pica internetul invata oamenii sa ignore rosul. Ruleaza asa: npm run test:live npm run test:live -- https://rpc2.aere.network Ordinea conteaza si e deliberata: PASUL 1 ESEC PLANTAT. Apelul brut chiar intoarce zeroul fals. PASUL 2 CONTROL NEGATIV. Cu paznicii opriti, cititorul da zeroul mai departe. PASUL 3 PAZNICUL. Cu paznicii porniti, refuza. PASUL 4 MASOARA. Cauta marginea in loc sa creada constanta. Adevarul e ancorat intr-un CORP de bloc, nu in stare, deci proba nu depinde de lucrul pe care il testeaza: blocul 8.236.382 spune ca 0xbeb33d20 a semnat cu nonce 123.063. MASURAT azi pe ambele puncte, iesire 0: rpc.aere.network 511 raspunde, 512 refuzat, nonce brut la adancime "0x0" rpc2.aere.network 511 raspunde, 512 refuzat, nonce brut la adancime "0x0" Si paznicul a fost dovedit ca poate sa cada. Cu cei trei paznici inlocuiti cu cioturi care accepta tot, in dist, 5 din 12 teste trec pe rosu si suita iese cu 1. Reconstruit dupa, dist/state-window.js identic octet cu octet cu inainte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7287d8ad11
commit
067dd3d242
29
package.json
29
package.json
@ -1,10 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@aere/sdk",
|
"name": "@aere/sdk",
|
||||||
"version": "0.16.1",
|
"version": "0.16.12",
|
||||||
"description": "Official AERE Network SDK — typed ethers v6 client for the 16 contracts deployed on AERE L1 (chain ID 2800). WAERE, oracle, identity, faucet, card-escrow, delegated + locked staking, governance, AMM factory, bridge, NFT + marketplace, mining subscriptions.",
|
"description": "Official AERE Network SDK: typed ethers v6 clients for AERE L1 (chain ID 2800). 35+ typed clients over a 130+ contract address book, covering core DeFi, agentic x402 settlement, compliance, ERC-4337 account abstraction, t-of-n post-quantum custody, the 5 live NIST PQC precompiles (Falcon-512/1024, ML-DSA-44, SLH-DSA-128s, SHAKE256), and a seedless hybrid PQC wallet.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
"bin": {
|
||||||
|
"aere": "./dist/cli/aere-cli.js"
|
||||||
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -15,12 +18,25 @@
|
|||||||
"import": "./dist/addresses.js"
|
"import": "./dist/addresses.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": ["dist", "README.md"],
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "node --test dist/test/*.js"
|
"test": "node --test dist/test/*.js",
|
||||||
|
"test:live": "node dist/test/state-window-live.js"
|
||||||
},
|
},
|
||||||
"keywords": ["aere", "blockchain", "ethereum", "evm", "layer-1", "qbft", "defi", "sdk"],
|
"keywords": [
|
||||||
|
"aere",
|
||||||
|
"blockchain",
|
||||||
|
"ethereum",
|
||||||
|
"evm",
|
||||||
|
"layer-1",
|
||||||
|
"qbft",
|
||||||
|
"defi",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
"homepage": "https://aere.network/docs.html",
|
"homepage": "https://aere.network/docs.html",
|
||||||
"repository": "https://git.aere.network/aere-network/sdk-js",
|
"repository": "https://git.aere.network/aere-network/sdk-js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -31,5 +47,8 @@
|
|||||||
"@types/node": "^22.5.0",
|
"@types/node": "^22.5.0",
|
||||||
"ethers": "^6.13.4",
|
"ethers": "^6.13.4",
|
||||||
"typescript": "^5.6.0"
|
"typescript": "^5.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/post-quantum": "^0.6.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
178
src/test/state-window-live.ts
Normal file
178
src/test/state-window-live.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/**
|
||||||
|
* state-window-live.ts — prove StateWindowReader against the REAL endpoint.
|
||||||
|
*
|
||||||
|
* The unit tests in state-window.test.ts run against a fake node. A fake node
|
||||||
|
* proves the code does what its author expected; it does not prove the endpoint
|
||||||
|
* still behaves the way the author measured. This file closes that gap by
|
||||||
|
* pointing the guard at production and asserting on what comes back.
|
||||||
|
*
|
||||||
|
* It is deliberately NOT part of `npm test`: it needs the network, and a test
|
||||||
|
* suite that fails when the internet is down teaches people to ignore red.
|
||||||
|
*
|
||||||
|
* node dist/test/state-window-live.js # rpc.aere.network
|
||||||
|
* node dist/test/state-window-live.js https://rpc2.aere.network
|
||||||
|
*
|
||||||
|
* Exit 0 = the guard held and the hazard is still real.
|
||||||
|
* Exit 1 = something changed. Read the output; do not silence it.
|
||||||
|
*
|
||||||
|
* Structure, in this order, because a guard that has never been shown to fail
|
||||||
|
* cannot be trusted:
|
||||||
|
*
|
||||||
|
* STEP 1 PLANTED FAILURE. The raw call really does return a false zero.
|
||||||
|
* STEP 2 NEGATIVE CONTROL. With the guards disabled, the reader hands that
|
||||||
|
* false zero straight to the caller.
|
||||||
|
* STEP 3 THE GUARD. With the guards on, the reader refuses.
|
||||||
|
*
|
||||||
|
* If step 1 or step 2 ever stops failing, this file must be revisited: either
|
||||||
|
* the endpoint was fixed, or the measurement it rests on has gone stale.
|
||||||
|
* Read-only. No keys, no transactions.
|
||||||
|
*/
|
||||||
|
import { StateWindowReader, StateWindowError } from '../state-window.js';
|
||||||
|
|
||||||
|
const RPC = process.argv[2] ?? 'https://rpc.aere.network';
|
||||||
|
|
||||||
|
/** Measured: this address signed with nonce 123,063 in block 8,236,382. */
|
||||||
|
const SIGNER = '0xbeb33d20dfbbd49ec7ac1f617667f1f02dfd6465';
|
||||||
|
const TX_HASH = '0xbfd3620dc705cc1dbf5bf747c02f71f0d4f68227ab8b5ccafe3de15955587ce3';
|
||||||
|
|
||||||
|
let failures = 0;
|
||||||
|
const ok = (label: string, detail: string) => console.log(` PASS ${label}\n ${detail}`);
|
||||||
|
const bad = (label: string, detail: string) => {
|
||||||
|
failures++;
|
||||||
|
console.log(` FAIL ${label}\n ${detail}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function send(method: string, params: unknown[]): Promise<unknown> {
|
||||||
|
const res = await fetch(RPC, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
|
||||||
|
});
|
||||||
|
const body = (await res.json()) as { result?: unknown; error?: { code: number; message: string } };
|
||||||
|
if (body.error) throw new Error(`${body.error.code} ${body.error.message}`);
|
||||||
|
return body.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
console.log(`state-window live proof against ${RPC}`);
|
||||||
|
console.log(`run at ${new Date().toISOString()}\n`);
|
||||||
|
|
||||||
|
// Anchor the truth in a block BODY, which is retained at any depth and so does
|
||||||
|
// not itself depend on the world state we are testing.
|
||||||
|
const tx = (await send('eth_getTransactionByHash', [TX_HASH])) as {
|
||||||
|
from: string; nonce: string; blockNumber: string;
|
||||||
|
} | null;
|
||||||
|
if (!tx) {
|
||||||
|
bad('anchor', `the endpoint does not know transaction ${TX_HASH}; cannot proceed`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const deepBlock = Number.parseInt(tx.blockNumber, 16);
|
||||||
|
const trueNonce = Number.parseInt(tx.nonce, 16);
|
||||||
|
const tag = tx.blockNumber;
|
||||||
|
console.log(`ANCHOR block ${deepBlock} body says ${tx.from} signed with nonce ${trueNonce}`);
|
||||||
|
if (tx.from.toLowerCase() !== SIGNER) bad('anchor', `expected ${SIGNER}, block body says ${tx.from}`);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
console.log('STEP 1 PLANTED FAILURE: the raw call must still lie');
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
const rawNonce = await send('eth_getTransactionCount', [SIGNER, tag]);
|
||||||
|
if (rawNonce === '0x0') {
|
||||||
|
ok('eth_getTransactionCount returns a false zero',
|
||||||
|
`result "0x0" at block ${deepBlock}, where the block body proves ${trueNonce}`);
|
||||||
|
} else {
|
||||||
|
bad('eth_getTransactionCount returns a false zero',
|
||||||
|
`expected "0x0", got ${JSON.stringify(rawNonce)}. If this endpoint now answers honestly, ` +
|
||||||
|
`the published documentation must be updated, not this assertion.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawBalance = await send('eth_getBalance', [SIGNER, tag]);
|
||||||
|
if (rawBalance === null) {
|
||||||
|
ok('eth_getBalance is honest at the same block', 'result null, which is a refusal and not a value');
|
||||||
|
} else {
|
||||||
|
bad('eth_getBalance is honest at the same block', `expected null, got ${JSON.stringify(rawBalance)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await send('eth_getProof', [SIGNER, [], tag]).then(
|
||||||
|
() => bad('eth_getProof is honest at the same block', 'it answered; the state window may have changed'),
|
||||||
|
(e: Error) => ok('eth_getProof is honest at the same block', `error ${e.message}`),
|
||||||
|
);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
console.log('STEP 2 NEGATIVE CONTROL: with the guards off, the lie gets through');
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
const unguarded = new StateWindowReader(send, {
|
||||||
|
windowBlocks: 100_000_000, safetyMarginBlocks: 0, corroborateNonce: false,
|
||||||
|
});
|
||||||
|
const leaked = await unguarded.getTransactionCount(SIGNER, deepBlock);
|
||||||
|
if (leaked === 0) {
|
||||||
|
ok('the disabled guard returns 0', `getTransactionCount answered ${leaked}, which is wrong by ${trueNonce}`);
|
||||||
|
} else {
|
||||||
|
bad('the disabled guard returns 0', `expected 0, got ${leaked}; the negative control no longer controls anything`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
console.log('STEP 3 THE GUARD: it refuses instead of guessing');
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
const reader = new StateWindowReader(send);
|
||||||
|
|
||||||
|
await reader.getTransactionCount(SIGNER, deepBlock).then(
|
||||||
|
(v) => bad('pre-flight refuses the deep nonce', `expected a throw, got ${v}`),
|
||||||
|
(e: unknown) =>
|
||||||
|
e instanceof StateWindowError && e.detail.reason === 'requested-block-outside-window'
|
||||||
|
? ok('pre-flight refuses the deep nonce', `StateWindowError ${e.detail.reason}, depth ${e.detail.depth}`)
|
||||||
|
: bad('pre-flight refuses the deep nonce', `wrong error: ${e}`),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Corroboration is the guard that survives a caller who races past pre-flight.
|
||||||
|
const racedPast = new StateWindowReader(send, { windowBlocks: 100_000_000, safetyMarginBlocks: 0 });
|
||||||
|
await racedPast.getTransactionCount(SIGNER, deepBlock).then(
|
||||||
|
(v) => bad('corroboration catches what pre-flight missed', `expected a throw, got ${v}`),
|
||||||
|
(e: unknown) =>
|
||||||
|
e instanceof StateWindowError && e.detail.reason === 'nonce-not-corroborated'
|
||||||
|
? ok('corroboration catches what pre-flight missed', `StateWindowError ${e.detail.reason}, refused value ${e.detail.rawResult}`)
|
||||||
|
: bad('corroboration catches what pre-flight missed', `wrong error: ${e}`),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const [name, call] of [
|
||||||
|
['getBalance', () => reader.getBalance(SIGNER, deepBlock)],
|
||||||
|
['getCode', () => reader.getCode(SIGNER, deepBlock)],
|
||||||
|
['getStorageAt', () => reader.getStorageAt(SIGNER, '0x0', deepBlock)],
|
||||||
|
] as [string, () => Promise<unknown>][]) {
|
||||||
|
await call().then(
|
||||||
|
(v) => bad(`${name} refuses at depth`, `expected a throw, got ${JSON.stringify(v)}`),
|
||||||
|
(e: unknown) =>
|
||||||
|
e instanceof StateWindowError
|
||||||
|
? ok(`${name} refuses at depth`, `StateWindowError ${e.detail.reason}`)
|
||||||
|
: bad(`${name} refuses at depth`, `wrong error: ${e}`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And it still answers where the node can actually answer.
|
||||||
|
const live = await reader.getTransactionCount(SIGNER, 'latest');
|
||||||
|
ok('the reader still answers at latest', `nonce ${live}`);
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
console.log('STEP 4 MEASURE the window rather than trusting the constant');
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
const m = await reader.measureWindow(SIGNER, 100_000);
|
||||||
|
console.log(` head ${m.head}, deepest depth answered ${m.deepestOkDepth}, first depth refused ${m.firstFailDepth}`);
|
||||||
|
if (m.firstFailDepth === 512) {
|
||||||
|
ok('the window is still 512 blocks', `511 answers, 512 does not, measured just now`);
|
||||||
|
} else {
|
||||||
|
bad('the window is still 512 blocks',
|
||||||
|
`measured ${m.firstFailDepth}. This is not necessarily a bug, but every published ` +
|
||||||
|
`number that says 512 is now wrong and must be corrected.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n${failures === 0 ? 'RESULT: PASS' : `RESULT: FAIL, ${failures} check(s)`}`);
|
||||||
|
process.exit(failures === 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => {
|
||||||
|
console.error('live proof aborted:', e);
|
||||||
|
process.exit(2);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user