igneum/tools/harness/lib/address.mjs
igneum-labs 18f6cddd4e Harness: consensus attack catalogue runner and first results
tools/harness runs the standard consensus-attack catalogue against a private
test network of our own igneumd nodes (127.0.0.1 ports 27200+, /tmp/igneum-harness,
never the live devnet or the PC node), with a pass criterion per scenario from the
spec and a measured result each. Built on the node fork's own crates
(igneum-harness-sim on kaspa_utils::sim as simpa does; igneum-p2p-probe for the
wire). Scenarios: 1 withholding, 2 timestamp edges and drift, 3 partition and heal,
4 eclipse, 5 malformed and boundary inputs on every p2p and RPC surface, 6 resource
exhaustion, 7 fast-miner flood. Finality and difficulty-controller scenarios are
stubs with their criteria written.

bench-log: one dated entry, a row per scenario (criterion, measured, pass or fail).
First run: 19 of 20 measured rows pass. Findings recorded in the entry: scenario 5
reproduces ledger M15 on HEAD (bogus past-day or DAA headers build a 256 MiB cache
before rejection; the r3-fixes branch removes it); scenario 1 at 45% hash with
burst withholding shows a selfish-mining blue-share gain (50.7% of blues), the one
failing row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 22:17:37 +00:00

36 lines
1.5 KiB
JavaScript

// Kaspa-style address encoder (copied from tools/observer/observer.mjs). Devnet prefix is igneumdev.
const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
function polymod(values) {
let c = 1n;
for (const d of values) {
const c0 = c >> 35n;
c = ((c & 0x07ffffffffn) << 5n) ^ BigInt(d);
if (c0 & 0x01n) c ^= 0x98f2bc8e61n;
if (c0 & 0x02n) c ^= 0x79b76d99e2n;
if (c0 & 0x04n) c ^= 0xf33e5fb3c4n;
if (c0 & 0x08n) c ^= 0xae2eabe2a8n;
if (c0 & 0x10n) c ^= 0x1e4f43e470n;
}
return c ^ 1n;
}
function conv8to5(bytes) {
const out = []; let buff = 0, bits = 0;
for (const b of bytes) {
buff = ((buff << 8) | b) & 0xffff; bits += 8;
while (bits >= 5) { bits -= 5; out.push((buff >> bits) & 31); buff &= (1 << bits) - 1; }
}
if (bits > 0) out.push((buff << (5 - bits)) & 31);
return out;
}
export function encodeAddress(prefix, version, payload) {
const five = conv8to5([version, ...payload]);
const pre = [...prefix].map(ch => ch.charCodeAt(0) & 0x1f);
const sum = polymod([...pre, 0, ...five, 0, 0, 0, 0, 0, 0, 0, 0]);
const sumBytes = []; for (let i = 4; i >= 0; i--) sumBytes.push(Number((sum >> BigInt(i * 8)) & 0xffn));
return `${prefix}:${[...five, ...conv8to5(sumBytes)].map(v => CHARSET[v]).join('')}`;
}
/// A deterministic devnet pay address for a miner label (32-byte payload from the label).
export function devAddress(label = 'harness') {
const payload = Array.from({ length: 32 }, (_, i) => (label.charCodeAt(i % label.length) * (i + 1)) & 0xff);
return encodeAddress('igneumdev', 0, payload);
}