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(¤t).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 }