Просмотр исходного кода

blockchain/monero: Add async serialization

parazyd 1 год назад
Родитель
Сommit
cc1b72cb6e
2 измененных файлов с 126 добавлено и 12 удалено
  1. 48 4
      src/blockchain/monero/merkle_proof.rs
  2. 78 8
      src/blockchain/monero/mod.rs

+ 48 - 4
src/blockchain/monero/merkle_proof.rs

@@ -16,9 +16,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::io::{Error, Read, Result, Write};
+use std::io::{self, Cursor, Error, Read, Write};
 
-use darkfi_serial::{Decodable, Encodable, ReadExt};
+use async_trait::async_trait;
+use darkfi_serial::{
+    AsyncDecodable, AsyncEncodable, AsyncRead, AsyncReadExt, AsyncWrite, Decodable, Encodable,
+    ReadExt,
+};
 use monero::{
     consensus::{Decodable as XmrDecodable, Encodable as XmrEncodable},
     Hash,
@@ -36,7 +40,7 @@ pub struct MerkleProof {
 }
 
 impl Encodable for MerkleProof {
-    fn encode<S: Write>(&self, s: &mut S) -> Result<usize> {
+    fn encode<S: Write>(&self, s: &mut S) -> io::Result<usize> {
         let mut n = 0;
 
         let len = self.branch.len() as u8;
@@ -52,8 +56,28 @@ impl Encodable for MerkleProof {
     }
 }
 
+#[async_trait]
+impl AsyncEncodable for MerkleProof {
+    async fn encode_async<S: AsyncWrite + Unpin + Send>(&self, s: &mut S) -> io::Result<usize> {
+        let mut n = 0;
+
+        let len = self.branch.len() as u8;
+        n += len.encode_async(s).await?;
+
+        for hash in &self.branch {
+            let mut buf = vec![];
+            (*hash).consensus_encode(&mut buf)?;
+            n += buf.encode_async(s).await?;
+        }
+
+        n += self.path_bitmap.encode_async(s).await?;
+
+        Ok(n)
+    }
+}
+
 impl Decodable for MerkleProof {
-    fn decode<D: Read>(d: &mut D) -> Result<Self> {
+    fn decode<D: Read>(d: &mut D) -> io::Result<Self> {
         let len: u8 = d.read_u8()?;
         let mut branch = Vec::with_capacity(len as usize);
 
@@ -67,6 +91,26 @@ impl Decodable for MerkleProof {
     }
 }
 
+#[async_trait]
+impl AsyncDecodable for MerkleProof {
+    async fn decode_async<D: AsyncRead + Unpin + Send>(d: &mut D) -> io::Result<Self> {
+        let len: u8 = d.read_u8_async().await?;
+        let mut branch = Vec::with_capacity(len as usize);
+
+        for _ in 0..len {
+            let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
+            let mut buf = Cursor::new(buf);
+            branch.push(
+                Hash::consensus_decode(&mut buf).map_err(|_| Error::other("Invalid XMR hash"))?,
+            );
+        }
+
+        let path_bitmap: u32 = AsyncDecodable::decode_async(d).await?;
+
+        Ok(Self { branch, path_bitmap })
+    }
+}
+
 impl MerkleProof {
     pub fn try_construct(branch: Vec<Hash>, path_bitmap: u32) -> Option<Self> {
         if branch.len() >= MAX_MERKLE_TREE_PROOF_SIZE {

+ 78 - 8
src/blockchain/monero/mod.rs

@@ -16,9 +16,10 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::io::{Error, Read, Result, Write};
+use std::io::{self, Cursor, Error, Read, Write};
 
-use darkfi_serial::{Decodable, Encodable};
+use async_trait::async_trait;
+use darkfi_serial::{AsyncDecodable, AsyncEncodable, AsyncRead, AsyncWrite, Decodable, Encodable};
 use monero::{
     blockdata::transaction::RawExtraField,
     consensus::{Decodable as XmrDecodable, Encodable as XmrEncodable},
@@ -61,13 +62,14 @@ pub struct MoneroPowData {
 }
 
 impl Encodable for MoneroPowData {
-    fn encode<S: Write>(&self, s: &mut S) -> Result<usize> {
+    fn encode<S: Write>(&self, s: &mut S) -> io::Result<usize> {
         let mut n = 0;
 
         n += self.header.consensus_encode(s)?;
         n += self.randomx_key.encode(s)?;
         n += self.transaction_count.encode(s)?;
-        n += self.merkle_root.as_fixed_bytes().encode(s)?;
+        n += self.merkle_root.consensus_encode(s)?;
+        n += self.coinbase_merkle_proof.encode(s)?;
 
         // This is an incomplete hasher. Dump it from memory
         // and write it down. We can restore it the same way.
@@ -81,16 +83,47 @@ impl Encodable for MoneroPowData {
     }
 }
 
+#[async_trait]
+impl AsyncEncodable for MoneroPowData {
+    async fn encode_async<S: AsyncWrite + Unpin + Send>(&self, s: &mut S) -> io::Result<usize> {
+        let mut n = 0;
+
+        let mut buf = vec![];
+        self.header.consensus_encode(&mut buf)?;
+        n += buf.encode_async(s).await?;
+
+        n += self.randomx_key.encode_async(s).await?;
+        n += self.transaction_count.encode_async(s).await?;
+
+        let mut buf = vec![];
+        self.merkle_root.consensus_encode(&mut buf)?;
+        n += buf.encode_async(s).await?;
+
+        n += self.coinbase_merkle_proof.encode_async(s).await?;
+
+        // This is an incomplete hasher. Dump it from memory
+        // and write it down. We can restore it the same way.
+        let buf = keccak_to_bytes(&self.coinbase_tx_hasher);
+        n += buf.encode_async(s).await?;
+
+        n += self.coinbase_tx_extra.0.encode_async(s).await?;
+        n += self.aux_chain_merkle_proof.encode_async(s).await?;
+
+        Ok(n)
+    }
+}
+
+#[async_trait]
 impl Decodable for MoneroPowData {
-    fn decode<D: Read>(d: &mut D) -> Result<Self> {
+    fn decode<D: Read>(d: &mut D) -> io::Result<Self> {
         let header =
             BlockHeader::consensus_decode(d).map_err(|_| Error::other("Invalid XMR header"))?;
 
         let randomx_key: [u8; 64] = Decodable::decode(d)?;
         let transaction_count: u16 = Decodable::decode(d)?;
 
-        let merkle_root: [u8; 32] = Decodable::decode(d)?;
-        let merkle_root = Hash::from_slice(&merkle_root);
+        let merkle_root =
+            Hash::consensus_decode(d).map_err(|_| Error::other("Invamid XMR hash"))?;
 
         let coinbase_merkle_proof: MerkleProof = Decodable::decode(d)?;
 
@@ -99,7 +132,6 @@ impl Decodable for MoneroPowData {
 
         let coinbase_tx_extra: Vec<u8> = Decodable::decode(d)?;
         let coinbase_tx_extra = RawExtraField(coinbase_tx_extra);
-
         let aux_chain_merkle_proof: MerkleProof = Decodable::decode(d)?;
 
         Ok(Self {
@@ -115,6 +147,44 @@ impl Decodable for MoneroPowData {
     }
 }
 
+#[async_trait]
+impl AsyncDecodable for MoneroPowData {
+    async fn decode_async<D: AsyncRead + Unpin + Send>(d: &mut D) -> io::Result<Self> {
+        let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
+        let mut buf = Cursor::new(buf);
+        let header = BlockHeader::consensus_decode(&mut buf)
+            .map_err(|_| Error::other("Invalid XMR header"))?;
+
+        let randomx_key: [u8; 64] = AsyncDecodable::decode_async(d).await?;
+        let transaction_count: u16 = AsyncDecodable::decode_async(d).await?;
+
+        let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
+        let mut buf = Cursor::new(buf);
+        let merkle_root =
+            Hash::consensus_decode(&mut buf).map_err(|_| Error::other("Invalid XMR hash"))?;
+
+        let coinbase_merkle_proof: MerkleProof = AsyncDecodable::decode_async(d).await?;
+
+        let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
+        let coinbase_tx_hasher = keccak_from_bytes(&buf);
+
+        let coinbase_tx_extra: Vec<u8> = AsyncDecodable::decode_async(d).await?;
+        let coinbase_tx_extra = RawExtraField(coinbase_tx_extra);
+        let aux_chain_merkle_proof: MerkleProof = AsyncDecodable::decode_async(d).await?;
+
+        Ok(Self {
+            header,
+            randomx_key,
+            transaction_count,
+            merkle_root,
+            coinbase_merkle_proof,
+            coinbase_tx_hasher,
+            coinbase_tx_extra,
+            aux_chain_merkle_proof,
+        })
+    }
+}
+
 impl MoneroPowData {
     /// Returns true if the coinbase Merkle proof produces the `merkle_root` hash.
     pub fn is_coinbase_valid_merkle_root(&self) -> bool {