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"))?;