Skip to content

sgns::PruneEligibility

Read-only prune-eligibility evaluator (PRUNE-01, GATE-01). More...

#include <PruneEligibility.hpp>

Public Functions

Name
outcome::result< std::shared_ptr< PruneEligibility > > New(crdt::GlobalDB & globaldb, TransactionManager & transaction_manager, UTXOManager & utxo_manager, NodeType node_type, const PruningConfig & config)
Fail-closed factory (the construction gate).
std::string BuildPruneMarkerKey(const std::string & tx_hash)
Builds the node-local marker key for tx_hash.
outcome::result< std::pair< PrunedLookup, std::optional< SGTransaction::PrunedTransactionRecord > > > LookupPrunedEntry(crdt::GlobalDB & db, const std::string & tx_hash)
Answers "was this transaction's history pruned here?" (D-04).
std::pair< base::Buffer, base::Buffer > BuildPruneMarkerEntry(const std::string & tx_hash, const std::string & resolved_tx_path)
Builds the production marker entry for tx_hash (D-C1).
outcome::result< void > WritePrunedEntryForTest(crdt::GlobalDB & db, const std::string & tx_hash, const SGTransaction::PrunedTransactionRecord & record)
TEST-ONLY marker writer (the D-04 test seam).
bool IsAllowlistedTxKey(const std::string & key) const
THE allowlist (D-C7): exact /bc-/tx/ prefix membership.
outcome::result< PruneEvaluationResult > Evaluate() const
Enumerates and evaluates every candidate (read-only).
outcome::result< BlockGateResult > EvaluateDeltaBlockErasable(const std::string & cid_string, const PruneEvaluationResult & eligible) const
THE multi-element block gate (PRUNE-03, D-C3).

Public Attributes

Name
constexpr std::string_view PRUNE_MARKER_PREFIX

Detailed Description

class sgns::PruneEligibility;

Read-only prune-eligibility evaluator (PRUNE-01, GATE-01).

PURE evaluator (D-C6): it runs on committed state only — driven from a timer cycle by the caller, NEVER from CRDT element callbacks (they fire pre-batch-commit). It performs ZERO writes: no Put, no Erase, no staging, no hooks. The Phase-18 TxPruner is the reuse seam — it calls Evaluate() verbatim and owns every mutation.

Gates:

  • Construction fails closed unless NodeType is Light (GATE-01 role gate; full/archive never erase history).
  • IsAllowlistedTxKey is the ONE allowlist home (D-C7): exact base + "tx/" prefix over monitored networks only, with the trailing slash (a slashless prefix would also match /bc-/txfoo siblings).
  • Evaluate fails closed with std::errc::invalid_argument when no finality_window is configured.
  • EvaluateDeltaBlockErasable is the PRUNE-03 gate: a block erases only when every element AND tombstone key it carries is eligible and allowlist-conformant, parsed from the block itself (D-C3).

Public Functions Documentation

function New

static outcome::result< std::shared_ptr< PruneEligibility > > New(
    crdt::GlobalDB & globaldb,
    TransactionManager & transaction_manager,
    UTXOManager & utxo_manager,
    NodeType node_type,
    const PruningConfig & config
)

Fail-closed factory (the construction gate).

Parameters:

  • globaldb Committed-state reader for tx enumeration, priorities, and head height.
  • transaction_manager Owner of the tx path/allowlist contracts and the tx->CID map resolution.
  • utxo_manager Owner of the outpoint lifecycle (spend discriminator and spender carrier).
  • node_type Deployment role of the constructing node.
  • config Validated pruning policy.

Return: The evaluator, or outcome::failure for a non-Light role.

Rejects any role other than NodeType::Light with std::errc::operation_not_permitted before any state is read (GATE-01). The PruningConfig default-disabled is the separate consent gate and is NOT re-checked here.

function BuildPruneMarkerKey

static std::string BuildPruneMarkerKey(
    const std::string & tx_hash
)

Builds the node-local marker key for tx_hash.

Parameters:

  • tx_hash Transaction hash (readable string form).

Return: "/prune/tx/<tx_hash>".

PRUNE_MARKER_PREFIX + hash; the tx PATH travels inside the record value because lookups are by hash.

function LookupPrunedEntry

static outcome::result< std::pair< PrunedLookup, std::optional< SGTransaction::PrunedTransactionRecord > > > LookupPrunedEntry(
    crdt::GlobalDB & db,
    const std::string & tx_hash
)

Answers "was this transaction's history pruned here?" (D-04).

Parameters:

  • db Committed-state reader (marker + value presence).
  • tx_hash Transaction hash (readable string form).

Return: (verdict, decoded record when a marker decoded), or outcome::failure for a raw-read/decode/presence error.

Reads the marker at BuildPruneMarkerKey(tx_hash) through the node-local raw surface, then establishes value presence for the record's tx_path through the same CRDT-layer query surface the evaluator enumerates — both reads share one resolution path (T-17-0503). Verdicts: marker ∧ ¬value ⇒ PRUNED (record decoded); ¬marker ∧ ¬value ⇒ NOT_FOUND; marker ∧ value ⇒ VALUE_PRESENT_INVARIANT_VIOLATION (logged at ERROR — never guessed). A malformed marker payload is an error result, never a silent PRUNED (T-17-0502), and a decoded record whose tx_path does not end with the requested tx_hash (the empty-payload degenerate case included) is an invariant-violation error too — never a silent PRUNED and never a whole-store prefix scan (WR-04). Writes nothing.

function BuildPruneMarkerEntry

static std::pair< base::Buffer, base::Buffer > BuildPruneMarkerEntry(
    const std::string & tx_hash,
    const std::string & resolved_tx_path
)

Builds the production marker entry for tx_hash (D-C1).

Parameters:

  • tx_hash Transaction hash (readable string form).
  • resolved_tx_path The tx path RESOLVED by the caller for this erase — the path whose value the erase targets. The record names THIS path, never a local-network formatting of the hash alone, so the lookup's value-presence probe queries the key the erase actually addressed, whatever monitored network it lives under (WR-02). Must end with tx_hash (the WR-04 shape).

Return: (marker key buffer, serialized record buffer).

The production twin of WritePrunedEntryForTest: returns the key/value buffer pair — BuildPruneMarkerKey(tx_hash) plus a PrunedTransactionRecord naming resolved_tx_path — instead of writing it. The caller stages the pair into the SAME WriteBatch as the erase, so the value-XOR-marker invariant is established atomically with the erase (one commit: value absent AND marker present, never either alone). The key home and record shape live HERE — callers never rebuild them.

function WritePrunedEntryForTest

static outcome::result< void > WritePrunedEntryForTest(
    crdt::GlobalDB & db,
    const std::string & tx_hash,
    const SGTransaction::PrunedTransactionRecord & record
)

TEST-ONLY marker writer (the D-04 test seam).

Parameters:

  • db Store receiving the marker.
  • tx_hash Transaction hash the marker is keyed by.
  • record Marker payload to persist.

Return: outcome::success, or outcome::failure on I/O error.

Note: No production caller may invoke this method.

Serializes record and writes it at the marker key on the node-local raw surface. Production NEVER calls this: the real marker write joins Phase 18's erase WriteBatch so the value-XOR-marker invariant is established atomically with the erase itself.

function IsAllowlistedTxKey

bool IsAllowlistedTxKey(
    const std::string & key
) const

THE allowlist (D-C7): exact /bc-/tx/ prefix membership.

Parameters:

  • key Candidate storage key.

Return: true when the key is inside the allowlisted prefix.

True only when key starts with GetBlockChainBase(net) + "tx/" for a net in TransactionManager::GetMonitoredNetworkIDs(). The trailing slash is mandatory (T-17-0401): cert slots, registration paths, proof keys, unmonitored networks, and slashless "txfoo" siblings all fail here.

function Evaluate

outcome::result< PruneEvaluationResult > Evaluate() const

Enumerates and evaluates every candidate (read-only).

Return: The structured eligible/ineligible report, or outcome::failure(std::errc::invalid_argument) when no finality_window is configured (fail closed — a window without N cannot make anything eligible).

Per monitored network: QueryKeyValues(base + "tx/") (WITH the trailing slash), deserialize each value, then per candidate: genuine-consumption of every output (D-C2), spender resolution with existence BEFORE any priority read, spend_height = MAX spender priority over outputs (the most-recent spend binds), and the window maxHeight − spend_height ≥ finality_window (D-02). The window arithmetic lives HERE and nowhere else. Query or per-entry failures are logged and the scan continues (never aborts); every ineligible candidate carries its PruneReason codes.

function EvaluateDeltaBlockErasable

outcome::result< BlockGateResult > EvaluateDeltaBlockErasable(
    const std::string & cid_string,
    const PruneEvaluationResult & eligible
) const

THE multi-element block gate (PRUNE-03, D-C3).

Parameters:

  • cid_string CID of the delta block to gate.
  • eligible Evaluation whose eligible set (PRUNE-01 verdicts) the carried keys are matched against.

Return: The block verdict (erasable=false with reasons on any miss or parse failure).

Parses the delta block cid_string itself, at evaluation time, via GlobalDB::GetLocalDeltaKeys (elements AND tombstones; "what this node applied" is forbidden as an oracle — light nodes store elements they never applied). The block is erasable only when EVERY carried key is (a) IsAllowlistedTxKey-true and (b) present in eligible's eligible set (matched by tx path). A non-conformant key reports OUT_OF_PREFIX; an allowlisted key outside the eligible set reports NON_ELIGIBLE_SIBLING (an elements-only gate would miss tombstone keys — Pitfall 4). Parse failure fails closed: a not-erasable result carrying DESERIALIZE_FAILED, never a crash and never a guess. Read-only; writes nothing.

Public Attributes Documentation

variable PRUNE_MARKER_PREFIX

static constexpr std::string_view PRUNE_MARKER_PREFIX = "/prune/tx/";

Node-local marker key namespace (CRDTWorkJournal prefix discipline: same shared RocksDB, direct datastore writes, never broadcast).


Updated on 2026-10-22 at 19:28:22 +0000