diff --git a/dash/src/consensus/encode.rs b/dash/src/consensus/encode.rs index f24e62e37..cc9dc2086 100644 --- a/dash/src/consensus/encode.rs +++ b/dash/src/consensus/encode.rs @@ -35,7 +35,7 @@ use core::{fmt, mem, u32}; use hashes::{sha256, sha256d, hash_x11, Hash, hash160}; use internals::write_err; -use crate::{address, ScriptBuf}; +use crate::{address, OutPoint, ScriptBuf}; use crate::transaction::special_transaction::TransactionType; use crate::bip152::{PrefilledTransaction, ShortId}; use crate::transaction::{txin::TxIn, txout::TxOut}; @@ -672,6 +672,7 @@ impl_vec!(u64); impl_vec!(TapLeafHash); impl_vec!(VarInt); impl_vec!(ShortId); +impl_vec!(OutPoint); impl_vec!(PrefilledTransaction); #[cfg(feature = "std")] diff --git a/dash/src/ephemerealdata/instant_lock.rs b/dash/src/ephemerealdata/instant_lock.rs index 1ee3b0c67..9c33fbe4b 100644 --- a/dash/src/ephemerealdata/instant_lock.rs +++ b/dash/src/ephemerealdata/instant_lock.rs @@ -2,19 +2,21 @@ //! confirm transaction within 1 or 2 seconds. This data structure //! represents a p2p message containing a data to verify such a lock. -use consensus::{Decodable, Encodable, encode}; -use consensus::encode::MAX_VEC_SIZE; -use ::{io, Txid}; -use core::fmt::{Debug, Formatter}; +use crate::io; + #[cfg(all(not(feature = "std"), not(test)))] use alloc::vec::Vec; +use core::fmt::{Debug, Formatter}; #[cfg(any(feature = "std", test))] pub use std::vec::Vec; -use blockdata::transaction::OutPoint; - -type BlsSignature = [u8; 96]; +use hashes::{Hash, HashEngine}; +use crate::hash_types::{CycleHash, QuorumSigningRequestId}; +use crate::{OutPoint, Txid, VarInt}; +use crate::bls_sig_utils::BLSSignature; +use crate::consensus::{Encodable}; +use crate::internal_macros::impl_consensus_encoding; -type CycleHash = [u8; 32]; +const IS_LOCK_REQUEST_ID_PREFIX: &str = "islock"; #[derive(Clone, Eq, PartialEq)] /// Instant send lock is a mechanism used by the Dash network to @@ -30,18 +32,32 @@ pub struct InstantLock { /// Hash to figure out which quorum was used to sign this IS lock pub cyclehash: CycleHash, /// Quorum signature for this IS lock - pub signature: BlsSignature, + pub signature: BLSSignature, } -impl Default for InstantLock { - fn default() -> Self { - Self { - version: 1, - inputs: Default::default(), - txid: Default::default(), - cyclehash: Default::default(), - signature: [0; 96] +impl_consensus_encoding!(InstantLock, version, inputs, txid, cyclehash, signature); + +impl InstantLock { + /// Returns quorum signing request ID + pub fn request_id(&self) -> Result { + let mut engine = QuorumSigningRequestId::engine(); + + // Prefix + let prefix_len = VarInt(IS_LOCK_REQUEST_ID_PREFIX.len() as u64); + prefix_len.consensus_encode(&mut engine)?; + + engine.input(IS_LOCK_REQUEST_ID_PREFIX.as_bytes()); + + // Inputs + let inputs_len = VarInt(self.inputs.len() as u64); + inputs_len.consensus_encode(&mut engine)?; + + for input in &self.inputs { + engine.input(&input.txid[..]); + engine.input(&input.vout.to_le_bytes()); } + + Ok(QuorumSigningRequestId::from_engine(engine)) } } @@ -52,43 +68,16 @@ impl Debug for InstantLock { .field("inputs", &format_args!("{:?}", self.inputs)) .field("txid", &format_args!("{}", self.txid)) .field("cyclehash", &format_args!("{:?}", self.cyclehash)) - .field("signature", &format_args!("{:?}", self.signature.to_vec())) + .field("signature", &format_args!("{:?}", self.signature.as_bytes())) .finish() } } -impl Decodable for InstantLock { - fn consensus_decode(d: D) -> Result { - let mut d = d.take(MAX_VEC_SIZE as u64); - let version = u8::consensus_decode(&mut d)?; - let inputs = Vec::::consensus_decode(&mut d)?; - let txid = Txid::consensus_decode(&mut d)?; - let cyclehash = <[u8; 32]>::consensus_decode(&mut d)?; - let signature = <[u8; 96]>::consensus_decode(&mut d)?; - - Ok(Self { - version, inputs, txid, cyclehash, signature - }) - } -} - -impl Encodable for InstantLock { - fn consensus_encode(&self, mut s: S) -> Result { - let mut len = 0; - len += self.version.consensus_encode(&mut s)?; - len += self.inputs.consensus_encode(&mut s)?; - len += self.txid.consensus_encode(&mut s)?; - len += self.cyclehash.consensus_encode(&mut s)?; - len += self.signature.consensus_encode(&mut s)?; - Ok(len) - } -} - #[cfg(test)] -mod is_lock_test { - use hashes::hex::{FromHex, ToHex}; - use consensus::{deserialize, serialize}; - use ephemerealdata::instant_lock::InstantLock; +mod tests { + use super::*; + use crate::consensus::{deserialize, serialize}; + use crate::internal_macros::hex; #[test] pub fn should_decode_vec() { @@ -105,26 +94,34 @@ mod is_lock_test { // cyclehash: "7c30826123d0f29fe4c4a8895d7ba4eb469b1fafa6ad7b23896a1a591766a536", // signature: "85e12d70ca7118c5034004f93e45384079f46c6c2928b45cfc5d3ad640e70dfd87a9a3069899adfb3b1622daeeead19809b74354272ccf95290678f55c13728e3c5ee8f8417fcce3dfdca2a7c9c33ec981abdff1ec35a2e4b558c3698f01c1b8" // }; - let vec = Vec::from_hex(hex).unwrap(); + + let vec = hex!(hex); // let expected_hash = "4ee6a4ed2b6c70efd401c6c91dfaf6c61badd13f80ec07c281bb93d5270fcd58"; // let expected_request_id = "495be44677e82895a9396fef02c6e9afc1f01d4aff70622b9f78e0e10d57064c"; - + let is_lock: InstantLock = deserialize(&vec).unwrap(); assert_eq!(is_lock.version, 1); - + // TODO: check outpoints - let mut cycle_clone = is_lock.cyclehash.clone(); - cycle_clone.reverse(); - assert_eq!(cycle_clone.to_hex(), "7c30826123d0f29fe4c4a8895d7ba4eb469b1fafa6ad7b23896a1a591766a536"); + assert_eq!(is_lock.cyclehash.to_string(), "7c30826123d0f29fe4c4a8895d7ba4eb469b1fafa6ad7b23896a1a591766a536"); - let mut signature_clone = is_lock.signature.clone(); - signature_clone.reverse(); - //assert_eq!(signature_clone.to_hex(), "85e12d70ca7118c5034004f93e45384079f46c6c2928b45cfc5d3ad640e70dfd87a9a3069899adfb3b1622daeeead19809b74354272ccf95290678f55c13728e3c5ee8f8417fcce3dfdca2a7c9c33ec981abdff1ec35a2e4b558c3698f01c1b8"); - - let serialized = serialize(&is_lock).to_hex(); - assert_eq!(serialized, hex); + let serialized = serialize(&is_lock); + assert_eq!(serialized, vec); + } + + #[test] + pub fn should_create_request_id() { + let hex = "010101102862a43d122e6675aba4b507ae307af8e1e17febc77907e08b3efa28f41b000000004b446de00a592c67402c0a65649f4ad69f29084b3e9054f5aa6b85a50b497fe136a56617591a6a89237bada6af1f9b46eba47b5d89a8c4e49ff2d0236182307c85e12d70ca7118c5034004f93e45384079f46c6c2928b45cfc5d3ad640e70dfd87a9a3069899adfb3b1622daeeead19809b74354272ccf95290678f55c13728e3c5ee8f8417fcce3dfdca2a7c9c33ec981abdff1ec35a2e4b558c3698f01c1b8"; + let vec = hex!(hex); + + let expected_request_id = "495be44677e82895a9396fef02c6e9afc1f01d4aff70622b9f78e0e10d57064c"; + + let is_lock: InstantLock = deserialize(vec.as_slice()).unwrap(); + + let request_id = is_lock.request_id().expect("should return request id"); + assert_eq!(request_id.to_string(), expected_request_id); } // #[test] @@ -146,4 +143,4 @@ mod is_lock_test { // // let is_lock: InstantLock = serde_json::from_str(str).unwrap(); // } -} \ No newline at end of file +} diff --git a/dash/src/hash_types.rs b/dash/src/hash_types.rs index d3f5b8dea..5727b2908 100644 --- a/dash/src/hash_types.rs +++ b/dash/src/hash_types.rs @@ -74,13 +74,10 @@ mod newtypes { use core::str::FromStr; use hashes::{sha256, sha256d, hash160, hash_x11, hash_newtype, Hash}; use hashes::hex::Error; - use internals::hex::Case; - use internals::hex::display::DisplayHex; use crate::prelude::String; hash_newtype! { /// A dash transaction hash/transaction ID. - /// pub struct Txid(sha256d::Hash); /// A dash witness transaction ID. @@ -126,9 +123,13 @@ mod newtypes { pub struct QuorumHash(sha256d::Hash); /// A hash of a quorum verification vector pub struct QuorumVVecHash(sha256d::Hash); + /// A hash of a quorum signing request id + pub struct QuorumSigningRequestId(sha256d::Hash); /// ProTxHash is a pro-tx hash #[hash_newtype(forward)] pub struct ProTxHash(sha256d::Hash); + /// CycleHash is a cycle hash + pub struct CycleHash(hash_x11::Hash); } impl_hashencode!(Txid); @@ -149,7 +150,9 @@ mod newtypes { impl_hashencode!(QuorumHash); impl_hashencode!(QuorumVVecHash); + impl_hashencode!(QuorumSigningRequestId); impl_hashencode!(PubkeyHash); + impl_hashencode!(CycleHash); impl_asref_push_bytes!(PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash); @@ -204,7 +207,7 @@ mod newtypes { /// Convert a PubkeyHash to a string pub fn to_hex(&self) -> String { - self.0.as_byte_array().to_hex_string(Case::Lower) + self.0.to_string() } } } diff --git a/dash/src/lib.rs b/dash/src/lib.rs index 35c670b63..5e646d971 100644 --- a/dash/src/lib.rs +++ b/dash/src/lib.rs @@ -113,6 +113,7 @@ pub mod taproot; pub mod util; pub mod bls_sig_utils; mod signer; +mod ephemerealdata; // May depend on crate features and we don't want to bother with it #[allow(unused)]