From 703b18c6e86fa767fe1e6e02eebf774873da0257 Mon Sep 17 00:00:00 2001
From: Luke Parker <lukeparker5132@gmail.com>
Date: Sat, 21 May 2022 21:35:25 -0400
Subject: [PATCH] Implement Block types

Finishes updating the RPC to not use monero, tests now pass
---
 coins/monero/src/block.rs       | 64 +++++++++++++++++++++++++++++++++
 coins/monero/src/lib.rs         |  5 +--
 coins/monero/src/rpc.rs         | 29 +++++++--------
 coins/monero/src/transaction.rs | 10 +++---
 4 files changed, 85 insertions(+), 23 deletions(-)
 create mode 100644 coins/monero/src/block.rs

diff --git a/coins/monero/src/block.rs b/coins/monero/src/block.rs
new file mode 100644
index 00000000..328e9c7f
--- /dev/null
+++ b/coins/monero/src/block.rs
@@ -0,0 +1,64 @@
+use crate::{
+  serialize::*,
+  transaction::Transaction
+};
+
+pub struct BlockHeader {
+  pub major_version: u64,
+  pub minor_version: u64,
+  pub timestamp: u64,
+  pub previous: [u8; 32],
+  pub nonce: u32
+}
+
+impl BlockHeader {
+  pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
+    write_varint(&self.major_version, w)?;
+    write_varint(&self.minor_version, w)?;
+    write_varint(&self.timestamp, w)?;
+    w.write_all(&self.previous)?;
+    w.write_all(&self.nonce.to_le_bytes())
+  }
+
+  pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<BlockHeader> {
+    Ok(
+      BlockHeader {
+        major_version: read_varint(r)?,
+        minor_version: read_varint(r)?,
+        timestamp: read_varint(r)?,
+        previous: { let mut previous = [0; 32]; r.read_exact(&mut previous)?; previous },
+        nonce: { let mut nonce = [0; 4]; r.read_exact(&mut nonce)?; u32::from_le_bytes(nonce) }
+      }
+    )
+  }
+}
+
+pub struct Block {
+  pub header: BlockHeader,
+  pub miner_tx: Transaction,
+  pub txs: Vec<[u8; 32]>
+}
+
+impl Block {
+  pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
+    self.header.serialize(w)?;
+    self.miner_tx.serialize(w)?;
+    write_varint(&self.txs.len().try_into().unwrap(), w)?;
+    for tx in &self.txs {
+      w.write_all(tx)?;
+    }
+    Ok(())
+  }
+
+  pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Block> {
+    Ok(
+      Block {
+        header: BlockHeader::deserialize(r)?,
+        miner_tx: Transaction::deserialize(r)?,
+        txs: (0 .. read_varint(r)?).map(
+          |_| { let mut tx = [0; 32]; r.read_exact(&mut tx).map(|_| tx) }
+        ).collect::<Result<_, _>>()?
+      }
+    )
+  }
+}
diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs
index 58fd72c7..7534a3db 100644
--- a/coins/monero/src/lib.rs
+++ b/coins/monero/src/lib.rs
@@ -17,10 +17,11 @@ mod serialize;
 pub mod bulletproofs;
 pub mod clsag;
 
-pub mod rpc;
 pub mod transaction;
-pub mod wallet;
+pub mod block;
 
+pub mod rpc;
+pub mod wallet;
 
 #[cfg(test)]
 mod tests;
diff --git a/coins/monero/src/rpc.rs b/coins/monero/src/rpc.rs
index 839cb291..c8732074 100644
--- a/coins/monero/src/rpc.rs
+++ b/coins/monero/src/rpc.rs
@@ -9,7 +9,7 @@ use serde_json::json;
 
 use reqwest;
 
-use crate::transaction::{Input, Transaction};
+use crate::{transaction::{Input, Transaction}, block::Block};
 
 #[derive(Deserialize, Debug)]
 pub struct EmptyResponse {}
@@ -97,7 +97,11 @@ impl Rpc {
     Ok(self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height)
   }
 
-  pub async fn get_transactions(&self, hashes: Vec<[u8; 32]>) -> Result<Vec<Transaction>, RpcError> {
+  pub async fn get_transactions(&self, hashes: &[[u8; 32]]) -> Result<Vec<Transaction>, RpcError> {
+    if hashes.len() == 0 {
+      return Ok(vec![]);
+    }
+
     #[derive(Deserialize, Debug)]
     struct TransactionResponse {
       as_hex: String,
@@ -135,38 +139,31 @@ impl Rpc {
     )
   }
 
-  /*
   pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> {
     #[derive(Deserialize, Debug)]
     struct BlockResponse {
-      json: String
+      blob: String
     }
 
     let block: JsonRpcResponse<BlockResponse> = self.rpc_call("json_rpc", Some(json!({
       "method": "get_block",
       "params": {
-        "height": height
+        "height": dbg!(height)
       }
     }))).await?;
 
     Ok(
-      deserialize(
-        &rpc_hex(&block.result.blob)?
+      Block::deserialize(
+        &mut std::io::Cursor::new(rpc_hex(&block.result.blob)?)
       ).expect("Monero returned a block we couldn't deserialize")
     )
   }
-  */
 
   pub async fn get_block_transactions(&self, height: usize) -> Result<Vec<Transaction>, RpcError> {
-    /*
     let block = self.get_block(height).await?;
     let mut res = vec![block.miner_tx];
-    if block.tx_hashes.len() != 0 {
-      res.extend(self.get_transactions(block.tx_hashes.iter().map(|hash| hash.0).collect()).await?);
-    }
+    res.extend(self.get_transactions(&block.txs).await?);
     Ok(res)
-    */
-    Ok(vec![])
   }
 
   pub async fn get_o_indexes(&self, hash: [u8; 32]) -> Result<Vec<u64>, RpcError> {
@@ -220,10 +217,10 @@ impl Rpc {
     }))).await?;
 
     let txs = self.get_transactions(
-      outs.outs.iter().map(|out|
+      &outs.outs.iter().map(|out|
         rpc_hex(&out.txid).expect("Monero returned an invalidly encoded hash")
           .try_into().expect("Monero returned an invalid sized hash")
-      ).collect()
+      ).collect::<Vec<_>>()
     ).await?;
     // TODO: Support time based lock times. These shouldn't be needed, and it may be painful to
     // get the median time for the given height, yet we do need to in order to be complete
diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs
index abe7c721..4d10ce2c 100644
--- a/coins/monero/src/transaction.rs
+++ b/coins/monero/src/transaction.rs
@@ -20,7 +20,7 @@ impl Input {
   pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
     match self {
       Input::Gen(height) => {
-        w.write_all(&[0])?;
+        w.write_all(&[255])?;
         write_varint(height, w)
       },
 
@@ -34,17 +34,17 @@ impl Input {
   }
 
   pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Input> {
-    let mut variant = [0; 1];
+    let mut variant = [0];
     r.read_exact(&mut variant)?;
     Ok(
       match variant[0] {
-        0 => Input::Gen(read_varint(r)?),
+        255 => Input::Gen(read_varint(r)?),
         2 => Input::ToKey {
           amount: read_varint(r)?,
           key_offsets: read_vec(read_varint, r)?,
           key_image: read_point(r)?
         },
-        _ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown/unused output type"))?
+        _ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown/unused input type"))?
       }
     )
   }
@@ -70,7 +70,7 @@ impl Output {
 
   pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Output> {
     let amount = read_varint(r)?;
-    let mut tag = [0; 1];
+    let mut tag = [0];
     r.read_exact(&mut tag)?;
     if (tag[0] != 2) && (tag[0] != 3) {
       Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown/unused output type"))?;