fast-time: program_class_v3_activation_daa in both override files (never), the README row, and class-v3.mjs, the rollout gate G4 script
class-v3.mjs: a 3-node private network (ports 29600 and up, igneum-devnet-960) on override-60x.json merged with a CPU genesis difficulty (0x1f010000) and the class switch a few epochs ahead (default 150: inside epoch 2 at 60 DAA per epoch, so the switch rounds up to epoch 3 at DAA 180); one real CPU miner per node; reports blocks on each side of the boundary, the class and program id of every epoch, rejected blocks (miners and nodes), the sinks and block counts of every node, and every node's switch line; exit 0 when every check passes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
9ed787e33b
commit
464d6e140f
4 changed files with 215 additions and 1 deletions
|
|
@ -24,6 +24,12 @@ simulator takes the same file: `igneum-harness-sim --override-params-file infra/
|
|||
Proof script: `node infra/fast-time/simnet.mjs` (3 nodes on ports 29500 and up, `igneum-devnet-950`, data
|
||||
`/tmp/igneum-fast-time`; records the first lock and the first program swap; see "Measured" below).
|
||||
|
||||
Class switch gate (Counter ASIC 2.0 rollout G4): `node infra/fast-time/class-v3.mjs` (3 nodes on ports 29600 and up,
|
||||
`igneum-devnet-960`, data `/tmp/igneum-fast-time-v3`, CPU difficulty `genesis_bits` 0x1f010000, real CPU mining on
|
||||
every node, `program_class_v3_activation_daa` a few epochs ahead; reports blocks on both sides of the boundary, the
|
||||
program id and class before and after, rejected blocks, forks, and every node's switch line; see
|
||||
`docs/plans/counter-asic-2-node.md`).
|
||||
|
||||
Miners: `igneum-miner` follows the epoch length and lead its node reports in every template (`pow_epoch`), no flag.
|
||||
The dataset day is not in the template, so a real-hash miner on a fast-time network takes `IGNEUM_POW_DAY_MS=1440000`
|
||||
in its environment (the node reads it from the file). The environment variables `IGNEUM_POW_EPOCH_BLOCKS`,
|
||||
|
|
@ -51,6 +57,7 @@ Time parameters, divided by 60 (devnet value, 60x value):
|
|||
| `difficulty_v2_activation_daa` | never (`18446744073709551615`) | never | a height, not a clock: difficulty rule v2 (4 Oct 2026, `docs/analysis/difficulty-2026-10-04-oscillation.md`) switches on at this DAA score; a test network sets it in its merged file (`sim/difficulty/testnet_v2.py` uses 900) |
|
||||
| `proving_v0_activation_daa` | never | never | a height: proving v0 payouts (spec 7.7) switch on at this DAA score; `tools/proving-v0/run.mjs` sets 60 in its merged file |
|
||||
| `finality_v3_activation_daa` | never | never | a height, not a clock: finality rule v3 (the frozen weight table of ledger F21 and the certificate fold of F22, 4 Oct 2026 evening) applies to checkpoints at or above this DAA score; `tools/finality-attacks/v3.mjs` sets 0 in its merged file |
|
||||
| `program_class_v3_activation_daa` | never | never | a height, not a clock: the lottery hash draws programs from class v3 (Counter ASIC 2.0, 5 Oct 2026) from the first EPOCH whose start is at or above this DAA score (rounded up to an epoch boundary: at 60 DAA per epoch, 150 means epoch 3 at DAA 180); `infra/fast-time/class-v3.mjs` sets it a few epochs ahead in its merged file |
|
||||
|
||||
Unchanged, and why:
|
||||
|
||||
|
|
|
|||
206
infra/fast-time/class-v3.mjs
Normal file
206
infra/fast-time/class-v3.mjs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
#!/usr/bin/env node
|
||||
// Counter ASIC 2.0 rollout gate G4 (docs/plans/counter-asic-2-rollout.md section 7): the fast-time 3-node network
|
||||
// mining across a program class v3 activation. A private network on 127.0.0.1 ports 29600 and up, data under
|
||||
// /tmp/igneum-fast-time-v3, network id igneum-devnet-960, every node on infra/fast-time/override-60x.json merged with
|
||||
// a CPU genesis difficulty (genesis_bits 0x1f010000, 2^16 hashes per block, as sim/difficulty/testnet_v2.py) and
|
||||
// `program_class_v3_activation_daa` a few epochs ahead (default 150: inside epoch 2 at 60 DAA per epoch, so the
|
||||
// switch rounds UP to epoch 3 at DAA 180, which is the boundary rule under test). One real CPU miner per node
|
||||
// (igneum-miner --engine igneum-pow, 1 thread) follows its node's templates, so every block of the run is a real
|
||||
// lottery-hash solution and every node verifies every block of the other two under the class of its epoch.
|
||||
//
|
||||
// Reports, from the nodes' RPC and the logs: blocks on each side of the boundary, the program class and id of every
|
||||
// epoch (before and after), rejected blocks (the miners' submit answers and the nodes' "PoW rejected" lines), forks
|
||||
// (every node's sink, selected tip and block count at the end), and every node's switch line. Exit 0 when every
|
||||
// check passes. Never touches the live devnet (26610/26611, 26640/26641, 28640) or the simnet.mjs ports.
|
||||
//
|
||||
// node infra/fast-time/class-v3.mjs [--secs 420] [--activation 150] [--epochs-after 2] [--threads 1]
|
||||
// IGNEUMD and IGNEUM_MINER name the binaries (default: the ca2 fork worktree's target-ca2/release).
|
||||
|
||||
import { spawn } from 'node:child_process';
|
||||
import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync } from 'node:fs';
|
||||
import { connectRpc } from '../../tools/finality-attacks/lib/rpc.mjs';
|
||||
import { devAddress } from '../../tools/harness/lib/address.mjs';
|
||||
|
||||
const ROOT = new URL('../../', import.meta.url).pathname;
|
||||
const FILE = `${ROOT}infra/fast-time/override-60x.json`;
|
||||
const BIN = process.env.IGNEUM_CA2_BIN || `${ROOT}vendor/igneum-node-ca2/target-ca2/release`;
|
||||
const IGNEUMD = process.env.IGNEUMD || `${BIN}/igneumd`;
|
||||
const CPU_MINER = process.env.IGNEUM_MINER || `${BIN}/igneum-miner`;
|
||||
const TMP = '/tmp/igneum-fast-time-v3';
|
||||
const BASE = 29600, SUFFIX = 960;
|
||||
const GENESIS_BITS = 0x1f010000;
|
||||
const args = process.argv.slice(2);
|
||||
const flag = (name, dflt) => { const i = args.indexOf(`--${name}`); return i >= 0 ? +args[i + 1] : dflt; };
|
||||
const SECS = flag('secs', 420);
|
||||
const ACTIVATION = flag('activation', 150);
|
||||
const EPOCHS_AFTER = flag('epochs-after', 2);
|
||||
const THREADS = flag('threads', 1);
|
||||
const started = [];
|
||||
const log = (...a) => console.log(new Date().toISOString().slice(11, 23), ...a);
|
||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
for (const b of [IGNEUMD, CPU_MINER]) if (!existsSync(b)) { console.error(`missing ${b}`); process.exit(2); }
|
||||
|
||||
rmSync(TMP, { recursive: true, force: true }); mkdirSync(TMP, { recursive: true });
|
||||
const base = JSON.parse(readFileSync(FILE, 'utf8'));
|
||||
const EPOCH = base.pow_epoch_blocks;
|
||||
const FIRST_V3_EPOCH = Math.ceil(ACTIVATION / EPOCH);
|
||||
const BOUNDARY = FIRST_V3_EPOCH * EPOCH;
|
||||
const override = `${TMP}/override.json`;
|
||||
writeFileSync(override, JSON.stringify({ ...base, genesis_bits: GENESIS_BITS, skip_proof_of_work: false, program_class_v3_activation_daa: ACTIVATION }));
|
||||
log(`activation ${ACTIVATION} at ${EPOCH} DAA per epoch: the first v3 epoch is ${FIRST_V3_EPOCH} (DAA ${BOUNDARY}); run ${SECS} s, CPU genesis bits 0x${GENESIS_BITS.toString(16)}`);
|
||||
|
||||
class Node {
|
||||
constructor(i, connect = []) {
|
||||
this.i = i; this.grpcPort = BASE + i * 10; this.p2pPort = BASE + i * 10 + 1; this.jsonPort = BASE + i * 10 + 2;
|
||||
this.connect = connect; this.dir = `${TMP}/n${i}`; this.logFile = `${this.dir}/node.log`;
|
||||
}
|
||||
get grpc() { return `grpc://127.0.0.1:${this.grpcPort}`; }
|
||||
async start() {
|
||||
mkdirSync(this.dir, { recursive: true });
|
||||
const a = ['--devnet', `--devnet-suffix=${SUFFIX}`, '--nodnsseed', '--disable-upnp', '--nologfiles', '--enable-unsynced-mining', '--utxoindex',
|
||||
`--appdir=${this.dir}`, `--rpclisten=127.0.0.1:${this.grpcPort}`, `--rpclisten-json=127.0.0.1:${this.jsonPort}`,
|
||||
`--listen=127.0.0.1:${this.p2pPort}`, `--override-params-file=${override}`, '--loglevel=info', '--yes'];
|
||||
if (this.connect.length) a.push(`--connect=${this.connect.join(',')}`); else a.push('--outpeers=0');
|
||||
const out = openSync(this.logFile, 'a');
|
||||
this.proc = spawn(IGNEUMD, a, { stdio: ['ignore', out, out] });
|
||||
started.push(this.proc);
|
||||
await sleep(1200);
|
||||
this.rpc = await connectRpc(`ws://127.0.0.1:${this.jsonPort}`);
|
||||
log(`n${this.i} up pid ${this.proc.pid} json ${this.jsonPort} p2p ${this.p2pPort}`);
|
||||
return this;
|
||||
}
|
||||
grepLog(re) { try { return readFileSync(this.logFile, 'utf8').split('\n').filter(l => re.test(l)); } catch { return []; } }
|
||||
}
|
||||
function miner(bin, argv, name, env = {}) {
|
||||
const out = openSync(`${TMP}/${name}.log`, 'a');
|
||||
const p = spawn(bin, argv, { stdio: ['ignore', out, out], env: { ...process.env, ...env } });
|
||||
started.push(p);
|
||||
return p;
|
||||
}
|
||||
async function stopAll() {
|
||||
for (const p of started.reverse()) { try { p.kill('SIGINT'); } catch { } }
|
||||
await sleep(1500);
|
||||
for (const p of started) { try { p.kill('SIGKILL'); } catch { } }
|
||||
}
|
||||
process.on('SIGINT', async () => { await stopAll(); process.exit(130); });
|
||||
const minerLog = (i) => { try { return readFileSync(`${TMP}/cpu${i}.log`, 'utf8').split('\n'); } catch { return []; } };
|
||||
|
||||
const t0 = Date.now();
|
||||
const since = () => ((Date.now() - t0) / 1000).toFixed(1);
|
||||
const n0 = await new Node(0).start();
|
||||
const n1 = await new Node(1, [`127.0.0.1:${n0.p2pPort}`]).start();
|
||||
const n2 = await new Node(2, [`127.0.0.1:${n0.p2pPort}`, `127.0.0.1:${n1.p2pPort}`]).start();
|
||||
const nodes = [n0, n1, n2];
|
||||
for (const n of nodes) {
|
||||
const line = n.grepLog(/Program class v3 from the override file/)[0];
|
||||
log(`n${n.i} switch line: ${line ? line.replace(/^.*?(Program class v3)/, '$1') : '(none)'}`);
|
||||
}
|
||||
log(`n0 PoW schedule: ${n0.grepLog(/PoW schedule from the override file/).map(l => l.replace(/^.*?(PoW schedule)/, '$1')).join(' | ') || '(no line)'}`);
|
||||
log(`n0 digest: ${n0.grepLog(/Consensus params digest/).map(l => l.replace(/^.*?digest: /, '').slice(0, 16)).join(' ')}`);
|
||||
|
||||
// one real CPU miner per node, 1 thread, 2^16 expected hashes per block at genesis
|
||||
nodes.forEach((n, i) => miner(CPU_MINER, ['mine', n.grpc, String(THREADS), String(SECS), `cpu${i}`, '--engine', 'igneum-pow', '--payout-label', `cpu${i}`, '--status-secs', '30', '--no-vote'], `cpu${i}`, { IGNEUM_POW_DAY_MS: String(base.pow_day_ms) }));
|
||||
const pay = devAddress('fast-time-v3');
|
||||
|
||||
const epochs = new Map(); // epoch index -> { class, firstSeenDaa, at }
|
||||
let firstV3 = null, lastEpoch = -1, lastReport = 0, lastDaa = 0, switchEnd = null;
|
||||
const samples = [];
|
||||
while (Date.now() - t0 < SECS * 1000) {
|
||||
await sleep(1000);
|
||||
let daa = null, epoch = null, cls = null, nextCls = null, era = null, eraSeed = null, act = null;
|
||||
try {
|
||||
const t = await n0.rpc.call('getBlockTemplate', { payAddress: pay, extraData: [] });
|
||||
const pe = t.powEpoch || t.pow_epoch || {};
|
||||
daa = pe.virtualDaaScore ?? t.block?.header?.daaScore; epoch = pe.epochIndex; cls = pe.programClass; nextCls = pe.nextProgramClass;
|
||||
era = pe.eraIndex; eraSeed = pe.eraSeed; act = pe.programClassV3ActivationDaa;
|
||||
} catch (e) { log(`template: ${e.message}`); }
|
||||
if (epoch != null && epoch !== lastEpoch) {
|
||||
epochs.set(epoch, { class: cls, firstSeenDaa: daa, at: +since() });
|
||||
log(`epoch ${lastEpoch} -> ${epoch} at daa ${daa}, ${since()} s: template class ${cls} (generator), next epoch class ${nextCls}, era ${era} seed ${String(eraSeed).slice(0, 16)}, activation ${act}`);
|
||||
if (firstV3 == null && cls === 3) { firstV3 = { epoch, daa, at: +since() }; log(`CLASS SWITCH: the template is class v3 from epoch ${epoch} (daa ${daa}) at ${since()} s wall`); }
|
||||
lastEpoch = epoch;
|
||||
}
|
||||
lastDaa = daa ?? lastDaa;
|
||||
if (Date.now() - lastReport > 15000) {
|
||||
lastReport = Date.now();
|
||||
const counts = await Promise.all(nodes.map(async n => { try { const d = await n.rpc.call('getBlockDagInfo'); return `${d.blockCount}/${String(d.sink).slice(0, 8)}`; } catch { return '?'; } }));
|
||||
log(`t=${since()} s daa ${daa} epoch ${epoch} class ${cls} blocks/sink per node ${counts.join(' ')}`);
|
||||
samples.push({ t: +since(), daa, epoch, class: cls, nodes: counts });
|
||||
}
|
||||
if (firstV3 != null && daa != null && daa >= BOUNDARY + EPOCHS_AFTER * EPOCH) { switchEnd = +since(); break; }
|
||||
}
|
||||
await sleep(3000); // let the last blocks relay before the end-of-run reads
|
||||
|
||||
// ---- the end-of-run reads -----------------------------------------------------------------------------------------
|
||||
const dag = await Promise.all(nodes.map(async n => { try { return await n.rpc.call('getBlockDagInfo'); } catch (e) { return { error: e.message }; } }));
|
||||
const genesis = dag[0].pruningPointHash;
|
||||
// every block the first node holds, by DAA score, from genesis
|
||||
async function allBlocks(n) {
|
||||
const out = []; let low = genesis; const seen = new Set();
|
||||
for (let round = 0; round < 500; round++) {
|
||||
const r = await n.rpc.call('getBlocks', { lowHash: low, includeBlocks: true, includeTransactions: false });
|
||||
const blocks = r.blocks || [];
|
||||
let added = 0;
|
||||
for (const b of blocks) { const h = b.verboseData?.hash || b.header?.hash; if (seen.has(h)) continue; seen.add(h); out.push({ hash: h, daa: +b.header.daaScore, chain: !!b.verboseData?.isChainBlock, blue: +(b.verboseData?.blueScore ?? 0) }); added++; }
|
||||
if (!blocks.length || added === 0) break;
|
||||
low = (r.blockHashes || []).at(-1) || blocks.at(-1).verboseData?.hash; if (!low) break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
let blocks = [];
|
||||
try { blocks = await allBlocks(n0); } catch (e) { log(`getBlocks: ${e.message}`); }
|
||||
const before = blocks.filter(b => b.daa < BOUNDARY), after = blocks.filter(b => b.daa >= BOUNDARY);
|
||||
const chainBefore = before.filter(b => b.chain).length, chainAfter = after.filter(b => b.chain).length;
|
||||
|
||||
// program ids and classes per epoch from the miners' "program and 256 MiB cache ready" lines
|
||||
const programs = new Map(); // epoch seed -> { class, id, miners: Set }
|
||||
for (const i of [0, 1, 2]) for (const l of minerLog(i)) {
|
||||
const m = /epoch seed ([0-9a-f]{64}) day (\d+) \(daa (\d+)\): program and 256 MiB cache ready in [\d.]+ ms; class (v\d) program id ([0-9a-f]{16})/.exec(l);
|
||||
if (!m) continue;
|
||||
const k = m[1]; const e = programs.get(k) || { seed: k.slice(0, 16), epoch: Math.floor(+m[3] / EPOCH), class: m[4], id: m[5], miners: new Set() };
|
||||
if (e.id !== m[5] || e.class !== m[4]) e.disagree = true;
|
||||
e.miners.add(i); programs.set(k, e);
|
||||
}
|
||||
const programRows = [...programs.values()].sort((a, b) => a.epoch - b.epoch).map(p => ({ epoch: p.epoch, class: p.class, program_id: p.id, seed: p.seed, miners: p.miners.size, disagree: !!p.disagree }));
|
||||
const v2Ids = programRows.filter(p => p.class === 'v2').map(p => p.program_id), v3Ids = programRows.filter(p => p.class === 'v3').map(p => p.program_id);
|
||||
|
||||
// rejections: the miners' submit answers and the nodes' PoW lines
|
||||
const accepted = [0, 1, 2].map(i => minerLog(i).filter(l => /ACCEPTED block/.test(l)).length);
|
||||
const rejectedMiner = [0, 1, 2].map(i => minerLog(i).filter(l => /rejected nonce=|submit error/.test(l)));
|
||||
const rejectedNode = nodes.map(n => n.grepLog(/PoW rejected|Rejected block|rejected block/i));
|
||||
const switchLines = nodes.map(n => n.grepLog(/Program class v3 from the override file/).map(l => l.replace(/^.*?(Program class v3)/, '$1'))[0] || null);
|
||||
const sinks = dag.map(d => String(d.sink || '?').slice(0, 16));
|
||||
const counts = dag.map(d => d.blockCount ?? '?');
|
||||
const tips = dag.map(d => (d.tipHashes || []).length);
|
||||
|
||||
const checks = {
|
||||
switch_line_on_every_node: switchLines.every(Boolean),
|
||||
switch_line_names_the_rounded_epoch: switchLines.every(l => l && l.includes(`active from epoch ${FIRST_V3_EPOCH} `)),
|
||||
template_switched_at_the_first_v3_epoch: firstV3 != null && firstV3.epoch === FIRST_V3_EPOCH,
|
||||
blocks_before_the_boundary: before.length > 0,
|
||||
blocks_after_the_boundary: after.length > 0,
|
||||
v2_and_v3_programs_seen: v2Ids.length > 0 && v3Ids.length > 0,
|
||||
program_ids_differ_across_the_switch: v2Ids.length > 0 && v3Ids.length > 0 && !v2Ids.some(id => v3Ids.includes(id)),
|
||||
miners_agree_on_every_program: programRows.every(p => !p.disagree),
|
||||
zero_rejected_by_miners: rejectedMiner.every(r => r.length === 0),
|
||||
zero_rejected_by_nodes: rejectedNode.every(r => r.length === 0),
|
||||
sinks_agree: new Set(sinks).size === 1,
|
||||
block_counts_agree: new Set(counts.map(String)).size === 1,
|
||||
};
|
||||
const pass = Object.values(checks).every(Boolean);
|
||||
const summary = {
|
||||
pass, checks, activation: ACTIVATION, epoch_blocks: EPOCH, first_v3_epoch: FIRST_V3_EPOCH, boundary_daa: BOUNDARY, secs: SECS, threads: THREADS,
|
||||
node: IGNEUMD, miner: CPU_MINER, genesis_bits: `0x${GENESIS_BITS.toString(16)}`,
|
||||
template_switch: firstV3, run_ended_at_s: switchEnd, final_daa: lastDaa,
|
||||
blocks: { total: blocks.length, before_boundary: before.length, after_boundary: after.length, chain_before: chainBefore, chain_after: chainAfter },
|
||||
programs: programRows, accepted_per_miner: accepted,
|
||||
rejected_by_miners: rejectedMiner.map(r => r.length), rejected_by_nodes: rejectedNode.map(r => r.length),
|
||||
rejected_lines: [...rejectedMiner.flat(), ...rejectedNode.flat()].slice(0, 20),
|
||||
sinks, block_counts: counts, tips_per_node: tips, switch_lines: switchLines, samples,
|
||||
};
|
||||
writeFileSync(`${TMP}/summary.json`, JSON.stringify(summary, null, 2));
|
||||
log(`SUMMARY ${pass ? 'PASS' : 'FAIL'}: blocks ${before.length} before / ${after.length} after the boundary at DAA ${BOUNDARY} (chain ${chainBefore} / ${chainAfter}); programs ${programRows.map(p => `e${p.epoch}:${p.class}:${p.program_id}`).join(' ')}; rejected miners ${rejectedMiner.map(r => r.length).join('/')} nodes ${rejectedNode.map(r => r.length).join('/')}; sinks ${sinks.join(' ')} (${checks.sinks_agree ? 'agree' : 'DIFFER'}); block counts ${counts.join('/')}; switch lines ${switchLines.filter(Boolean).length}/3`);
|
||||
for (const [k, v] of Object.entries(checks)) if (!v) log(`FAILED CHECK ${k}`);
|
||||
log(`summary: ${TMP}/summary.json`);
|
||||
await stopAll();
|
||||
process.exit(pass ? 0 : 1);
|
||||
|
|
@ -54,6 +54,7 @@
|
|||
"difficulty_v2_activation_daa": 18446744073709551615,
|
||||
"proving_v0_activation_daa": 18446744073709551615,
|
||||
"finality_v3_activation_daa": 18446744073709551615,
|
||||
"program_class_v3_activation_daa": 18446744073709551615,
|
||||
"fees_v1_activation_daa": 0,
|
||||
"fees": {"pgas": {"version": 1, "cycles_per_pgas": 1000, "intrinsic_pgas_per_tx": 300, "modexp_base": 10, "modexp_per_byte_numer": 1, "modexp_per_byte_denom": 10}, "block_proving_gas_limit": 120000, "shard_proving_gas_budget": 30000, "min_execution_base_fee_wei": 100000000000, "min_proving_base_fee_wei": 10000000000000, "initial_execution_base_fee_wei": 100000000000, "initial_proving_base_fee_wei": 10000000000000, "base_fee_change_denominator": 8}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"timestamp_deviation_tolerance": 132, "past_median_time_window_size": 27, "difficulty_window_size": 661, "min_difficulty_window_size": 150, "difficulty_rule": "igneum-dual", "coinbase_payload_script_public_key_max_len": 150, "max_coinbase_payload_len": 16384, "max_tx_inputs": 1000, "max_tx_outputs": 1000, "max_signature_script_len": 250000, "max_script_public_key_len": 10000, "mass_per_tx_byte": 1, "mass_per_script_pub_key_byte": 10, "mass_per_sig_op": 1000, "block_mass_limits": {"compute": 500000, "storage": 500000, "transient": 1000000}, "block_lane_limits": {"lanes_per_block": 50, "gas_per_lane": 1000000000}, "storage_mass_parameter": 1000000000000, "deflationary_phase_daa_score": 0, "pre_deflationary_phase_base_subsidy": 50000000000, "skip_proof_of_work": false, "max_block_level": 250, "pruning_proof_m": 1000, "blockrate": {"target_time_per_block": 1000, "ghostdag_k": 18, "past_median_time_sample_rate": 10, "difficulty_sample_rate": 4, "max_block_parents": 10, "mergeset_size_limit": 180, "merge_depth": 60, "finality_depth": 720, "pruning_depth": 13838, "coinbase_maturity": 2}, "pre_crescendo_target_time_per_block": 1000, "crescendo_activation": 0, "genesis_bits": 487587840, "finality": {"checkpoint_interval": 30, "checkpoint_depth": 20, "weight_window": 120, "dust": 5, "presence_window": 1, "aggregators": 8, "equivocation_ban": 120, "min_daa": 120, "aggregator_fallback": 1}, "pow_epoch_blocks": 60, "pow_epoch_lead": 10, "pow_day_ms": 1440000, "finality_v3_activation_daa": 0}
|
||||
{"timestamp_deviation_tolerance": 132, "past_median_time_window_size": 27, "difficulty_window_size": 661, "min_difficulty_window_size": 150, "difficulty_rule": "igneum-dual", "coinbase_payload_script_public_key_max_len": 150, "max_coinbase_payload_len": 16384, "max_tx_inputs": 1000, "max_tx_outputs": 1000, "max_signature_script_len": 250000, "max_script_public_key_len": 10000, "mass_per_tx_byte": 1, "mass_per_script_pub_key_byte": 10, "mass_per_sig_op": 1000, "block_mass_limits": {"compute": 500000, "storage": 500000, "transient": 1000000}, "block_lane_limits": {"lanes_per_block": 50, "gas_per_lane": 1000000000}, "storage_mass_parameter": 1000000000000, "deflationary_phase_daa_score": 0, "pre_deflationary_phase_base_subsidy": 50000000000, "skip_proof_of_work": false, "max_block_level": 250, "pruning_proof_m": 1000, "blockrate": {"target_time_per_block": 1000, "ghostdag_k": 18, "past_median_time_sample_rate": 10, "difficulty_sample_rate": 4, "max_block_parents": 10, "mergeset_size_limit": 180, "merge_depth": 60, "finality_depth": 720, "pruning_depth": 13838, "coinbase_maturity": 2}, "pre_crescendo_target_time_per_block": 1000, "crescendo_activation": 0, "genesis_bits": 487587840, "finality": {"checkpoint_interval": 30, "checkpoint_depth": 20, "weight_window": 120, "dust": 5, "presence_window": 1, "aggregators": 8, "equivocation_ban": 120, "min_daa": 120, "aggregator_fallback": 1}, "pow_epoch_blocks": 60, "pow_epoch_lead": 10, "pow_day_ms": 1440000, "finality_v3_activation_daa": 0, "program_class_v3_activation_daa": 18446744073709551615}
|
||||
Loading…
Reference in a new issue