feat(sdk): ERA faucet claim flow — B3: ticket claim end to end, Req 15.8 registers, faucet-mint machinery deleted - #734
Merged
Conversation
…5.8 registers, faucet-mint machinery deleted The third and final PR of the ERA faucet ticket model (B1 #732 wire/core, B2 #733 node registers). The SDK now drives the complete claim lifecycle: select a ticket deterministically, sign the claim envelope ONCE and freeze the exact bytes before any member write, win the write-once quorum cell, advance the fence-coupled FaucetClaim operation, freeze all four admission artifacts in the accepting transaction, publish evidence attributed to q members, register the economic root, validate with the same predicate any foreign verifier runs, and admit the position durably. - sdk/faucet_claim_flow.rs (new): the orchestration, including resume of a pending admission from any crash boundary using only frozen bytes — nothing is ever re-signed and no timeout aborts an admission. - sdk/economic_registers.rs (new): ticket selection (strategy, not protocol), Req 15.8 attributed quorum counting (generic refused NEVER counts; refused-with-our-digest counts only when attributed), root-cell Contested => Conflict quarantine, live provenance resolver. - sdk/storage_io.rs: seams for register I/O with a cfg(test) fake-register fleet speaking the REAL protocol digests. - storage/client_db: schema v8 (beta wipe policy) — frozen ticket/root claims, admitted coordinate, economic leaf cache written in the admission transaction and admitted only on root equality. - put_immutable_to_all_members now enforces member-echo attribution. - faucet.claim route rewritten to orchestration only; the committed network comes from the stored genesis record, fail closed. check_nearby advertises the fixed 100-ERA payout. - DELETED, not disabled: mint_for_self, era-source-dlv pseudo-identity, build_faucet_protocol_payload, faucet_clean, core/token/faucet.rs plus its cargo feature, FaucetState/FaucetConfig/FaucetLimiter cooldown machinery. V1 has no cooldown/quota; dead paths that know how to mint are what a later edit resurrects. Tests: 5 e2e flow tests over the fake registers (full claim +100 at position 1, repeat claimant, poisoned ticket THROUGH THE WHOLE FLOW, crash resume on frozen bytes, monotonic triple claim); route contract (no stored genesis record fails closed naming it); 5 direct unit controls on the Req 15.8 counting clauses with a compiling mutation control (attribution clause disabled => named test red; restored => green). Boards (pinned 1.98.0, exact final tree): workspace 68 suites 3826/0 (dsm lib 1664/0, dsm_sdk lib 1775/0), dsm_storage_node 264/0, make lint exit 0, production_safety_checks.sh exit 0.
…rofile at launch The literal "mainnet" was only the beta fleet's network label (BETA_NETWORK_ID, client-DB genesis-record default), but it read as a launch-phase claim. Testnet runs before mainnet, so the beta network is renamed to dsm-testnet BEFORE any deployment — the only cheap moment: the network id feeds the GRK derivation, era_faucet_id, and the register profile, so a rename is identity-breaking and free only under the beta wipe policy. The real mainnet is deliberately NOT pre-added: it arrives later as an explicit new profile in resolve_root_register_profile, with its own fresh 800M-ticket / 80B ERA allocation. Nothing claimed on testnet can validate there — different genesis (and thus keys), different faucet id, different register cells. - dsm/economic/register.rs: BETA_NETWORK_ID = b"dsm-testnet"; unknown networks still fail closed. - system.createGenesisV2 default and the frontend genesis literal: dsm-testnet. - client_db: genesis-record DDL default 'dsm-testnet' (schema v8 is unreleased in this PR, amended in place). - storage_node_config.toml: [genesis].network renamed AND the previously undocumented node.network_id gains a documented sample entry — the B2 faucet endpoint fail-closes 503 without it, and a fail-closed gate needs a visible producer. - Tests pinning the resolvable network updated across dsm, dsm_sdk, the node, and the frontend (useGenesisFlow 15/15 under jest); "dsm-test" remains the throwaway fixture network that resolves no profile. Boards (pinned 1.98.0, exact final tree): workspace 68 suites 3826/0 (dsm lib 1664/0, dsm_sdk lib 1775/0), dsm_storage_node 270/0, make lint exit 0, production_safety_checks.sh exit 0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The third and final PR of the ERA faucet ticket model — B1 #732 (wire/core), B2 #733 (node write-once registers), and now the SDK claim flow. After this, a fresh mainnet identity can fund itself: one single-use ticket of the network's finite 800,000,000 × 100 ERA bootstrap allocation, admitted into a validated economic lineage that any foreign verifier can check.
The claim lifecycle (
sdk/faucet_claim_flow.rs, new)Crash recovery is resume-only: a pending admission found at entry is FINISHED from whichever boundary the crash hit, using only durable frozen bytes. Nothing is ever re-signed (deterministic SPHINCS+ makes silent divergence undetectable — so regeneration is made impossible, not discouraged), and no timeout aborts an admission.
Req 15.8 counting (
sdk/economic_registers.rs, new)x-dsm-node-idequals the member queried.refusedNEVER counts toward quorum — it fails the claim closed as contested.refusedcarrying OUR exact digest is an acceptance in different words, with the same attribution bar.Contested ⇒ Conflictquarantine — a cell only this device writes holding foreign bytes is catastrophic, never hash-ordered, never overwritten.put_immutable_to_all_membersnow enforces member-echo attribution (tightened, never loosened).Client DB schema 7 → 8 (beta wipe policy, no migration)
faucet_ticket_claim_local,economic_root_claim_local(frozen sign-once envelopes),economic_admitted(the durable coordinate finally has its producer),economic_leaf_cache(strategy A — written in the admission tx, admitted on load ONLY if it recomputes the admitted root; never an authority).Deletions (dead paths that know how to mint)
mint_for_self, theera-source-dlvkeyless pseudo-identity,build_faucet_protocol_payload,faucet_clean,core/token/faucet.rs+ itsfaucetcargo feature, and the wholeFaucetState/FaucetConfig/FaucetLimitercooldown machinery — V1 deliberately has no cooldown or quota, and keeping the machinery would define policy V1 lacks. The route is orchestration only; the committed network comes from the STORED genesis record, fail closed.Tests
check_nearbyadvertises the fixed payout.an_unattributed_acceptance_never_countsred; restored ⇒ green.Boards (pinned 1.98.0, rerun in full on the exact final tree after the rename)
The beta network is
dsm-testnet(second commit, owner-directed)Testnet runs before mainnet, so the literal network id the beta system serves is renamed
"mainnet"→dsm-testnetacross every normative site (register profile,createGenesisV2default, client-DB DDL default, frontend genesis literal, node sample config) plus every test pinning the resolvable network. The rename is identity-breaking — the network id feeds the GRK derivation,era_faucet_id, and the register profile — which is exactly why it happens NOW, pre-deployment, under the beta wipe policy.The real mainnet is deliberately not pre-added: it arrives at launch as an explicit new profile with its own fresh 800M-ticket / 80B allocation. Nothing claimed on testnet can validate there.
dsm-test(no "net") remains the throwaway fixture network that resolves no profile.Deployment note
Live fleet nodes need
node.network_id = "dsm-testnet"in their config before faucet claims will be accepted (B2's fail-closed 503 otherwise). A documented sample entry now exists instorage_node_config.toml.Documented residuals (unchanged from the frozen plan)
V1 promises conservation, not fairness: unlimited public claims may burn the per-network allocation, and selection is publicly predictable, so targeted pre-consumption of a victim's upcoming tickets is possible — it breaks neither the 80B cap nor faucet-wide liveness.