iuna

iuna

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

types.rs (7798B)


      1 use std::collections::BTreeMap;
      2 
      3 use serde::{Deserialize, Serialize};
      4 
      5 use crate::domain::{
      6     Amount, Block, BurnBundle, ChainStatus, LaunchProfile, PreparedBlock, StratumMineTemplate,
      7     Transaction, Wallet,
      8 };
      9 
     10 #[derive(Clone, Debug)]
     11 pub struct NodeConfig {
     12     pub wallet: Wallet,
     13     pub genesis_allocations: BTreeMap<String, Amount>,
     14     pub vdf_rounds: u64,
     15     pub burn_per_block: Amount,
     16     pub burn_fee: Amount,
     17     pub pow_mining_workers: u8,
     18     pub recovery_vdf_top_rank_percent: u8,
     19 }
     20 
     21 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     22 pub struct FeeEstimate {
     23     pub bytes: usize,
     24     pub fee: Amount,
     25 }
     26 
     27 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
     28 pub struct QuantumMigrationPreview {
     29     pub address: String,
     30     pub transaction_id: String,
     31     pub input_count: usize,
     32     pub remaining_legacy_utxos: usize,
     33     pub bytes: usize,
     34     pub fee: Amount,
     35     pub amount: Amount,
     36 }
     37 
     38 #[derive(Clone, Debug, Eq, PartialEq)]
     39 pub struct ExternalMineJob {
     40     pub template: StratumMineTemplate,
     41 }
     42 
     43 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
     44 #[serde(tag = "type", rename_all = "snake_case")]
     45 pub enum GossipEnvelope {
     46     Hello(ProtocolHello),
     47     PeerStatus {
     48         height: u64,
     49         tip_hash: String,
     50         #[serde(default)]
     51         time_ms: u64,
     52     },
     53     ChainBootstrapRequest,
     54     ChainBootstrap(ChainBootstrap),
     55     BlockLocatorRequest {
     56         locator: Vec<String>,
     57         limit: usize,
     58     },
     59     BlockRangeRequest {
     60         from_height: u64,
     61         limit: usize,
     62     },
     63     BlockRequest {
     64         hashes: Vec<String>,
     65     },
     66     Inventory {
     67         blocks: Vec<BlockInventory>,
     68     },
     69     Transaction(Transaction),
     70     Transactions {
     71         transactions: Vec<Transaction>,
     72     },
     73     TransactionV2 {
     74         envelope: String,
     75     },
     76     TransactionsV2 {
     77         envelopes: Vec<String>,
     78     },
     79     BurnBundle(BurnBundle),
     80     BurnBundles {
     81         bundles: Vec<BurnBundle>,
     82     },
     83     BurnBundleRequest {
     84         height: u64,
     85         prev_hash: String,
     86         slots: Vec<u8>,
     87     },
     88     Block(Block),
     89     Blocks {
     90         blocks: Vec<Block>,
     91     },
     92     PeerAnnouncement {
     93         address: String,
     94         #[serde(default)]
     95         node_id: Option<String>,
     96     },
     97     PeerVerificationChallenge {
     98         address: String,
     99         nonce: String,
    100     },
    101     PeerVerificationResponse {
    102         address: String,
    103         nonce: String,
    104         node_id: String,
    105         signature: String,
    106     },
    107     PeerList {
    108         peers: Vec<String>,
    109     },
    110 }
    111 
    112 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    113 pub struct ChainBootstrap {
    114     pub genesis_allocations: BTreeMap<String, Amount>,
    115     pub vdf_rounds: u64,
    116     pub launch_profile: LaunchProfile,
    117     pub genesis_block: Block,
    118     pub height: u64,
    119     pub tip_hash: String,
    120 }
    121 
    122 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    123 pub struct ProtocolHello {
    124     pub protocol_version: u32,
    125     #[serde(default, skip_serializing_if = "Vec::is_empty")]
    126     pub capabilities: Vec<String>,
    127     pub network_id: String,
    128     pub genesis_hash: String,
    129     pub listen_addr: Option<String>,
    130     #[serde(default)]
    131     pub node_id: Option<String>,
    132     pub height: u64,
    133     pub tip_hash: String,
    134     #[serde(default)]
    135     pub time_ms: u64,
    136 }
    137 
    138 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    139 pub struct BlockInventory {
    140     pub height: u64,
    141     pub hash: String,
    142 }
    143 
    144 #[cfg(test)]
    145 mod protocol_hello_tests {
    146     use serde::Deserialize;
    147 
    148     use super::ProtocolHello;
    149 
    150     #[derive(Deserialize)]
    151     struct V0430ProtocolHello {
    152         protocol_version: u32,
    153         network_id: String,
    154     }
    155 
    156     #[test]
    157     fn legacy_hello_without_capabilities_remains_compatible() {
    158         let json = r#"{"protocol_version":2,"network_id":"test","genesis_hash":"genesis","listen_addr":null,"node_id":null,"height":0,"tip_hash":"tip","time_ms":1}"#;
    159         let hello: ProtocolHello = serde_json::from_str(json).unwrap();
    160 
    161         assert!(hello.capabilities.is_empty());
    162         assert!(
    163             !serde_json::to_string(&hello)
    164                 .unwrap()
    165                 .contains("capabilities")
    166         );
    167     }
    168 
    169     #[test]
    170     fn v0430_shape_ignores_new_capabilities_field() {
    171         let current = ProtocolHello {
    172             protocol_version: 2,
    173             capabilities: vec!["address-v1-read".to_string()],
    174             network_id: "iuna-mainnet-candidate".to_string(),
    175             genesis_hash: "00".repeat(32),
    176             listen_addr: None,
    177             node_id: None,
    178             height: 0,
    179             tip_hash: "00".repeat(32),
    180             time_ms: 1,
    181         };
    182         let legacy: V0430ProtocolHello =
    183             serde_json::from_str(&serde_json::to_string(&current).unwrap()).unwrap();
    184 
    185         assert_eq!(legacy.protocol_version, 2);
    186         assert_eq!(legacy.network_id, "iuna-mainnet-candidate");
    187     }
    188 }
    189 
    190 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    191 pub struct NodeStatus {
    192     pub app_version: String,
    193     pub wallet_address: String,
    194     pub wallet_receive_address: String,
    195     #[serde(default)]
    196     pub funded_wallet_addresses: Vec<FundedWalletAddressStatus>,
    197     pub wallet_balance: Amount,
    198     pub wallet_locked: bool,
    199     pub quantum_migration: QuantumMigrationStatus,
    200     pub launch_profile: LaunchProfileStatus,
    201     pub mining: MiningStatus,
    202     pub stratum: StratumStatus,
    203     pub chain: ChainStatus,
    204     pub network_migration: NetworkMigrationStatus,
    205 }
    206 
    207 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    208 pub struct FundedWalletAddressStatus {
    209     pub address: String,
    210     pub balance: Amount,
    211     pub utxos: usize,
    212     pub spendable_utxos: usize,
    213     pub legacy: bool,
    214 }
    215 
    216 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    217 pub struct QuantumMigrationStatus {
    218     pub active: bool,
    219     pub hybrid_address: Option<String>,
    220     pub legacy_balance: Amount,
    221     pub hybrid_balance: Amount,
    222     pub legacy_utxos: usize,
    223     pub migration_pending: bool,
    224     pub pending_transaction_id: Option<String>,
    225 }
    226 
    227 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    228 pub struct NetworkMigrationStatus {
    229     pub required: bool,
    230     pub from_network: Option<String>,
    231     pub to_network: String,
    232 }
    233 
    234 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    235 pub struct LaunchProfileStatus {
    236     pub profile_id: String,
    237     pub profile_hash: String,
    238     pub ticket_maturity_delay_heights: u64,
    239     pub ticket_expiry_window_heights: u64,
    240     pub mine_difficulty_bits: u32,
    241     pub burn_lineage_maturity_heights: u64,
    242 }
    243 
    244 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    245 pub struct MiningStatus {
    246     pub automatic: bool,
    247     pub pow_mining_enabled: bool,
    248     pub pow_mining_workers: u8,
    249     pub max_pow_mining_workers: u8,
    250     pub burn_per_block: Amount,
    251     pub automatic_burn_fee: Amount,
    252     pub automatic_pow_mine_fee: Amount,
    253     pub last_auto_finalization_status: Option<String>,
    254     pub last_auto_pow_mine_anchor: Option<String>,
    255     pub last_auto_pow_mine_status: Option<String>,
    256     pub vdf_rounds: u64,
    257     pub vdf_target_block_ms: u64,
    258     pub current_leader: Option<String>,
    259     pub wallet_is_current_leader: bool,
    260     pub last_auto_burn_height: Option<u64>,
    261     pub recovery_vdf_top_rank_percent: u8,
    262 }
    263 
    264 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    265 pub struct StratumStatus {
    266     pub enabled: bool,
    267     pub listen_addr: Option<String>,
    268 }
    269 
    270 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
    271 pub struct AutoMineOutcome {
    272     pub pow_mined: Option<Transaction>,
    273     pub burned: Option<Transaction>,
    274     pub block: Option<Block>,
    275     pub skipped_reason: Option<String>,
    276 }
    277 
    278 #[derive(Clone, Debug)]
    279 pub struct AutoMinePlan {
    280     pub pow_mined: Option<Transaction>,
    281     pub burned: Option<Transaction>,
    282     pub work: Option<PreparedBlock>,
    283     pub skipped_reason: Option<String>,
    284 }