docs(sec): SEC-16 — безвозвратная утечка ренты PDA-ставки с кошелька игрока
Найдено при приёмке боевого домена smart-updown.binom.pw (симптом «SOL не обновляется»). - SEC-16: при create_bet ренту PDA-аккаунта ставки (1 559 040 lamports = (96+32+128)*6960) платит БЕТТОР, а не шлюз; баланс шлюза-админа при этом не меняется (замер whose-fee.cjs). Аккаунт не закрывается никогда (в контракте 9ALs четыре инструкции, ни одной close = bettor) → рента теряется безвозвратно. В цепи 75 аккаунтов = 0.116928 SOL заперто, растёт линейно. Вердикт: на тестах терпимо (маскируется краном, 5 SOL = ~3207 раундов), перед mainnet — блокер. - TASKS.md: фича «если цена не изменилась — подождать ещё 15 с» (НЕ доделана), заметка про боевой домен на общем TS-шлюзе и лаг крана 8–13 с. - tools: доказательные скрипты (whose-fee, bet-pda-rent, faucet-latency, sol-balance-cycle, settle-math-test, backend-full-test) + README с питфоллами замера. - k8s/smart-updown-api-ingress.yaml: /api,/ws вынесены вне helm (релиз игры их сносил).
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env node
|
||||
// Замер: сколько времени кран зачисляет SOL на цепь (и почему фронт видит 0).
|
||||
const B = "https://smart-updown.binom.pw/api";
|
||||
const RPC = "https://smart-updown.binom.pw/solana-rpc/";
|
||||
const WebSocket = require(process.env.WS_MODULE || "ws");
|
||||
|
||||
const j = async (p, init) => {
|
||||
const r = await fetch(B + p, init);
|
||||
return { s: r.status, d: await r.json().catch(() => null) };
|
||||
};
|
||||
const rpcBal = async (a) => {
|
||||
const r = await fetch(RPC, {
|
||||
method: "POST", headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getBalance", params: [a] }),
|
||||
});
|
||||
return (await r.json()).result.value;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
const w = await j("/wallet", { method: "POST" });
|
||||
const addr = w.d.address;
|
||||
console.log("адрес:", addr);
|
||||
|
||||
const t0 = Date.now();
|
||||
const f = await j(`/faucet/${addr}`);
|
||||
console.log(`кран ответил: ${f.s} sol=${f.d.sol} (t=${Date.now() - t0}ms)`);
|
||||
console.log("\nвремя_от_крана RPC_баланс шлюз_sol");
|
||||
for (const wait of [0, 250, 500, 1000, 2000, 4000, 8000, 16000, 30000]) {
|
||||
while (Date.now() - t0 < wait) await new Promise((r) => setTimeout(r, 50));
|
||||
const chain = await rpcBal(addr);
|
||||
const gw = await j(`/balance/${addr}`);
|
||||
console.log(`${String(Date.now() - t0).padStart(9)}ms ${String(chain).padStart(14)} ${String(gw.d && gw.d.sol).padStart(12)}`);
|
||||
if (chain > 0 && Date.now() - t0 > 3000) break;
|
||||
}
|
||||
process.exit(0);
|
||||
})();
|
||||
Reference in New Issue
Block a user