iuna

iuna

iuna - experimental mainnet-candidate protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

types.rs (16792B)


      1 use secrecy::{ExposeSecret, SecretString};
      2 use serde::{Deserialize, Serialize, Serializer};
      3 
      4 use crate::{
      5     adapters::{config_store::UiConfig, ui_data_store::BlockMetricRow},
      6     app::PeerInfo,
      7     domain::{Amount, BurnLeaderRank, OutPoint, Transaction, TransactionV2, TxOutput},
      8     ip_geolocation::CountryCode,
      9 };
     10 
     11 #[derive(Debug, Deserialize)]
     12 pub(super) struct AuthForm {
     13     pub(super) password: SecretString,
     14 }
     15 
     16 #[derive(Debug, Deserialize)]
     17 pub(super) struct ChangePasswordForm {
     18     pub(super) old_password: SecretString,
     19     pub(super) new_password: SecretString,
     20 }
     21 
     22 #[derive(Debug, Serialize)]
     23 pub(super) struct AuthStatusResponse {
     24     pub(super) configured: bool,
     25     pub(super) authenticated: bool,
     26 }
     27 
     28 #[derive(Debug, Serialize)]
     29 pub(super) struct NetworkHealthResponse {
     30     pub(super) ok: bool,
     31     pub(super) state: String,
     32     pub(super) local_height: u64,
     33     pub(super) local_tip_hash: String,
     34     pub(super) finalized_height: Option<u64>,
     35     pub(super) finalized_hash: Option<String>,
     36     pub(super) last_block_age_ms: Option<u64>,
     37     pub(super) best_known_height: u64,
     38     pub(super) sync_start_height: Option<u64>,
     39     pub(super) sync_validated_height: Option<u64>,
     40     pub(super) sync_target_height: Option<u64>,
     41     pub(super) shared_height: u64,
     42     pub(super) lag_blocks: u64,
     43     pub(super) outbound_peers: usize,
     44     pub(super) inbound_peers: usize,
     45     pub(super) healthy_peers: usize,
     46     pub(super) failed_peers: usize,
     47     pub(super) stale_peers: usize,
     48     pub(super) banned_peers: usize,
     49     pub(super) pending_transactions: usize,
     50     pub(super) pending_plain_transactions: usize,
     51     pub(super) pending_v2_transactions: usize,
     52     pub(super) last_finalizer_mode: Option<String>,
     53     pub(super) last_finalizer_rank: Option<u32>,
     54     pub(super) last_block_finalizer: Option<String>,
     55     pub(super) current_leader: Option<String>,
     56     pub(super) wallet_is_current_leader: bool,
     57     pub(super) last_auto_finalization_status: Option<String>,
     58     pub(super) vdf_rounds: u64,
     59     pub(super) vdf_target_block_ms: u64,
     60     pub(super) rejected_blocks: u64,
     61     pub(super) rejected_block_batches: u64,
     62     pub(super) rejected_snapshots: u64,
     63     pub(super) rejected_chain_payloads: u64,
     64     pub(super) last_chain_payload_error: Option<String>,
     65     pub(super) network_time_offset_ms: Option<i64>,
     66     pub(super) bad_clock_peers: usize,
     67     pub(super) last_error: Option<String>,
     68 }
     69 
     70 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
     71 pub(super) struct PeerPresentation {
     72     #[serde(flatten)]
     73     pub(super) peer: PeerInfo,
     74     #[serde(skip_serializing_if = "Option::is_none")]
     75     pub(super) country_code: Option<CountryCode>,
     76 }
     77 
     78 #[derive(Clone, Copy, Debug, Default)]
     79 pub(super) struct MempoolCounts {
     80     pub(super) plain_transactions: usize,
     81     pub(super) v2_transactions: usize,
     82 }
     83 
     84 impl MempoolCounts {
     85     pub(super) fn total(&self) -> usize {
     86         self.plain_transactions.saturating_add(self.v2_transactions)
     87     }
     88 }
     89 
     90 #[derive(Clone, Debug)]
     91 pub(super) struct NetworkHealthLocalState {
     92     pub(super) height: u64,
     93     pub(super) tip_hash: String,
     94     pub(super) finalized_height: Option<u64>,
     95     pub(super) finalized_hash: Option<String>,
     96     pub(super) tip_timestamp_ms: Option<u64>,
     97     pub(super) sync_start_height: Option<u64>,
     98     pub(super) sync_validated_height: Option<u64>,
     99     pub(super) sync_target_height: Option<u64>,
    100     pub(super) pending_transactions: usize,
    101     pub(super) last_finalizer_mode: Option<String>,
    102     pub(super) last_finalizer_rank: Option<u32>,
    103     pub(super) last_block_finalizer: Option<String>,
    104     pub(super) current_leader: Option<String>,
    105     pub(super) wallet_is_current_leader: bool,
    106     pub(super) last_auto_finalization_status: Option<String>,
    107     pub(super) vdf_rounds: u64,
    108     pub(super) vdf_target_block_ms: u64,
    109     pub(super) rejected_blocks: u64,
    110     pub(super) rejected_block_batches: u64,
    111     pub(super) rejected_snapshots: u64,
    112     pub(super) last_chain_payload_error: Option<String>,
    113 }
    114 
    115 #[derive(Debug, Deserialize)]
    116 pub(super) struct BurnSettingsForm {
    117     pub(super) enabled: Option<bool>,
    118     pub(super) amount: Amount,
    119     pub(super) fee_per_byte: Option<Amount>,
    120 }
    121 
    122 #[derive(Debug, Deserialize)]
    123 pub(super) struct RecoveryVdfSettingsForm {
    124     pub(super) top_rank_percent: u8,
    125 }
    126 
    127 #[derive(Debug, Deserialize)]
    128 pub(super) struct PowMiningForm {
    129     pub(super) enabled: bool,
    130     pub(super) workers: Option<u8>,
    131 }
    132 
    133 #[derive(Debug, Deserialize)]
    134 pub(super) struct MetricsSettingsForm {
    135     pub(super) enabled: bool,
    136 }
    137 
    138 #[derive(Debug, Deserialize)]
    139 pub(super) struct ChainResetForm {
    140     pub(super) confirm: String,
    141 }
    142 
    143 #[derive(Debug, Deserialize)]
    144 pub(super) struct P2pAnnounceForm {
    145     pub(super) addr: String,
    146 }
    147 
    148 #[derive(Debug, Deserialize)]
    149 pub(super) struct P2pInboundForm {
    150     pub(super) enabled: bool,
    151     pub(super) bind_port: Option<u16>,
    152 }
    153 
    154 #[derive(Debug, Deserialize)]
    155 pub(super) struct StratumSettingsForm {
    156     pub(super) enabled: bool,
    157     pub(super) bind_port: Option<u16>,
    158 }
    159 
    160 #[derive(Debug, Deserialize)]
    161 pub(super) struct WalletEndpointSettingsForm {
    162     pub(super) enabled: bool,
    163     pub(super) bind_port: Option<u16>,
    164 }
    165 
    166 #[derive(Debug, Serialize)]
    167 pub(super) struct ConfigResponse {
    168     #[serde(flatten)]
    169     pub(super) config: UiConfig,
    170     pub(super) p2p_inbound_runtime_active: bool,
    171     pub(super) p2p_runtime_bind_addr: String,
    172     pub(super) stratum_runtime_enabled: bool,
    173     pub(super) stratum_runtime_listen_addr: Option<String>,
    174     pub(super) wallet_endpoint_runtime_enabled: bool,
    175     pub(super) wallet_endpoint_runtime_listen_addr: Option<String>,
    176 }
    177 
    178 #[derive(Debug, Deserialize)]
    179 pub(super) struct TransferForm {
    180     pub(super) to: String,
    181     pub(super) amount: Amount,
    182     pub(super) fee_per_byte: Option<Amount>,
    183     #[serde(default)]
    184     pub(super) utxos: String,
    185 }
    186 
    187 #[derive(Debug, Deserialize)]
    188 pub(super) struct PeerForm {
    189     pub(super) peer: String,
    190 }
    191 
    192 #[derive(Debug, Deserialize)]
    193 pub(super) struct AddressBookForm {
    194     pub(super) address: String,
    195     pub(super) name: String,
    196     pub(super) old_address: Option<String>,
    197 }
    198 
    199 #[derive(Debug, Deserialize)]
    200 pub(super) struct AddressBookDeleteForm {
    201     pub(super) address: String,
    202 }
    203 
    204 #[derive(Debug, Deserialize)]
    205 pub(super) struct ConfigForm {
    206     pub(super) setup_complete: bool,
    207     #[serde(default)]
    208     pub(super) peer: String,
    209 }
    210 
    211 #[derive(Debug, Deserialize)]
    212 pub(super) struct SeedPhraseForm {
    213     pub(super) seed_phrase: SecretString,
    214 }
    215 
    216 #[derive(Debug, Deserialize)]
    217 pub(super) struct BlocksQuery {
    218     pub(super) before_height: Option<u64>,
    219     pub(super) limit: Option<usize>,
    220 }
    221 
    222 #[derive(Debug, Deserialize)]
    223 pub(super) struct MetricsQuery {
    224     pub(super) limit: Option<usize>,
    225 }
    226 
    227 #[derive(Debug, Default, Deserialize)]
    228 pub(super) struct PageQuery {
    229     pub(super) offset: Option<usize>,
    230     pub(super) limit: Option<usize>,
    231 }
    232 
    233 #[derive(Debug, Default, Deserialize)]
    234 pub(super) struct WalletTransactionsQuery {
    235     pub(super) tx: Option<bool>,
    236     pub(super) mine: Option<bool>,
    237     pub(super) burn: Option<bool>,
    238     pub(super) reward: Option<bool>,
    239     pub(super) offset: Option<usize>,
    240     pub(super) limit: Option<usize>,
    241 }
    242 
    243 impl WalletTransactionsQuery {
    244     pub(super) fn page(&self) -> PageQuery {
    245         PageQuery {
    246             offset: self.offset,
    247             limit: self.limit,
    248         }
    249     }
    250 }
    251 
    252 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    253 pub(crate) struct WalletTransactionFilters {
    254     pub(crate) transfer: bool,
    255     pub(crate) mine: bool,
    256     pub(crate) burn: bool,
    257     pub(crate) reward: bool,
    258 }
    259 
    260 impl Default for WalletTransactionFilters {
    261     fn default() -> Self {
    262         Self {
    263             transfer: true,
    264             mine: true,
    265             burn: true,
    266             reward: true,
    267         }
    268     }
    269 }
    270 
    271 impl WalletTransactionFilters {
    272     pub(super) fn from_query(query: WalletTransactionsQuery) -> Self {
    273         Self {
    274             transfer: query.tx.unwrap_or(true),
    275             mine: query.mine.unwrap_or(true),
    276             burn: query.burn.unwrap_or(true),
    277             reward: query.reward.unwrap_or(true),
    278         }
    279     }
    280 
    281     pub(super) fn allows(self, transaction: &Transaction) -> bool {
    282         match transaction {
    283             Transaction::Transfer { .. } => self.transfer,
    284             Transaction::Mine { .. } => self.mine,
    285             Transaction::Burn { .. } => self.burn,
    286         }
    287     }
    288 
    289     pub(super) fn allows_v2(self, transaction: &TransactionV2) -> bool {
    290         match transaction {
    291             TransactionV2::Migration { .. } | TransactionV2::Transfer { .. } => self.transfer,
    292             TransactionV2::Mine { .. } => self.mine,
    293             TransactionV2::Burn { .. } => self.burn,
    294         }
    295     }
    296 }
    297 
    298 #[derive(Debug, Serialize)]
    299 pub(super) struct ActionResponse {
    300     pub(super) ok: bool,
    301     pub(super) error: Option<String>,
    302 }
    303 
    304 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    305 #[serde(rename_all = "camelCase")]
    306 pub(super) struct Page<T> {
    307     pub(super) items: Vec<T>,
    308     pub(super) offset: usize,
    309     pub(super) limit: usize,
    310     pub(super) total: usize,
    311     pub(super) has_more: bool,
    312     pub(super) next_offset: Option<usize>,
    313 }
    314 
    315 #[derive(Clone, Debug, PartialEq, Serialize)]
    316 #[serde(rename_all = "camelCase")]
    317 pub(super) struct MetricsResponse {
    318     pub(super) enabled: bool,
    319     pub(super) preparing: bool,
    320     pub(super) latest: Option<BlockMetricRow>,
    321     pub(super) charts: Vec<MetricsChart>,
    322     pub(super) leaderboards: MetricsLeaderboards,
    323     pub(super) top_mine_proofs: Vec<MineProofLeaderboardEntry>,
    324 }
    325 
    326 #[derive(Clone, Debug, Default, PartialEq, Serialize)]
    327 #[serde(rename_all = "camelCase")]
    328 pub(super) struct MetricsLeaderboards {
    329     pub(super) balances: Vec<LeaderboardEntry>,
    330     pub(super) miners: Vec<LeaderboardEntry>,
    331     pub(super) burners: Vec<LeaderboardEntry>,
    332 }
    333 
    334 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    335 #[serde(rename_all = "camelCase")]
    336 pub(super) struct LeaderboardEntry {
    337     pub(super) address: String,
    338     pub(super) amount: Amount,
    339     pub(super) count: u64,
    340 }
    341 
    342 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    343 #[serde(rename_all = "camelCase")]
    344 pub(super) struct MineProofLeaderboardEntry {
    345     pub(super) height: u64,
    346     pub(super) address: String,
    347     pub(super) proof_bits: u32,
    348     pub(super) difficulty_bits: u32,
    349     pub(super) proof_hash: String,
    350 }
    351 
    352 #[derive(Clone, Debug, PartialEq, Serialize)]
    353 #[serde(rename_all = "camelCase")]
    354 pub(super) struct MetricsChart {
    355     pub(super) id: &'static str,
    356     pub(super) title: &'static str,
    357     pub(super) unit: &'static str,
    358     pub(super) value_kind: MetricsValueKind,
    359     pub(super) points: Vec<MetricsPoint>,
    360 }
    361 
    362 #[derive(Clone, Debug, PartialEq, Serialize)]
    363 #[serde(rename_all = "camelCase")]
    364 pub(super) struct MetricsPoint {
    365     pub(super) height: u64,
    366     pub(super) value: f64,
    367 }
    368 
    369 #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
    370 #[serde(rename_all = "camelCase")]
    371 pub(super) enum MetricsValueKind {
    372     Number,
    373     Seconds,
    374     Iuna,
    375     Bytes,
    376 }
    377 
    378 #[derive(Debug, Serialize)]
    379 #[serde(rename_all = "camelCase")]
    380 pub(super) struct FeeEstimateResponse {
    381     pub(super) ok: bool,
    382     pub(super) error: Option<String>,
    383     pub(super) bytes: Option<usize>,
    384     pub(super) fee: Option<Amount>,
    385 }
    386 
    387 #[derive(Debug, Serialize)]
    388 pub(super) struct WalletSetupResponse {
    389     pub(super) ok: bool,
    390     pub(super) error: Option<String>,
    391     pub(super) address: Option<String>,
    392     #[serde(serialize_with = "serialize_optional_secret")]
    393     pub(super) seed_phrase: Option<SecretString>,
    394     pub(super) dev_verify_bypass: bool,
    395     pub(super) requires_peer: bool,
    396 }
    397 
    398 fn serialize_optional_secret<S>(
    399     value: &Option<SecretString>,
    400     serializer: S,
    401 ) -> Result<S::Ok, S::Error>
    402 where
    403     S: Serializer,
    404 {
    405     match value {
    406         Some(secret) => serializer.serialize_some(secret.expose_secret()),
    407         None => serializer.serialize_none(),
    408     }
    409 }
    410 
    411 #[cfg(test)]
    412 mod secret_tests {
    413     use super::{AuthForm, ChangePasswordForm};
    414 
    415     #[test]
    416     fn auth_form_debug_output_redacts_passwords() {
    417         let auth = AuthForm {
    418             password: "correct-horse-battery-staple".into(),
    419         };
    420         let change = ChangePasswordForm {
    421             old_password: "old-password-value".into(),
    422             new_password: "new-password-value".into(),
    423         };
    424 
    425         let debug = format!("{auth:?} {change:?}");
    426         assert!(debug.contains("[REDACTED]"));
    427         assert!(!debug.contains("correct-horse-battery-staple"));
    428         assert!(!debug.contains("old-password-value"));
    429         assert!(!debug.contains("new-password-value"));
    430     }
    431 }
    432 
    433 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    434 #[serde(rename_all = "camelCase")]
    435 pub(crate) struct WalletTransactionRow {
    436     pub(super) kind: &'static str,
    437     pub(super) from: String,
    438     pub(super) to: Option<String>,
    439     pub(super) amount: Amount,
    440     pub(super) fee: Amount,
    441     pub(super) inputs: Vec<UiTxInput>,
    442     pub(super) outputs: Vec<TxOutput>,
    443     pub(super) change: Vec<TxOutput>,
    444     pub(super) signature: String,
    445     pub(super) status: &'static str,
    446     pub(super) block_height: Option<u64>,
    447     pub(super) timestamp_ms: Option<u64>,
    448     pub(super) block_finalizer: Option<String>,
    449     pub(super) direction: &'static str,
    450     pub(super) difficulty_bits: Option<u32>,
    451     pub(super) proof_bits: Option<u32>,
    452     pub(super) proof_hash: Option<String>,
    453     pub(super) reward_total: Option<Amount>,
    454     pub(super) reward_fee_inputs: Vec<UiRewardFeeInput>,
    455     pub(super) reward_outputs: Vec<UiRewardOutput>,
    456 }
    457 
    458 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    459 #[serde(rename_all = "camelCase")]
    460 pub(super) struct UiRewardFeeInput {
    461     pub(super) transaction_kind: &'static str,
    462     pub(super) amount: Amount,
    463     pub(super) owner: String,
    464     pub(super) signature: String,
    465 }
    466 
    467 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    468 #[serde(rename_all = "camelCase")]
    469 pub(super) struct UiRewardOutput {
    470     pub(super) label: String,
    471     pub(super) amount: Amount,
    472     pub(super) address: String,
    473 }
    474 
    475 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    476 #[serde(rename_all = "camelCase")]
    477 pub(super) struct WalletUtxoRow {
    478     pub(super) outpoint: OutPoint,
    479     pub(super) address: String,
    480     pub(super) amount: Amount,
    481     pub(super) spendable: bool,
    482 }
    483 
    484 #[derive(Clone, Debug)]
    485 pub(crate) struct WalletTransactionContext {
    486     pub(crate) status: &'static str,
    487     pub(crate) block_height: Option<u64>,
    488     pub(crate) timestamp_ms: Option<u64>,
    489     pub(crate) block_finalizer: Option<String>,
    490 }
    491 
    492 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    493 pub(super) struct UiBlock {
    494     pub(super) height: u64,
    495     pub(super) prev_hash: String,
    496     pub(super) timestamp_ms: u64,
    497     pub(super) miner: String,
    498     pub(super) finalizer_mode: crate::domain::FinalizerMode,
    499     pub(super) finalizer_rank: u32,
    500     pub(super) reward: Amount,
    501     pub(super) total_fees: Amount,
    502     pub(super) lost_iuna: Amount,
    503     pub(super) total_bytes: usize,
    504     pub(super) header_and_proof_bytes: usize,
    505     pub(super) transaction_bytes: usize,
    506     pub(super) transaction_byte_breakdown: Vec<UiByteBreakdown>,
    507     pub(super) burn_bundle_bytes: usize,
    508     pub(super) burn_bundle_quorum: UiBurnBundleQuorum,
    509     pub(super) vdf_rounds: u64,
    510     pub(super) vdf_output: String,
    511     pub(super) leader_proof: Option<crate::domain::LeaderProof>,
    512     pub(super) burn_leader_ranks: Vec<BurnLeaderRank>,
    513     pub(super) transactions: Vec<UiTransaction>,
    514     pub(super) burn_bundles: Vec<UiBurnBundle>,
    515     pub(super) hash: String,
    516 }
    517 
    518 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    519 pub(super) struct UiBurnBundleQuorum {
    520     pub(super) burn_bundles_included: usize,
    521     pub(super) committee_size: usize,
    522 }
    523 
    524 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    525 pub(super) struct UiByteBreakdown {
    526     pub(super) label: &'static str,
    527     pub(super) bytes: usize,
    528 }
    529 
    530 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    531 #[serde(rename_all = "camelCase")]
    532 pub(super) struct UiBurnBundle {
    533     pub(super) slot: u8,
    534     pub(super) member: String,
    535     pub(super) hash: String,
    536     pub(super) byte_size: usize,
    537     pub(super) burns: Vec<UiTransaction>,
    538 }
    539 
    540 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    541 pub(super) struct UiTransaction {
    542     pub(super) kind: &'static str,
    543     pub(super) from: String,
    544     pub(super) to: Option<String>,
    545     pub(super) amount: Amount,
    546     pub(super) fee: Amount,
    547     pub(super) inputs: Vec<UiTxInput>,
    548     pub(super) outputs: Vec<TxOutput>,
    549     pub(super) change: Vec<TxOutput>,
    550     pub(super) signature: String,
    551     pub(super) difficulty_bits: Option<u32>,
    552     pub(super) proof_bits: Option<u32>,
    553     pub(super) proof_hash: Option<String>,
    554 }
    555 
    556 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
    557 pub(super) struct UiTxInput {
    558     pub(super) outpoint: OutPoint,
    559     pub(super) owner: String,
    560     pub(super) signature: String,
    561     pub(super) amount: Option<Amount>,
    562     pub(super) address: Option<String>,
    563 }