Skip to main content

urma_node_client/
names.rs

1//! Local Names V0 projection of fully scanned selected history. These results
2//! are operator index data, not portable proofs or pre-application coverage.
3use crate::{model::ChainPoint, projection::IndexSnapshot};
4use bitcoin::{BlockHash, Txid};
5use serde::{Deserialize, Serialize};
6use urma_names::state::{Outcome, Resolution};
7
8pub const MAX_NAMES_PAGE: u32 = 128;
9/// Bounds one stored JSON state before decoding, including up to 255 approvers.
10pub const MAX_NAMES_STATE_BYTES: usize = 64 * 1024;
11/// Oversized pages fail as a whole; entries are never silently omitted.
12pub const MAX_NAMES_PAGE_BYTES: usize = 16 * 1024 * 1024;
13
14/// Canonical traversal order is all names (ASCII), then pending TXIDs (display
15/// hex). In particular, TXID internal byte order is not the wire cursor order.
16#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(deny_unknown_fields)]
18pub enum NamesKey {
19    Name(urma_names::name::Name),
20    Pending(Txid),
21}
22
23impl NamesKey {
24    pub fn order_key(&self) -> (u8, String) {
25        match self {
26            Self::Name(name) => (0, name.to_string()),
27            Self::Pending(txid) => (1, txid.to_string()),
28        }
29    }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(deny_unknown_fields)]
34pub struct NamesCursor {
35    pub genesis: Txid,
36    pub snapshot: IndexSnapshot,
37    pub after: NamesKey,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
41#[serde(deny_unknown_fields)]
42pub enum NamesEntry {
43    Name {
44        name: urma_names::name::Name,
45        state: urma_names::state::NameState,
46    },
47    Pending {
48        txid: Txid,
49        record: urma_names::state::PendingRecord,
50    },
51}
52
53impl NamesEntry {
54    pub fn key(&self) -> NamesKey {
55        match self {
56            Self::Name { name, .. } => NamesKey::Name(name.clone()),
57            Self::Pending { txid, .. } => NamesKey::Pending(*txid),
58        }
59    }
60}
61
62/// One immutable local projection page. A full traversal includes unbound and
63/// suspended states and completed pending records; consumers must not omit them
64/// when reproducing local resolution/review views. No undo, commit window or
65/// autonomous scanner checkpoints are supplied. This is not a NamesIndex import
66/// or portable proof. `next == None` ends this local snapshot only; completeness
67/// through the selected tip is reported separately by `status`.
68#[derive(Clone, Debug, Serialize, Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct NamesPage {
71    pub snapshot: IndexSnapshot,
72    pub chain_genesis: BlockHash,
73    pub status: NamesStatus,
74    pub rules: urma_names::payload::Genesis,
75    pub entries: Vec<NamesEntry>,
76    pub next: Option<NamesCursor>,
77}
78
79#[derive(Clone, Debug, Serialize, Deserialize)]
80#[serde(deny_unknown_fields)]
81pub struct NamesStatus {
82    pub genesis: Txid,
83    pub genesis_block: ChainPoint,
84    pub projected: ChainPoint,
85    pub generation: u64,
86    pub selected_tip: Option<ChainPoint>,
87    pub complete_to_tip: bool,
88}
89
90#[derive(Clone, Debug, Serialize, Deserialize)]
91#[serde(deny_unknown_fields)]
92pub struct NamesStep {
93    pub status: NamesStatus,
94    pub applied: Option<ChainPoint>,
95    pub rolled_back: u64,
96    pub outcomes: Vec<Outcome>,
97}
98
99#[derive(Clone, Debug, Serialize, Deserialize)]
100#[serde(deny_unknown_fields)]
101pub struct NamesResolution {
102    pub status: NamesStatus,
103    pub resolution: Resolution,
104}