Skip to content

Commit

Permalink
Merge pull request #13 from xelis-project/dev
Browse files Browse the repository at this point in the history
Version 1.6.0
  • Loading branch information
Slixe authored Oct 26, 2023
2 parents 3603ab9 + 9ed1268 commit f4e4de9
Show file tree
Hide file tree
Showing 63 changed files with 3,939 additions and 1,427 deletions.
304 changes: 286 additions & 18 deletions API.md

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ All theses data are saved in plaintext.
| transactions | Hash | Transaction | Save the whole transaction based on its hash |
| blocks | Hash | Block Header | Save the block header only based on its hash |
| blocks_at_height | Integer | Array of Hash | Save all blocks hash at a specific height |
| extra | Bytes | No specific type | Actually used to save the highest topo height and TIPS |
| extra | Bytes | No specific type |Save the highest topo height, pruned topoheight and TIPS|
| topo_by_hash | Hash | Integer | Save a block hash at a specific topo height |
| hash_by_topo | Integer | Hash | Save a topo height for a specific block hash |
| cumulative_difficulty | Hash | Integer | Save the cumulative difficulty for each block hash |
Expand All @@ -228,6 +228,7 @@ All theses data are saved in plaintext.
**NOTE**:
- Balances and nonces are versioned, which means they are stored each time a change happened on disk.
- Assets registered have in value their topoheight at which it was registered.
- Supply and block rewards are only stored when the block is topologically ordered

The database engine used is sled. It may changes in future.

Expand All @@ -249,7 +250,9 @@ Password hashing algorithm used is Argon2id with a configuration of 15 MB and 16
Wallet implement a fully-encrypted storage system with following features:
- Tree names are hashed with generated salt
- Keys data are hashed with generated salt
- Values are encrypted using XChaCha20Poly1305 and a random newly generated Nonce each time its saved.
- Values are encrypted using XChaCha20Poly1305 and a random newly generated nonce each time its saved.

Exception for assets list which has its key encrypted to be able to retrieve them later.

Hash algorithm used is Keccak-256 for keys / tree names.
The random salt generated is a 64 bytes length.
Expand Down
6 changes: 3 additions & 3 deletions xelis_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
rand = "0.8.4"
ed25519-dalek = { version = "1.0.1", features = ["serde"] }
curve25519-dalek = { package = "curve25519-dalek-ng", version = "4.1.1" }
thiserror = "1.0.30"
anyhow = "1.0.57"
log = "0.4"
fern = { version = "0.6", features = ["colored"] }
fern = { version = "0.6", features = ["colored", "date-based"] }
chrono = "0.4.19"
tokio = { version = "1.25", features = ["macros", "signal", "time", "sync"], optional = true }
reqwest = { version = "0.11.10", default-features = false, features = ["json", "rustls"], optional = true }
lazy_static = "1.4.0"
clap = { version = "3.1.18", features = ["derive"], optional = true }
crossterm = "*"
indexmap = { version = "2.0.0", features = ["serde"] }

actix-rt = { version = "2.8.0", optional = true }
actix-web = { version = "4", optional = true }
actix-ws = { version = "0.2.5", optional = true }
futures-util = { version = "0.3.28", optional = true }
async-trait = { version = "0.1.64", optional = true }
regex = "1"

[features]
json_rpc = ["dep:reqwest"]
Expand Down
127 changes: 116 additions & 11 deletions xelis_common/src/api/daemon.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{borrow::Cow, collections::HashSet};
use std::{borrow::Cow, collections::HashSet, net::SocketAddr};

use serde::{Deserialize, Serialize};

use crate::{crypto::{hash::Hash, address::Address}, account::{VersionedBalance, VersionedNonce}, network::Network, block::Difficulty};
use crate::{crypto::{hash::Hash, address::Address}, account::{VersionedBalance, VersionedNonce}, network::Network, block::Difficulty, transaction::Transaction};

use super::DataHash;

Expand Down Expand Up @@ -72,12 +72,6 @@ pub struct SubmitBlockParams {
pub block_template: String, // hex: represent the BlockHeader (Block)
}

#[derive(Serialize, Deserialize)]
pub struct GetMessagesParams<'a> {
pub address: Address<'a>,
pub from: Option<Address<'a>>
}

#[derive(Serialize, Deserialize)]
pub struct GetBalanceParams<'a> {
pub address: Cow<'a, Address<'a>>,
Expand All @@ -98,13 +92,25 @@ pub struct GetNonceParams<'a> {
pub topoheight: Option<u64>
}

#[derive(Serialize, Deserialize)]
pub struct HasNonceParams<'a> {
pub address: Cow<'a, Address<'a>>,
#[serde(default)]
pub topoheight: Option<u64>
}

#[derive(Serialize, Deserialize)]
pub struct GetNonceResult {
pub topoheight: u64,
#[serde(flatten)]
pub version: VersionedNonce
}

#[derive(Serialize, Deserialize)]
pub struct HasNonceResult {
pub exist: bool
}

#[derive(Serialize, Deserialize)]
pub struct GetLastBalanceResult {
pub balance: VersionedBalance,
Expand Down Expand Up @@ -139,6 +145,21 @@ pub struct GetTransactionParams<'a> {
pub hash: Cow<'a, Hash>
}

#[derive(Serialize, Deserialize)]
pub struct PeerEntry<'a> {
pub id: u64,
pub addr: Cow<'a, SocketAddr>,
pub tag: Cow<'a, Option<String>>,
pub version: Cow<'a, String>,
pub top_block_hash: Hash,
pub topoheight: u64,
pub height: u64,
pub last_ping: u64,
pub pruned_topoheight: Option<u64>,
pub peers: HashSet<SocketAddr>,
pub cumulative_difficulty: Difficulty
}

#[derive(Serialize, Deserialize)]
pub struct P2pStatusResult<'a> {
pub peer_count: usize,
Expand Down Expand Up @@ -167,17 +188,63 @@ pub struct GetTransactionsParams {
}

#[derive(Serialize, Deserialize)]
pub struct TransactionResponse<'a, T: Clone> {
pub struct TransactionResponse<'a, T: Clone + AsRef<Transaction>> {
// in which blocks it was included
pub blocks: Option<HashSet<Hash>>,
// in which blocks it was executed
pub executed_in_block: Option<Hash>,
// if it is in mempool
pub in_mempool: bool,
// if its a mempool tx, we add the timestamp when it was added
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub first_seen: Option<u64>,
#[serde(flatten)]
pub data: DataHash<'a, T>
}

fn default_xelis_asset() -> Hash {
crate::config::XELIS_ASSET
}

#[derive(Serialize, Deserialize)]
pub struct GetAccountHistoryParams<'a> {
pub address: Address<'a>,
#[serde(default = "default_xelis_asset")]
pub asset: Hash,
pub minimum_topoheight: Option<u64>,
pub maximum_topoheight: Option<u64>
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AccountHistoryType {
Mining { reward: u64 },
Burn { amount: u64 },
// TODO delete those two fields with upcoming privacy layer
Outgoing { amount: u64 },
Incoming { amount: u64 },
}

#[derive(Serialize, Deserialize)]
pub struct AccountHistoryEntry {
pub topoheight: u64,
pub hash: Hash,
#[serde(flatten)]
pub history_type: AccountHistoryType,
pub block_timestamp: u128
}

#[derive(Serialize, Deserialize)]
pub struct GetAccountAssetsParams<'a> {
pub address: Address<'a>,
}

#[derive(Serialize, Deserialize)]
pub struct GetAssetParams {
pub asset: Hash
}

#[derive(Serialize, Deserialize)]
pub struct GetAssetsParams {
pub skip: Option<usize>,
Expand All @@ -186,7 +253,15 @@ pub struct GetAssetsParams {
pub maximum_topoheight: Option<u64>
}

#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct GetAccountsParams {
pub skip: Option<usize>,
pub maximum: Option<usize>,
pub minimum_topoheight: Option<u64>,
pub maximum_topoheight: Option<u64>
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum NotifyEvent {
// When a new block is accepted by chain
// it contains Block struct as value
Expand All @@ -208,7 +283,21 @@ pub enum NotifyEvent {
TransactionSCResult,
// When a new asset has been registered
// TODO: Smart Contracts
NewAsset
NewAsset,
// When a new peer has connected to us
// It contains PeerEntry struct as value
PeerConnected,
// When a peer has disconnected from us
// It contains peer id as value
// TODO not implemented yet
PeerDisconnected,
// Peer peerlist updated, its all its connected peers
// It contains PeerPeerListUpdatedEvent as value
PeerPeerListUpdated,
// When a peer of a peer has disconnected
// and that he notified us
// It contains PeerPeerDisconnectedEvent as value
PeerPeerDisconnected,
}

#[derive(Serialize, Deserialize)]
Expand All @@ -231,4 +320,20 @@ pub struct TransactionExecutedEvent<'a> {
pub block_hash: Cow<'a, Hash>,
pub tx_hash: Cow<'a, Hash>,
pub topoheight: u64,
}

#[derive(Serialize, Deserialize)]
pub struct PeerPeerListUpdatedEvent {
// Peer ID of the peer that sent us the new peer list
pub peer_id: u64,
// Peerlist received from this peer
pub peerlist: Vec<SocketAddr>
}

#[derive(Serialize, Deserialize)]
pub struct PeerPeerDisconnectedEvent {
// Peer ID of the peer that sent us this notification
pub peer_id: u64,
// address of the peer that disconnected from him
pub peer_addr: SocketAddr
}
26 changes: 20 additions & 6 deletions xelis_common/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod wallet;
pub mod daemon;

// All types availables
#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone)]
#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone, Copy)]
pub enum DataType {
Bool,
String,
Expand All @@ -31,25 +31,39 @@ pub enum DataElement {
}

impl DataElement {
pub fn get_value(&self, name: String, data_type: DataType) -> Option<&DataValue> {
pub fn has_key(&self, key: &DataValue) -> bool {
let Self::Fields(fields) = &self else {
return false
};

fields.contains_key(key)
}

pub fn get_value_by_key(&self, key: &DataValue, data_type: Option<DataType>) -> Option<&DataValue> {
let Self::Fields(data) = &self else {
return None
};

let Self::Value(value) = data.get(&DataValue::String(name))? else {
let Self::Value(value) = data.get(key)? else {
return None;
};

let Some(unwrapped) = &value else {
return None;
};

if unwrapped.kind() != data_type {
return None
if let Some(data_type) = data_type {
if unwrapped.kind() != data_type {
return None
}
}

value.as_ref()
}

pub fn get_value_by_string_key(&self, name: String, data_type: DataType) -> Option<&DataValue> {
self.get_value_by_key(&DataValue::String(name), Some(data_type))
}
}

impl Serializer for DataElement {
Expand Down Expand Up @@ -188,7 +202,7 @@ impl Serializer for DataValue {
}
}

#[derive(Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct SubscribeParams<E> {
pub notify: E
}
Expand Down
Loading

0 comments on commit f4e4de9

Please sign in to comment.