From 307760dc2ae9bffca8cb5f8f308ca42444ebc3ab Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 23 Jul 2024 16:18:50 +0200 Subject: [PATCH 01/83] daemon: verify the current timestamp against tips for block template --- xelis_daemon/src/core/blockchain.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/xelis_daemon/src/core/blockchain.rs b/xelis_daemon/src/core/blockchain.rs index ebac231f..ec6e9391 100644 --- a/xelis_daemon/src/core/blockchain.rs +++ b/xelis_daemon/src/core/blockchain.rs @@ -1484,8 +1484,25 @@ impl Blockchain { debug!("Dropping tips {} because they are not in the first 3 heavier tips", dropped_tips.map(|h| h.to_string()).collect::>().join(", ")); } + // find the newest timestamp + let mut timestamp = 0; + for tip in sorted_tips.iter() { + let tip_timestamp = storage.get_timestamp_for_block_hash(tip).await?; + if tip_timestamp > timestamp { + timestamp = tip_timestamp; + } + } + + // Check that our current timestamp is correct + let current_timestamp = get_current_time_in_millis(); + if current_timestamp < timestamp { + warn!("Current timestamp is less than the newest tip timestamp, using newest timestamp from tips"); + } else { + timestamp = current_timestamp; + } + let height = blockdag::calculate_height_at_tips(storage, sorted_tips.iter()).await?; - let block = BlockHeader::new(get_version_at_height(self.get_network(), height), height, get_current_time_in_millis(), sorted_tips, extra_nonce, address, IndexSet::new()); + let block = BlockHeader::new(get_version_at_height(self.get_network(), height), height, timestamp, sorted_tips, extra_nonce, address, IndexSet::new()); Ok(block) } From 782a622b788cc1bfd5e9bde00af0f9fab8913b89 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 00:24:36 +0200 Subject: [PATCH 02/83] wallet: prevent empty assets sync --- xelis_wallet/src/network_handler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index 724cbdf5..daac5113 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -662,7 +662,7 @@ impl NetworkHandler { None }; - let assets = if let Some(assets) = assets { + let assets = if let Some(assets) = assets.filter(|a| !a.is_empty()) { assets } else { trace!("no assets provided, fetching all assets"); From 34568b1b116cbd0b0f093ce7a59897c3e56824df Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 00:33:34 +0200 Subject: [PATCH 03/83] wallet: improve logs for rescan --- xelis_wallet/src/network_handler.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index daac5113..817653b8 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -32,7 +32,6 @@ use xelis_common::{ Address, Hash }, - serializer::Serializer, transaction::Role, utils::sanitize_daemon_address }; @@ -732,7 +731,7 @@ impl NetworkHandler { }; if must_update { - trace!("must update balance for asset: {}, ct: {:?}", asset, ciphertext.to_bytes()); + debug!("must update balance for asset: {}, ct: {}", asset, ciphertext); let value = if let Some(cache) = balance_cache { cache } else { @@ -752,6 +751,8 @@ impl NetworkHandler { // We should sync new blocks to get the TXs should_sync_blocks = true; + } else { + debug!("balance for asset {} is already up-to-date", asset); } } } From bc2c2b2795321d20ac0d979d6e234155ad89d6ad Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 15:34:35 +0200 Subject: [PATCH 04/83] wallet: prevent duplicate sync head state --- xelis_wallet/src/network_handler.rs | 31 +++++++++++------------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index 817653b8..a5f263e1 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -815,7 +815,8 @@ impl NetworkHandler { } // we have something that changed, sync transactions - if sync_new_blocks { + // prevent a double sync head state if history scan is disabled + if sync_new_blocks && self.wallet.get_history_scan() { debug!("Syncing new blocks"); self.sync_new_blocks(address, wallet_topoheight, true).await?; } @@ -938,26 +939,18 @@ impl NetworkHandler { storage.get_assets().await? }; - // get balance and transactions for each asset - if self.wallet.get_history_scan() { - debug!("Scanning history for each asset"); - // cache for all topoheight we already processed - // this will prevent us to request more than one time the same topoheight - let mut topoheight_processed = HashSet::new(); - let mut highest_nonce = None; - for asset in assets { - debug!("calling get balances and transactions {}", current_topoheight); - if let Err(e) = self.get_balance_and_transactions(&mut topoheight_processed, &address, &asset, current_topoheight, balances, &mut highest_nonce).await { - error!("Error while syncing balance for asset {}: {}", asset, e); - } - } - } else { - // We don't need to scan the history, we can just sync the head state - debug!("calling sync head state"); - if let Err(e) = self.sync_head_state(&self.wallet.get_address(), Some(assets), None, true).await { - error!("Error while syncing head state: {}", e); + debug!("Scanning history for each asset"); + // cache for all topoheight we already processed + // this will prevent us to request more than one time the same topoheight + let mut topoheight_processed = HashSet::new(); + let mut highest_nonce = None; + for asset in assets { + debug!("calling get balances and transactions {}", current_topoheight); + if let Err(e) = self.get_balance_and_transactions(&mut topoheight_processed, &address, &asset, current_topoheight, balances, &mut highest_nonce).await { + error!("Error while syncing balance for asset {}: {}", asset, e); } } + Ok(()) } } \ No newline at end of file From e98972edae1666760da3c5f3f5c23cf15e2d1ac6 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 17:54:43 +0200 Subject: [PATCH 05/83] wallet: daemon api on_stable_topoheight_changed_event --- xelis_wallet/src/daemon_api.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xelis_wallet/src/daemon_api.rs b/xelis_wallet/src/daemon_api.rs index fa4c9d58..90f4f19e 100644 --- a/xelis_wallet/src/daemon_api.rs +++ b/xelis_wallet/src/daemon_api.rs @@ -153,6 +153,12 @@ impl DaemonAPI { Ok(receiver) } + pub async fn on_stable_topoheight_changed_event(&self) -> Result> { + trace!("on_stable_topoheight_changed_event"); + let receiver = self.client.subscribe_event(NotifyEvent::StableTopoHeightChanged, self.capacity).await?; + Ok(receiver) + } + pub async fn get_version(&self) -> Result { trace!("get_version"); let version = self.client.call("get_version").await?; From 65c675b62b430b1898328b2554cd88240a8a73f8 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 18:14:21 +0200 Subject: [PATCH 06/83] common: implement std hash for transaction entry --- xelis_common/src/api/wallet.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index c1790475..2f326ed4 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -234,6 +234,12 @@ pub struct TransactionEntry { pub entry: EntryType, } +impl std::hash::Hash for TransactionEntry { + fn hash(&self, state: &mut H) { + self.hash.hash(state); + } +} + #[derive(Serialize, Deserialize)] pub struct EstimateExtraDataSizeParams { pub destinations: Vec
, From 5620e21d24d093444fdad89d88e2e80ab2e1881f Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 18:15:32 +0200 Subject: [PATCH 07/83] common: implement std eq for transaction entry --- xelis_common/src/api/wallet.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index 2f326ed4..18d4bb91 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -240,6 +240,14 @@ impl std::hash::Hash for TransactionEntry { } } +impl std::cmp::PartialEq for TransactionEntry { + fn eq(&self, other: &Self) -> bool { + self.hash == other.hash + } +} + +impl std::cmp::Eq for TransactionEntry {} + #[derive(Serialize, Deserialize)] pub struct EstimateExtraDataSizeParams { pub destinations: Vec
, From c110181325cf8faa425c1ab6dcf29a85b6dccbbd Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 24 Jul 2024 18:28:42 +0200 Subject: [PATCH 08/83] wallet: use correct type --- xelis_wallet/src/daemon_api.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xelis_wallet/src/daemon_api.rs b/xelis_wallet/src/daemon_api.rs index 90f4f19e..177d20cf 100644 --- a/xelis_wallet/src/daemon_api.rs +++ b/xelis_wallet/src/daemon_api.rs @@ -28,6 +28,7 @@ use xelis_common::{ NewBlockEvent, BlockOrderedEvent, StableHeightChangedEvent, + StableTopoHeightChangedEvent, TransactionAddedInMempoolEvent, GetAccountAssetsParams, GetAssetParams, @@ -153,7 +154,7 @@ impl DaemonAPI { Ok(receiver) } - pub async fn on_stable_topoheight_changed_event(&self) -> Result> { + pub async fn on_stable_topoheight_changed_event(&self) -> Result> { trace!("on_stable_topoheight_changed_event"); let receiver = self.client.subscribe_event(NotifyEvent::StableTopoHeightChanged, self.capacity).await?; Ok(receiver) From 960ccffbd016fd1ecdd3006f1af189f2c113cab7 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 25 Jul 2024 11:20:00 +0200 Subject: [PATCH 09/83] common: file log level --- xelis_common/src/prompt/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xelis_common/src/prompt/mod.rs b/xelis_common/src/prompt/mod.rs index 81cbd9e0..9cf85967 100644 --- a/xelis_common/src/prompt/mod.rs +++ b/xelis_common/src/prompt/mod.rs @@ -479,7 +479,8 @@ impl Prompt { disable_file_log_date_based: bool, disable_colors: bool, interactive: bool, - module_logs: Vec + module_logs: Vec, + file_level: LogLevel, ) -> Result { let (read_input_sender, read_input_receiver) = mpsc::channel(1); let prompt = Self { @@ -489,7 +490,7 @@ impl Prompt { read_input_sender, disable_colors }; - prompt.setup_logger(level, dir_path, filename_log, disable_file_logging, disable_file_log_date_based, module_logs)?; + prompt.setup_logger(level, dir_path, filename_log, disable_file_logging, disable_file_log_date_based, module_logs, file_level)?; #[cfg(target_os = "windows")] { @@ -760,7 +761,8 @@ impl Prompt { filename_log: &String, disable_file_logging: bool, disable_file_log_date_based: bool, - module_logs: Vec + module_logs: Vec, + file_level: LogLevel ) -> Result<(), fern::InitError> { let colors = ColoredLevelConfig::new() .debug(Color::Green) @@ -820,7 +822,7 @@ impl Prompt { } let mut file_log = fern::Dispatch::new() - .level(level.into()) + .level(file_level.into()) .format(move |out, message, record| { let pad = " ".repeat((30i16 - record.target().len() as i16).max(0) as usize); let level_pad = if record.level() == Level::Error || record.level() == Level::Debug { "" } else { " " }; From 17eb0a19781ce77a64f4fe65a91df9f4ba3a2a93 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 25 Jul 2024 11:20:06 +0200 Subject: [PATCH 10/83] daemon: file log level --- xelis_daemon/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xelis_daemon/src/main.rs b/xelis_daemon/src/main.rs index 3cc0bd9b..0b609f72 100644 --- a/xelis_daemon/src/main.rs +++ b/xelis_daemon/src/main.rs @@ -94,6 +94,9 @@ pub struct NodeConfig { /// Set log level #[clap(long, value_enum, default_value_t = LogLevel::Info)] log_level: LogLevel, + /// Set file log level + #[clap(long, value_enum, default_value_t = LogLevel::Info)] + file_log_level: LogLevel, /// Disable the log file #[clap(long)] disable_file_logging: bool, @@ -135,7 +138,7 @@ const BLOCK_TIME: Difficulty = Difficulty::from_u64(BLOCK_TIME_MILLIS / MILLIS_P async fn main() -> Result<()> { let mut config: NodeConfig = NodeConfig::parse(); - let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules)?; + let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules, config.file_log_level)?; info!("XELIS Blockchain running version: {}", VERSION); info!("----------------------------------------------"); From 94507046887f54b12822642b490a2e0b91447aa0 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 25 Jul 2024 11:20:12 +0200 Subject: [PATCH 11/83] miner: file log level --- xelis_miner/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xelis_miner/src/main.rs b/xelis_miner/src/main.rs index 89081d4d..649fa41b 100644 --- a/xelis_miner/src/main.rs +++ b/xelis_miner/src/main.rs @@ -104,6 +104,9 @@ pub struct MinerConfig { /// Set log level #[clap(long, value_enum, default_value_t = LogLevel::Info)] log_level: LogLevel, + /// Set file log level + #[clap(long, value_enum, default_value_t = LogLevel::Info)] + file_log_level: LogLevel, /// Enable the benchmark mode with the specified algorithm #[clap(long)] benchmark: Option, @@ -184,7 +187,7 @@ const UPDATE_EVERY_NONCE: u64 = 10; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { let config: MinerConfig = MinerConfig::parse(); - let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules)?; + let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules, config.file_log_level)?; let detected_threads = match thread::available_parallelism() { Ok(value) => value.get() as u16, From 1bd60f6d207fe96fb3d9382a830eac7870379b85 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 25 Jul 2024 11:20:19 +0200 Subject: [PATCH 12/83] wallet: file log level --- xelis_wallet/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xelis_wallet/src/main.rs b/xelis_wallet/src/main.rs index cad78698..d262d876 100644 --- a/xelis_wallet/src/main.rs +++ b/xelis_wallet/src/main.rs @@ -110,6 +110,9 @@ pub struct Config { /// Set log level #[clap(long, value_enum, default_value_t = LogLevel::Info)] log_level: LogLevel, + /// Set file log level + #[clap(long, value_enum, default_value_t = LogLevel::Info)] + file_log_level: LogLevel, /// Disable the log file #[clap(long)] disable_file_logging: bool, @@ -190,7 +193,7 @@ impl ecdlp::ProgressTableGenerationReportFunction for LogProgressTableGeneration #[tokio::main] async fn main() -> Result<()> { let config: Config = Config::parse(); - let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules)?; + let prompt = Prompt::new(config.log_level, &config.logs_path, &config.filename_log, config.disable_file_logging, config.disable_file_log_date_based, config.disable_log_color, !config.disable_interactive_mode, config.logs_modules, config.file_log_level)?; #[cfg(feature = "api_server")] { From 0027ba579b454f03c455ead59b34838ea725c260 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 25 Jul 2024 11:24:02 +0200 Subject: [PATCH 13/83] daemon: use correct peer state for whitelist --- xelis_daemon/src/p2p/peer_list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_daemon/src/p2p/peer_list.rs b/xelis_daemon/src/p2p/peer_list.rs index 9142d695..cbe5cded 100644 --- a/xelis_daemon/src/p2p/peer_list.rs +++ b/xelis_daemon/src/p2p/peer_list.rs @@ -413,7 +413,7 @@ impl PeerList { // Retrieve whitelist stored peers pub fn get_whitelist<'a>(&'a self, stored_peers: &'a HashMap) -> Vec<(&'a IpAddr, &'a StoredPeer)> { - self.get_list_with_state(stored_peers, &StoredPeerState::Blacklist) + self.get_list_with_state(stored_peers, &StoredPeerState::Whitelist) } // blacklist a peer address From 4f403b0ac962e8ed7ec7dfe0bea0bfe5c66672bd Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 28 Jul 2024 23:33:07 +0200 Subject: [PATCH 14/83] daemon: double check ip address --- xelis_daemon/src/p2p/mod.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/xelis_daemon/src/p2p/mod.rs b/xelis_daemon/src/p2p/mod.rs index 1bd83bb6..61c515cb 100644 --- a/xelis_daemon/src/p2p/mod.rs +++ b/xelis_daemon/src/p2p/mod.rs @@ -1012,7 +1012,7 @@ impl P2pServer { let addr = p.get_outgoing_address(); // Don't share local network addresses if it's external peer - if is_local_address(addr) && !is_local_peer { + if (is_local_address(addr) && !is_local_peer) || !is_valid_address(addr) { debug!("{} is a local address but peer is external, skipping", addr); continue; } @@ -1571,11 +1571,11 @@ impl P2pServer { { let is_local_peer = is_local_address(peer.get_connection().get_address()); for addr in ping.get_peers() { - if is_local_address(addr) && !is_local_peer { + if (is_local_address(addr) && !is_local_peer) || !is_valid_address(addr) { error!("{} is a local address from {} but peer is external", addr, peer); return Err(P2pError::InvalidPeerlist) } - + if !self.is_connected_to_addr(addr).await && !self.peer_list.has_peer_stored(&addr.ip()).await { if !self.peer_list.store_peer_address(*addr).await { debug!("{} already stored in peer list", addr); @@ -2907,4 +2907,31 @@ pub fn is_local_address(socket_addr: &SocketAddr) -> bool { ipv6.is_loopback() // || ipv6.is_unique_local() } } +} + +// Check if a socket address is a valid address +// Only public and private addresses that can be used in a network are considered valid +pub fn is_valid_address(socket_addr: &SocketAddr) -> bool { + match socket_addr.ip() { + IpAddr::V4(ipv4) => { + // Check if it's a valid IPv4 address + !ipv4.is_unspecified() && !ipv4.is_loopback() && !ipv4.is_multicast() && !ipv4.is_documentation() && !ipv4.is_link_local() && !ipv4.is_broadcast() + } + IpAddr::V6(ipv6) => { + // Check if it's a valid IPv6 address + !ipv6.is_unspecified() && !ipv6.is_loopback() && !ipv6.is_multicast() // && !ipv6.is_documentation() && !ipv6.is_unicast_link_local() + } + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use super::*; + + #[test] + fn test_is_local_address() { + assert!(is_local_address(&SocketAddr::from_str("172.20.0.1:2125").unwrap())); + assert!(!is_local_address(&SocketAddr::from_str("1.1.1.1:2125").unwrap())); + } } \ No newline at end of file From a7f3272a4a71cb56587ceb7c1a67080e29fef0bb Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 28 Jul 2024 23:39:07 +0200 Subject: [PATCH 15/83] common: filter on daemon rpc method account history --- xelis_common/src/api/daemon.rs | 11 +++++++++-- xelis_common/src/api/mod.rs | 11 +++++++++++ xelis_common/src/api/wallet.rs | 10 +--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/xelis_common/src/api/daemon.rs b/xelis_common/src/api/daemon.rs index e03a7a77..45d401e1 100644 --- a/xelis_common/src/api/daemon.rs +++ b/xelis_common/src/api/daemon.rs @@ -19,7 +19,7 @@ use crate::{ network::Network, time::{TimestampMillis, TimestampSeconds} }; -use super::RPCTransaction; +use super::{default_true_value, RPCTransaction}; #[derive(Serialize, Deserialize, PartialEq, Eq)] pub enum BlockType { @@ -395,7 +395,14 @@ pub struct GetAccountHistoryParams { #[serde(default = "default_xelis_asset")] pub asset: Hash, pub minimum_topoheight: Option, - pub maximum_topoheight: Option + pub maximum_topoheight: Option, + // Special case for dev fee, its considered as coinbase + #[serde(default = "default_true_value")] + pub accept_coinbase: bool, + #[serde(default = "default_true_value")] + pub accept_outgoing_txs: bool, + #[serde(default = "default_true_value")] + pub accept_incoming_txs: bool, } #[derive(Serialize, Deserialize)] diff --git a/xelis_common/src/api/mod.rs b/xelis_common/src/api/mod.rs index 88897667..43ae2998 100644 --- a/xelis_common/src/api/mod.rs +++ b/xelis_common/src/api/mod.rs @@ -195,4 +195,15 @@ pub struct SplitAddressResult { pub integrated_data: DataElement, // Integrated data size pub size: usize +} + +// :( +// We are forced to create function for the default value path requested by serde +fn default_true_value() -> bool { + true +} + +// same here +fn default_false_value() -> bool { + false } \ No newline at end of file diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index 18d4bb91..5d031d8d 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -8,6 +8,7 @@ use crate::{ } }; use super::{DataHash, DataElement, DataValue, query::Query}; +use super::{default_false_value, default_true_value}; #[derive(Serialize, Deserialize)] pub struct BuildTransactionParams { @@ -27,15 +28,6 @@ pub struct EstimateFeesParams { pub tx_type: TransactionTypeBuilder, } -// :( -fn default_true_value() -> bool { - true -} - -fn default_false_value() -> bool { - false -} - #[derive(Serialize, Deserialize)] pub struct ListTransactionsParams { pub min_topoheight: Option, From 1eb8967b9c92f13596c620432fdb254cac8dbb9d Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 28 Jul 2024 23:51:50 +0200 Subject: [PATCH 16/83] daemon: filter on account history rpc method --- xelis_daemon/src/rpc/rpc.rs | 168 +++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 80 deletions(-) diff --git a/xelis_daemon/src/rpc/rpc.rs b/xelis_daemon/src/rpc/rpc.rs index c56185fa..6d50f939 100644 --- a/xelis_daemon/src/rpc/rpc.rs +++ b/xelis_daemon/src/rpc/rpc.rs @@ -966,6 +966,10 @@ async fn get_account_history(context: &Context, body: Value) -> Resu return Err(InternalRpcError::InvalidParamsAny(BlockchainError::InvalidNetwork.into())) } + if !params.accept_coinbase && !params.accept_incoming_txs && !params.accept_outgoing_txs { + return Err(InternalRpcError::InvalidParams("No history type was selected")); + } + let key = params.address.get_public_key(); let minimum_topoheight = params.minimum_topoheight.unwrap_or(0); let storage = blockchain.get_storage().read().await; @@ -982,112 +986,116 @@ async fn get_account_history(context: &Context, body: Value) -> Resu let mut history_count = 0; let mut history = Vec::new(); let is_dev_address = *key == *DEV_PUBLIC_KEY; - loop { - if let Some((topo, versioned_balance)) = version.take() { - trace!("Searching history at topoheight {}", topo); - if topo < minimum_topoheight || topo < pruned_topoheight { - break; - } + while let Some((topo, versioned_balance)) = version.take() { + trace!("Searching history of {} ({}) at topoheight {}", params.address, params.asset, topo); + if topo < minimum_topoheight || topo < pruned_topoheight { + break; + } - let (hash, block_header) = storage.get_block_header_at_topoheight(topo).await.context(format!("Error while retrieving block header at topo height {topo}"))?; - // Block reward is only paid in XELIS - if params.asset == XELIS_ASSET { - let is_miner = *block_header.get_miner() == *key; - if is_miner || is_dev_address { - let mut reward = storage.get_block_reward_at_topo_height(topo).context(format!("Error while retrieving reward at topo height {topo}"))?; - // subtract dev fee if any - let dev_fee_percentage = get_block_dev_fee(block_header.get_height()); - if dev_fee_percentage != 0 { - let dev_fee = reward * dev_fee_percentage / 100; - if is_dev_address { - history.push(AccountHistoryEntry { - topoheight: topo, - hash: hash.clone(), - history_type: AccountHistoryType::DevFee { reward: dev_fee }, - block_timestamp: block_header.get_timestamp() - }); - } - reward -= dev_fee; - } - - if is_miner { - let history_type = AccountHistoryType::Mining { reward }; + // Used to track if we have any new history entries + let previous_len = history.len(); + + // Get the block header at topoheight + // we will scan it below for transactions and rewards + let (hash, block_header) = storage.get_block_header_at_topoheight(topo).await.context(format!("Error while retrieving block header at topo height {topo}"))?; + + // Block reward is only paid in XELIS + if params.asset == XELIS_ASSET { + let is_miner = *block_header.get_miner() == *key; + if (is_miner || is_dev_address) && params.accept_coinbase { + let mut reward = storage.get_block_reward_at_topo_height(topo).context(format!("Error while retrieving reward at topo height {topo}"))?; + // subtract dev fee if any + let dev_fee_percentage = get_block_dev_fee(block_header.get_height()); + if dev_fee_percentage != 0 { + let dev_fee = reward * dev_fee_percentage / 100; + if is_dev_address { history.push(AccountHistoryEntry { topoheight: topo, hash: hash.clone(), - history_type, + history_type: AccountHistoryType::DevFee { reward: dev_fee }, block_timestamp: block_header.get_timestamp() }); } + reward -= dev_fee; } - } - // Reverse the order of transactions to get the latest first - for tx_hash in block_header.get_transactions().iter().rev() { - // Don't show unexecuted TXs in the history - if !storage.is_tx_executed_in_block(tx_hash, &hash)? { - continue; + if is_miner { + let history_type = AccountHistoryType::Mining { reward }; + history.push(AccountHistoryEntry { + topoheight: topo, + hash: hash.clone(), + history_type, + block_timestamp: block_header.get_timestamp() + }); } + } + } - trace!("Searching tx {} in block {}", tx_hash, hash); - let tx = storage.get_transaction(tx_hash).await.context(format!("Error while retrieving transaction {tx_hash} from block {hash}"))?; - let is_sender = *tx.get_source() == *key; - match tx.get_data() { - TransactionType::Transfers(transfers) => { - for transfer in transfers { - if *transfer.get_asset() == params.asset { - if *transfer.get_destination() == *key { - history.push(AccountHistoryEntry { - topoheight: topo, - hash: tx_hash.clone(), - history_type: AccountHistoryType::Incoming { - from: tx.get_source().as_address(blockchain.get_network().is_mainnet()) - }, - block_timestamp: block_header.get_timestamp() - }); - } - - if is_sender { - history.push(AccountHistoryEntry { - topoheight: topo, - hash: tx_hash.clone(), - history_type: AccountHistoryType::Outgoing { - to: transfer.get_destination().as_address(blockchain.get_network().is_mainnet()) - }, - block_timestamp: block_header.get_timestamp() - }); - } + // Reverse the order of transactions to get the latest first + for tx_hash in block_header.get_transactions().iter().rev() { + // Don't show unexecuted TXs in the history + if !storage.is_tx_executed_in_block(tx_hash, &hash)? { + continue; + } + + trace!("Searching tx {} in block {}", tx_hash, hash); + let tx = storage.get_transaction(tx_hash).await.context(format!("Error while retrieving transaction {tx_hash} from block {hash}"))?; + let is_sender = *tx.get_source() == *key; + match tx.get_data() { + TransactionType::Transfers(transfers) => { + for transfer in transfers { + if *transfer.get_asset() == params.asset { + if *transfer.get_destination() == *key && params.accept_incoming_txs { + history.push(AccountHistoryEntry { + topoheight: topo, + hash: tx_hash.clone(), + history_type: AccountHistoryType::Incoming { + from: tx.get_source().as_address(blockchain.get_network().is_mainnet()) + }, + block_timestamp: block_header.get_timestamp() + }); } - } - } - TransactionType::Burn(payload) => { - if payload.asset == params.asset { - if is_sender { + + if is_sender && params.accept_outgoing_txs { history.push(AccountHistoryEntry { topoheight: topo, hash: tx_hash.clone(), - history_type: AccountHistoryType::Burn { amount: payload.amount }, + history_type: AccountHistoryType::Outgoing { + to: transfer.get_destination().as_address(blockchain.get_network().is_mainnet()) + }, block_timestamp: block_header.get_timestamp() }); } } } } + TransactionType::Burn(payload) => { + if payload.asset == params.asset { + if is_sender && params.accept_outgoing_txs { + history.push(AccountHistoryEntry { + topoheight: topo, + hash: tx_hash.clone(), + history_type: AccountHistoryType::Burn { amount: payload.amount }, + block_timestamp: block_header.get_timestamp() + }); + } + } + } } + } + if previous_len != history.len() { history_count += 1; if history_count >= MAX_HISTORY { - break; - } - - if let Some(previous) = versioned_balance.get_previous_topoheight() { - if previous < pruned_topoheight { - break; - } - version = Some((previous, storage.get_balance_at_exact_topoheight(key, ¶ms.asset, previous).await.context(format!("Error while retrieving previous balance at topo height {previous}"))?)); + break; } - } else { - break; + } + + if let Some(previous) = versioned_balance.get_previous_topoheight() { + if previous < pruned_topoheight { + break; + } + version = Some((previous, storage.get_balance_at_exact_topoheight(key, ¶ms.asset, previous).await.context(format!("Error while retrieving previous balance at topo height {previous}"))?)); } } From 6a88691aa6395a9721bf5e48866b9ec355096765 Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 28 Jul 2024 23:52:14 +0200 Subject: [PATCH 17/83] misc: add new parameters for get_account_history rpc method --- API.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/API.md b/API.md index a2ff7b8b..51cc01b7 100644 --- a/API.md +++ b/API.md @@ -5635,13 +5635,15 @@ NOTE: If no asset is provided, default is set to XELIS. ##### Method `get_account_history` ##### Parameters -| Name | Type | Required | Note | -|:------------------:|:-------:|:--------:|:---------------------------------:| -| address | Address | Required | Valid address registered on chain | -| asset | Hash | Optional | Asset to track | -| minimum_topoheight | Integer | Optional | minimum topoheight for history | -| maximum_topoheight | Integer | Optional | Maximum topoheight for history | - +| Name | Type | Required | Note | +|:-------------------:|:-------:|:--------:|:----------------------------------------------------:| +| address | Address | Required | Valid address registered on chain | +| asset | Hash | Optional | Asset to track | +| minimum_topoheight | Integer | Optional | minimum topoheight for history | +| maximum_topoheight | Integer | Optional | Maximum topoheight for history | +| accept_coinbase | Boolean | Optional | Set to true by default, filter mining rewards | +| accept_outgoing_txs | Boolean | Optional | Set to true by default, filter outgoing transactions | +| accept_incoming_txs | Boolean | Optional | Set to true by default, filter incoming transactions | ##### Request ```json { @@ -5650,7 +5652,10 @@ NOTE: If no asset is provided, default is set to XELIS. "method": "get_account_history", "params": { "address": "xet:6eadzwf5xdacts6fs4y3csmnsmy4mcxewqt3xyygwfx0hm0tm32sqxdy9zk", - "asset": "0000000000000000000000000000000000000000000000000000000000000000" + "asset": "0000000000000000000000000000000000000000000000000000000000000000", + "accept_coinbase": true, + "accept_outgoing_txs": true, + "accept_incoming_txs": false, } } ``` From 619be2764413df94c191563e5be43c98007809f1 Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 28 Jul 2024 23:57:52 +0200 Subject: [PATCH 18/83] daemon: prevent ddos attack from get_account_history, limit to history max iterations --- xelis_daemon/src/rpc/rpc.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/xelis_daemon/src/rpc/rpc.rs b/xelis_daemon/src/rpc/rpc.rs index 6d50f939..169351f9 100644 --- a/xelis_daemon/src/rpc/rpc.rs +++ b/xelis_daemon/src/rpc/rpc.rs @@ -992,9 +992,6 @@ async fn get_account_history(context: &Context, body: Value) -> Resu break; } - // Used to track if we have any new history entries - let previous_len = history.len(); - // Get the block header at topoheight // we will scan it below for transactions and rewards let (hash, block_header) = storage.get_block_header_at_topoheight(topo).await.context(format!("Error while retrieving block header at topo height {topo}"))?; @@ -1084,11 +1081,9 @@ async fn get_account_history(context: &Context, body: Value) -> Resu } } - if previous_len != history.len() { - history_count += 1; - if history_count >= MAX_HISTORY { - break; - } + history_count += 1; + if history_count >= MAX_HISTORY { + break; } if let Some(previous) = versioned_balance.get_previous_topoheight() { From f8ec7fe65582f7dc8c2f5fc032890c3d5c5bcbb5 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 00:20:43 +0200 Subject: [PATCH 19/83] common: simplify to incoming/outgoing flows --- xelis_common/src/api/daemon.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/xelis_common/src/api/daemon.rs b/xelis_common/src/api/daemon.rs index 45d401e1..d61c24eb 100644 --- a/xelis_common/src/api/daemon.rs +++ b/xelis_common/src/api/daemon.rs @@ -396,13 +396,12 @@ pub struct GetAccountHistoryParams { pub asset: Hash, pub minimum_topoheight: Option, pub maximum_topoheight: Option, - // Special case for dev fee, its considered as coinbase + // Any incoming funds tracked #[serde(default = "default_true_value")] - pub accept_coinbase: bool, + pub incoming_flow: bool, + // Any outgoing funds tracked #[serde(default = "default_true_value")] - pub accept_outgoing_txs: bool, - #[serde(default = "default_true_value")] - pub accept_incoming_txs: bool, + pub outgoing_flow: bool, } #[derive(Serialize, Deserialize)] From af564c93587db5fd3c88cbb863e2f6b20eab43ee Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 00:21:15 +0200 Subject: [PATCH 20/83] daemon: optimize get_account_history for fast search based on filter --- xelis_daemon/src/rpc/rpc.rs | 58 +++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/xelis_daemon/src/rpc/rpc.rs b/xelis_daemon/src/rpc/rpc.rs index 169351f9..8069ce2c 100644 --- a/xelis_daemon/src/rpc/rpc.rs +++ b/xelis_daemon/src/rpc/rpc.rs @@ -966,7 +966,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu return Err(InternalRpcError::InvalidParamsAny(BlockchainError::InvalidNetwork.into())) } - if !params.accept_coinbase && !params.accept_incoming_txs && !params.accept_outgoing_txs { + if !params.incoming_flow && !params.outgoing_flow { return Err(InternalRpcError::InvalidParams("No history type was selected")); } @@ -974,20 +974,48 @@ async fn get_account_history(context: &Context, body: Value) -> Resu let minimum_topoheight = params.minimum_topoheight.unwrap_or(0); let storage = blockchain.get_storage().read().await; let pruned_topoheight = storage.get_pruned_topoheight().await.context("Error while retrieving pruned topoheight")?.unwrap_or(0); - let mut version = if let Some(topo) = params.maximum_topoheight { + let mut version: Option<(u64, Option, _)> = if let Some(topo) = params.maximum_topoheight { if topo < pruned_topoheight { return Err(InternalRpcError::InvalidParams("Maximum topoheight is lower than pruned topoheight")); } - storage.get_balance_at_maximum_topoheight(key, ¶ms.asset, topo).await.context(format!("Error while retrieving balance at topo height {topo}"))? + + + // if incoming flows aren't accepted + // use nonce versions to determine topoheight + if !params.incoming_flow { + if let Some((topo, nonce)) = storage.get_nonce_at_maximum_topoheight(key, topo).await.context("Error while retrieving last nonce")? { + let version = storage.get_balance_at_exact_topoheight(key, ¶ms.asset, topo).await.context(format!("Error while retrieving balance at nonce topo height {topo}"))?; + Some((topo, nonce.get_previous_topoheight(), version)) + } else { + None + } + } else { + storage.get_balance_at_maximum_topoheight(key, ¶ms.asset, topo).await + .context(format!("Error while retrieving balance at topo height {topo}"))? + .map(|(topo, version)| (topo, None, version)) + } } else { - Some(storage.get_last_balance(key, ¶ms.asset).await.context("Error while retrieving last balance")?) + if !params.incoming_flow { + // don't return any error, maybe this account never spend anything + // (even if we force 0 nonce at first activity) + let (topo, nonce) = storage.get_last_nonce(key).await.context("Error while retrieving last topoheight for nonce")?; + let version = storage.get_balance_at_exact_topoheight(key, ¶ms.asset, topo).await.context(format!("Error while retrieving balance at topo height {topo}"))?; + Some((topo, nonce.get_previous_topoheight(), version)) + } else { + Some( + storage.get_last_balance(key, ¶ms.asset).await + .map(|(topo, version)| (topo, None, version)) + .context("Error while retrieving last balance")? + ) + } }; let mut history_count = 0; let mut history = Vec::new(); + let is_dev_address = *key == *DEV_PUBLIC_KEY; - while let Some((topo, versioned_balance)) = version.take() { - trace!("Searching history of {} ({}) at topoheight {}", params.address, params.asset, topo); + while let Some((topo, prev_nonce, versioned_balance)) = version.take() { + trace!("Searching history of {} ({}) at topoheight {}, nonce: {:?}", params.address, params.asset, topo, prev_nonce); if topo < minimum_topoheight || topo < pruned_topoheight { break; } @@ -999,7 +1027,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu // Block reward is only paid in XELIS if params.asset == XELIS_ASSET { let is_miner = *block_header.get_miner() == *key; - if (is_miner || is_dev_address) && params.accept_coinbase { + if (is_miner || is_dev_address) && params.incoming_flow { let mut reward = storage.get_block_reward_at_topo_height(topo).context(format!("Error while retrieving reward at topo height {topo}"))?; // subtract dev fee if any let dev_fee_percentage = get_block_dev_fee(block_header.get_height()); @@ -1042,7 +1070,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu TransactionType::Transfers(transfers) => { for transfer in transfers { if *transfer.get_asset() == params.asset { - if *transfer.get_destination() == *key && params.accept_incoming_txs { + if *transfer.get_destination() == *key && params.incoming_flow { history.push(AccountHistoryEntry { topoheight: topo, hash: tx_hash.clone(), @@ -1053,7 +1081,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu }); } - if is_sender && params.accept_outgoing_txs { + if is_sender && params.outgoing_flow { history.push(AccountHistoryEntry { topoheight: topo, hash: tx_hash.clone(), @@ -1068,7 +1096,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu } TransactionType::Burn(payload) => { if payload.asset == params.asset { - if is_sender && params.accept_outgoing_txs { + if is_sender && params.outgoing_flow { history.push(AccountHistoryEntry { topoheight: topo, hash: tx_hash.clone(), @@ -1086,11 +1114,17 @@ async fn get_account_history(context: &Context, body: Value) -> Resu break; } - if let Some(previous) = versioned_balance.get_previous_topoheight() { + // if incoming flows aren't accepted + // use nonce versions to determine topoheight + if let Some(previous) = prev_nonce.filter(|_| !params.incoming_flow) { + let nonce_version = storage.get_nonce_at_exact_topoheight(key, previous).await.context(format!("Error while retrieving nonce at topo height {previous}"))?; + version = Some((previous, nonce_version.get_previous_topoheight(), storage.get_balance_at_exact_topoheight(key, ¶ms.asset, previous).await.context(format!("Error while retrieving previous balance at topo height {previous}"))?)); + } else if let Some(previous) = versioned_balance.get_previous_topoheight().filter(|_| params.incoming_flow) { if previous < pruned_topoheight { break; } - version = Some((previous, storage.get_balance_at_exact_topoheight(key, ¶ms.asset, previous).await.context(format!("Error while retrieving previous balance at topo height {previous}"))?)); + + version = Some((previous, None, storage.get_balance_at_exact_topoheight(key, ¶ms.asset, previous).await.context(format!("Error while retrieving previous balance at topo height {previous}"))?)); } } From ec0c0a209aca7def79042ab1f89b1fcaaf352635 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 00:22:37 +0200 Subject: [PATCH 21/83] misc: get_account_history --- API.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/API.md b/API.md index 51cc01b7..334cd567 100644 --- a/API.md +++ b/API.md @@ -5635,15 +5635,15 @@ NOTE: If no asset is provided, default is set to XELIS. ##### Method `get_account_history` ##### Parameters -| Name | Type | Required | Note | -|:-------------------:|:-------:|:--------:|:----------------------------------------------------:| -| address | Address | Required | Valid address registered on chain | -| asset | Hash | Optional | Asset to track | -| minimum_topoheight | Integer | Optional | minimum topoheight for history | -| maximum_topoheight | Integer | Optional | Maximum topoheight for history | -| accept_coinbase | Boolean | Optional | Set to true by default, filter mining rewards | -| accept_outgoing_txs | Boolean | Optional | Set to true by default, filter outgoing transactions | -| accept_incoming_txs | Boolean | Optional | Set to true by default, filter incoming transactions | +| Name | Type | Required | Note | +|:------------------:|:-------:|:--------:|:---------------------------------------------------------------:| +| address | Address | Required | Valid address registered on chain | +| asset | Hash | Optional | Asset to track | +| minimum_topoheight | Integer | Optional | minimum topoheight for history | +| maximum_topoheight | Integer | Optional | Maximum topoheight for history | +| outgoing_flow | Boolean | Optional | Set to true by default, filter outgoing transactions | +| incoming_flow | Boolean | Optional | Set to true by default, filter incoming transactions / coinbase | + ##### Request ```json { @@ -5652,10 +5652,7 @@ NOTE: If no asset is provided, default is set to XELIS. "method": "get_account_history", "params": { "address": "xet:6eadzwf5xdacts6fs4y3csmnsmy4mcxewqt3xyygwfx0hm0tm32sqxdy9zk", - "asset": "0000000000000000000000000000000000000000000000000000000000000000", - "accept_coinbase": true, - "accept_outgoing_txs": true, - "accept_incoming_txs": false, + "asset": "0000000000000000000000000000000000000000000000000000000000000000" } } ``` From 511043ac751a149373106bd8264bfa56a9e267df Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 01:04:29 +0200 Subject: [PATCH 22/83] common: version_requirement for hardfork struct, derive debug --- xelis_common/src/api/daemon.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xelis_common/src/api/daemon.rs b/xelis_common/src/api/daemon.rs index d61c24eb..52c63d97 100644 --- a/xelis_common/src/api/daemon.rs +++ b/xelis_common/src/api/daemon.rs @@ -477,14 +477,17 @@ pub struct DevFeeThreshold { } // Struct to define hard fork -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct HardFork { // block height to start hard fork pub height: u64, // Block version to use pub version: BlockVersion, // All the changes that will be applied - pub changelog: &'static str + pub changelog: &'static str, + // Version requirement, example: >=1.13.0 + // This is used for p2p protocol + pub version_requirement: Option<&'static str>, } // Struct to returns the size of the blockchain on disk From a61c2b7e6bd286a6b2b81c78e4332287c7ec70bc Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 01:11:24 +0200 Subject: [PATCH 23/83] daemon: add semver check for p2p connections --- xelis_daemon/Cargo.toml | 1 + xelis_daemon/src/config.rs | 4 ++ xelis_daemon/src/core/hard_fork.rs | 97 ++++++++++++++++++++++++++---- xelis_daemon/src/p2p/error.rs | 2 + xelis_daemon/src/p2p/mod.rs | 7 ++- 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/xelis_daemon/Cargo.toml b/xelis_daemon/Cargo.toml index 2b010cc2..89844350 100644 --- a/xelis_daemon/Cargo.toml +++ b/xelis_daemon/Cargo.toml @@ -34,3 +34,4 @@ serde_json = "1" rand = "0.8.4" ed25519-dalek = "1" indexmap = { version = "2.0.0", features = ["serde"] } +semver = "1.0.23" diff --git a/xelis_daemon/src/config.rs b/xelis_daemon/src/config.rs index 2036c6d1..6737ce53 100644 --- a/xelis_daemon/src/config.rs +++ b/xelis_daemon/src/config.rs @@ -182,11 +182,13 @@ const HARD_FORKS: [HardFork; 2] = [ height: 0, version: BlockVersion::V0, changelog: "Initial version", + version_requirement: None }, HardFork { height: 434_100, // Expected date: 10/07/2024 12am UTC version: BlockVersion::V1, changelog: "xelis-hash v2", + version_requirement: Some(">=1.13.0") } ]; @@ -196,11 +198,13 @@ const TESTNET_HARD_FORKS: [HardFork; 2] = [ height: 0, version: BlockVersion::V0, changelog: "Initial version", + version_requirement: None }, HardFork { height: 5, version: BlockVersion::V1, changelog: "xelis-hash v2", + version_requirement: Some(">=1.13.0") } ]; diff --git a/xelis_daemon/src/core/hard_fork.rs b/xelis_daemon/src/core/hard_fork.rs index abf7cd0b..34be3fb2 100644 --- a/xelis_daemon/src/core/hard_fork.rs +++ b/xelis_daemon/src/core/hard_fork.rs @@ -1,22 +1,28 @@ -use xelis_common::{block::{Algorithm, BlockVersion}, network::Network}; +use anyhow::Result; +use xelis_common::{ + api::daemon::HardFork, + block::{Algorithm, BlockVersion}, + network::Network +}; use crate::config::get_hard_forks; -// Get the version of the hard fork at a given height -// and returns true if there is a hard fork (version change) at that height -pub fn has_hard_fork_at_height(network: &Network, height: u64) -> (bool, BlockVersion) { - let mut version = BlockVersion::V0; - let mut hard_fork = false; +// Get the hard fork at a given height +pub fn get_hard_fork_at_height(network: &Network, height: u64) -> Option<&HardFork> { for hardfork in get_hard_forks(network) { - if height >= hardfork.height { - version = hardfork.version; - } - if height == hardfork.height { - hard_fork = true; - break; + return Some(hardfork); } } - (hard_fork, version) + None +} + +// Get the version of the hard fork at a given height +// and returns true if there is a hard fork (version change) at that height +pub fn has_hard_fork_at_height(network: &Network, height: u64) -> (bool, BlockVersion) { + match get_hard_fork_at_height(network, height) { + Some(hard_fork) => (hard_fork.height == height, hard_fork.version), + None => (false, BlockVersion::V0) + } } // This function returns the block version at a given height @@ -32,10 +38,75 @@ pub fn get_pow_algorithm_for_version(version: BlockVersion) -> Algorithm { } } +// This function checks if a version is matching the requirements +// it split the version if it contains a `-` and only takes the first part +// to support our git commit hash +fn is_version_matching_requirement(version: &str, req: &str) -> Result { + let r = semver::VersionReq::parse(req)?; + let str_version = match version.split_once('-') { + Some((v, _)) => v, + None => version + }; + + let v = semver::Version::parse(str_version)?; + + Ok(r.matches(&v)) +} + +// This function checks if a version is allowed at a given height +pub fn is_version_allowed_at_height(network: &Network, height: u64, version: &str) -> Result { + for hard_fork in get_hard_forks(network) { + if let Some(req) = hard_fork.version_requirement.filter(|_| hard_fork.height <= height) { + if !is_version_matching_requirement(version, req)? { + return Ok(false); + } + } + } + + Ok(true) +} + #[cfg(test)] mod tests { + use xelis_common::config::VERSION; + use super::*; + #[test] + fn test_version_matching_requirement() { + assert_eq!(is_version_matching_requirement("1.0.0-abcdef", ">=1.0.0").unwrap(), true); + assert_eq!(is_version_matching_requirement("1.0.0-999", ">=1.0.0").unwrap(), true); + assert_eq!(is_version_matching_requirement("1.0.0-abcdef999", ">=1.0.0").unwrap(), true); + assert_eq!(is_version_matching_requirement("1.0.0", ">=1.0.1").unwrap(), false); + assert_eq!(is_version_matching_requirement("1.0.0", "<1.0.1").unwrap(), true); + assert_eq!(is_version_matching_requirement("1.0.0", "<1.0.0").unwrap(), false); + } + + #[test] + fn test_current_version_against_mainnet_hard_forks() { + const VERSIONS: [&str; 3] = ["1.0.0", "1.0.0-abcdef", "1.0.0-abcdef999"]; + + for version in VERSIONS { + assert!(is_version_allowed_at_height(&Network::Mainnet, 0, version).unwrap()); + } + + // Should still be valid as we don't have any requirement + assert!(is_version_allowed_at_height(&Network::Mainnet, 0, "0.0.0").unwrap()); + + // Current version should always be valid on previous versions + assert!(is_version_allowed_at_height(&Network::Mainnet, 0, &VERSION).unwrap()); + + // Should be invalid as we require 1.13.0 + for version in VERSIONS { + println!("Testing version: {}", version); + assert!(!is_version_allowed_at_height(&Network::Mainnet, 435_000, version).unwrap()); + } + + // Should be valid as we require 1.13.0 + assert!(is_version_allowed_at_height(&Network::Mainnet, 435_000, "1.13.0").unwrap()); + assert!(is_version_allowed_at_height(&Network::Mainnet, 435_000, VERSION).unwrap()); + } + #[test] fn test_has_hard_fork_at_height() { let (hard_fork, version) = has_hard_fork_at_height(&Network::Testnet, 0); diff --git a/xelis_daemon/src/p2p/error.rs b/xelis_daemon/src/p2p/error.rs index 31f76b22..10f8279d 100644 --- a/xelis_daemon/src/p2p/error.rs +++ b/xelis_daemon/src/p2p/error.rs @@ -35,6 +35,8 @@ use super::{ #[derive(Error, Debug)] pub enum P2pError { + #[error("Invalid P2P version: {}", _0)] + InvalidP2pVersion(String), #[error("Invalid tag, it must be greater than 0 and maximum 16 chars")] InvalidTag, #[error("Invalid max chain response size, it must be between {} and {}", CHAIN_SYNC_RESPONSE_MIN_BLOCKS, CHAIN_SYNC_RESPONSE_MAX_BLOCKS)] diff --git a/xelis_daemon/src/p2p/mod.rs b/xelis_daemon/src/p2p/mod.rs index 61c515cb..cbdf80b4 100644 --- a/xelis_daemon/src/p2p/mod.rs +++ b/xelis_daemon/src/p2p/mod.rs @@ -46,7 +46,7 @@ use crate::{ blockchain::Blockchain, error::BlockchainError, storage::Storage, - hard_fork::get_version_at_height + hard_fork::{get_version_at_height, is_version_allowed_at_height} }, p2p::{ chain_validator::ChainValidator, @@ -582,6 +582,11 @@ impl P2pServer { } } + // check if the version of this peer is allowed + if !is_version_allowed_at_height(self.blockchain.get_network(), self.blockchain.get_height(), handshake.get_version()).map_err(|e| P2pError::InvalidP2pVersion(e.to_string()))? { + return Err(P2pError::InvalidP2pVersion(handshake.get_version().clone())); + } + Ok(()) } From 25397d976d0eaccbd694881bf7ed734290cf6f21 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 01:11:35 +0200 Subject: [PATCH 24/83] daemon: add semver dependency --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 82e2528c..5fe951b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3498,6 +3498,7 @@ dependencies = [ "log", "lru", "rand 0.8.5", + "semver", "serde", "serde_json", "sled", From ec0ca924a24c78a60695ba0dc5f14665e4c81ab3 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 16:30:55 +0200 Subject: [PATCH 25/83] common: fix resubscribe event --- xelis_common/src/api/wallet.rs | 2 +- xelis_common/src/json_rpc/websocket.rs | 37 +++++++++++++++++--------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index 5d031d8d..801c1e70 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -90,7 +90,7 @@ pub struct GetTransactionParams { pub hash: Hash } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct BalanceChanged { pub asset: Hash, pub balance: u64 diff --git a/xelis_common/src/json_rpc/websocket.rs b/xelis_common/src/json_rpc/websocket.rs index aa0e48fb..c88527b8 100644 --- a/xelis_common/src/json_rpc/websocket.rs +++ b/xelis_common/src/json_rpc/websocket.rs @@ -113,7 +113,7 @@ pub struct WebSocketJsonRPCClientImpl WebSocketJsonRPCClientImpl { +impl WebSocketJsonRPCClientImpl { async fn connect_to(target: &String) -> Result { let ws = connect(target).await?; @@ -210,19 +210,32 @@ impl WebSocketJsonRPCC } // resubscribe to all events because of a reconnection - async fn resubscribe_events(&self) -> Result<(), JsonRPCError> { + async fn resubscribe_events(self: Arc) -> Result<(), JsonRPCError> { let events = { let events = self.events_to_id.lock().await; events.clone() }; - for (event, id) in events { - // Send it to the server - if !self.send::<_, bool>("subscribe", Some(id), &SubscribeParams { - notify: Cow::Borrowed(&event), - }).await? { - error!("Error while resubscribing to event with id {}", id); + + spawn_task("resubscribe-events", async move { + for (event, id) in events { + debug!("Resubscribing to event {:?} with id {}", event, id); + + // Send it to the server + let res = match self.send::<_, bool>("subscribe", Some(id), &SubscribeParams { + notify: Cow::Borrowed(&event), + }).await { + Ok(res) => res, + Err(e) => { + error!("Error while resubscribing to event with id {}: {:?}", id, e); + false + } + }; + + if !res { + error!("Error while resubscribing to event with id {}", id); + } } - } + }); Ok(()) } @@ -284,7 +297,7 @@ impl WebSocketJsonRPCC } - if let Err(e) = self.resubscribe_events().await { + if let Err(e) = Arc::clone(&self).resubscribe_events().await { error!("Error while resubscribing to events: {:?}", e); } @@ -351,8 +364,8 @@ impl WebSocketJsonRPCC ws = Some(websocket); // Register all events again - if let Err(e) = zelf.resubscribe_events().await { - error!("Error while resubscribing to events: {:?}", e); + if let Err(e) = Arc::clone(&zelf).resubscribe_events().await { + error!("Error while resubscribing to events due to reconnect: {:?}", e); } break; From 4cbe3e110d267a0cdad816ebeee5446d95cb6dd2 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 16:32:15 +0200 Subject: [PATCH 26/83] wallet: propagate event log --- xelis_wallet/src/wallet.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index 1a840c0e..a64aded9 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -124,7 +124,7 @@ use { )))] use xelis_common::tokio::task::spawn_blocking; -#[derive(Serialize, Clone)] +#[derive(Serialize, Clone, Debug)] #[serde(untagged)] pub enum Event { // When a TX is detected from daemon and is added in wallet storage @@ -428,6 +428,7 @@ impl Wallet { // Propagate a new event to registered listeners pub async fn propagate_event(&self, event: Event) { + trace!("Propagate event: {:?}", event); // Broadcast it to the API Server #[cfg(feature = "api_server")] { From 846c854f227e073409abf840104b87f3ad53b67e Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 17:30:48 +0200 Subject: [PATCH 27/83] wallet: propagate online event correctly --- xelis_wallet/src/network_handler.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index a5f263e1..cbe56476 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -119,6 +119,9 @@ impl NetworkHandler { let zelf = Arc::clone(&self); *self.task.lock().await = Some(spawn_task("network-handler", async move { loop { + // Notify that we are online + zelf.wallet.propagate_event(Event::Online).await; + let res = zelf.start_syncing().await; if let Err(e) = res.as_ref() { error!("Error while syncing: {}", e); @@ -152,10 +155,6 @@ impl NetworkHandler { } })); - - // Notify that we are online - self.wallet.propagate_event(Event::Online).await; - Ok(()) } From 11c22fd87ce99c450f0243c279d706f441af07d3 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 17:49:13 +0200 Subject: [PATCH 28/83] wallet: prevent double online event propagation --- xelis_wallet/src/network_handler.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index cbe56476..e3568665 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -143,9 +143,6 @@ impl NetworkHandler { if !zelf.api.reconnect().await? { error!("Couldn't reconnect to server, trying again in {} seconds", AUTO_RECONNECT_INTERVAL); sleep(Duration::from_secs(AUTO_RECONNECT_INTERVAL)).await; - } else { - // Notify that we are back online - zelf.wallet.propagate_event(Event::Online).await; } } else { warn!("Daemon is online but we couldn't sync, trying again in {} seconds", AUTO_RECONNECT_INTERVAL); From 75296a11e7399ccbb27aae6718737d28f38578d1 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 20:44:18 +0200 Subject: [PATCH 29/83] daemon: go through whole configured hard forks --- xelis_daemon/src/core/hard_fork.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xelis_daemon/src/core/hard_fork.rs b/xelis_daemon/src/core/hard_fork.rs index 34be3fb2..5960f3fd 100644 --- a/xelis_daemon/src/core/hard_fork.rs +++ b/xelis_daemon/src/core/hard_fork.rs @@ -8,12 +8,14 @@ use crate::config::get_hard_forks; // Get the hard fork at a given height pub fn get_hard_fork_at_height(network: &Network, height: u64) -> Option<&HardFork> { - for hardfork in get_hard_forks(network) { - if height == hardfork.height { - return Some(hardfork); + let mut hardfork: Option<&HardFork> = None; + for conf in get_hard_forks(network) { + if height >= conf.height { + hardfork = Some(conf); } } - None + + hardfork } // Get the version of the hard fork at a given height From e2feec6d6129dc21ae667d25ba9ab463657ca63c Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 29 Jul 2024 20:48:33 +0200 Subject: [PATCH 30/83] daemon: break if next hard fork is above requested height --- xelis_daemon/src/core/hard_fork.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xelis_daemon/src/core/hard_fork.rs b/xelis_daemon/src/core/hard_fork.rs index 5960f3fd..311a8a09 100644 --- a/xelis_daemon/src/core/hard_fork.rs +++ b/xelis_daemon/src/core/hard_fork.rs @@ -12,6 +12,8 @@ pub fn get_hard_fork_at_height(network: &Network, height: u64) -> Option<&HardFo for conf in get_hard_forks(network) { if height >= conf.height { hardfork = Some(conf); + } else { + break; } } From 69d25d1213126d6dec52bc5d0e594081f1098ec9 Mon Sep 17 00:00:00 2001 From: Slixe Date: Sun, 4 Aug 2024 19:27:39 +0200 Subject: [PATCH 31/83] daemon: invalid chain response size error typo --- xelis_daemon/src/p2p/error.rs | 2 +- xelis_daemon/src/p2p/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xelis_daemon/src/p2p/error.rs b/xelis_daemon/src/p2p/error.rs index 10f8279d..abfebfb9 100644 --- a/xelis_daemon/src/p2p/error.rs +++ b/xelis_daemon/src/p2p/error.rs @@ -90,7 +90,7 @@ pub enum P2pError { #[error("Received a unrequested chain response")] UnrequestedChainResponse, #[error("Invalid chain response size, got {} blocks while maximum set was {}", _0, _1)] - InvaliChainResponseSize(usize, usize), + InvalidChainResponseSize(usize, usize), #[error("Received a unrequested bootstrap chain response")] UnrequestedBootstrapChainResponse, #[error("Invalid common point at topoheight {}", _0)] diff --git a/xelis_daemon/src/p2p/mod.rs b/xelis_daemon/src/p2p/mod.rs index cbdf80b4..9823a87c 100644 --- a/xelis_daemon/src/p2p/mod.rs +++ b/xelis_daemon/src/p2p/mod.rs @@ -2884,7 +2884,7 @@ impl P2pServer { // Check that the peer followed our requirements if response.blocks_size() > requested_max_size { - return Err(P2pError::InvaliChainResponseSize(response.blocks_size(), requested_max_size).into()) + return Err(P2pError::InvalidChainResponseSize(response.blocks_size(), requested_max_size).into()) } // Update last chain sync time From 818e5963f1b641a983257f0778f37c4a2668255e Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 11:12:30 +0200 Subject: [PATCH 32/83] common: add a test case, add MakeIntegratedAddressParams for daemon --- xelis_common/src/api/daemon.rs | 8 +++++++- xelis_common/src/utils.rs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/xelis_common/src/api/daemon.rs b/xelis_common/src/api/daemon.rs index 52c63d97..e19ca91e 100644 --- a/xelis_common/src/api/daemon.rs +++ b/xelis_common/src/api/daemon.rs @@ -19,7 +19,7 @@ use crate::{ network::Network, time::{TimestampMillis, TimestampSeconds} }; -use super::{default_true_value, RPCTransaction}; +use super::{default_true_value, DataElement, RPCTransaction}; #[derive(Serialize, Deserialize, PartialEq, Eq)] pub enum BlockType { @@ -550,6 +550,12 @@ pub enum ExtractKeyFromAddressResult { Hex(String) } +#[derive(Serialize, Deserialize)] +pub struct MakeIntegratedAddressParams<'a> { + pub address: Cow<'a, Address>, + pub integrated_data: Cow<'a, DataElement> +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum NotifyEvent { diff --git a/xelis_common/src/utils.rs b/xelis_common/src/utils.rs index 3c20e99c..69f94ce2 100644 --- a/xelis_common/src/utils.rs +++ b/xelis_common/src/utils.rs @@ -137,6 +137,7 @@ mod tests { assert_eq!(format_xelis(FEE_PER_KB), "0.00010000"); assert_eq!(format_xelis(FEE_PER_TRANSFER), "0.00005000"); assert_eq!(format_xelis(COIN_VALUE), "1.00000000"); + assert_eq!(format_xelis(1), "0.00000001"); } #[test] From ea0919ca57eff5a68eb4b339a3f6d2205ab5b82d Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 11:13:17 +0200 Subject: [PATCH 33/83] daemon: add make_integrated_address, also verify addresses are compatible with daemon network --- xelis_daemon/src/rpc/rpc.rs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/xelis_daemon/src/rpc/rpc.rs b/xelis_daemon/src/rpc/rpc.rs index 8069ce2c..6f38f487 100644 --- a/xelis_daemon/src/rpc/rpc.rs +++ b/xelis_daemon/src/rpc/rpc.rs @@ -40,7 +40,7 @@ use xelis_common::{ XELIS_ASSET }, context::Context, - crypto::Hash, + crypto::{Address, AddressType, Hash}, difficulty::{ CumulativeDifficulty, Difficulty @@ -320,6 +320,7 @@ pub fn register_methods(handler: &mut RPCHandler>> handler.register_method("validate_address", async_handler!(validate_address::)); handler.register_method("split_address", async_handler!(split_address::)); handler.register_method("extract_key_from_address", async_handler!(extract_key_from_address::)); + handler.register_method("make_integrated_address", async_handler!(make_integrated_address::)); if allow_mining_methods { handler.register_method("get_block_template", async_handler!(get_block_template::)); @@ -1015,7 +1016,7 @@ async fn get_account_history(context: &Context, body: Value) -> Resu let is_dev_address = *key == *DEV_PUBLIC_KEY; while let Some((topo, prev_nonce, versioned_balance)) = version.take() { - trace!("Searching history of {} ({}) at topoheight {}, nonce: {:?}", params.address, params.asset, topo, prev_nonce); + trace!("Searching history of {} ({}) at topoheight {}, nonce: {:?}, type: {:?}", params.address, params.asset, topo, prev_nonce, versioned_balance.get_balance_type()); if topo < minimum_topoheight || topo < pruned_topoheight { break; } @@ -1301,9 +1302,14 @@ async fn validate_address(context: &Context, body: Value) -> Result< })) } -async fn extract_key_from_address(_: &Context, body: Value) -> Result { +async fn extract_key_from_address(context: &Context, body: Value) -> Result { let params: ExtractKeyFromAddressParams = parse_params(body)?; + let blockchain: &Arc> = context.get()?; + if params.address.is_mainnet() != blockchain.get_network().is_mainnet() { + return Err(InternalRpcError::InvalidParamsAny(BlockchainError::InvalidNetwork.into())) + } + if params.as_hex { Ok(json!(ExtractKeyFromAddressResult::Hex(params.address.get_public_key().to_hex()))) } else { @@ -1313,10 +1319,15 @@ async fn extract_key_from_address(_: &Context, body: Value) -> Resul // Split an integrated address into its address and data -async fn split_address(_: &Context, body: Value) -> Result { +async fn split_address(context: &Context, body: Value) -> Result { let params: SplitAddressParams = parse_params(body)?; let address = params.address; + let blockchain: &Arc> = context.get()?; + if address.is_mainnet() != blockchain.get_network().is_mainnet() { + return Err(InternalRpcError::InvalidParamsAny(BlockchainError::InvalidNetwork.into())) + } + let (data, address) = address.extract_data(); let integrated_data = data.ok_or(InternalRpcError::InvalidParams("Address is not an integrated address"))?; let size = integrated_data.size(); @@ -1325,4 +1336,21 @@ async fn split_address(_: &Context, body: Value) -> Result(context: &Context, body: Value) -> Result { + let params: MakeIntegratedAddressParams = parse_params(body)?; + + let blockchain: &Arc> = context.get()?; + if params.address.is_mainnet() != blockchain.get_network().is_mainnet() { + return Err(InternalRpcError::InvalidParamsAny(BlockchainError::InvalidNetwork.into())) + } + + if !params.address.is_normal() { + return Err(InternalRpcError::InvalidParams("Address is not a normal address")) + } + + let address = Address::new(params.address.is_mainnet(), AddressType::Data(params.integrated_data.into_owned()), params.address.into_owned().to_public_key()); + + Ok(json!(address)) } \ No newline at end of file From e715f61314a52da6bd10cc4f62d384114d43e2f6 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 11:16:03 +0200 Subject: [PATCH 34/83] misc: add make_integrated_address in API.md --- API.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/API.md b/API.md index 334cd567..b176098e 100644 --- a/API.md +++ b/API.md @@ -589,6 +589,49 @@ NOTE: If `as_hex` is `false`, the response result will contains a field named `b } ``` +#### Make Integrated Address +Create an integrated address using a wallet address and data to include. + +##### Method `make_integrated_address` + +##### Parameters +| Name | Type | Required | Note | +|:-------:|:-------:|:--------:|:--------------------------------------------------------------------:| +| address | Address | Required | Address to split in two parts: original address, and integrated data | + +##### Request +```json +{ + "jsonrpc": "2.0", + "method": "make_integrated_address", + "id": 1, + "params": { + "address": "xet:6eadzwf5xdacts6fs4y3csmnsmy4mcxewqt3xyygwfx0hm0tm32sqxdy9zk", + "integrated_data": { + "hello": "world", + "items": { + "sword": 5 + }, + "words": [ + "Hello", + "World", + "from", + "XELIS" + ] + } + } +} +``` + +##### Response +```json +{ + "id": 1, + "jsonrpc": "2.0", + "result": "xel:6eadzwf5xdacts6fs4y3csmnsmy4mcxewqt3xyygwfx0hm0tm32szqsrqyzkjar9d4esyqgpq4ehwmmjvsqqypgpq45x2mrvduqqzpthdaexceqpq4mk7unywvqsgqqpq4yx2mrvduqqzp2hdaexceqqqyzxvun0d5qqzp2cg4xyj5ct5udlg" +} +``` + #### Get Block Template Retrieve the block template (Block Header) for PoW work. From dbd45938d13ff836dc9099ae92be4db7611a7ef0 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 11:35:41 +0200 Subject: [PATCH 35/83] wallet: support 24 words seed, add comments, remove lazy_static --- xelis_wallet/src/mnemonics/mod.rs | 66 ++++++++++++++++++------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/xelis_wallet/src/mnemonics/mod.rs b/xelis_wallet/src/mnemonics/mod.rs index fc1404ec..5ebe40ae 100644 --- a/xelis_wallet/src/mnemonics/mod.rs +++ b/xelis_wallet/src/mnemonics/mod.rs @@ -2,7 +2,6 @@ pub mod languages; use std::collections::HashMap; use anyhow::{Result, Context, anyhow}; -use lazy_static::lazy_static; use log::debug; use xelis_common::{ crypto::PrivateKey, @@ -15,28 +14,29 @@ const SEED_LENGTH: usize = 24; const WORDS_LIST: usize = 1626; const WORDS_LIST_U32: u32 = WORDS_LIST as u32; -lazy_static! { - pub static ref LANGUAGES: Vec> = vec![ - english::ENGLISH, - french::FRENCH, - italian::ITALIAN, - spanish::SPANISH, - portuguese::PORTUGUESE, - japanese::JAPANESE, - chinese_simplified::CHINESE_SIMPLIFIED, - russian::RUSSIAN, - esperanto::ESPERANTO, - dutch::DUTCH, - german::GERMAN - ]; -} - +pub const LANGUAGES: [Language<'static>; 11] = [ + english::ENGLISH, + french::FRENCH, + italian::ITALIAN, + spanish::SPANISH, + portuguese::PORTUGUESE, + japanese::JAPANESE, + chinese_simplified::CHINESE_SIMPLIFIED, + russian::RUSSIAN, + esperanto::ESPERANTO, + dutch::DUTCH, + german::GERMAN +]; pub struct Language<'a> { + // Language name, like "English" or "French" name: &'a str, - prefix_length: usize, // number of utf-8 chars to use for checksum + // number of utf-8 chars to use for checksum + prefix_length: usize, + // list of words in the language words: [&'a str; WORDS_LIST] } +// Calculate the checksum index for the seed based on the language prefix length fn calculate_checksum_index(words: &[String], prefix_len: usize) -> Result { if words.len() != SEED_LENGTH { return Err(anyhow!("Invalid number of words")); @@ -56,13 +56,14 @@ fn calculate_checksum_index(words: &[String], prefix_len: usize) -> Result Ok(checksum % SEED_LENGTH as u32) } -fn verify_checksum(words: &Vec, prefix_len: usize) -> Result { +// Verify the checksum of the seed based on the language prefix length and if the seed is composed of 25 words +fn verify_checksum(words: &Vec, prefix_len: usize) -> Result> { let checksum_index = calculate_checksum_index(&words[0..SEED_LENGTH], prefix_len)?; let checksum_word = words.get(checksum_index as usize).context("Invalid checksum index")?; - let expected_checksum_word = words.get(SEED_LENGTH).context("Invalid checksum word")?; - Ok(checksum_word == expected_checksum_word) + Ok(words.get(SEED_LENGTH).map(|v| v == checksum_word)) } +// Find the indices of the words in the languages fn find_indices(words: &Vec) -> Result, usize)>> { 'main: for (i, language) in LANGUAGES.iter().enumerate() { // this map is used to store the indices of the words in the language @@ -84,7 +85,7 @@ fn find_indices(words: &Vec) -> Result, usize)>> { } // we were able to build the indices, now verify checksum - if !verify_checksum(&words, language.prefix_length)? { + if !verify_checksum(&words, language.prefix_length)?.unwrap_or(true) { return Err(anyhow!("Invalid checksum for seed")); } @@ -95,8 +96,8 @@ fn find_indices(words: &Vec) -> Result, usize)>> { // convert a words list to a Private Key (32 bytes) pub fn words_to_key(words: &Vec) -> Result { - if words.len() != SEED_LENGTH + 1 { - return Err(anyhow!("Invalid number of words")); + if !(words.len() == SEED_LENGTH + 1 || words.len() == SEED_LENGTH) { + return Err(anyhow!("Invalid number of words, expected 24 or 25 words, got {}", words.len())); } let (indices, language_index) = find_indices(words)?.context("No indices found")?; @@ -104,9 +105,9 @@ pub fn words_to_key(words: &Vec) -> Result { let mut dest = Vec::with_capacity(KEY_SIZE); for i in (0..SEED_LENGTH).step_by(3) { - let a = indices.get(i).context("Index out of bounds")?; - let b = indices.get(i + 1).context("Index out of bounds")?; - let c = indices.get(i + 2).context("Index out of bounds")?; + let a = indices.get(i).context("Index out of bounds for a")?; + let b = indices.get(i + 1).context("Index out of bounds for b")?; + let c = indices.get(i + 2).context("Index out of bounds for c")?; let val = a + WORDS_LIST * (((WORDS_LIST - a) + b) % WORDS_LIST) + WORDS_LIST * WORDS_LIST * (((WORDS_LIST - b) + c) % WORDS_LIST); if val % WORDS_LIST != *a { @@ -120,11 +121,13 @@ pub fn words_to_key(words: &Vec) -> Result { Ok(PrivateKey::from_bytes(&dest)?) } +// Transform a Private Key to a list of words based on the language index pub fn key_to_words(key: &PrivateKey, language_index: usize) -> Result> { let language = LANGUAGES.get(language_index).context("Invalid language index")?; key_to_words_with_language(key, language) } +// Transform a Private Key to a list of words with a specific language pub fn key_to_words_with_language(key: &PrivateKey, language: &Language) -> Result> { if language.words.len() != WORDS_LIST { return Err(anyhow!("Invalid word list length")); @@ -165,8 +168,15 @@ mod tests { let nkey = super::words_to_key(&words).unwrap(); assert_eq!(key.as_scalar(), nkey.as_scalar()); - let words2 = super::key_to_words_with_language(&nkey, language).unwrap(); + let mut words2 = super::key_to_words_with_language(&nkey, language).unwrap(); assert_eq!(words, words2); + + // Also test with 24 words only + words2.pop(); + assert_eq!(words2.len(), 24); + + let nkey = super::words_to_key(&words2).unwrap(); + assert_eq!(key.as_scalar(), nkey.as_scalar()); } } } \ No newline at end of file From 85cbd4389b4b19704b2dacccd4e249768db0dfd2 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 11:50:51 +0200 Subject: [PATCH 36/83] wallet: create mnemonics error enum --- xelis_wallet/src/mnemonics/mod.rs | 69 +++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/xelis_wallet/src/mnemonics/mod.rs b/xelis_wallet/src/mnemonics/mod.rs index 5ebe40ae..035200d9 100644 --- a/xelis_wallet/src/mnemonics/mod.rs +++ b/xelis_wallet/src/mnemonics/mod.rs @@ -1,7 +1,7 @@ pub mod languages; +use thiserror::Error; use std::collections::HashMap; -use anyhow::{Result, Context, anyhow}; use log::debug; use xelis_common::{ crypto::PrivateKey, @@ -27,6 +27,33 @@ pub const LANGUAGES: [Language<'static>; 11] = [ dutch::DUTCH, german::GERMAN ]; + +#[derive(Debug, Error)] +pub enum MnemonicsError { + #[error("Invalid words count")] + InvalidWordsCount, + #[error("Invalid checksum")] + InvalidChecksum, + #[error("Invalid checksum index")] + InvalidChecksumIndex, + #[error("Invalid language index")] + InvalidLanguageIndex, + #[error("Invalid language")] + InvalidLanguage, + #[error("Invalid key size")] + InvalidKeySize, + #[error("Invalid key from bytes")] + InvalidKeyFromBytes, + #[error("Invalid checksum calculation")] + InvalidChecksumCalculation, + #[error("No indices found")] + NoIndicesFound, + #[error("Word list sanity check error")] + WordListSanityCheckError, + #[error("Out of bounds")] + OutOfBounds +} + pub struct Language<'a> { // Language name, like "English" or "French" name: &'a str, @@ -37,9 +64,9 @@ pub struct Language<'a> { } // Calculate the checksum index for the seed based on the language prefix length -fn calculate_checksum_index(words: &[String], prefix_len: usize) -> Result { +fn calculate_checksum_index(words: &[String], prefix_len: usize) -> Result { if words.len() != SEED_LENGTH { - return Err(anyhow!("Invalid number of words")); + return Err(MnemonicsError::InvalidWordsCount); } let mut chars: Vec = Vec::new(); @@ -57,14 +84,14 @@ fn calculate_checksum_index(words: &[String], prefix_len: usize) -> Result } // Verify the checksum of the seed based on the language prefix length and if the seed is composed of 25 words -fn verify_checksum(words: &Vec, prefix_len: usize) -> Result> { +fn verify_checksum(words: &Vec, prefix_len: usize) -> Result, MnemonicsError> { let checksum_index = calculate_checksum_index(&words[0..SEED_LENGTH], prefix_len)?; - let checksum_word = words.get(checksum_index as usize).context("Invalid checksum index")?; + let checksum_word = words.get(checksum_index as usize).ok_or(MnemonicsError::InvalidChecksumIndex)?; Ok(words.get(SEED_LENGTH).map(|v| v == checksum_word)) } // Find the indices of the words in the languages -fn find_indices(words: &Vec) -> Result, usize)>> { +fn find_indices(words: &Vec) -> Result, usize)>, MnemonicsError> { 'main: for (i, language) in LANGUAGES.iter().enumerate() { // this map is used to store the indices of the words in the language let mut language_words: HashMap<&str, usize> = HashMap::with_capacity(WORDS_LIST); @@ -86,7 +113,7 @@ fn find_indices(words: &Vec) -> Result, usize)>> { // we were able to build the indices, now verify checksum if !verify_checksum(&words, language.prefix_length)?.unwrap_or(true) { - return Err(anyhow!("Invalid checksum for seed")); + return Err(MnemonicsError::InvalidChecksum); } return Ok(Some((indices, i))); @@ -95,47 +122,47 @@ fn find_indices(words: &Vec) -> Result, usize)>> { } // convert a words list to a Private Key (32 bytes) -pub fn words_to_key(words: &Vec) -> Result { +pub fn words_to_key(words: &Vec) -> Result { if !(words.len() == SEED_LENGTH + 1 || words.len() == SEED_LENGTH) { - return Err(anyhow!("Invalid number of words, expected 24 or 25 words, got {}", words.len())); + return Err(MnemonicsError::InvalidWordsCount); } - let (indices, language_index) = find_indices(words)?.context("No indices found")?; + let (indices, language_index) = find_indices(words)?.ok_or(MnemonicsError::NoIndicesFound)?; debug!("Language found: {}", LANGUAGES[language_index].name); let mut dest = Vec::with_capacity(KEY_SIZE); for i in (0..SEED_LENGTH).step_by(3) { - let a = indices.get(i).context("Index out of bounds for a")?; - let b = indices.get(i + 1).context("Index out of bounds for b")?; - let c = indices.get(i + 2).context("Index out of bounds for c")?; + let a = indices.get(i).ok_or(MnemonicsError::OutOfBounds)?; + let b = indices.get(i + 1).ok_or(MnemonicsError::OutOfBounds)?; + let c = indices.get(i + 2).ok_or(MnemonicsError::OutOfBounds)?; let val = a + WORDS_LIST * (((WORDS_LIST - a) + b) % WORDS_LIST) + WORDS_LIST * WORDS_LIST * (((WORDS_LIST - b) + c) % WORDS_LIST); if val % WORDS_LIST != *a { - return Err(anyhow::anyhow!("Word list sanity check error")) + return Err(MnemonicsError::WordListSanityCheckError); } let val = val as u32; dest.extend_from_slice(&val.to_le_bytes()); } - Ok(PrivateKey::from_bytes(&dest)?) + Ok(PrivateKey::from_bytes(&dest).map_err(|_| MnemonicsError::InvalidKeyFromBytes)?) } // Transform a Private Key to a list of words based on the language index -pub fn key_to_words(key: &PrivateKey, language_index: usize) -> Result> { - let language = LANGUAGES.get(language_index).context("Invalid language index")?; +pub fn key_to_words(key: &PrivateKey, language_index: usize) -> Result, MnemonicsError> { + let language = LANGUAGES.get(language_index).ok_or(MnemonicsError::InvalidLanguageIndex)?; key_to_words_with_language(key, language) } // Transform a Private Key to a list of words with a specific language -pub fn key_to_words_with_language(key: &PrivateKey, language: &Language) -> Result> { +pub fn key_to_words_with_language(key: &PrivateKey, language: &Language) -> Result, MnemonicsError> { if language.words.len() != WORDS_LIST { - return Err(anyhow!("Invalid word list length")); + return Err(MnemonicsError::InvalidLanguage); } let bytes = key.to_bytes(); if bytes.len() != KEY_SIZE { - return Err(anyhow!("Invalid key length")); + return Err(MnemonicsError::InvalidKeySize); } let mut words = Vec::with_capacity(SEED_LENGTH + 1); @@ -151,7 +178,7 @@ pub fn key_to_words_with_language(key: &PrivateKey, language: &Language) -> Resu } let checksum = calculate_checksum_index(&words, language.prefix_length)?; - words.push(words.get(checksum as usize).context("error no checksum calculation")?.clone()); + words.push(words.get(checksum as usize).ok_or(MnemonicsError::InvalidChecksumCalculation)?.clone()); Ok(words) } From 6c7decfb1abbd43dc590ac56c08a0acaaf012b4c Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 12:11:01 +0200 Subject: [PATCH 37/83] common: remove temp code --- xelis_common/src/transaction/verify.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/xelis_common/src/transaction/verify.rs b/xelis_common/src/transaction/verify.rs index f3c4608f..fd16a347 100644 --- a/xelis_common/src/transaction/verify.rs +++ b/xelis_common/src/transaction/verify.rs @@ -282,15 +282,8 @@ impl Transaction { } } - // TODO: this is temporary until the hardfork has passed - let max_size = if state.get_block_version() == BlockVersion::V0 { - EXTRA_DATA_LIMIT_SIZE - } else { - EXTRA_DATA_LIMIT_SUM_SIZE - }; - // Check the sum of extra data size - if extra_data_size > max_size { + if extra_data_size > EXTRA_DATA_LIMIT_SUM_SIZE { return Err(VerificationError::TransactionExtraDataSize); } From 4f5ebb80019bce167199a42043958b2f8c91a686 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 12:22:29 +0200 Subject: [PATCH 38/83] common: no clone in builder functions --- xelis_common/src/transaction/builder.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/xelis_common/src/transaction/builder.rs b/xelis_common/src/transaction/builder.rs index d0bdd8c1..018e9ae4 100644 --- a/xelis_common/src/transaction/builder.rs +++ b/xelis_common/src/transaction/builder.rs @@ -181,20 +181,20 @@ impl TransferWithCommitment { impl TransactionTypeBuilder { // Get the assets used in the transaction - pub fn used_assets(&self) -> HashSet { + pub fn used_assets<'a>(&'a self) -> HashSet<&'a Hash> { let mut consumed = HashSet::new(); // Native asset is always used. (fees) - consumed.insert(XELIS_ASSET); + consumed.insert(&XELIS_ASSET); match &self { TransactionTypeBuilder::Transfers(transfers) => { for transfer in transfers { - consumed.insert(transfer.asset.clone()); + consumed.insert(&transfer.asset); } } TransactionTypeBuilder::Burn(payload) => { - consumed.insert(payload.asset.clone()); + consumed.insert(&payload.asset); } } @@ -202,13 +202,13 @@ impl TransactionTypeBuilder { } // Get the destination keys used in the transaction - pub fn used_keys(&self) -> Vec { - let mut used_keys = Vec::new(); + pub fn used_keys<'a>(&'a self) -> HashSet<&'a CompressedPublicKey> { + let mut used_keys = HashSet::new(); match &self { TransactionTypeBuilder::Transfers(transfers) => { for transfer in transfers { - used_keys.push(transfer.destination.get_public_key().clone()); + used_keys.insert(transfer.destination.get_public_key()); } } TransactionTypeBuilder::Burn(_) => {} @@ -425,8 +425,7 @@ impl TransactionBuilder { // 0.a Create the commitments - let used_assets = self.data.used_assets(); - + // Data is mutable only to extract extra data let transfers = if let TransactionTypeBuilder::Transfers(transfers) = &mut self.data { if transfers.len() == 0 { return Err(GenerationError::EmptyTransfers); @@ -503,6 +502,8 @@ impl TransactionBuilder { let reference = state.get_reference(); let mut transcript = Transaction::prepare_transcript(self.version, &self.source, fee, nonce); + let used_assets = self.data.used_assets(); + let mut range_proof_openings: Vec<_> = iter::repeat_with(|| PedersenOpening::generate_new().as_scalar()) .take(used_assets.len()) @@ -562,7 +563,7 @@ impl TransactionBuilder { .map_err(GenerationError::State)?; Ok(SourceCommitment { - asset, + asset: asset.clone(), commitment, proof, }) From df1995d00e0c14c2b0a3420eb8d10699a5199c7e Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 12:23:17 +0200 Subject: [PATCH 39/83] wallet: clone if needed for assets and keys --- xelis_wallet/src/wallet.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index a64aded9..8a71c46b 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -64,7 +64,6 @@ use crate::{ }; #[cfg(feature = "network_handler")] use { - std::collections::HashSet, log::warn, crate::{ network_handler::{ @@ -661,7 +660,7 @@ impl Wallet { if use_stable_balance { warn!("Using stable balance for TX creation"); let address = self.get_address(); - for asset in &used_assets { + for asset in used_assets.iter() { debug!("Searching stable balance for asset {}", asset); let stable_point = network_handler.get_api().get_stable_balance(&address, &asset).await?; @@ -675,7 +674,7 @@ impl Wallet { ciphertext }; - storage.set_unconfirmed_balance_for(asset.clone(), balance).await?; + storage.set_unconfirmed_balance_for((*asset).clone(), balance).await?; // Build the stable reference // We need to find the highest stable point if reference.is_none() || reference.as_ref().is_some_and(|r| r.topoheight < stable_point.stable_topoheight) { @@ -715,12 +714,12 @@ impl Wallet { for asset in used_assets { trace!("Checking balance for asset {}", asset); if !storage.has_balance_for(&asset).await? { - return Err(WalletError::BalanceNotFound(asset)); + return Err(WalletError::BalanceNotFound(asset.clone())); } let (balance, unconfirmed) = storage.get_unconfirmed_balance_for(&asset).await?; info!("Adding balance (unconfirmed: {}) for asset {} with amount {}, ciphertext: {}", unconfirmed, asset, balance.amount, balance.ciphertext); - state.add_balance(asset, balance); + state.add_balance(asset.clone(), balance); } #[cfg(feature = "network_handler")] @@ -763,17 +762,12 @@ impl Wallet { if let FeeBuilder::Multiplier(_) = fee { // To pay exact fees needed, we must verify that we don't have to pay more than needed let used_keys = transaction_type.used_keys(); - let mut processed_keys = HashSet::new(); if !used_keys.is_empty() { trace!("Checking if destination keys are registered"); if let Some(network_handler) = self.network_handler.lock().await.as_ref() { if network_handler.is_running().await { trace!("Network handler is running, checking if keys are registered"); for key in used_keys { - if processed_keys.contains(&key) { - continue; - } - let addr = key.as_address(self.network.is_mainnet()); trace!("Checking if {} is registered in stable height", addr); let registered = network_handler.get_api().is_account_registered(&addr, true).await?; @@ -781,8 +775,6 @@ impl Wallet { if registered { state.add_registered_key(addr.to_public_key()); } - - processed_keys.insert(key); } } } From 3a76d1b28bf9cdaae1752710abf2c31ae1962a65 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 16:02:51 +0200 Subject: [PATCH 40/83] common: improve both display ciphertextcache --- xelis_common/src/account/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_common/src/account/mod.rs b/xelis_common/src/account/mod.rs index aab49bcc..e95b67f3 100644 --- a/xelis_common/src/account/mod.rs +++ b/xelis_common/src/account/mod.rs @@ -173,7 +173,7 @@ impl Display for CiphertextCache { write!(f, "CiphertextCache[{}]", match self { Self::Compressed(c) => format!("Compressed({})", hex::encode(&c.to_bytes())), Self::Decompressed(e) => format!("Decompressed({})", hex::encode(&e.compress().to_bytes())), - Self::Both(c, _, dirty) => format!("Both({}, dirty: {dirty})", hex::encode(&c.to_bytes())) + Self::Both(c, d, dirty) => format!("Both(c: {}, d: {}, dirty: {dirty})", hex::encode(&c.to_bytes()), hex::encode(&d.compress().to_bytes())) }) } } From e9dd0ef14265b674f763a80d3cedfa2fb0b5ebf0 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 16:03:05 +0200 Subject: [PATCH 41/83] wallet: add more logs in get_balance_and_transactions fn --- xelis_wallet/src/network_handler.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xelis_wallet/src/network_handler.rs b/xelis_wallet/src/network_handler.rs index e3568665..a8410f00 100644 --- a/xelis_wallet/src/network_handler.rs +++ b/xelis_wallet/src/network_handler.rs @@ -416,8 +416,11 @@ impl NetworkHandler { async fn get_balance_and_transactions(&self, topoheight_processed: &mut HashSet, address: &Address, asset: &Hash, min_topoheight: u64, balances: bool, highest_nonce: &mut Option) -> Result<(), Error> { // Retrieve the highest version let (mut topoheight, mut version) = self.api.get_balance(address, asset).await.map(|res| (res.topoheight, res.version))?; + debug!("Starting sync from topoheight {} for asset {}", topoheight, asset); + // don't sync already synced blocks if min_topoheight >= topoheight { + debug!("Reached minimum topoheight {}, topo: {}", min_topoheight, topoheight); return Ok(()) } From c679abbf7118c337c97d69f72df8dac8c9b96f3f Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 18:22:40 +0200 Subject: [PATCH 42/83] common: to_type & to_blob --- xelis_common/src/api/data.rs | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/xelis_common/src/api/data.rs b/xelis_common/src/api/data.rs index 7ac20b75..670384b7 100644 --- a/xelis_common/src/api/data.rs +++ b/xelis_common/src/api/data.rs @@ -350,6 +350,20 @@ impl DataValue { } } + pub fn to_blob(self) -> Result, DataConversionError> { + match self { + Self::Blob(v) => Ok(v), + _ => Err(DataConversionError::UnexpectedValue(self.kind())) + } + } + + pub fn to_type(self) -> Result { + match &self { + Self::Blob(v) => T::from_bytes(&v).map_err(|_| DataConversionError::UnexpectedValue(self.kind())), + _ => Err(DataConversionError::UnexpectedValue(self.kind())) + } + } + pub fn as_bool(&self) -> Result { match self { Self::Bool(v) => Ok(*v), @@ -658,4 +672,75 @@ mod tests { let element: DataElement = serde_json::from_str(json).unwrap(); assert_eq!(element.kind(), ElementType::Array); } + + #[test] + fn test_map() { + let json = r#"{"name": "John", "age": 25, "is_active": true}"#; + let element: DataElement = serde_json::from_str(json).unwrap(); + assert_eq!(element.kind(), ElementType::Fields); + + let bytes = element.to_bytes(); + let element2 = DataElement::from_bytes(&bytes).unwrap(); + assert_eq!(element, element2); + } + + #[test] + fn test_map_array() { + let json = r#"{"name": "John", "age": 25, "is_active": true, "friends": [0, 1, 2, 3, 4]}"#; + let element: DataElement = serde_json::from_str(json).unwrap(); + assert_eq!(element.kind(), ElementType::Fields); + + let bytes = element.to_bytes(); + let element2 = DataElement::from_bytes(&bytes).unwrap(); + assert_eq!(element, element2); + } + + #[test] + fn test_dummy_struct() { + #[derive(Debug, Serialize, Deserialize, Clone)] + struct Dummy { + name: String, + age: u8, + is_active: bool, + friends: Vec + } + + impl Serializer for Dummy { + fn read(reader: &mut Reader) -> Result { + let name = String::read(reader)?; + let age = u8::read(reader)?; + let is_active = bool::read(reader)?; + let friends = Vec::::read(reader)?; + Ok(Self { + name, + age, + is_active, + friends + }) + } + + fn write(&self, writer: &mut Writer) { + self.name.write(writer); + self.age.write(writer); + self.is_active.write(writer); + self.friends.write(writer); + } + } + + let dummy = Dummy { + name: "John".to_string(), + age: 25, + is_active: true, + friends: vec![0, 1, 2, 3, 4] + }; + + let value = DataValue::Blob(dummy.to_bytes()); + assert_eq!(value.kind(), ValueType::Blob); + + let dummy: Dummy = value.to_type().unwrap(); + assert_eq!(dummy.name, "John"); + assert_eq!(dummy.age, 25); + assert_eq!(dummy.is_active, true); + assert_eq!(dummy.friends, vec![0, 1, 2, 3, 4]); + } } \ No newline at end of file From 7fb700186ac4151ec5f9ff9e195d50cc46976cc5 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 18:27:31 +0200 Subject: [PATCH 43/83] common: add as_type --- xelis_common/src/api/data.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xelis_common/src/api/data.rs b/xelis_common/src/api/data.rs index 670384b7..174aef3d 100644 --- a/xelis_common/src/api/data.rs +++ b/xelis_common/src/api/data.rs @@ -420,6 +420,13 @@ impl DataValue { } } + pub fn as_type(&self) -> Result { + match self { + Self::Blob(v) => T::from_bytes(&v).map_err(|_| DataConversionError::UnexpectedValue(self.kind())), + _ => Err(DataConversionError::UnexpectedValue(self.kind())) + } + } + fn read_with_type(reader: &mut Reader, value_type: ValueType) -> Result { Ok(match value_type { ValueType::Bool => Self::Bool(reader.read_bool()?), From 601e88b7570c822589e645e41c4c12ba7e57b769 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 22:08:04 +0200 Subject: [PATCH 44/83] all: update dependencies --- Cargo.lock | 239 +++++++++++++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5fe951b6..96c2be12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -121,16 +121,16 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02303ce8d4e8be5b855af6cf3c3a08f3eff26880faad82bab679c22d3650cb5" +checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894" dependencies = [ "actix-rt", "actix-service", "actix-utils", "futures-core", "futures-util", - "mio", + "mio 1.0.1", "socket2", "tokio", "tracing", @@ -225,7 +225,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -265,7 +265,7 @@ checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -364,9 +364,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -379,33 +379,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -448,7 +448,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -470,7 +470,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -481,7 +481,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -656,10 +656,10 @@ dependencies = [ [[package]] name = "bulletproofs" version = "5.0.2" -source = "git+https://github.com/xelis-project/bulletproofs?branch=main#cd0d434ba5ae55e1b5417b5cf6d65922548df3ec" +source = "git+https://github.com/xelis-project/bulletproofs?branch=main#d950e30eec804e27bf7bbb1853158c788acb3deb" dependencies = [ "byteorder", - "curve25519-dalek 4.1.2", + "curve25519-dalek 4.1.3", "digest 0.10.7", "group", "merlin", @@ -687,9 +687,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" dependencies = [ "bytemuck_derive", ] @@ -702,7 +702,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -713,9 +713,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "bytestring" @@ -728,9 +728,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", @@ -793,9 +793,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.9" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", "clap_derive", @@ -803,9 +803,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" dependencies = [ "anstream", "anstyle", @@ -815,27 +815,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -975,7 +975,7 @@ dependencies = [ "bitflags 2.6.0", "crossterm_winapi", "libc", - "mio", + "mio 0.8.11", "parking_lot 0.12.3", "signal-hook", "signal-hook-mio", @@ -1023,8 +1023,8 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.2" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#5fbf1fb147183280c508158a8151b8594fc04aee" +version = "4.1.3" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#e88fda2460720a9ef3995a4827cad93e8434c7a4" dependencies = [ "bytemuck", "cfg-if", @@ -1043,11 +1043,11 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#5fbf1fb147183280c508158a8151b8594fc04aee" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#e88fda2460720a9ef3995a4827cad93e8434c7a4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1075,7 +1075,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1183,9 +1183,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" dependencies = [ "crc32fast", "miniz_oxide", @@ -1245,7 +1245,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1347,7 +1347,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util", @@ -1568,9 +1568,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1614,9 +1614,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1635,9 +1635,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -1713,9 +1713,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ "hashbrown 0.14.5", ] @@ -1786,6 +1786,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + [[package]] name = "nom" version = "7.1.3" @@ -1811,21 +1824,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.36.1" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "memchr", ] @@ -1962,7 +1965,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2002,9 +2005,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "primitive-types" @@ -2056,7 +2062,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2174,9 +2180,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -2323,9 +2329,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -2339,9 +2345,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.5" +version = "0.102.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ "ring", "rustls-pki-types", @@ -2421,16 +2427,17 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -2512,12 +2519,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", - "mio", + "mio 0.8.11", "signal-hook", ] @@ -2614,9 +2621,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -2673,7 +2680,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2743,22 +2750,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.1", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2773,13 +2779,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2867,9 +2873,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" @@ -2877,7 +2883,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "toml_datetime", "winnow", ] @@ -2961,7 +2967,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3102,9 +3108,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -3148,7 +3154,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-shared", ] @@ -3182,7 +3188,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3449,12 +3455,12 @@ dependencies = [ "clap", "console-subscriber", "crossterm", - "curve25519-dalek 4.1.2", + "curve25519-dalek 4.1.3", "fern", "futures-util", "getrandom 0.2.15", "hex", - "indexmap 2.2.6", + "indexmap 2.3.0", "lazy_static", "log", "merlin", @@ -3493,7 +3499,7 @@ dependencies = [ "hex", "human_bytes", "humantime", - "indexmap 2.2.6", + "indexmap 2.3.0", "lazy_static", "log", "lru", @@ -3542,7 +3548,7 @@ dependencies = [ "crc32fast", "fern", "hex", - "indexmap 2.2.6", + "indexmap 2.3.0", "lazy_static", "log", "lru", @@ -3562,6 +3568,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -3573,7 +3580,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3593,7 +3600,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3607,18 +3614,18 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.2.0" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.12+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", From cb7b6b8ff818bc97f83e46572a3650371e58378e Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 22:22:53 +0200 Subject: [PATCH 45/83] wallet: clear_custom_tree --- xelis_wallet/src/storage/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xelis_wallet/src/storage/mod.rs b/xelis_wallet/src/storage/mod.rs index c52fa7d4..ced34394 100644 --- a/xelis_wallet/src/storage/mod.rs +++ b/xelis_wallet/src/storage/mod.rs @@ -296,6 +296,14 @@ impl EncryptedStorage { Ok(tree) } + // Clear all entries from the custom tree + pub fn clear_custom_tree(&self, name: impl Into) -> Result<()> { + trace!("clear custom tree"); + let tree = self.get_custom_tree(name)?; + tree.clear()?; + Ok(()) + } + // Store a custom serializable data pub fn set_custom_data(&mut self, tree: impl Into, key: &DataValue, value: &DataElement) -> Result<()> { trace!("set custom data"); From cc0c51a3d1097f4e2a428ba2c28706494308efb1 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 5 Aug 2024 22:23:26 +0200 Subject: [PATCH 46/83] wallet: self mut --- xelis_wallet/src/storage/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_wallet/src/storage/mod.rs b/xelis_wallet/src/storage/mod.rs index ced34394..2abf6696 100644 --- a/xelis_wallet/src/storage/mod.rs +++ b/xelis_wallet/src/storage/mod.rs @@ -297,7 +297,7 @@ impl EncryptedStorage { } // Clear all entries from the custom tree - pub fn clear_custom_tree(&self, name: impl Into) -> Result<()> { + pub fn clear_custom_tree(&mut self, name: impl Into) -> Result<()> { trace!("clear custom tree"); let tree = self.get_custom_tree(name)?; tree.clear()?; From 5a9f70cf0b17e5bf11e73ed79571b80466fcb1d9 Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 6 Aug 2024 15:25:32 +0200 Subject: [PATCH 47/83] common: build transaction offline params --- xelis_common/src/api/wallet.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index 801c1e70..df40159b 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -1,14 +1,22 @@ -use std::borrow::Cow; +use std::{borrow::Cow, collections::HashMap}; use serde::{Deserialize, Serialize}; use crate::{ + account::CiphertextCache, crypto::{Address, Hash}, transaction::{ builder::{FeeBuilder, TransactionTypeBuilder}, + Reference, Transaction } }; -use super::{DataHash, DataElement, DataValue, query::Query}; -use super::{default_false_value, default_true_value}; +use super::{ + DataHash, + DataElement, + DataValue, + query::Query, + default_false_value, + default_true_value +}; #[derive(Serialize, Deserialize)] pub struct BuildTransactionParams { @@ -22,6 +30,25 @@ pub struct BuildTransactionParams { pub tx_as_hex: bool } +#[derive(Serialize, Deserialize)] +pub struct BuildTransactionOfflineParams { + #[serde(flatten)] + pub tx_type: TransactionTypeBuilder, + // Fixed fee is required and must be checked before calling this + pub fee: FeeBuilder, + // Returns the TX in HEX format also + #[serde(default = "default_false_value")] + pub tx_as_hex: bool, + // Encrypted balances to use + // Assets spent in the transaction must be present + pub balances: HashMap, + // Reference to use for the transaction + // This must point to the most up-to-date topoheight/block hash + pub reference: Reference, + // Nonce to use for the transaction + pub nonce: u64 +} + #[derive(Serialize, Deserialize)] pub struct EstimateFeesParams { #[serde(flatten)] From 085a5aa00ad629b6d3ad93281adfdc65cf8e8fbb Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 6 Aug 2024 15:29:18 +0200 Subject: [PATCH 48/83] wallet: build_transaction_offline rpc method --- xelis_wallet/src/api/rpc.rs | 40 +++++++++++++++++++++++++++++++++++-- xelis_wallet/src/wallet.rs | 10 ++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/xelis_wallet/src/api/rpc.rs b/xelis_wallet/src/api/rpc.rs index 2ebaf3a3..109917dc 100644 --- a/xelis_wallet/src/api/rpc.rs +++ b/xelis_wallet/src/api/rpc.rs @@ -4,6 +4,7 @@ use xelis_common::{ api::{ wallet::{ BuildTransactionParams, + BuildTransactionOfflineParams, DeleteParams, EstimateFeesParams, GetAddressParams, @@ -43,8 +44,10 @@ use xelis_common::{ }; use serde_json::{Value, json}; use crate::{ - wallet::Wallet, - error::WalletError + error::WalletError, + storage::Balance, + transaction_builder::TransactionBuilderState, + wallet::Wallet }; use super::xswd::XSWDWebSocketHandler; use log::{info, warn}; @@ -65,6 +68,7 @@ pub fn register_methods(handler: &mut RPCHandler>) { handler.register_method("get_asset_precision", async_handler!(get_asset_precision)); handler.register_method("get_transaction", async_handler!(get_transaction)); handler.register_method("build_transaction", async_handler!(build_transaction)); + handler.register_method("build_transaction_offline", async_handler!(build_transaction_offline)); handler.register_method("clear_tx_cache", async_handler!(clear_tx_cache)); handler.register_method("list_transactions", async_handler!(list_transactions)); handler.register_method("is_online", async_handler!(is_online)); @@ -289,6 +293,38 @@ async fn build_transaction(context: &Context, body: Value) -> Result Result { + let params: BuildTransactionOfflineParams = parse_params(body)?; + let wallet: &Arc = context.get()?; + + // Create the state with the provided balances + let mut state = TransactionBuilderState::new(wallet.get_network().is_mainnet(), params.reference, params.nonce); + + for (hash, mut ciphertext) in params.balances { + let compressed = ciphertext.decompressed().context(format!("Error decompressing ciphertext {}", hash))?; + let amount = wallet.decrypt_ciphertext(compressed.clone()).await?; + + state.add_balance(hash, Balance { + amount, + ciphertext + }); + } + + let tx = wallet.create_transaction_with(&mut state, params.tx_type, params.fee)?; + Ok(json!(TransactionResponse { + tx_as_hex: if params.tx_as_hex { + Some(hex::encode(tx.to_bytes())) + } else { + None + }, + inner: DataHash { + hash: Cow::Owned(tx.hash()), + data: Cow::Owned(tx) + } + })) +} + // Clear the transaction cache async fn clear_tx_cache(context: &Context, body: Value) -> Result { if body != Value::Null { diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index 8a71c46b..7c79b0fa 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -725,18 +725,24 @@ impl Wallet { #[cfg(feature = "network_handler")] self.add_registered_keys_for_fees_estimation(state.as_mut(), &fee, &transaction_type).await?; + let transaction = self.create_transaction_with(&mut state, transaction_type, fee)?; + Ok((state, transaction)) + } + + // Create the transaction with all needed parameters + pub fn create_transaction_with(&self, state: &mut TransactionBuilderState, transaction_type: TransactionTypeBuilder, fee: FeeBuilder) -> Result { // Create the transaction builder let builder = TransactionBuilder::new(TxVersion::V0, self.get_public_key().clone(), transaction_type, fee); // Build the final transaction - let transaction = builder.build(&mut state, &self.inner.keypair) + let transaction = builder.build(state, &self.inner.keypair) .map_err(|e| WalletError::Any(e.into()))?; let tx_hash = transaction.hash(); debug!("Transaction created: {} with nonce {} and reference {}", tx_hash, transaction.get_nonce(), transaction.get_reference()); state.set_tx_hash_built(tx_hash); - Ok((state, transaction)) + Ok(transaction) } // submit a transaction to the network through the connection to daemon From 51b5822be0995afea1df3361a90066d770b494db Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 6 Aug 2024 16:39:09 +0200 Subject: [PATCH 49/83] common: set default serde for BuildTransactionOfflineParams --- xelis_common/src/api/wallet.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index df40159b..efb703fe 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -35,6 +35,7 @@ pub struct BuildTransactionOfflineParams { #[serde(flatten)] pub tx_type: TransactionTypeBuilder, // Fixed fee is required and must be checked before calling this + #[serde(default)] pub fee: FeeBuilder, // Returns the TX in HEX format also #[serde(default = "default_false_value")] From e975b2a35a4ce041f472272707926f4a03f2f66b Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 6 Aug 2024 16:55:49 +0200 Subject: [PATCH 50/83] wallet: delete_tree_entries rpc method --- xelis_wallet/src/api/rpc.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xelis_wallet/src/api/rpc.rs b/xelis_wallet/src/api/rpc.rs index 109917dc..7aeb9290 100644 --- a/xelis_wallet/src/api/rpc.rs +++ b/xelis_wallet/src/api/rpc.rs @@ -87,6 +87,7 @@ pub fn register_methods(handler: &mut RPCHandler>) { handler.register_method("get_value_from_key", async_handler!(get_value_from_key)); handler.register_method("store", async_handler!(store)); handler.register_method("delete", async_handler!(delete)); + handler.register_method("delete_tree_entries", async_handler!(delete_tree_entries)); handler.register_method("has_key", async_handler!(has_key)); handler.register_method("query_db", async_handler!(query_db)); } @@ -495,6 +496,16 @@ async fn delete(context: &Context, body: Value) -> Result Result { + let params: DeleteParams = parse_params(body)?; + let wallet: &Arc = context.get()?; + let tree = get_tree_name(&context, params.tree).await?; + let mut storage = wallet.get_storage().write().await; + storage.clear_custom_tree(&tree)?; + Ok(json!(true)) +} + // Verify if the key is present in the requested tree async fn has_key(context: &Context, body: Value) -> Result { let params: HasKeyParams = parse_params(body)?; From 60246812ebb8273e919b2094601c53d82b8dcae7 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 7 Aug 2024 14:01:31 +0200 Subject: [PATCH 51/83] wallet: verify db file is present --- xelis_wallet/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_wallet/src/main.rs b/xelis_wallet/src/main.rs index d262d876..62c89839 100644 --- a/xelis_wallet/src/main.rs +++ b/xelis_wallet/src/main.rs @@ -230,7 +230,7 @@ async fn main() -> Result<()> { let precomputed_tables = Wallet::read_or_generate_precomputed_tables(config.precomputed_tables_path, LogProgressTableGenerationReportFunction)?; let p = Path::new(&path); - let wallet = if p.exists() && p.is_dir() { + let wallet = if p.exists() && p.is_dir() && Path::new(&format!("{}/db", path)).exists() { info!("Opening wallet {}", path); Wallet::open(path, password, config.network, precomputed_tables)? } else { From 3a47748aef1fbd031fccefc72f9d49faae486bc5 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 7 Aug 2024 14:53:19 +0200 Subject: [PATCH 52/83] common: add nonce optional param for build transaction --- xelis_common/src/api/wallet.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index efb703fe..f42805b6 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -22,7 +22,12 @@ use super::{ pub struct BuildTransactionParams { #[serde(flatten)] pub tx_type: TransactionTypeBuilder, + // Fee to use, if value is fixed, + // it will be used as is, otherwise it will be calculated pub fee: Option, + // Nonce to use for the transaction + // If not present, it will be generated by the wallet + pub nonce: Option, // Cannot be broadcasted if set to false pub broadcast: bool, // Returns the TX in HEX format also From 8f9d8a064217be007b31f0703f77db4f716779c3 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 7 Aug 2024 14:58:32 +0200 Subject: [PATCH 53/83] wallet: support optional nonce param for build_transaction rpc method --- xelis_wallet/src/api/rpc.rs | 4 ++-- xelis_wallet/src/wallet.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/xelis_wallet/src/api/rpc.rs b/xelis_wallet/src/api/rpc.rs index 7aeb9290..a0005971 100644 --- a/xelis_wallet/src/api/rpc.rs +++ b/xelis_wallet/src/api/rpc.rs @@ -40,7 +40,7 @@ use xelis_common::{ RPCHandler }, serializer::Serializer, - transaction::{builder::FeeBuilder, extra_data::ExtraData} + transaction::extra_data::ExtraData, }; use serde_json::{Value, json}; use crate::{ @@ -265,7 +265,7 @@ async fn build_transaction(context: &Context, body: Value) -> Result Result { trace!("create transaction"); let mut storage = self.storage.write().await; - let (mut state, transaction) = self.create_transaction_with_storage(&storage, transaction_type, fee).await?; + let (mut state, transaction) = self.create_transaction_with_storage(&storage, transaction_type, fee, None).await?; state.apply_changes(&mut storage).await?; @@ -620,9 +620,9 @@ impl Wallet { // This will returns the transaction builder state along the transaction // You must handle "apply changes" to the storage // Warning: this is locking the network handler to access to the daemon api - pub async fn create_transaction_with_storage(&self, storage: &EncryptedStorage, transaction_type: TransactionTypeBuilder, fee: FeeBuilder) -> Result<(TransactionBuilderState, Transaction), WalletError> { + pub async fn create_transaction_with_storage(&self, storage: &EncryptedStorage, transaction_type: TransactionTypeBuilder, fee: FeeBuilder, nonce: Option) -> Result<(TransactionBuilderState, Transaction), WalletError> { trace!("create transaction with storage"); - let nonce = storage.get_unconfirmed_nonce(); + let nonce = nonce.unwrap_or_else(|| storage.get_unconfirmed_nonce()); // Build the state for the builder let used_assets = transaction_type.used_assets(); From 8029db2c13c602718f6c7863a937283397fc8215 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 7 Aug 2024 15:00:08 +0200 Subject: [PATCH 54/83] misc: add optional nonce in API.md --- API.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/API.md b/API.md index b176098e..eab72c90 100644 --- a/API.md +++ b/API.md @@ -6844,12 +6844,15 @@ It can be broadcasted or not to the network. ##### Method `build_transaction` ##### Parameters -| Name | Type | Required | Note | -|:-----------------:|:---------------:|:--------:|:----------------------------------------------------:| -| fee | FeeBuilder | Optional | Set an exact fee value or a multiplier | -| broadcast | Boolean | Optional | Broadcast TX to daemon. By default set to true | -| tx_as_hex | Boolean | Optional | Serialize TX to hexadecimal. By default set to false | -| transfers OR burn | TransactionType | Required | Transaction Type parameter | +| Name | Type | Required | Note | +|:-----------------:|:---------------:|:--------:|:--------------------------------------------------------------------------:| +| fee | FeeBuilder | Optional | Set an exact fee value or a multiplier | +| nonce | Integer | Optional | Set the nonce to use by the transaction. By default its provided by wallet | +| broadcast | Boolean | Optional | Broadcast TX to daemon. By default set to true | +| tx_as_hex | Boolean | Optional | Serialize TX to hexadecimal. By default set to false | +| transfers OR burn | TransactionType | Required | Transaction Type parameter | +| outgoing_flow | Boolean | Optional | Set to true by default, filter outgoing transactions | +| incoming_flow | Boolean | Optional | Set to true by default, filter incoming transactions / coinbase | Fee builder has two variants: - One to provide a multiplier applied on estimated fees. From 321616716409e63885ea76d8408d4768214aec31 Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 7 Aug 2024 15:01:00 +0200 Subject: [PATCH 55/83] misc: remove wrong parameters in API.md --- API.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/API.md b/API.md index eab72c90..9de773ed 100644 --- a/API.md +++ b/API.md @@ -6851,8 +6851,6 @@ It can be broadcasted or not to the network. | broadcast | Boolean | Optional | Broadcast TX to daemon. By default set to true | | tx_as_hex | Boolean | Optional | Serialize TX to hexadecimal. By default set to false | | transfers OR burn | TransactionType | Required | Transaction Type parameter | -| outgoing_flow | Boolean | Optional | Set to true by default, filter outgoing transactions | -| incoming_flow | Boolean | Optional | Set to true by default, filter incoming transactions / coinbase | Fee builder has two variants: - One to provide a multiplier applied on estimated fees. From 9cff1a11a1f22020be92a5e8f9164f90d7cc09f6 Mon Sep 17 00:00:00 2001 From: Slixe Date: Thu, 8 Aug 2024 12:06:26 +0200 Subject: [PATCH 56/83] misc: fix invalid path for ws in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a81611a..143a13a4 100644 --- a/README.md +++ b/README.md @@ -400,7 +400,7 @@ For a much more detailed API, see the API documentation [here](API.md). ### WebSocket WebSocket allow JSON-RPC call and any app to be notified when a specific event happens on the daemon. -It is running on `/ws` route on same RPC server address. +It is running on the same route (`/json_rpc`) route / RPC server address. Example to subscribe to a registered event in the WebSocket connection: ```json From 55810cc72348fcc312ed19768862690483043134 Mon Sep 17 00:00:00 2001 From: Slixe Date: Fri, 9 Aug 2024 17:59:40 +0200 Subject: [PATCH 57/83] all: update version to 1.13.3 --- Cargo.lock | 8 ++++---- xelis_common/Cargo.toml | 2 +- xelis_daemon/Cargo.toml | 2 +- xelis_miner/Cargo.toml | 2 +- xelis_wallet/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96c2be12..c17bc68b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3440,7 +3440,7 @@ dependencies = [ [[package]] name = "xelis_common" -version = "1.13.2" +version = "1.13.3" dependencies = [ "actix-rt", "actix-web", @@ -3483,7 +3483,7 @@ dependencies = [ [[package]] name = "xelis_daemon" -version = "1.13.2" +version = "1.13.3" dependencies = [ "actix", "actix-web", @@ -3515,7 +3515,7 @@ dependencies = [ [[package]] name = "xelis_miner" -version = "1.13.2" +version = "1.13.3" dependencies = [ "anyhow", "clap", @@ -3533,7 +3533,7 @@ dependencies = [ [[package]] name = "xelis_wallet" -version = "1.13.2" +version = "1.13.3" dependencies = [ "actix", "actix-web", diff --git a/xelis_common/Cargo.toml b/xelis_common/Cargo.toml index 3ab37620..7ad91b4e 100644 --- a/xelis_common/Cargo.toml +++ b/xelis_common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xelis_common" -version = "1.13.2" +version = "1.13.3" edition = "2021" authors = ["Slixe "] build = "build.rs" diff --git a/xelis_daemon/Cargo.toml b/xelis_daemon/Cargo.toml index 89844350..377a9bed 100644 --- a/xelis_daemon/Cargo.toml +++ b/xelis_daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xelis_daemon" -version = "1.13.2" +version = "1.13.3" edition = "2021" authors = ["Slixe "] diff --git a/xelis_miner/Cargo.toml b/xelis_miner/Cargo.toml index 75b898c2..e1e6e5ba 100644 --- a/xelis_miner/Cargo.toml +++ b/xelis_miner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xelis_miner" -version = "1.13.2" +version = "1.13.3" edition = "2021" authors = ["Slixe "] diff --git a/xelis_wallet/Cargo.toml b/xelis_wallet/Cargo.toml index ea950bde..f89a4910 100644 --- a/xelis_wallet/Cargo.toml +++ b/xelis_wallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xelis_wallet" -version = "1.13.2" +version = "1.13.3" edition = "2021" authors = ["Slixe "] From 3ef0845bc5fe6301d24aa4e588a21784e7de9d07 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 01:38:19 +0200 Subject: [PATCH 58/83] common: delete boxed scratchpad --- xelis_common/src/block/miner.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xelis_common/src/block/miner.rs b/xelis_common/src/block/miner.rs index 6e4e55bd..69fff911 100644 --- a/xelis_common/src/block/miner.rs +++ b/xelis_common/src/block/miner.rs @@ -24,8 +24,8 @@ use super::{BlockHeader, BLOCK_WORK_SIZE, EXTRA_NONCE_SIZE}; pub enum WorkVariant { Uninitialized, - V1(Box), - V2(Box), + V1(v1::ScratchPad), + V2(v2::ScratchPad), } impl WorkVariant { @@ -131,11 +131,11 @@ impl<'a> Worker<'a> { match kind { Algorithm::V1 => { let scratch_pad = v1::ScratchPad::default(); - self.variant = WorkVariant::V1(Box::new(scratch_pad)); + self.variant = WorkVariant::V1(scratch_pad); }, Algorithm::V2 => { let scratch_pad = v2::ScratchPad::default(); - self.variant = WorkVariant::V2(Box::new(scratch_pad)); + self.variant = WorkVariant::V2(scratch_pad); } } } From 44f105c708ae1afdb23cc68693b88f524f49df3f Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 01:44:43 +0200 Subject: [PATCH 59/83] all: update dependencies --- Cargo.lock | 101 ++++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c17bc68b..7d2b154a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.8.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae682f693a9cd7b058f2b0b5d9a6d7728a8555779bedbbc35dd88528611d020" +checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" dependencies = [ "actix-codec", "actix-rt", @@ -90,7 +90,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.8.0" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1988c02af8d2b718c05bc4aeb6a66395b7cdf32858c2c71131e5637a8c05a9ff" +checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" dependencies = [ "actix-codec", "actix-http", @@ -181,6 +181,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", + "impl-more", "itoa", "language-tags", "log", @@ -200,9 +201,9 @@ dependencies = [ [[package]] name = "actix-web-actors" -version = "4.3.0" +version = "4.3.1+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420b001bb709d8510c3e2659dae046e54509ff9528018d09c78381e765a1f9fa" +checksum = "f98c5300b38fd004fe7d2a964f9a90813fdbe8a81fed500587e78b1b71c6f980" dependencies = [ "actix", "actix-codec", @@ -225,7 +226,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -265,7 +266,7 @@ checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -448,7 +449,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -470,7 +471,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -481,7 +482,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -702,7 +703,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -728,9 +729,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" dependencies = [ "jobserver", "libc", @@ -793,9 +794,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" dependencies = [ "clap_builder", "clap_derive", @@ -803,9 +804,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -822,7 +823,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -920,9 +921,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" @@ -1047,7 +1048,7 @@ source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#e88f dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -1075,7 +1076,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -1245,7 +1246,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -1536,6 +1537,12 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-more" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" + [[package]] name = "impl-serde" version = "0.4.0" @@ -1826,9 +1833,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -1965,7 +1972,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2062,7 +2069,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2339,9 +2346,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -2412,29 +2419,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" dependencies = [ "itoa", "memchr", @@ -2621,9 +2628,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" dependencies = [ "proc-macro2", "quote", @@ -2680,7 +2687,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2785,7 +2792,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2967,7 +2974,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3154,7 +3161,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", "wasm-bindgen-shared", ] @@ -3188,7 +3195,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3580,7 +3587,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3600,7 +3607,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] From ad514026312e3427859eff4874467df16bcd1c67 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 15:34:32 +0200 Subject: [PATCH 60/83] wallet: use ecdlp tables --- xelis_wallet/src/precomputed_tables/mod.rs | 83 +------------------ xelis_wallet/src/precomputed_tables/native.rs | 32 ++++--- xelis_wallet/src/precomputed_tables/web.rs | 33 +------- xelis_wallet/src/wallet.rs | 8 +- 4 files changed, 30 insertions(+), 126 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/mod.rs b/xelis_wallet/src/precomputed_tables/mod.rs index f77d32c2..6b053e15 100644 --- a/xelis_wallet/src/precomputed_tables/mod.rs +++ b/xelis_wallet/src/precomputed_tables/mod.rs @@ -27,86 +27,11 @@ mod native; pub use native::*; use std::sync::Arc; - -use log::debug; use xelis_common::crypto::ecdlp; -// This is a 32 bytes aligned struct -// It is necessary for the precomputed tables points -#[derive(bytemuck::Pod, bytemuck::Zeroable, Copy, Clone)] -#[repr(C, align(32))] -struct Bytes32Alignment([u8; 32]); - -enum Inner { - Allocated(Vec), - Borrowed(&'static [u8]), -} - -impl Inner { - fn as_slice(&self, count: usize) -> &[u8] { - match self { - Inner::Allocated(v) => &bytemuck::cast_slice(v.as_slice())[..count], - Inner::Borrowed(v) => v - } - } - - fn as_mut_slice(&mut self, count: usize) -> &mut [u8] { - match self { - Inner::Allocated(v) => &mut bytemuck::cast_slice_mut(v.as_mut_slice())[..count], - Inner::Borrowed(_) => panic!("Cannot get mutable reference to borrowed data"), - } - } -} - - -pub struct PrecomputedTables { - inner: Inner, - l1: usize, - bytes_count: usize, -} +// ECDLP Tables L1 size +// L1 at 26 is around ~330 MB of RAM and support up to 2^48 values +pub const PRECOMPUTED_TABLES_L1: usize = 26; // Allows to be used in several wallets at the same time -pub type PrecomputedTablesShared = Arc; - -impl PrecomputedTables { - pub fn new(l1: usize) -> Self { - let bytes_count = ecdlp::table_generation::table_file_len(l1); - debug!("Precomputed tables size: {} bytes", bytes_count); - let mut n = bytes_count / 32; - if bytes_count % 32 != 0 { - n += 1; - } - - let bytes = vec![Bytes32Alignment([0; 32]); n]; - - Self { - inner: Inner::Allocated(bytes), - l1, - bytes_count - } - } - - pub fn with_bytes(bytes: &'static [u8], l1: usize) -> Self { - Self { - inner: Inner::Borrowed(bytes), - l1, - bytes_count: bytes.len() - } - } - - pub fn get<'a>(&'a self) -> &'a [u8] { - self.inner.as_slice(self.bytes_count) - } - - pub fn get_mut<'a>(&'a mut self) -> &'a mut [u8] { - self.inner.as_mut_slice(self.bytes_count) - } - - pub fn l1(&self) -> usize { - self.l1 - } - - pub fn bytes_count(&self) -> usize { - self.bytes_count - } -} +pub type PrecomputedTablesShared = Arc>; \ No newline at end of file diff --git a/xelis_wallet/src/precomputed_tables/native.rs b/xelis_wallet/src/precomputed_tables/native.rs index 18de2c6b..dafc82fa 100644 --- a/xelis_wallet/src/precomputed_tables/native.rs +++ b/xelis_wallet/src/precomputed_tables/native.rs @@ -1,34 +1,40 @@ -use std::{fs::{create_dir_all, File}, io::{Read, Write}, path::Path, sync::Arc}; +use std::{ + fs::create_dir_all, + path::Path, + sync::Arc +}; use anyhow::Result; use log::info; use xelis_common::crypto::ecdlp; -use super::{PrecomputedTables, PrecomputedTablesShared}; +use super::{PrecomputedTablesShared, PRECOMPUTED_TABLES_L1}; // This will read from file if exists, or generate and store it in file // This must be call only one time, and can be cloned to be shared through differents wallets -pub fn read_or_generate_precomputed_tables(path: Option, progress_report: P, l1: usize) -> Result { - let mut precomputed_tables = PrecomputedTables::new(l1); - +pub fn read_or_generate_precomputed_tables(path: Option, progress_report: P) -> Result { if let Some(path) = path.as_ref() { let path = Path::new(&path); if !path.exists() { create_dir_all(path)?; } } + let path = path.unwrap_or_default(); + let full_path = format!("{path}precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); - // Try to read from file - if let Ok(mut file) = File::open(format!("{path}precomputed_tables_{l1}.bin")) { - info!("Reading precomputed tables from file"); - file.read_exact(precomputed_tables.get_mut())?; + let tables = if Path::new(&full_path).exists() { + info!("Loading precomputed tables from {}", full_path); + ecdlp::ECDLPTables::load_from_file(full_path.as_str())? } else { // File does not exists, generate and store it info!("Generating precomputed tables"); - ecdlp::table_generation::create_table_file_with_progress_report(l1, precomputed_tables.get_mut(), progress_report)?; - File::create(format!("{path}precomputed_tables_{l1}.bin"))?.write_all(precomputed_tables.get())?; - } + let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; + info!("Precomputed tables generated, storing to {}", full_path); + tables.write_to_file(full_path.as_str())?; + + tables + }; - Ok(Arc::new(precomputed_tables)) + Ok(Arc::new(tables)) } \ No newline at end of file diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 16f9ec2b..cda02b20 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -3,36 +3,11 @@ use std::sync::Arc; use anyhow::Result; use xelis_common::crypto::ecdlp; -use super::{PrecomputedTables, PrecomputedTablesShared}; +use super::PrecomputedTablesShared; // Precomputed tables is too heavy to be stored in local Storage, and generating it on the fly would be too slow // So we will generate it on the server and store it in a file, and then we will read it from the file -pub fn read_or_generate_precomputed_tables(_: Option, _: P, l1: usize) -> Result { - let mut precomputed_tables = PrecomputedTables::new(l1); - let bytes = include_bytes!("precomputed_tables.bin"); - // We are forced to re-allocate the precomputed tables instead of using the reference - // to have the correct alignment in memory - precomputed_tables.get_mut().copy_from_slice(bytes); - // let precomputed_tables = PrecomputedTables::with_bytes(bytes, l1); - Ok(Arc::new(precomputed_tables)) -} - -#[cfg(test)] -mod tests { - use super::*; - use ecdlp::NoOpProgressTableGenerationReportFunction; - use xelis_common::crypto::ecdlp::table_generation::table_file_len; - - #[test] - fn test_read_or_generate_precomputed_tables() { - let l1 = 26; - let precomputed_tables = read_or_generate_precomputed_tables(None, NoOpProgressTableGenerationReportFunction, l1).unwrap(); - let expected = table_file_len(l1); - assert_eq!(precomputed_tables.bytes_count, expected); - assert_eq!(precomputed_tables.get().len(), expected); - - let bytes = include_bytes!("precomputed_tables.bin"); - assert_eq!(precomputed_tables.get(), bytes); - assert_eq!(bytes.len(), expected); - } +pub fn read_or_generate_precomputed_tables(_: Option, progress_report: P) -> Result { + let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; + Ok(Arc::new(tables)) } \ No newline at end of file diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index 7969c982..82884e9c 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -21,7 +21,7 @@ use xelis_common::{ }, asset::AssetWithData, crypto::{ - ecdlp::{self, ECDLPTablesFileView}, + ecdlp, elgamal::{Ciphertext, DecryptHandle}, Address, Hashable, @@ -213,7 +213,7 @@ impl InnerAccount { pub fn decrypt_ciphertext(&self, ciphertext: &Ciphertext) -> Result { trace!("decrypt ciphertext"); - let view = ECDLPTablesFileView::::from_bytes(self.precomputed_tables.get()); + let view = self.precomputed_tables.view(); self.keypair.get_private_key() .decrypt(&view, &ciphertext) .ok_or(WalletError::CiphertextDecode) @@ -226,12 +226,10 @@ pub fn hash_password(password: String, salt: &[u8]) -> Result<[u8; PASSWORD_HASH Ok(output) } -const PRECOMPUTED_TABLES_L1: usize = 26; - impl Wallet { // Read or generate precomputed tables based on the path and platform architecture pub fn read_or_generate_precomputed_tables(path: Option, progress_report: P) -> Result { - precomputed_tables::read_or_generate_precomputed_tables(path, progress_report, PRECOMPUTED_TABLES_L1) + precomputed_tables::read_or_generate_precomputed_tables(path, progress_report) } // Create a new wallet with the specificed storage, keypair and its network From 583ff29086e854d1ca1d137ad2838f5076bbe20a Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 15:51:13 +0200 Subject: [PATCH 61/83] misc: add asset in list_transactions API.md --- API.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/API.md b/API.md index 9de773ed..fe012f5b 100644 --- a/API.md +++ b/API.md @@ -8236,19 +8236,23 @@ By default it accepts every TXs. For `address` param, it is compared to the sender if it's an incoming TX, and to destination address for outgoing TX. +Topoheight range if specified is inclusive. +Meaning if you set max_topoheight at 10 and you have a TX at 10 its returned. + ##### Method `list_transactions` ##### Parameters -| Name | Type | Required | Note | -|:---------------:|:-------:|:--------:|:-----------------------------:| -| min_topoheight | Integer | Optional | Start from specific topo | -| max_topoheight | Integer | Optional | End at specific topo | -| address | String | Optional | Filter with address | -| accept_incoming | Boolean | Optional | Filter incoming | -| accept_outgoing | Boolean | Optional | Filter outgoing | -| accept_coinbase | Boolean | Optional | Filter coinbase | -| accept_burn | Boolean | Optional | Filter burn | -| query | Query | Optional | Allow to filter on extra data | +| Name | Type | Required | Note | +|:---------------:|:-------:|:--------:|:-------------------------------------------------------------:| +| asset | Hash | Optional | Filter on a specific asset only. By default accept all assets | +| min_topoheight | Integer | Optional | Start from specific topo | +| max_topoheight | Integer | Optional | End at specific topo | +| address | String | Optional | Filter with address | +| accept_incoming | Boolean | Optional | Filter incoming | +| accept_outgoing | Boolean | Optional | Filter outgoing | +| accept_coinbase | Boolean | Optional | Filter coinbase | +| accept_burn | Boolean | Optional | Filter burn | +| query | Query | Optional | Allow to filter on extra data | ##### Request ```json From 7ced022cc1e080ab6d37b21e7dae0ab4902e2a69 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 15:53:30 +0200 Subject: [PATCH 62/83] common: add asset parameter for list transaction --- xelis_common/src/api/wallet.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xelis_common/src/api/wallet.rs b/xelis_common/src/api/wallet.rs index f42805b6..f9227cf3 100644 --- a/xelis_common/src/api/wallet.rs +++ b/xelis_common/src/api/wallet.rs @@ -63,6 +63,9 @@ pub struct EstimateFeesParams { #[derive(Serialize, Deserialize)] pub struct ListTransactionsParams { + // Filter by asset + pub asset: Option, + // Filter by topoheight range (inclusive) pub min_topoheight: Option, pub max_topoheight: Option, /// Receiver address for outgoing txs, and owner/sender for incoming From 7176c6490c20b178d8fd40126a650e0a0ea13114 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 16:02:38 +0200 Subject: [PATCH 63/83] wallet: filter by asset for list_transactions rpc method --- xelis_wallet/src/api/rpc.rs | 2 +- xelis_wallet/src/storage/mod.rs | 122 ++++++++++++++++++++------------ 2 files changed, 76 insertions(+), 48 deletions(-) diff --git a/xelis_wallet/src/api/rpc.rs b/xelis_wallet/src/api/rpc.rs index a0005971..8ce6e58a 100644 --- a/xelis_wallet/src/api/rpc.rs +++ b/xelis_wallet/src/api/rpc.rs @@ -362,7 +362,7 @@ async fn list_transactions(context: &Context, body: Value) -> Result>(); diff --git a/xelis_wallet/src/storage/mod.rs b/xelis_wallet/src/storage/mod.rs index 2abf6696..66da46ab 100644 --- a/xelis_wallet/src/storage/mod.rs +++ b/xelis_wallet/src/storage/mod.rs @@ -7,7 +7,6 @@ use std::{ use indexmap::IndexMap; use lru::LruCache; use xelis_common::{ - tokio::sync::Mutex, account::CiphertextCache, api::{ query::{ @@ -17,6 +16,7 @@ use xelis_common::{ DataElement, DataValue }, + config::XELIS_ASSET, crypto::{ elgamal::CompressedCiphertext, Hash, @@ -30,6 +30,7 @@ use xelis_common::{ Serializer, Writer }, + tokio::sync::Mutex, transaction::Reference }; use anyhow::{ @@ -685,7 +686,7 @@ impl EncryptedStorage { // read whole disk and returns all transactions pub fn get_transactions(&self) -> Result> { trace!("get transactions"); - self.get_filtered_transactions(None, None, None, true, true, true, true, None) + self.get_filtered_transactions(None, None, None, None, true, true, true, true, None) } // delete all transactions above the specified topoheight @@ -720,7 +721,7 @@ impl EncryptedStorage { } // Filter when the data is deserialized to not load all transactions in memory - pub fn get_filtered_transactions(&self, address: Option<&PublicKey>, min_topoheight: Option, max_topoheight: Option, accept_incoming: bool, accept_outgoing: bool, accept_coinbase: bool, accept_burn: bool, query: Option<&Query>) -> Result> { + pub fn get_filtered_transactions(&self, address: Option<&PublicKey>, asset: Option<&Hash>, min_topoheight: Option, max_topoheight: Option, accept_incoming: bool, accept_outgoing: bool, accept_coinbase: bool, accept_burn: bool, query: Option<&Query>) -> Result> { trace!("get filtered transactions"); let mut transactions = Vec::new(); for el in self.transactions.iter().values() { @@ -731,60 +732,87 @@ impl EncryptedStorage { continue; } } - - if let Some(topoheight) = &max_topoheight { - if entry.get_topoheight() > *topoheight { + + if let Some(topoheight) = max_topoheight { + if entry.get_topoheight() > topoheight { continue; } } - - let (save, mut transfers) = match entry.get_mut_entry() { - EntryData::Coinbase { .. } if accept_coinbase => (true, None), - EntryData::Burn { .. } if accept_burn => (true, None), - EntryData::Incoming { from, transfers } if accept_incoming => match address { - Some(key) => (*key == *from, Some(transfers.into_iter().map(|t| Transfer::In(t)).collect::>())), - None => (true, None) + + let mut transfers: Option> = match entry.get_mut_entry() { + EntryData::Coinbase { .. } if accept_coinbase && (asset.map(|a| *a == XELIS_ASSET).unwrap_or(true)) => None, + EntryData::Burn { asset: burn_asset, .. } if accept_burn => { + if let Some(asset) = asset { + if *asset != *burn_asset { + continue; + } + } + + None }, - EntryData::Outgoing { transfers, .. } if accept_outgoing => match address { - Some(filter_key) => (transfers.iter().find(|tx| { - *tx.get_destination() == *filter_key - }).is_some(), Some(transfers.into_iter().map(|t| Transfer::Out(t)).collect::>())), - None => (true, None), + EntryData::Incoming { from, transfers } if accept_incoming => { + + // Filter by address + if let Some(filter_key) = address { + if *from != *filter_key { + continue; + } + } + + // Filter by asset + if let Some(asset) = asset { + transfers.retain(|transfer| *transfer.get_asset() == *asset); + } + + Some(transfers.iter_mut().map(|t| Transfer::In(t)).collect()) }, - _ => (false, None) - }; + EntryData::Outgoing { transfers, .. } if accept_outgoing => { + // Filter by address + if let Some(filter_key) = address { + if !transfers.iter().any(|transfer| *transfer.get_destination() == *filter_key) { + continue; + } + } - if save { - // Check if it has requested extra data - if let Some(query) = query { - if let Some(transfers) = transfers.as_mut() { - transfers.retain(|transfer| { - if let Some(element) = transfer.get_extra_data() { - query.verify_element(element) - } else { - false - } - }); - } else { - // Coinbase, burn, etc will be discarded always with such filter - continue; + // Filter by asset + if let Some(asset) = asset { + transfers.retain(|transfer| *transfer.get_asset() == *asset); } - } - // Keep only transactions entries that have one transfer at least - match transfers { - // Transfers which are not empty - Some(transfers) if !transfers.is_empty() => { - transactions.push(entry); - }, - // Something else than outgoing/incoming txs - None => { - transactions.push(entry); - }, - // All the left is discarded - _ => {} + Some(transfers.iter_mut().map(|t| Transfer::Out(t)).collect()) + }, + _ => continue, + }; + + // Check if it has requested extra data + if let Some(query) = query { + if let Some(transfers) = transfers.as_mut() { + transfers.retain(|transfer| { + if let Some(element) = transfer.get_extra_data() { + query.verify_element(element) + } else { + false + } + }); + } else { + // Coinbase, burn, etc will be discarded always with such filter + continue; } } + + // Keep only transactions entries that have one transfer at least + match transfers { + // Transfers which are not empty + Some(transfers) if !transfers.is_empty() => { + transactions.push(entry); + }, + // Something else than outgoing/incoming txs + None => { + transactions.push(entry); + }, + // All the left is discarded + _ => {} + } } Ok(transactions) From 134e3116e68f498fef83156a513c3e7d81c33087 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 16:03:42 +0200 Subject: [PATCH 64/83] all: update dependencies --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d2b154a..2c18ac2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,7 +130,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio 1.0.1", + "mio 1.0.2", "socket2", "tokio", "tracing", @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.1.3" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#e88fda2460720a9ef3995a4827cad93e8434c7a4" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#ea7da7a8623242b01f8baf83bdb2668028430de8" dependencies = [ "bytemuck", "cfg-if", @@ -1044,7 +1044,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#e88fda2460720a9ef3995a4827cad93e8434c7a4" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#ea7da7a8623242b01f8baf83bdb2668028430de8" dependencies = [ "proc-macro2", "quote", @@ -1795,9 +1795,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -2764,7 +2764,7 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.1", + "mio 1.0.2", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", From abe41faec6bcb6888d9a3896069d1dabed2e9339 Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 16:27:54 +0200 Subject: [PATCH 65/83] wallet: show only transfers with expected destination --- xelis_wallet/src/storage/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/xelis_wallet/src/storage/mod.rs b/xelis_wallet/src/storage/mod.rs index 66da46ab..056cfaee 100644 --- a/xelis_wallet/src/storage/mod.rs +++ b/xelis_wallet/src/storage/mod.rs @@ -751,7 +751,6 @@ impl EncryptedStorage { None }, EntryData::Incoming { from, transfers } if accept_incoming => { - // Filter by address if let Some(filter_key) = address { if *from != *filter_key { @@ -769,9 +768,7 @@ impl EncryptedStorage { EntryData::Outgoing { transfers, .. } if accept_outgoing => { // Filter by address if let Some(filter_key) = address { - if !transfers.iter().any(|transfer| *transfer.get_destination() == *filter_key) { - continue; - } + transfers.retain(|transfer| *transfer.get_destination() == *filter_key); } // Filter by asset From 0451db9f99257f10935759932d6ad3324d484cbe Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 17:03:01 +0200 Subject: [PATCH 66/83] wallet: trim seed on create --- xelis_wallet/src/wallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index 82884e9c..504a084b 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -261,7 +261,7 @@ impl Wallet { // generate random keypair or recover it from seed let keypair = if let Some(seed) = seed { debug!("Retrieving keypair from seed..."); - let words: Vec = seed.split_whitespace().map(str::to_string).collect(); + let words: Vec = seed.trim().split_whitespace().map(str::to_string).collect(); let key = mnemonics::words_to_key(&words)?; KeyPair::from_private_key(key) } else { From 9158deceb10f708fbfc4535f53b80ec071d83d2b Mon Sep 17 00:00:00 2001 From: Slixe Date: Mon, 12 Aug 2024 17:28:09 +0200 Subject: [PATCH 67/83] wallet: l1 to 13 for web --- xelis_wallet/src/precomputed_tables/mod.rs | 4 ---- xelis_wallet/src/precomputed_tables/native.rs | 6 +++++- xelis_wallet/src/precomputed_tables/web.rs | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/mod.rs b/xelis_wallet/src/precomputed_tables/mod.rs index 6b053e15..d4efbfb4 100644 --- a/xelis_wallet/src/precomputed_tables/mod.rs +++ b/xelis_wallet/src/precomputed_tables/mod.rs @@ -29,9 +29,5 @@ pub use native::*; use std::sync::Arc; use xelis_common::crypto::ecdlp; -// ECDLP Tables L1 size -// L1 at 26 is around ~330 MB of RAM and support up to 2^48 values -pub const PRECOMPUTED_TABLES_L1: usize = 26; - // Allows to be used in several wallets at the same time pub type PrecomputedTablesShared = Arc>; \ No newline at end of file diff --git a/xelis_wallet/src/precomputed_tables/native.rs b/xelis_wallet/src/precomputed_tables/native.rs index dafc82fa..c4831abc 100644 --- a/xelis_wallet/src/precomputed_tables/native.rs +++ b/xelis_wallet/src/precomputed_tables/native.rs @@ -8,7 +8,11 @@ use anyhow::Result; use log::info; use xelis_common::crypto::ecdlp; -use super::{PrecomputedTablesShared, PRECOMPUTED_TABLES_L1}; +use super::PrecomputedTablesShared; + +// ECDLP Tables L1 size +// L1 at 26 is around ~330 MB of RAM and support up to 2^48 values +pub const PRECOMPUTED_TABLES_L1: usize = 26; // This will read from file if exists, or generate and store it in file // This must be call only one time, and can be cloned to be shared through differents wallets diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index cda02b20..89b43c8a 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -5,6 +5,10 @@ use xelis_common::crypto::ecdlp; use super::PrecomputedTablesShared; +// ECDLP Tables L1 size +// It is reduced to 13 for lower memory usage +pub const PRECOMPUTED_TABLES_L1: usize = 13; + // Precomputed tables is too heavy to be stored in local Storage, and generating it on the fly would be too slow // So we will generate it on the server and store it in a file, and then we will read it from the file pub fn read_or_generate_precomputed_tables(_: Option, progress_report: P) -> Result { From e166e27829394cd918c25900f0edbc75ca1951d6 Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 01:07:46 +0200 Subject: [PATCH 68/83] misc: add daemon events example in API.md --- API.md | 2789 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 2779 insertions(+), 10 deletions(-) diff --git a/API.md b/API.md index fe012f5b..d6e61363 100644 --- a/API.md +++ b/API.md @@ -83,7 +83,16 @@ When a block has been ordered and executed by the DAG order. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "block_hash": "e42555732f8ca3a55bf97cbb8d63c73c0e8db8b376f60f4794871d468ffe83fc", + "block_type": "Normal", + "event": "block_ordered", + "topoheight": 641917 + } +} ``` #### Block Orphaned @@ -106,7 +115,15 @@ This means no new blocks can be added at this height or below. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "event": "stable_height_changed", + "new_stable_height": 611815, + "previous_stable_height": 611814 + } +} ``` #### Transaction Orphaned @@ -118,7 +135,1337 @@ If transaction couldn't be added back to the mempool, it is orphaned. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "blocks": null, + "data": { + "transfers": [ + { + "asset": "0000000000000000000000000000000000000000000000000000000000000000", + "commitment": [ + 162, + 230, + 146, + 112, + 181, + 226, + 75, + 156, + 43, + 15, + 12, + 86, + 56, + 185, + 223, + 210, + 92, + 3, + 232, + 1, + 98, + 131, + 222, + 191, + 98, + 42, + 41, + 121, + 114, + 28, + 229, + 84 + ], + "ct_validity_proof": { + "Y_0": [ + 42, + 119, + 217, + 97, + 36, + 105, + 68, + 113, + 8, + 14, + 181, + 11, + 199, + 127, + 145, + 138, + 108, + 199, + 68, + 60, + 223, + 42, + 197, + 131, + 26, + 129, + 23, + 151, + 29, + 220, + 143, + 2 + ], + "Y_1": [ + 226, + 70, + 119, + 71, + 215, + 154, + 188, + 186, + 245, + 54, + 98, + 189, + 201, + 249, + 205, + 225, + 140, + 116, + 138, + 111, + 177, + 219, + 128, + 195, + 107, + 8, + 214, + 31, + 102, + 202, + 140, + 52 + ], + "z_r": [ + 156, + 132, + 140, + 181, + 57, + 116, + 96, + 158, + 164, + 230, + 216, + 36, + 53, + 156, + 1, + 136, + 171, + 140, + 254, + 13, + 111, + 162, + 133, + 170, + 234, + 54, + 98, + 190, + 203, + 171, + 141, + 5 + ], + "z_x": [ + 248, + 33, + 200, + 18, + 80, + 176, + 101, + 24, + 99, + 148, + 229, + 158, + 32, + 8, + 96, + 97, + 114, + 149, + 2, + 39, + 248, + 53, + 14, + 70, + 169, + 147, + 116, + 139, + 91, + 205, + 184, + 3 + ] + }, + "destination": "xel:qcd39a5u8cscztamjuyr7hdj6hh2wh9nrmhp86ljx2sz6t99ndjqqm7wxj8", + "extra_data": [ + 62, + 195, + 250, + 239, + 180, + 215, + 10, + 90, + 169, + 144, + 200, + 43, + 167, + 60, + 125, + 51, + 115, + 252, + 211, + 50, + 21, + 142, + 88, + 224, + 3, + 110, + 223, + 198, + 170, + 119, + 43, + 87, + 122, + 0, + 238, + 6, + 167, + 102, + 184, + 220, + 9, + 53, + 187, + 7, + 216, + 207, + 126, + 217, + 121, + 60, + 213, + 114, + 34, + 25, + 187, + 172, + 157, + 248, + 19, + 114, + 40, + 124, + 92, + 92, + 0, + 10, + 199, + 3, + 158, + 124, + 107, + 106, + 158, + 166, + 58, + 18 + ], + "receiver_handle": [ + 98, + 42, + 42, + 139, + 55, + 140, + 41, + 87, + 122, + 206, + 208, + 183, + 173, + 121, + 232, + 55, + 175, + 218, + 200, + 191, + 163, + 235, + 237, + 194, + 0, + 38, + 137, + 184, + 223, + 221, + 37, + 30 + ], + "sender_handle": [ + 58, + 58, + 7, + 151, + 230, + 30, + 126, + 7, + 119, + 135, + 208, + 160, + 24, + 161, + 14, + 196, + 39, + 232, + 144, + 128, + 128, + 232, + 232, + 134, + 180, + 238, + 170, + 140, + 135, + 206, + 140, + 10 + ] + } + ] + }, + "event": "transaction_orphaned", + "executed_in_block": null, + "fee": 25000, + "first_seen": 1723502900, + "hash": "4951a4d10b8921c8e08d3c380993305a1e4706cbba606e2e79ffdfc06c54eb5f", + "in_mempool": false, + "nonce": 46056, + "range_proof": [ + 126, + 4, + 65, + 27, + 193, + 7, + 204, + 138, + 201, + 105, + 27, + 92, + 62, + 158, + 244, + 162, + 94, + 226, + 166, + 185, + 56, + 131, + 93, + 64, + 162, + 66, + 168, + 47, + 13, + 76, + 210, + 126, + 220, + 51, + 212, + 70, + 92, + 213, + 205, + 70, + 135, + 123, + 171, + 152, + 243, + 251, + 32, + 99, + 60, + 96, + 240, + 104, + 79, + 119, + 146, + 75, + 168, + 132, + 95, + 1, + 148, + 174, + 163, + 0, + 210, + 162, + 226, + 80, + 115, + 99, + 255, + 49, + 216, + 83, + 155, + 20, + 166, + 144, + 45, + 96, + 152, + 95, + 79, + 81, + 124, + 7, + 246, + 90, + 249, + 193, + 55, + 160, + 157, + 152, + 200, + 60, + 44, + 63, + 19, + 240, + 222, + 212, + 225, + 20, + 147, + 212, + 148, + 2, + 157, + 200, + 119, + 92, + 56, + 39, + 133, + 154, + 163, + 227, + 127, + 253, + 144, + 122, + 190, + 111, + 182, + 105, + 193, + 110, + 112, + 161, + 149, + 47, + 238, + 124, + 211, + 41, + 240, + 61, + 242, + 191, + 144, + 214, + 216, + 83, + 186, + 125, + 243, + 229, + 157, + 200, + 125, + 235, + 150, + 86, + 87, + 251, + 25, + 196, + 252, + 12, + 33, + 174, + 67, + 13, + 229, + 59, + 15, + 104, + 12, + 79, + 105, + 147, + 31, + 55, + 173, + 18, + 9, + 149, + 137, + 89, + 91, + 98, + 180, + 144, + 42, + 107, + 138, + 114, + 83, + 135, + 155, + 9, + 43, + 227, + 101, + 241, + 216, + 230, + 169, + 144, + 206, + 162, + 194, + 144, + 165, + 227, + 67, + 230, + 61, + 195, + 225, + 14, + 228, + 117, + 20, + 208, + 174, + 10, + 114, + 99, + 95, + 29, + 74, + 6, + 106, + 140, + 17, + 132, + 134, + 229, + 175, + 102, + 157, + 28, + 242, + 186, + 179, + 28, + 36, + 117, + 72, + 66, + 203, + 168, + 204, + 167, + 21, + 199, + 205, + 8, + 96, + 249, + 24, + 197, + 212, + 107, + 36, + 63, + 26, + 184, + 193, + 80, + 183, + 225, + 56, + 207, + 244, + 154, + 245, + 243, + 117, + 53, + 121, + 203, + 138, + 183, + 52, + 68, + 61, + 114, + 226, + 126, + 163, + 201, + 93, + 141, + 94, + 39, + 80, + 41, + 111, + 140, + 206, + 26, + 146, + 83, + 119, + 18, + 163, + 219, + 30, + 99, + 183, + 26, + 41, + 217, + 158, + 122, + 30, + 199, + 145, + 114, + 49, + 107, + 10, + 248, + 7, + 159, + 199, + 105, + 124, + 154, + 139, + 37, + 33, + 184, + 16, + 116, + 217, + 70, + 124, + 153, + 168, + 48, + 190, + 211, + 185, + 166, + 213, + 33, + 167, + 33, + 113, + 142, + 182, + 213, + 21, + 255, + 115, + 135, + 105, + 101, + 158, + 20, + 121, + 227, + 253, + 227, + 92, + 74, + 92, + 91, + 124, + 60, + 231, + 42, + 69, + 148, + 153, + 142, + 93, + 54, + 157, + 158, + 174, + 205, + 70, + 51, + 140, + 100, + 203, + 182, + 53, + 112, + 44, + 156, + 72, + 121, + 233, + 111, + 197, + 155, + 163, + 117, + 198, + 196, + 36, + 121, + 138, + 2, + 7, + 120, + 18, + 112, + 122, + 160, + 37, + 212, + 242, + 30, + 160, + 253, + 10, + 227, + 154, + 106, + 50, + 87, + 215, + 95, + 154, + 65, + 255, + 70, + 176, + 39, + 33, + 148, + 172, + 163, + 120, + 189, + 26, + 208, + 180, + 201, + 204, + 238, + 152, + 165, + 94, + 198, + 16, + 226, + 30, + 181, + 182, + 26, + 44, + 157, + 39, + 204, + 114, + 57, + 70, + 72, + 30, + 116, + 190, + 18, + 35, + 253, + 115, + 236, + 150, + 194, + 106, + 67, + 207, + 86, + 50, + 129, + 47, + 68, + 87, + 169, + 217, + 72, + 216, + 111, + 96, + 79, + 83, + 81, + 198, + 251, + 111, + 147, + 145, + 58, + 197, + 193, + 135, + 224, + 224, + 177, + 145, + 145, + 230, + 116, + 52, + 9, + 117, + 223, + 197, + 168, + 87, + 86, + 62, + 19, + 231, + 82, + 82, + 109, + 117, + 167, + 162, + 248, + 228, + 163, + 232, + 26, + 15, + 104, + 31, + 122, + 70, + 23, + 26, + 44, + 226, + 196, + 129, + 96, + 161, + 231, + 15, + 37, + 180, + 96, + 104, + 84, + 46, + 31, + 28, + 255, + 80, + 113, + 44, + 255, + 191, + 136, + 38, + 80, + 88, + 24, + 41, + 162, + 146, + 75, + 43, + 136, + 222, + 215, + 119, + 101, + 109, + 138, + 60, + 246, + 160, + 205, + 126, + 120, + 254, + 13, + 174, + 228, + 10, + 59, + 54, + 81, + 138, + 183, + 106, + 224, + 136, + 31, + 199, + 3, + 117, + 74, + 235, + 41, + 30, + 75, + 87, + 187, + 203, + 84, + 109, + 29, + 240, + 48, + 140, + 248, + 106, + 78, + 168, + 116, + 114, + 102, + 153, + 77, + 15, + 145, + 68, + 162, + 152, + 174, + 153, + 89, + 82, + 156, + 216, + 230, + 81, + 171, + 13, + 73, + 211, + 207, + 158, + 71, + 212, + 51, + 67, + 190, + 55, + 112, + 24, + 216, + 200, + 193, + 242, + 83, + 56, + 231, + 104, + 1, + 8, + 189, + 95, + 22, + 185, + 121, + 11, + 142, + 247, + 174, + 58, + 115, + 63, + 146, + 71, + 181, + 183, + 8, + 210, + 33, + 31, + 80, + 143, + 223, + 183, + 251, + 115, + 236, + 17, + 178, + 157, + 237, + 168, + 203, + 141, + 55, + 230, + 111, + 187, + 159, + 252, + 216, + 23, + 236, + 36, + 115, + 241, + 122, + 89, + 226, + 77, + 189, + 27, + 7, + 125, + 128, + 227, + 73, + 254, + 108, + 18, + 178, + 169, + 37, + 200, + 220, + 144, + 190, + 133, + 174, + 60, + 63, + 127, + 110, + 137, + 192, + 170, + 216, + 179, + 48, + 177, + 123, + 79, + 29, + 78, + 5 + ], + "reference": { + "hash": "547ef0b63e8b6b26b299e8764614e439a4106a22418ade7f8b0280da405ca5b2", + "topoheight": 641930 + }, + "signature": "9c0b4d7db7221e5866ad11ee495113b56b77360a5782b53ba189afb120b2a004678facbdb167cd9db0dd7d376caed2f24af781f2bae247b43779e54107e5f500", + "size": 1517, + "source": "xel:ntpjg269f0efkvft8rckyqd0dwq480jphngy0fujxal7ng6qmfxqqnp3r5l", + "source_commitments": [ + { + "asset": "0000000000000000000000000000000000000000000000000000000000000000", + "commitment": [ + 26, + 90, + 197, + 230, + 48, + 81, + 242, + 232, + 10, + 0, + 0, + 90, + 61, + 168, + 200, + 43, + 187, + 188, + 93, + 164, + 210, + 126, + 151, + 165, + 188, + 220, + 245, + 42, + 174, + 163, + 171, + 40 + ], + "proof": { + "Y_0": [ + 104, + 49, + 234, + 19, + 145, + 65, + 26, + 230, + 245, + 166, + 100, + 66, + 95, + 247, + 191, + 45, + 223, + 114, + 211, + 60, + 35, + 230, + 198, + 216, + 123, + 229, + 249, + 79, + 71, + 163, + 213, + 64 + ], + "Y_1": [ + 98, + 207, + 64, + 143, + 132, + 103, + 110, + 95, + 60, + 80, + 126, + 178, + 207, + 253, + 197, + 144, + 5, + 145, + 213, + 156, + 114, + 233, + 164, + 100, + 247, + 150, + 58, + 48, + 154, + 50, + 168, + 73 + ], + "Y_2": [ + 212, + 8, + 19, + 112, + 86, + 178, + 0, + 190, + 189, + 138, + 148, + 39, + 194, + 145, + 128, + 123, + 120, + 139, + 67, + 9, + 229, + 170, + 174, + 89, + 120, + 19, + 39, + 213, + 195, + 114, + 65, + 90 + ], + "z_r": [ + 183, + 226, + 125, + 123, + 29, + 129, + 190, + 46, + 127, + 155, + 203, + 96, + 102, + 250, + 241, + 246, + 86, + 204, + 126, + 3, + 252, + 208, + 25, + 99, + 204, + 117, + 217, + 214, + 104, + 10, + 94, + 5 + ], + "z_s": [ + 16, + 103, + 85, + 142, + 245, + 197, + 35, + 63, + 154, + 84, + 220, + 144, + 172, + 156, + 221, + 7, + 202, + 220, + 227, + 25, + 21, + 104, + 4, + 238, + 88, + 4, + 105, + 229, + 58, + 145, + 78, + 12 + ], + "z_x": [ + 130, + 73, + 193, + 124, + 117, + 22, + 56, + 79, + 57, + 144, + 121, + 148, + 130, + 25, + 5, + 221, + 96, + 221, + 130, + 77, + 7, + 202, + 144, + 222, + 26, + 184, + 58, + 143, + 9, + 58, + 12, + 11 + ] + } + } + ], + "version": 0 + } +} ``` #### Transaction Added In Mempool @@ -129,7 +1476,1337 @@ When a valid transaction is added in the daemon mempool. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "blocks": null, + "data": { + "transfers": [ + { + "asset": "0000000000000000000000000000000000000000000000000000000000000000", + "commitment": [ + 162, + 230, + 146, + 112, + 181, + 226, + 75, + 156, + 43, + 15, + 12, + 86, + 56, + 185, + 223, + 210, + 92, + 3, + 232, + 1, + 98, + 131, + 222, + 191, + 98, + 42, + 41, + 121, + 114, + 28, + 229, + 84 + ], + "ct_validity_proof": { + "Y_0": [ + 42, + 119, + 217, + 97, + 36, + 105, + 68, + 113, + 8, + 14, + 181, + 11, + 199, + 127, + 145, + 138, + 108, + 199, + 68, + 60, + 223, + 42, + 197, + 131, + 26, + 129, + 23, + 151, + 29, + 220, + 143, + 2 + ], + "Y_1": [ + 226, + 70, + 119, + 71, + 215, + 154, + 188, + 186, + 245, + 54, + 98, + 189, + 201, + 249, + 205, + 225, + 140, + 116, + 138, + 111, + 177, + 219, + 128, + 195, + 107, + 8, + 214, + 31, + 102, + 202, + 140, + 52 + ], + "z_r": [ + 156, + 132, + 140, + 181, + 57, + 116, + 96, + 158, + 164, + 230, + 216, + 36, + 53, + 156, + 1, + 136, + 171, + 140, + 254, + 13, + 111, + 162, + 133, + 170, + 234, + 54, + 98, + 190, + 203, + 171, + 141, + 5 + ], + "z_x": [ + 248, + 33, + 200, + 18, + 80, + 176, + 101, + 24, + 99, + 148, + 229, + 158, + 32, + 8, + 96, + 97, + 114, + 149, + 2, + 39, + 248, + 53, + 14, + 70, + 169, + 147, + 116, + 139, + 91, + 205, + 184, + 3 + ] + }, + "destination": "xel:qcd39a5u8cscztamjuyr7hdj6hh2wh9nrmhp86ljx2sz6t99ndjqqm7wxj8", + "extra_data": [ + 62, + 195, + 250, + 239, + 180, + 215, + 10, + 90, + 169, + 144, + 200, + 43, + 167, + 60, + 125, + 51, + 115, + 252, + 211, + 50, + 21, + 142, + 88, + 224, + 3, + 110, + 223, + 198, + 170, + 119, + 43, + 87, + 122, + 0, + 238, + 6, + 167, + 102, + 184, + 220, + 9, + 53, + 187, + 7, + 216, + 207, + 126, + 217, + 121, + 60, + 213, + 114, + 34, + 25, + 187, + 172, + 157, + 248, + 19, + 114, + 40, + 124, + 92, + 92, + 0, + 10, + 199, + 3, + 158, + 124, + 107, + 106, + 158, + 166, + 58, + 18 + ], + "receiver_handle": [ + 98, + 42, + 42, + 139, + 55, + 140, + 41, + 87, + 122, + 206, + 208, + 183, + 173, + 121, + 232, + 55, + 175, + 218, + 200, + 191, + 163, + 235, + 237, + 194, + 0, + 38, + 137, + 184, + 223, + 221, + 37, + 30 + ], + "sender_handle": [ + 58, + 58, + 7, + 151, + 230, + 30, + 126, + 7, + 119, + 135, + 208, + 160, + 24, + 161, + 14, + 196, + 39, + 232, + 144, + 128, + 128, + 232, + 232, + 134, + 180, + 238, + 170, + 140, + 135, + 206, + 140, + 10 + ] + } + ] + }, + "event": "transaction_added_in_mempool", + "executed_in_block": null, + "fee": 25000, + "first_seen": 1723502900, + "hash": "4951a4d10b8921c8e08d3c380993305a1e4706cbba606e2e79ffdfc06c54eb5f", + "in_mempool": true, + "nonce": 46056, + "range_proof": [ + 126, + 4, + 65, + 27, + 193, + 7, + 204, + 138, + 201, + 105, + 27, + 92, + 62, + 158, + 244, + 162, + 94, + 226, + 166, + 185, + 56, + 131, + 93, + 64, + 162, + 66, + 168, + 47, + 13, + 76, + 210, + 126, + 220, + 51, + 212, + 70, + 92, + 213, + 205, + 70, + 135, + 123, + 171, + 152, + 243, + 251, + 32, + 99, + 60, + 96, + 240, + 104, + 79, + 119, + 146, + 75, + 168, + 132, + 95, + 1, + 148, + 174, + 163, + 0, + 210, + 162, + 226, + 80, + 115, + 99, + 255, + 49, + 216, + 83, + 155, + 20, + 166, + 144, + 45, + 96, + 152, + 95, + 79, + 81, + 124, + 7, + 246, + 90, + 249, + 193, + 55, + 160, + 157, + 152, + 200, + 60, + 44, + 63, + 19, + 240, + 222, + 212, + 225, + 20, + 147, + 212, + 148, + 2, + 157, + 200, + 119, + 92, + 56, + 39, + 133, + 154, + 163, + 227, + 127, + 253, + 144, + 122, + 190, + 111, + 182, + 105, + 193, + 110, + 112, + 161, + 149, + 47, + 238, + 124, + 211, + 41, + 240, + 61, + 242, + 191, + 144, + 214, + 216, + 83, + 186, + 125, + 243, + 229, + 157, + 200, + 125, + 235, + 150, + 86, + 87, + 251, + 25, + 196, + 252, + 12, + 33, + 174, + 67, + 13, + 229, + 59, + 15, + 104, + 12, + 79, + 105, + 147, + 31, + 55, + 173, + 18, + 9, + 149, + 137, + 89, + 91, + 98, + 180, + 144, + 42, + 107, + 138, + 114, + 83, + 135, + 155, + 9, + 43, + 227, + 101, + 241, + 216, + 230, + 169, + 144, + 206, + 162, + 194, + 144, + 165, + 227, + 67, + 230, + 61, + 195, + 225, + 14, + 228, + 117, + 20, + 208, + 174, + 10, + 114, + 99, + 95, + 29, + 74, + 6, + 106, + 140, + 17, + 132, + 134, + 229, + 175, + 102, + 157, + 28, + 242, + 186, + 179, + 28, + 36, + 117, + 72, + 66, + 203, + 168, + 204, + 167, + 21, + 199, + 205, + 8, + 96, + 249, + 24, + 197, + 212, + 107, + 36, + 63, + 26, + 184, + 193, + 80, + 183, + 225, + 56, + 207, + 244, + 154, + 245, + 243, + 117, + 53, + 121, + 203, + 138, + 183, + 52, + 68, + 61, + 114, + 226, + 126, + 163, + 201, + 93, + 141, + 94, + 39, + 80, + 41, + 111, + 140, + 206, + 26, + 146, + 83, + 119, + 18, + 163, + 219, + 30, + 99, + 183, + 26, + 41, + 217, + 158, + 122, + 30, + 199, + 145, + 114, + 49, + 107, + 10, + 248, + 7, + 159, + 199, + 105, + 124, + 154, + 139, + 37, + 33, + 184, + 16, + 116, + 217, + 70, + 124, + 153, + 168, + 48, + 190, + 211, + 185, + 166, + 213, + 33, + 167, + 33, + 113, + 142, + 182, + 213, + 21, + 255, + 115, + 135, + 105, + 101, + 158, + 20, + 121, + 227, + 253, + 227, + 92, + 74, + 92, + 91, + 124, + 60, + 231, + 42, + 69, + 148, + 153, + 142, + 93, + 54, + 157, + 158, + 174, + 205, + 70, + 51, + 140, + 100, + 203, + 182, + 53, + 112, + 44, + 156, + 72, + 121, + 233, + 111, + 197, + 155, + 163, + 117, + 198, + 196, + 36, + 121, + 138, + 2, + 7, + 120, + 18, + 112, + 122, + 160, + 37, + 212, + 242, + 30, + 160, + 253, + 10, + 227, + 154, + 106, + 50, + 87, + 215, + 95, + 154, + 65, + 255, + 70, + 176, + 39, + 33, + 148, + 172, + 163, + 120, + 189, + 26, + 208, + 180, + 201, + 204, + 238, + 152, + 165, + 94, + 198, + 16, + 226, + 30, + 181, + 182, + 26, + 44, + 157, + 39, + 204, + 114, + 57, + 70, + 72, + 30, + 116, + 190, + 18, + 35, + 253, + 115, + 236, + 150, + 194, + 106, + 67, + 207, + 86, + 50, + 129, + 47, + 68, + 87, + 169, + 217, + 72, + 216, + 111, + 96, + 79, + 83, + 81, + 198, + 251, + 111, + 147, + 145, + 58, + 197, + 193, + 135, + 224, + 224, + 177, + 145, + 145, + 230, + 116, + 52, + 9, + 117, + 223, + 197, + 168, + 87, + 86, + 62, + 19, + 231, + 82, + 82, + 109, + 117, + 167, + 162, + 248, + 228, + 163, + 232, + 26, + 15, + 104, + 31, + 122, + 70, + 23, + 26, + 44, + 226, + 196, + 129, + 96, + 161, + 231, + 15, + 37, + 180, + 96, + 104, + 84, + 46, + 31, + 28, + 255, + 80, + 113, + 44, + 255, + 191, + 136, + 38, + 80, + 88, + 24, + 41, + 162, + 146, + 75, + 43, + 136, + 222, + 215, + 119, + 101, + 109, + 138, + 60, + 246, + 160, + 205, + 126, + 120, + 254, + 13, + 174, + 228, + 10, + 59, + 54, + 81, + 138, + 183, + 106, + 224, + 136, + 31, + 199, + 3, + 117, + 74, + 235, + 41, + 30, + 75, + 87, + 187, + 203, + 84, + 109, + 29, + 240, + 48, + 140, + 248, + 106, + 78, + 168, + 116, + 114, + 102, + 153, + 77, + 15, + 145, + 68, + 162, + 152, + 174, + 153, + 89, + 82, + 156, + 216, + 230, + 81, + 171, + 13, + 73, + 211, + 207, + 158, + 71, + 212, + 51, + 67, + 190, + 55, + 112, + 24, + 216, + 200, + 193, + 242, + 83, + 56, + 231, + 104, + 1, + 8, + 189, + 95, + 22, + 185, + 121, + 11, + 142, + 247, + 174, + 58, + 115, + 63, + 146, + 71, + 181, + 183, + 8, + 210, + 33, + 31, + 80, + 143, + 223, + 183, + 251, + 115, + 236, + 17, + 178, + 157, + 237, + 168, + 203, + 141, + 55, + 230, + 111, + 187, + 159, + 252, + 216, + 23, + 236, + 36, + 115, + 241, + 122, + 89, + 226, + 77, + 189, + 27, + 7, + 125, + 128, + 227, + 73, + 254, + 108, + 18, + 178, + 169, + 37, + 200, + 220, + 144, + 190, + 133, + 174, + 60, + 63, + 127, + 110, + 137, + 192, + 170, + 216, + 179, + 48, + 177, + 123, + 79, + 29, + 78, + 5 + ], + "reference": { + "hash": "547ef0b63e8b6b26b299e8764614e439a4106a22418ade7f8b0280da405ca5b2", + "topoheight": 641930 + }, + "signature": "9c0b4d7db7221e5866ad11ee495113b56b77360a5782b53ba189afb120b2a004678facbdb167cd9db0dd7d376caed2f24af781f2bae247b43779e54107e5f500", + "size": 1517, + "source": "xel:ntpjg269f0efkvft8rckyqd0dwq480jphngy0fujxal7ng6qmfxqqnp3r5l", + "source_commitments": [ + { + "asset": "0000000000000000000000000000000000000000000000000000000000000000", + "commitment": [ + 26, + 90, + 197, + 230, + 48, + 81, + 242, + 232, + 10, + 0, + 0, + 90, + 61, + 168, + 200, + 43, + 187, + 188, + 93, + 164, + 210, + 126, + 151, + 165, + 188, + 220, + 245, + 42, + 174, + 163, + 171, + 40 + ], + "proof": { + "Y_0": [ + 104, + 49, + 234, + 19, + 145, + 65, + 26, + 230, + 245, + 166, + 100, + 66, + 95, + 247, + 191, + 45, + 223, + 114, + 211, + 60, + 35, + 230, + 198, + 216, + 123, + 229, + 249, + 79, + 71, + 163, + 213, + 64 + ], + "Y_1": [ + 98, + 207, + 64, + 143, + 132, + 103, + 110, + 95, + 60, + 80, + 126, + 178, + 207, + 253, + 197, + 144, + 5, + 145, + 213, + 156, + 114, + 233, + 164, + 100, + 247, + 150, + 58, + 48, + 154, + 50, + 168, + 73 + ], + "Y_2": [ + 212, + 8, + 19, + 112, + 86, + 178, + 0, + 190, + 189, + 138, + 148, + 39, + 194, + 145, + 128, + 123, + 120, + 139, + 67, + 9, + 229, + 170, + 174, + 89, + 120, + 19, + 39, + 213, + 195, + 114, + 65, + 90 + ], + "z_r": [ + 183, + 226, + 125, + 123, + 29, + 129, + 190, + 46, + 127, + 155, + 203, + 96, + 102, + 250, + 241, + 246, + 86, + 204, + 126, + 3, + 252, + 208, + 25, + 99, + 204, + 117, + 217, + 214, + 104, + 10, + 94, + 5 + ], + "z_s": [ + 16, + 103, + 85, + 142, + 245, + 197, + 35, + 63, + 154, + 84, + 220, + 144, + 172, + 156, + 221, + 7, + 202, + 220, + 227, + 25, + 21, + 104, + 4, + 238, + 88, + 4, + 105, + 229, + 58, + 145, + 78, + 12 + ], + "z_x": [ + 130, + 73, + 193, + 124, + 117, + 22, + 56, + 79, + 57, + 144, + 121, + 148, + 130, + 25, + 5, + 221, + 96, + 221, + 130, + 77, + 7, + 202, + 144, + 222, + 26, + 184, + 58, + 143, + 9, + 58, + 12, + 11 + ] + } + } + ], + "version": 0 + } +} ``` #### Transaction Executed @@ -140,7 +2817,16 @@ When a transaction has been executed by the DAG order. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "block_hash": "f51d9df594e8222a51d060469478bd8f0c73cf67dde47d8f22eb215f633692a6", + "event": "transaction_executed", + "topoheight": 641928, + "tx_hash": "591e28f8e03e234804fe51f6beef3553698f31015288f93a088f42430bbc0130" + } +} ``` #### Peer Connected @@ -151,7 +2837,28 @@ When a new peer is connected to our daemon and allows to be shared through API. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "addr": "127.0.0.1:9999", + "bytes_recv": 224, + "bytes_sent": 200, + "connected_on": 1723503355, + "cumulative_difficulty": "195612980025169136041", + "event": "peer_connected", + "height": 583755, + "id": 19831114311557978, + "last_ping": 0, + "local_port": 2125, + "peers": {}, + "pruned_topoheight": null, + "tag": null, + "top_block_hash": "14e037f9bcf2ef932b51fffdacdb0e40f5c13cbc8c213fad108f6f1c7508be6e", + "topoheight": 612269, + "version": "1.13.3-55810cc" + } +} ``` #### Peer Disconnected @@ -162,7 +2869,28 @@ When a peer previously connected disconnect from us. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "addr": "127.0.0.1:9999", + "bytes_recv": 224, + "bytes_sent": 200, + "connected_on": 1723503355, + "cumulative_difficulty": "195612980025169136041", + "event": "peer_disconnected", + "height": 583755, + "id": 19831114311557978, + "last_ping": 0, + "local_port": 2125, + "peers": {}, + "pruned_topoheight": null, + "tag": null, + "top_block_hash": "14e037f9bcf2ef932b51fffdacdb0e40f5c13cbc8c213fad108f6f1c7508be6e", + "topoheight": 612269, + "version": "1.13.3-55810cc" + } +} ``` #### Peer PeerList Updated @@ -173,7 +2901,17 @@ When a peer peerlist has been updated. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "event": "peer_peer_list_updated", + "peer_id": 7542674138406502028, + "peerlist": [ + "1.1.1.1:2125" + ] + } +} ``` #### Peer State Updated @@ -184,7 +2922,30 @@ When a peer state has been updated due to a ping packet. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "addr": "0.0.0.0:35202", + "bytes_recv": 20227736, + "bytes_sent": 23927245, + "connected_on": 1722433223, + "cumulative_difficulty": "195614728296525524836", + "event": "peer_state_updated", + "height": 611867, + "id": 7542674138406502028, + "last_ping": 1723503479, + "local_port": 2125, + "peers": { + "0.0.0.0:2125": "Out", + }, + "pruned_topoheight": 449592, + "tag": null, + "top_block_hash": "284dc3a7be770bf7b630df83d614aebbddb6a6e69b4a6c33b8cd42860aa13d7d", + "topoheight": 641967, + "version": "1.13.2-0027ba5" + } +} ``` #### Peer Peer Disconnected @@ -195,7 +2956,15 @@ When a peer's peer has disconnected from him and notified us. ##### On Event ```json - +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "event": "peer_peer_disconnected", + "peer_addr": "1.1.1.1:2125", + "peer_id": 7542674138406502028 + } +} ``` ### JSON-RPC methods From 9aaa8ecfaf926b14a636c9cb43f2a797fd778a26 Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 12:50:56 +0200 Subject: [PATCH 69/83] wallet: use OFS for web compatibility --- xelis_wallet/Cargo.toml | 3 +- xelis_wallet/src/main.rs | 11 ++- xelis_wallet/src/precomputed_tables/native.rs | 10 +- xelis_wallet/src/precomputed_tables/web.rs | 99 ++++++++++++++++++- xelis_wallet/src/wallet.rs | 8 +- 5 files changed, 115 insertions(+), 16 deletions(-) diff --git a/xelis_wallet/Cargo.toml b/xelis_wallet/Cargo.toml index f89a4910..178a3d10 100644 --- a/xelis_wallet/Cargo.toml +++ b/xelis_wallet/Cargo.toml @@ -39,8 +39,9 @@ async-trait = "0.1.64" # WASM dependencies [target.'cfg(target_arch = "wasm32")'.dependencies] -web-sys = { version = "0.3.69", features = ["Window", "Storage"] } +web-sys = { version = "0.3.69", features = ["Window", "Storage", "File", "StorageManager", "FileSystemGetFileOptions", "Navigator", "FileSystemFileHandle", "FileSystemDirectoryHandle", "FileSystemWritableFileStream", "FileSystemSyncAccessHandle"] } base64 = "0.22.1" +wasm-bindgen-futures = "0.4.43" [features] # Set as default dependencies until https://github.com/rust-lang/cargo/issues/4663 is resolved for binary targets diff --git a/xelis_wallet/src/main.rs b/xelis_wallet/src/main.rs index 62c89839..3509f595 100644 --- a/xelis_wallet/src/main.rs +++ b/xelis_wallet/src/main.rs @@ -51,7 +51,8 @@ use xelis_common::{ }; use xelis_wallet::{ wallet::Wallet, - config::DIR_PATH + config::DIR_PATH, + precomputed_tables, }; #[cfg(feature = "network_handler")] @@ -228,7 +229,7 @@ async fn main() -> Result<()> { prompt.read_input(format!("Enter Password for '{}': ", path), true).await? }; - let precomputed_tables = Wallet::read_or_generate_precomputed_tables(config.precomputed_tables_path, LogProgressTableGenerationReportFunction)?; + let precomputed_tables = precomputed_tables::read_or_generate_precomputed_tables(config.precomputed_tables_path, LogProgressTableGenerationReportFunction).await?; let p = Path::new(&path); let wallet = if p.exists() && p.is_dir() && Path::new(&format!("{}/db", path)).exists() { info!("Opening wallet {}", path); @@ -521,7 +522,7 @@ async fn open_wallet(manager: &CommandManager, _: ArgumentManager) -> Result<(), let wallet = { let context = manager.get_context().lock()?; let network = context.get::()?; - let precomputed_tables = Wallet::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction)?; + let precomputed_tables = precomputed_tables::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction).await?; Wallet::open(dir, password, *network, precomputed_tables)? }; @@ -566,7 +567,7 @@ async fn create_wallet(manager: &CommandManager, _: ArgumentManager) -> Result<( let wallet = { let context = manager.get_context().lock()?; let network = context.get::()?; - let precomputed_tables = Wallet::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction)?; + let precomputed_tables = precomputed_tables::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction).await?; Wallet::create(dir, password, None, *network, precomputed_tables)? }; @@ -628,7 +629,7 @@ async fn recover_wallet(manager: &CommandManager, _: ArgumentManager) -> Result< let wallet = { let context = manager.get_context().lock()?; let network = context.get::()?; - let precomputed_tables = Wallet::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction)?; + let precomputed_tables = precomputed_tables::read_or_generate_precomputed_tables(None, LogProgressTableGenerationReportFunction).await?; Wallet::create(dir, password, Some(seed), *network, precomputed_tables)? }; diff --git a/xelis_wallet/src/precomputed_tables/native.rs b/xelis_wallet/src/precomputed_tables/native.rs index c4831abc..4b47fa53 100644 --- a/xelis_wallet/src/precomputed_tables/native.rs +++ b/xelis_wallet/src/precomputed_tables/native.rs @@ -14,9 +14,17 @@ use super::PrecomputedTablesShared; // L1 at 26 is around ~330 MB of RAM and support up to 2^48 values pub const PRECOMPUTED_TABLES_L1: usize = 26; +// Check if the precomputed tables exists +pub async fn has_precomputed_tables(path: Option) -> Result { + let path = path.unwrap_or_default(); + let full_path = format!("{path}precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); + + Ok(Path::new(&full_path).exists()) +} + // This will read from file if exists, or generate and store it in file // This must be call only one time, and can be cloned to be shared through differents wallets -pub fn read_or_generate_precomputed_tables(path: Option, progress_report: P) -> Result { +pub async fn read_or_generate_precomputed_tables(path: Option, progress_report: P) -> Result { if let Some(path) = path.as_ref() { let path = Path::new(&path); if !path.exists() { diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 89b43c8a..7ba0aaa8 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -1,7 +1,19 @@ use std::sync::Arc; use anyhow::Result; +use thiserror::Error; +use web_sys::{ + js_sys::Uint8Array, + wasm_bindgen::{JsCast, JsValue}, + window, + File, + FileSystemDirectoryHandle, + FileSystemFileHandle, + FileSystemGetFileOptions, + FileSystemWritableFileStream +}; use xelis_common::crypto::ecdlp; +use wasm_bindgen_futures::JsFuture; use super::PrecomputedTablesShared; @@ -9,9 +21,92 @@ use super::PrecomputedTablesShared; // It is reduced to 13 for lower memory usage pub const PRECOMPUTED_TABLES_L1: usize = 13; +#[derive(Debug, Error)] +pub enum PrecomputedTablesError { + #[error("window error")] + Window, + #[error("file system error")] + FileSystem, + #[error("directory error")] + Directory, + #[error("file error")] + File, + #[error("writable file error")] + WritableFile, + #[error("write error")] + Write, + #[error("write result error")] + WriteResult, + #[error("into file error")] + IntoFile, + #[error("array buffer error")] + ArrayBuffer, +} + +macro_rules! js_future { + ($e:expr, $err:ident) => { + JsFuture::from($e).await.map(|v| v.unchecked_into()) + }; +} + +macro_rules! execute { + ($e:expr, $err:ident) => { + js_future!($e, $err).map_err(|_| PrecomputedTablesError::$err) + }; +} + +// Check if the precomputed tables exists +pub async fn has_precomputed_tables(_: Option) -> Result { + let path = format!("precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); + + let window = window().ok_or(PrecomputedTablesError::Window)?; + let navigator = window.navigator(); + let storage = navigator.storage(); + let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; + + // By default, it will not create a new file false + let file_handle: Option = js_future!(directory.get_file_handle(path.as_str()), File).ok(); + + Ok(file_handle.is_some()) +} + // Precomputed tables is too heavy to be stored in local Storage, and generating it on the fly would be too slow // So we will generate it on the server and store it in a file, and then we will read it from the file -pub fn read_or_generate_precomputed_tables(_: Option, progress_report: P) -> Result { - let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; +pub async fn read_or_generate_precomputed_tables(_: Option, progress_report: P) -> Result { + let path = format!("precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); + + let window = window().ok_or(PrecomputedTablesError::Window)?; + let navigator = window.navigator(); + let storage = navigator.storage(); + let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; + + // By default, it will not create a new file false + let file_handle: Option = js_future!(directory.get_file_handle(path.as_str()), File).ok(); + let tables = match file_handle { + Some(file) => { + // Read the tables + let file: File = execute!(file.get_file(), IntoFile)?; + let value: JsValue = execute!(file.array_buffer(), ArrayBuffer)?; + let buffer = Uint8Array::new(&value).to_vec(); + + let tables = ecdlp::ECDLPTables::from_bytes(&buffer); + tables + }, + None => { + // Generate the tables + let opts = FileSystemGetFileOptions::new(); + opts.set_create(true); + + let file_handle: FileSystemFileHandle = execute!(directory.get_file_handle_with_options(path.as_str(), &opts), File)?; + let writable: FileSystemWritableFileStream = execute!(file_handle.create_writable(), WritableFile)?; + + let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; + let promise = writable.write_with_u8_array(tables.as_slice()).map_err(|_| PrecomputedTablesError::Write)?; + let _: JsValue = execute!(promise, Write)?; + + tables + } + }; + Ok(Arc::new(tables)) } \ No newline at end of file diff --git a/xelis_wallet/src/wallet.rs b/xelis_wallet/src/wallet.rs index 504a084b..674fb74f 100644 --- a/xelis_wallet/src/wallet.rs +++ b/xelis_wallet/src/wallet.rs @@ -21,7 +21,6 @@ use xelis_common::{ }, asset::AssetWithData, crypto::{ - ecdlp, elgamal::{Ciphertext, DecryptHandle}, Address, Hashable, @@ -52,7 +51,7 @@ use crate::{ }, error::WalletError, mnemonics, - precomputed_tables::{self, PrecomputedTablesShared}, + precomputed_tables::PrecomputedTablesShared, storage::{ EncryptedStorage, Storage @@ -227,11 +226,6 @@ pub fn hash_password(password: String, salt: &[u8]) -> Result<[u8; PASSWORD_HASH } impl Wallet { - // Read or generate precomputed tables based on the path and platform architecture - pub fn read_or_generate_precomputed_tables(path: Option, progress_report: P) -> Result { - precomputed_tables::read_or_generate_precomputed_tables(path, progress_report) - } - // Create a new wallet with the specificed storage, keypair and its network fn new(storage: EncryptedStorage, keypair: KeyPair, network: Network, precomputed_tables: PrecomputedTablesShared) -> Arc { let zelf = Self { From 7e01c8326a90fba26fc76849a3d61539736fad6d Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 12:51:19 +0200 Subject: [PATCH 70/83] all: update dependencies --- Cargo.lock | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c18ac2d..fb388622 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -927,9 +927,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.1.3" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#ea7da7a8623242b01f8baf83bdb2668028430de8" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#32573c6fb0071175b6ba8e798d60d533bfd1f8f3" dependencies = [ "bytemuck", "cfg-if", @@ -1044,7 +1044,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#ea7da7a8623242b01f8baf83bdb2668028430de8" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#32573c6fb0071175b6ba8e798d60d533bfd1f8f3" dependencies = [ "proc-macro2", "quote", @@ -1651,9 +1651,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -2419,18 +2419,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.206" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" +checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.206" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" +checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" dependencies = [ "proc-macro2", "quote", @@ -3142,19 +3142,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -3167,9 +3168,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -3179,9 +3180,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3189,9 +3190,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -3202,15 +3203,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -3565,6 +3566,7 @@ dependencies = [ "sled", "thiserror", "tokio", + "wasm-bindgen-futures", "web-sys", "xelis_common", ] From 2a62f9d9a043f39c443feb43f2d193185e002e1c Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 13:46:41 +0200 Subject: [PATCH 71/83] wallet: use correct variant for web error --- xelis_wallet/src/precomputed_tables/web.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 7ba0aaa8..d6528b42 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -102,7 +102,7 @@ pub async fn read_or_generate_precomputed_tables Date: Tue, 13 Aug 2024 14:11:22 +0200 Subject: [PATCH 72/83] wallet: fix shared buffer error --- xelis_wallet/src/precomputed_tables/web.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index d6528b42..5bc0c96d 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -101,7 +101,14 @@ pub async fn read_or_generate_precomputed_tables Date: Tue, 13 Aug 2024 14:18:38 +0200 Subject: [PATCH 73/83] wallet: add logs --- xelis_wallet/src/precomputed_tables/web.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 5bc0c96d..c35033ab 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -14,6 +14,7 @@ use web_sys::{ }; use xelis_common::crypto::ecdlp; use wasm_bindgen_futures::JsFuture; +use log::info; use super::PrecomputedTablesShared; @@ -84,15 +85,19 @@ pub async fn read_or_generate_precomputed_tables = js_future!(directory.get_file_handle(path.as_str()), File).ok(); let tables = match file_handle { Some(file) => { + info!("Loading precomputed tables from {}", path); + // Read the tables let file: File = execute!(file.get_file(), IntoFile)?; let value: JsValue = execute!(file.array_buffer(), ArrayBuffer)?; let buffer = Uint8Array::new(&value).to_vec(); + info!("Loading {} bytes", buffer.len()); let tables = ecdlp::ECDLPTables::from_bytes(&buffer); tables }, None => { + info!("Generating precomputed tables"); // Generate the tables let opts = FileSystemGetFileOptions::new(); opts.set_create(true); @@ -103,6 +108,7 @@ pub async fn read_or_generate_precomputed_tables Date: Tue, 13 Aug 2024 14:34:05 +0200 Subject: [PATCH 74/83] wallet: wait on writable to be closed --- xelis_wallet/src/precomputed_tables/web.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index c35033ab..81891c54 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -38,6 +38,8 @@ pub enum PrecomputedTablesError { Write, #[error("write result error")] WriteResult, + #[error("write close error")] + WriteClose, #[error("into file error")] IntoFile, #[error("array buffer error")] @@ -89,6 +91,8 @@ pub async fn read_or_generate_precomputed_tables Date: Tue, 13 Aug 2024 16:34:46 +0200 Subject: [PATCH 75/83] wallet: verify web file correct size for precomputed tables --- xelis_wallet/src/precomputed_tables/web.rs | 61 ++++++++++++++-------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 81891c54..369d0c20 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -12,7 +12,7 @@ use web_sys::{ FileSystemGetFileOptions, FileSystemWritableFileStream }; -use xelis_common::crypto::ecdlp; +use xelis_common::crypto::ecdlp::{self, ECDLPTables}; use wasm_bindgen_futures::JsFuture; use log::info; @@ -70,7 +70,15 @@ pub async fn has_precomputed_tables(_: Option) -> Result { // By default, it will not create a new file false let file_handle: Option = js_future!(directory.get_file_handle(path.as_str()), File).ok(); - Ok(file_handle.is_some()) + if let Some(file_handle) = file_handle { + // Verify the size of the file + let file: File = execute!(file_handle.get_file(), IntoFile)?; + let value: JsValue = execute!(file.array_buffer(), ArrayBuffer)?; + let buffer = Uint8Array::new(&value).to_vec(); + Ok(buffer.len() == ECDLPTables::::get_required_sizes().0) + } else { + Ok(false) + } } // Precomputed tables is too heavy to be stored in local Storage, and generating it on the fly would be too slow @@ -86,19 +94,25 @@ pub async fn read_or_generate_precomputed_tables = js_future!(directory.get_file_handle(path.as_str()), File).ok(); let tables = match file_handle { - Some(file) => { + Some(file_handle) => { info!("Loading precomputed tables from {}", path); // Read the tables - let file: File = execute!(file.get_file(), IntoFile)?; + let file: File = execute!(file_handle.get_file(), IntoFile)?; info!("File size: {}", file.size()); let value: JsValue = execute!(file.array_buffer(), ArrayBuffer)?; let buffer = Uint8Array::new(&value).to_vec(); + if buffer.len() != ECDLPTables::::get_required_sizes().0 { + info!("File stored has an invalid size, generating precomputed tables again..."); + let writable: FileSystemWritableFileStream = execute!(file_handle.create_writable(), WritableFile)?; + generate_tables(path.as_str(), writable, progress_report).await? + } else { + info!("Loading {} bytes", buffer.len()); + let tables = ecdlp::ECDLPTables::from_bytes(&buffer); + tables + } - info!("Loading {} bytes", buffer.len()); - let tables = ecdlp::ECDLPTables::from_bytes(&buffer); - tables }, None => { info!("Generating precomputed tables"); @@ -109,22 +123,27 @@ pub async fn read_or_generate_precomputed_tables(path: &str, writable: FileSystemWritableFileStream, progress_report: P) -> Result> { + let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; + + let slice = tables.as_slice(); + info!("Precomputed tables generated, storing {} bytes to {}", slice.len(), path); + // We are forced to copy the slice to a buffer + // which means we are using twice the memory + let buffer = Uint8Array::new_with_length(slice.len() as u32); + buffer.copy_from(slice); + + let promise = writable.write_with_buffer_source(&buffer).map_err(|_| PrecomputedTablesError::Write)?; + let _: JsValue = execute!(promise, WriteResult)?; + let _: JsValue = execute!(writable.close(), WriteClose)?; + + Ok(tables) } \ No newline at end of file From 440808029a0b6c34f134a2f690eb8c058de8d74e Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 16:34:58 +0200 Subject: [PATCH 76/83] all: update dependencies --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb388622..e367a9c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.1.3" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#32573c6fb0071175b6ba8e798d60d533bfd1f8f3" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#450af4c329483c7289da71855e59402a75440e13" dependencies = [ "bytemuck", "cfg-if", @@ -1044,7 +1044,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#32573c6fb0071175b6ba8e798d60d533bfd1f8f3" +source = "git+https://github.com/xelis-project/curve25519-dalek?branch=main#450af4c329483c7289da71855e59402a75440e13" dependencies = [ "proc-macro2", "quote", From 19f78ce77c1d539e7135eec3d4d1b79e20a9c13f Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 17:34:51 +0200 Subject: [PATCH 77/83] wallet: check file size directly --- xelis_wallet/src/precomputed_tables/web.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 369d0c20..2e244205 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -73,9 +73,7 @@ pub async fn has_precomputed_tables(_: Option) -> Result { if let Some(file_handle) = file_handle { // Verify the size of the file let file: File = execute!(file_handle.get_file(), IntoFile)?; - let value: JsValue = execute!(file.array_buffer(), ArrayBuffer)?; - let buffer = Uint8Array::new(&value).to_vec(); - Ok(buffer.len() == ECDLPTables::::get_required_sizes().0) + Ok(file.size() as usize == ECDLPTables::::get_required_sizes().0) } else { Ok(false) } From f640423baa0262ae4f5d27ca2d0769f43fe77923 Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 18:00:57 +0200 Subject: [PATCH 78/83] wallet: support OFS optional --- xelis_wallet/src/precomputed_tables/web.rs | 60 ++++++++++++++-------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 2e244205..6aebd31e 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -14,7 +14,7 @@ use web_sys::{ }; use xelis_common::crypto::ecdlp::{self, ECDLPTables}; use wasm_bindgen_futures::JsFuture; -use log::info; +use log::{info, warn}; use super::PrecomputedTablesShared; @@ -47,14 +47,14 @@ pub enum PrecomputedTablesError { } macro_rules! js_future { - ($e:expr, $err:ident) => { - JsFuture::from($e).await.map(|v| v.unchecked_into()) + ($e:expr) => { + JsFuture::from($e).await }; } macro_rules! execute { ($e:expr, $err:ident) => { - js_future!($e, $err).map_err(|_| PrecomputedTablesError::$err) + js_future!($e).map(|v| v.unchecked_into()).map_err(|_| PrecomputedTablesError::$err) }; } @@ -68,7 +68,11 @@ pub async fn has_precomputed_tables(_: Option) -> Result { let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; // By default, it will not create a new file false - let file_handle: Option = js_future!(directory.get_file_handle(path.as_str()), File).ok(); + // we check if the file exists + // and expect the file to have the same size as the precomputed tables + let file_handle: Option = js_future!(directory.get_file_handle(path.as_str())) + .ok() + .map(|v| v.unchecked_into()); if let Some(file_handle) = file_handle { // Verify the size of the file @@ -90,7 +94,11 @@ pub async fn read_or_generate_precomputed_tables = js_future!(directory.get_file_handle(path.as_str()), File).ok(); + let file_handle: Option = js_future!(directory.get_file_handle(path.as_str())) + .ok() + .map(|v| v.try_into().ok()) + .flatten(); + let tables = match file_handle { Some(file_handle) => { info!("Loading precomputed tables from {}", path); @@ -103,8 +111,7 @@ pub async fn read_or_generate_precomputed_tables::get_required_sizes().0 { info!("File stored has an invalid size, generating precomputed tables again..."); - let writable: FileSystemWritableFileStream = execute!(file_handle.create_writable(), WritableFile)?; - generate_tables(path.as_str(), writable, progress_report).await? + generate_tables(path.as_str(), file_handle, progress_report).await? } else { info!("Loading {} bytes", buffer.len()); let tables = ecdlp::ECDLPTables::from_bytes(&buffer); @@ -119,29 +126,38 @@ pub async fn read_or_generate_precomputed_tables(path: &str, writable: FileSystemWritableFileStream, progress_report: P) -> Result> { +// Generate the tables and store them in a file if API is available +async fn generate_tables(path: &str, file_handle: FileSystemFileHandle, progress_report: P) -> Result> { let tables = ecdlp::ECDLPTables::generate_with_progress_report(progress_report)?; let slice = tables.as_slice(); - info!("Precomputed tables generated, storing {} bytes to {}", slice.len(), path); - // We are forced to copy the slice to a buffer - // which means we are using twice the memory - let buffer = Uint8Array::new_with_length(slice.len() as u32); - buffer.copy_from(slice); - - let promise = writable.write_with_buffer_source(&buffer).map_err(|_| PrecomputedTablesError::Write)?; - let _: JsValue = execute!(promise, WriteResult)?; - let _: JsValue = execute!(writable.close(), WriteClose)?; + info!("Precomputed tables generated"); + + let res: Option = js_future!(file_handle.create_writable()) + .ok() + .map(|v| v.try_into().ok()) + .flatten(); + + if let Some(writable) = res { + info!("Writing precomputed tables to {} with {} bytes", path, slice.len()); + // We are forced to copy the slice to a buffer + // which means we are using twice the memory + let buffer = Uint8Array::new_with_length(slice.len() as u32); + buffer.copy_from(slice); + + let promise = writable.write_with_buffer_source(&buffer).map_err(|_| PrecomputedTablesError::Write)?; + let _: JsValue = execute!(promise, WriteResult)?; + let _: JsValue = execute!(writable.close(), WriteClose)?; + } else { + warn!("Failed to create writable file stream"); + } Ok(tables) } \ No newline at end of file From e27ba2e10b7d70bd8083b540995628de60271cd3 Mon Sep 17 00:00:00 2001 From: Slixe Date: Tue, 13 Aug 2024 18:15:52 +0200 Subject: [PATCH 79/83] wallet: improve errors for web --- xelis_wallet/src/precomputed_tables/web.rs | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 6aebd31e..481ba20b 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -24,26 +24,26 @@ pub const PRECOMPUTED_TABLES_L1: usize = 13; #[derive(Debug, Error)] pub enum PrecomputedTablesError { - #[error("window error")] - Window, - #[error("file system error")] - FileSystem, - #[error("directory error")] - Directory, - #[error("file error")] - File, - #[error("writable file error")] - WritableFile, - #[error("write error")] - Write, - #[error("write result error")] - WriteResult, - #[error("write close error")] - WriteClose, - #[error("into file error")] - IntoFile, - #[error("array buffer error")] - ArrayBuffer, + #[error("window error: {0}")] + Window(String), + #[error("file system error: {0}")] + FileSystem(String), + #[error("directory error: {0}")] + Directory(String), + #[error("file error: {0}")] + File(String), + #[error("writable file error: {0}")] + WritableFile(String), + #[error("write error: {0}")] + Write(String), + #[error("write result error: {0}")] + WriteResult(String), + #[error("write close error: {0}")] + WriteClose(String), + #[error("into file error: {0}")] + IntoFile(String), + #[error("array buffer error: {0}")] + ArrayBuffer(String), } macro_rules! js_future { @@ -54,7 +54,7 @@ macro_rules! js_future { macro_rules! execute { ($e:expr, $err:ident) => { - js_future!($e).map(|v| v.unchecked_into()).map_err(|_| PrecomputedTablesError::$err) + js_future!($e).map(|v| v.unchecked_into()).map_err(|e| PrecomputedTablesError::$err(format!("{:?}", e))) }; } @@ -62,7 +62,7 @@ macro_rules! execute { pub async fn has_precomputed_tables(_: Option) -> Result { let path = format!("precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); - let window = window().ok_or(PrecomputedTablesError::Window)?; + let window = window().ok_or(PrecomputedTablesError::Window("window not found in context".to_owned()))?; let navigator = window.navigator(); let storage = navigator.storage(); let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; @@ -88,7 +88,7 @@ pub async fn has_precomputed_tables(_: Option) -> Result { pub async fn read_or_generate_precomputed_tables(_: Option, progress_report: P) -> Result { let path = format!("precomputed_tables_{PRECOMPUTED_TABLES_L1}.bin"); - let window = window().ok_or(PrecomputedTablesError::Window)?; + let window = window().ok_or(PrecomputedTablesError::Window("window not found in context".to_owned()))?; let navigator = window.navigator(); let storage = navigator.storage(); let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; @@ -152,7 +152,7 @@ async fn generate_tables Date: Tue, 13 Aug 2024 18:31:05 +0200 Subject: [PATCH 80/83] wallet: use js reflect to check writable support --- xelis_wallet/src/precomputed_tables/web.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/xelis_wallet/src/precomputed_tables/web.rs b/xelis_wallet/src/precomputed_tables/web.rs index 481ba20b..ef70086c 100644 --- a/xelis_wallet/src/precomputed_tables/web.rs +++ b/xelis_wallet/src/precomputed_tables/web.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use anyhow::Result; use thiserror::Error; use web_sys::{ - js_sys::Uint8Array, + js_sys::{Reflect, Uint8Array}, wasm_bindgen::{JsCast, JsValue}, window, File, @@ -44,6 +44,8 @@ pub enum PrecomputedTablesError { IntoFile(String), #[error("array buffer error: {0}")] ArrayBuffer(String), + #[error("reflect error: {0}")] + Reflect(String), } macro_rules! js_future { @@ -65,6 +67,7 @@ pub async fn has_precomputed_tables(_: Option) -> Result { let window = window().ok_or(PrecomputedTablesError::Window("window not found in context".to_owned()))?; let navigator = window.navigator(); let storage = navigator.storage(); + // On Safari, if directory is not available, it means he is in an ephemeral context (private tab), which is not supported by WebKit let directory: FileSystemDirectoryHandle = execute!(storage.get_directory(), Directory)?; // By default, it will not create a new file false @@ -139,11 +142,12 @@ async fn generate_tables = js_future!(file_handle.create_writable()) - .ok() - .map(|v| v.try_into().ok()) - .flatten(); + + let res: Option = if Reflect::has(&file_handle, &JsValue::from_str("createWritable")).map_err(|e| PrecomputedTablesError::Reflect(format!("{:?}", e)))? { + Some(execute!(file_handle.create_writable(), WritableFile)?) + } else { + None + }; if let Some(writable) = res { info!("Writing precomputed tables to {} with {} bytes", path, slice.len()); @@ -156,7 +160,7 @@ async fn generate_tables Date: Wed, 14 Aug 2024 15:25:22 +0200 Subject: [PATCH 81/83] misc: add CHANGELOG.md --- CHANGELOG.md | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..8411b1e0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,375 @@ +# Changelog + +This file contains all the changelogs to ensure that changes can be tracked and to provide a summary for interested parties. + +To see the full history and exact changes, please refer to the commits history directly. + +## v1.13.3 + +Bug fixes, add new features, new RPC methods for easier integration including documentation update. + +All: +- updated dependencies +- file log level is now separated from log-level param + +Wallet: +- workaround support iOS for the web wallet +- reduce ECDLP L1 to 13 for web wallet +- filter by asset for list_transactions rpc method +- show only transfers with expected destination in list_transactions rpc method +- support optional nonce param for build_transaction rpc method +- add build_transaction_offline rpc method +- better check to see if the wallet db exists +- clear_custom_tree rpc method +- rework mnemonics for better errors handling +- prevent double online event to be fired +- optimize network handler by reducing sync head state calls + +Common: +- new structs used by RPC methods +- fix resubscribe events during an auto reconnect of the WS client + +Daemon: +- semver requirements for p2p nodes +- optimize get_account_history for fast search based on filter +- get_block_template verify now the tips timestamp against current timestamp + +Miner: +- Scratchpad is allocated in heap, not in stack, preventing older devices to crash due to a stack overflow. + +## v1.13.2 + +Several bug fixes + +Common: +- support aggregated WS messages (up to 1 MB) +- serializable hard fork configurations +- move max block size constant from daemon to common +- differentiate two errors message with same display text + +Daemon: +- add bytes_sent/bytes_recv to p2p rpc results +- add `skip-block-template-txs-verification` launch option to not double check the validity of a TX +- add `swap_blocks_executions_positions` cli command, for debug purposes +- improve `verify_chain` cli command, which will now also check for executed txs and balances/nonces versions. +- add "Block Version" and "POW Algorithm" in `status` cli command +- Fix Chain Validator used to verify the heaviest chain between us and a peer +- Fix chain sync: give correct order of blocks for easier sync +- add `get_hard_forks` rpc method +- don't show transactions unexecuted in account history rpc method +- add `dev_reward` and `miner_reward` in `get_info` rpc method + +Miner: +- add `api-bind-address` option to report the stats of the miner in a HTTP response. Thanks to @epsiloong + +Wallet: +- add rpc method clear_tx_cache +- burn, store fee and nonce used +- track highest nonce within burn txs also +- add logout cli command to switch from one wallet to another +- Use indexmap in XSWD permissions to keep order due to signature validity check. +- Display real error of invalid TX with `transfer` cli command. +- Improve `burn` cli command to follow the same format as `transfer`. + +## v1.13.1 + +This minor version is only a fix for daemon: +- stable height not being updated correctly +- p2p tracker on disconnected peer +- missing `algorithm` field in block template result + +## v1.13.0 + +New hard fork version configured: +Expected date: 10/07/2024 12am UTC at block height 434 100. + +Common: +- xelis-hash-v2 update +- WASM compatibility +- Add variant "Blob" for extra data to share low overhead data. + +Wallet: +- fix missing transactions during scan / rescan +- fix transaction failing +- few bug fixes +- new config parameters to disable blocks scanning, use stable balances only, etc.. + +Miner: +- support both algorithm and auto switch for hard fork +- internal hasher rework + +Daemon: +- Several bug fixes +- add size in RPC Transaction struct +- Increase extra data size from 1 KB to 32 KB per TX. +- Set 1 KB extra data limit size per transfer + +## v1.12.0 + +Wallet: +- Add a new `extra_data` protocol version + +Daemon: +- Track block execution order in a new provider (this is also used for chain sync ordering with side blocks) +- Add DAG cancelled transactions in orphaned list. +- add config `--skip-pow-verification` parameter to skip the PoW verification on new blocks. +- lookup host for priority nodes connection, this support the use of a domain name for peers configuration at launch +- add rpc method get_transaction_executor +- fix corruption on pop blocks method + +Common: +- API changes in prompt read functions + +Wallet: +- Network handler: don't skip txs that aren't executed in the block scanned, search the block executor for it +- Rescan: only starting at requested topoheight + +## v1.11.0 + +Misc: +- rename `BlockMiner` to `BlockWork` +- fix Block Template explanation + +Common: +- Compatible with journactl (introducting `--disable-log-color`, `--disable-interactive-mode`) +- introduce `--disable-file-log-date-based` +- update dependencies +- add tests on serialization +- rework JSON RPC Errors + +Daemon: +- Fix mempool: no more ghost TXs stuck +- few refactoring +- Use correct channel to terminate p2p tasks +- prevent any deadlock on TX broadcast +- add `split_address` RPC method + +Wallet: +- Introduce Tx Cache to prevent any front running problem that may happen on high usage +- Fix estimate fees function + +## v1.10.0 + +Common: +- support JSON RPC batching requests +- If no id is set, don't return any response +- support string id + +Daemon: +- Several bug fixes for chain sync +- add `add_peer` command +- New P2P Engine +- New seed nodes (Canada & Great-Britain) +- add `miner_reward` and `dev_reward` in block response +- add `validate_address` and `extract_key_from_address` RPC methods +- add `get_difficulty` RPC method +- add `create_miner_work` RPC method +- correct dev fee to 10% + +Miner: +- show node topoheight instead of current job height to prevent misleading + +Wallet: +- fix missing transactions due to DAG reorg + +## v1.9.5 + +Daemon: +- Hotfix for sync chain: a transaction having a block hash orphaned as reference may cause an error during syncing. + +All: +- Set a specific name for each tokio task in case of debug + +## v1.9.4 + +Daemon: +- fix fast sync +- new p2p engine to support more connections, refactor peer/connection struct +- rename struct BlockMiner to MinerWork +- add topoheight field in BlockTemplate & MinerWork +- support MinerWork in SubmitBlockParams to apply the miner job on the node based on a block template. +- new parameter: `disable-rpc-server` to disable the RPC Server +- rename `disable-outgoing-connections` to `disable-p2p-outgoing-connections` +- add `p2p-concurrency-task-count-limit` to configure the count of parallel tasks for handling incoming connections. +- Keep track of all accepted blocks from a miner connected to the GetWorkServer. + +Miner: +- support up to 65535 threads +- Show TopoHeight instead of Height on miner + +Wallet: +- auto reconnect mode + +Misc: +- update README.md +- update API.md +- add suport for ARMv7 +- fix certificate not found due to rustls dependency + +## v1.9.3 + +misc: +- Explain FeeBuilder with variant examples +- SIMD usage compatible in nightly for xelis-hash + +Daemon: +- add logs +- few bug fixes (return error to miner on invalid block template) +- reduce update to every 1s for CLI bottom bar +- don't temp ban whitelisted/priority peers +- reduce temp ban for connection error to 1m and increase fail count to 10 +- set new genesis block for testnet, update its genesis hash +- set a minimum difficulty for devnet/testnet +- disable http error logs from actix + +## v1.9.2 + +- Fix invalid fee for tx that can happen when using fast sync or auto pruned mode +- Add tx hash in logs during pre verify tx. +- Update dependencies + +## v1.9.1 + +Daemon: +- add --disable-outgoing-connections to not try to connect to potential outgoing peers. +- priorize incoming p2p connections using biased in select! +- auto temp ban on multiple connection failures + +Common: +- fix build on arm due to curve dependency update +- alignment fix for POW hashing algorithm that can happen on Windows and/or MacOS. + +Misc: +- update README.md +- improve CI/CD + +Wallet: +- wallet estimate fees take in count registered keys +- flush wallet storage on creation +- add transfer_all in CLI wallet + +## v1.9.0 + +XELIS mainnet release + +Daemon: +- POW `xelis-hash` algorithm released +- Bug fixes +- Side blocks reward function updated +- Registration system through unique fee paid one time. + +## v1.8.0 + +- XELIS HE implementation +- Fully Encrypted P2p Network + +Several bug fixes and new RPC methods + +## v1.7.0 + +Common +- Include short commit hash in version +- Schnorr Signature implementation with ElGamal keypair +- improve prompt engine +- ... + +Daemon +- Fix deadlocks +- Improve database management +- rework chain sync system +- add new commands +- Bug fixes +- ... + +Wallet +- Improve XSWD implementation +- allow a advanced query system for searching/filtering entries in DB +- add feature to use wallet as a encrypted DB for dApps and other services through RPC & XSWD +- add new RPC methods +- Fix bugs +- ... + +## v1.6.0 + +Common +- fix prompt bug in Windows +- ElGamal implementation based on Ristretto255 for homomorphic encryption (not used yet) +- Improve API, add new events +- rotating file log based on day (and in logs folder now) +- fix bug in terminal after a crash +- ... + +Daemon +- optimize disk usage +- add new API methods +- fix errors that could occurs while rewinding chain +- optimize mempool greatly +- improve (and fix) fast sync +- add new events +- better tx propagation +- clean up code +- fix bugs +- fix block reward emission +- ... + +Wallet +- improve XSWD protocol +- disk optimizations +- new APIs methods +- Asset standard with decimals precision +- ... + +## v1.5.0 + +Common +- Prompt in raw mode for better management of terminal +- Fix display glitch in terminal + +Daemon +- Better fast sync: can fast sync from any height +- better synchronization of blockchain +- add / change RPC methods API +- rework whole mempool system +- better block propagation (optimized to reduce network load) +- fix several bugs +- several optimizations + +Wallet +- Improve commands system +- Allow starting wallet without parameters for prompt request mode +- Implementation of XSWD v1 (this is a safe way for dApp to communicate with any wallet API) +- Fix bugs and some optimizations + +## v1.4.0 + +- Fast sync: if enabled when starting the node, no need to synchronize the whole chain history, but only the top blocks. +- Pruning mode: delete all blocks/transactions/balances before a specific stable topoheight to save lot of storage on disk. +- P2p Inventory: send mempool txs after syncing the chain +- keep-alive feature for websockets +- fix bugs, clean up code + +## v1.3.0 + +- fix wallet bugs +- fix miner SSL/TLS bugs +- improve daemon WebSocket events +- Change POW form, better performances +- optimizations in core & p2p +- full rework of RPC Server part +- Client protocol +- Add `version` in block header + +## v1.2.0 + +- Fix chain sync bug +- One tokio task for all ping interval (optimization) + +## v1.1.0 + +- Fix overflow bugs +- improve chain sync +- split Peer connection in two tasks +- others fixes / improvements + + +**NOTE**: Previous versions were not documented correctly, only commits history and small PR for features-specific were created, please see them [here](https://github.com/xelis-project/xelis-blockchain/pulls?q=is%3Apr+is%3Aclosed). \ No newline at end of file From b5194d67e181f7df207828b87322888e854cf28c Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 14 Aug 2024 16:19:23 +0200 Subject: [PATCH 82/83] misc: add CHANGELOG.md in binaries --- build_all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_all.sh b/build_all.sh index 1ff36ac7..c5f1c12f 100755 --- a/build_all.sh +++ b/build_all.sh @@ -3,7 +3,7 @@ # support: ARM64, ARMv7, x86_64 linux, Windows x86_64 targets=("aarch64-unknown-linux-gnu" "armv7-unknown-linux-gnueabihf" "x86_64-unknown-linux-musl" "x86_64-unknown-linux-gnu" "x86_64-pc-windows-gnu") binaries=("xelis_daemon" "xelis_miner" "xelis_wallet") -extra_files=("README.md" "API.md") +extra_files=("README.md" "API.md" "CHANGELOG.md") # verify that we have cross installed if ! command -v cross &> /dev/null From 108c7e4792c72e4ef284d240c9a1786dbc02b1ae Mon Sep 17 00:00:00 2001 From: Slixe Date: Wed, 14 Aug 2024 16:27:36 +0200 Subject: [PATCH 83/83] all: update dependencies --- Cargo.lock | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e367a9c7..526fd5b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,12 +729,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -1348,7 +1349,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -1575,9 +1576,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -2514,6 +2515,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2890,7 +2897,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "toml_datetime", "winnow", ] @@ -2944,15 +2951,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -3436,7 +3443,7 @@ dependencies = [ [[package]] name = "xelis-hash" version = "0.1.0" -source = "git+https://github.com/xelis-project/xelis-hash?branch=master#af1ea607b5183e6067031381fd00692fa8d15575" +source = "git+https://github.com/xelis-project/xelis-hash?branch=master#478dd8d8924bb2d38684193656d38b112ab2f532" dependencies = [ "aes", "blake3", @@ -3468,7 +3475,7 @@ dependencies = [ "futures-util", "getrandom 0.2.15", "hex", - "indexmap 2.3.0", + "indexmap 2.4.0", "lazy_static", "log", "merlin", @@ -3507,7 +3514,7 @@ dependencies = [ "hex", "human_bytes", "humantime", - "indexmap 2.3.0", + "indexmap 2.4.0", "lazy_static", "log", "lru", @@ -3556,7 +3563,7 @@ dependencies = [ "crc32fast", "fern", "hex", - "indexmap 2.3.0", + "indexmap 2.4.0", "lazy_static", "log", "lru",