use std::collections::HashMap; use anyhow::Result; use rand::{thread_rng, RngCore}; use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize, Serializer}; use serde_json::Value; use sp_client::bitcoin::consensus::serialize; use sp_client::bitcoin::hex::DisplayHex; use sp_client::bitcoin::{OutPoint, Transaction}; use tsify::Tsify; use crate::error::AnkError; use crate::pcd::{Member, RoleDefinition}; use crate::process::Process; use crate::signature::Proof; #[derive(Debug, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub enum AnkFlag { NewTx, Faucet, Cipher, Commit, Handshake, Unknown, } impl From<&str> for AnkFlag { fn from(value: &str) -> Self { match value { "NewTx" => Self::NewTx, "Faucet" => Self::Faucet, "Cipher" => Self::Cipher, "Commit" => Self::Commit, "Handshake" => Self::Handshake, _ => Self::Unknown, } } } impl From for AnkFlag { fn from(value: String) -> Self { (&value[..]).into() } } impl AnkFlag { pub fn new_from_byte(byte: u8) -> Self { match byte { 0 => Self::NewTx, 1 => Self::Faucet, 2 => Self::Cipher, 3 => Self::Commit, 4 => Self::Handshake, _ => Self::Unknown, } } pub fn as_str(&self) -> &str { match self { Self::NewTx => "NewTx", Self::Faucet => "Faucet", Self::Cipher => "Cipher", Self::Commit => "Commit", Self::Handshake => "Handshake", Self::Unknown => "Unknown", } } } /// Message sent to the server to commit some state in a transaction /// Client must first send a commit message with empty validation_tokens /// Relay will ignore a commit message for an update he's not aware of that also bears validation_tokens #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct CommitMessage { pub init_tx: String, // Can be tx or txid of the first transaction of the chain, which is maybe not ideal pub pcd_commitment: Value, // map of field <=> hash of the clear value pub roles: HashMap, // Can be hashed and compared with the value above pub validation_tokens: Vec, pub error: Option, } impl CommitMessage { /// Create a new commitment message for the first transaction of the chain /// init_tx must be the hex string of the transaction /// validation_tokens must be empty pub fn new_first_commitment( transaction: Transaction, pcd_commitment: Value, roles: HashMap, ) -> Self { Self { init_tx: serialize(&transaction).to_lower_hex_string(), pcd_commitment, roles, validation_tokens: vec![], error: None, } } /// Create a new commitment message for an update transaction /// init_tx must be the hex string of the txid of the first commitment transaction /// validation_tokens must be empty pub fn new_update_commitment( init_tx: OutPoint, pcd_commitment: Value, roles: HashMap, ) -> Self { Self { init_tx: init_tx.to_string(), pcd_commitment, roles, validation_tokens: vec![], error: None, } } /// Set the validation tokens for a pending commitment pub fn set_validation_tokens(&mut self, validation_tokens: Vec) { self.validation_tokens = validation_tokens; } } #[derive(Debug, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct FaucetMessage { pub sp_address: String, pub commitment: String, pub error: Option, } impl FaucetMessage { pub fn new(sp_address: String) -> Self { let mut buf = [0u8; 32]; thread_rng().fill_bytes(&mut buf); Self { sp_address, commitment: buf.to_lower_hex_string(), error: None, } } pub fn to_string(&self) -> String { serde_json::to_string(self).unwrap() } } #[derive(Debug, PartialEq, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct NewTxMessage { pub transaction: String, pub tweak_data: Option, pub error: Option, } impl NewTxMessage { pub fn new(transaction: String, tweak_data: Option) -> Self { Self { transaction, tweak_data, error: None, } } pub fn to_string(&self) -> String { serde_json::to_string(self).unwrap() } } #[derive(Debug, PartialEq, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct HandshakeMessage { pub sp_address: String, pub peers_list: HashMap, pub processes_list: HashMap, } impl Serialize for HandshakeMessage { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("HandshakeMessage", 3)?; state.serialize_field("sp_address", &self.sp_address)?; let peers_list: HashMap = self .peers_list .iter() .map(|(member, outpoint)| { let member_str = serde_json::to_string(member).unwrap(); (member_str, outpoint) }) .collect(); state.serialize_field("peers_list", &peers_list)?; // Serialize `processes_list` normally state.serialize_field("processes_list", &self.processes_list)?; state.end() } } impl HandshakeMessage { pub fn new(sp_address: String, peers_list: HashMap, processes_list: HashMap) -> Self { Self { sp_address, peers_list, processes_list, } } pub fn to_string(&self) -> String { serde_json::to_string(self).unwrap() } } #[derive(Debug, Serialize, Deserialize)] pub struct Envelope { pub flag: AnkFlag, pub content: String, } impl Envelope { pub fn new(flag: AnkFlag, raw: &str) -> Self { Self { flag, content: raw.into(), } } pub fn from_string(json: &str) -> Result { let res: Self = serde_json::from_str(json)?; Ok(res) } pub fn to_string(&self) -> String { serde_json::to_string(self).unwrap() } }