Implement Block types

Finishes updating the RPC to not use monero, tests now pass
This commit is contained in:
Luke Parker
2022-05-21 21:35:25 -04:00
parent 3282b19536
commit 703b18c6e8
4 changed files with 85 additions and 23 deletions

64
coins/monero/src/block.rs Normal file
View File

@@ -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<_, _>>()?
}
)
}
}

View File

@@ -17,10 +17,11 @@ mod serialize;
pub mod bulletproofs; pub mod bulletproofs;
pub mod clsag; pub mod clsag;
pub mod rpc;
pub mod transaction; pub mod transaction;
pub mod wallet; pub mod block;
pub mod rpc;
pub mod wallet;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View File

@@ -9,7 +9,7 @@ use serde_json::json;
use reqwest; use reqwest;
use crate::transaction::{Input, Transaction}; use crate::{transaction::{Input, Transaction}, block::Block};
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct EmptyResponse {} pub struct EmptyResponse {}
@@ -97,7 +97,11 @@ impl Rpc {
Ok(self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height) 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)] #[derive(Deserialize, Debug)]
struct TransactionResponse { struct TransactionResponse {
as_hex: String, as_hex: String,
@@ -135,38 +139,31 @@ impl Rpc {
) )
} }
/*
pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> { pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> {
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct BlockResponse { struct BlockResponse {
json: String blob: String
} }
let block: JsonRpcResponse<BlockResponse> = self.rpc_call("json_rpc", Some(json!({ let block: JsonRpcResponse<BlockResponse> = self.rpc_call("json_rpc", Some(json!({
"method": "get_block", "method": "get_block",
"params": { "params": {
"height": height "height": dbg!(height)
} }
}))).await?; }))).await?;
Ok( Ok(
deserialize( Block::deserialize(
&rpc_hex(&block.result.blob)? &mut std::io::Cursor::new(rpc_hex(&block.result.blob)?)
).expect("Monero returned a block we couldn't deserialize") ).expect("Monero returned a block we couldn't deserialize")
) )
} }
*/
pub async fn get_block_transactions(&self, height: usize) -> Result<Vec<Transaction>, RpcError> { pub async fn get_block_transactions(&self, height: usize) -> Result<Vec<Transaction>, RpcError> {
/*
let block = self.get_block(height).await?; let block = self.get_block(height).await?;
let mut res = vec![block.miner_tx]; let mut res = vec![block.miner_tx];
if block.tx_hashes.len() != 0 { res.extend(self.get_transactions(&block.txs).await?);
res.extend(self.get_transactions(block.tx_hashes.iter().map(|hash| hash.0).collect()).await?);
}
Ok(res) Ok(res)
*/
Ok(vec![])
} }
pub async fn get_o_indexes(&self, hash: [u8; 32]) -> Result<Vec<u64>, RpcError> { pub async fn get_o_indexes(&self, hash: [u8; 32]) -> Result<Vec<u64>, RpcError> {
@@ -220,10 +217,10 @@ impl Rpc {
}))).await?; }))).await?;
let txs = self.get_transactions( 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") rpc_hex(&out.txid).expect("Monero returned an invalidly encoded hash")
.try_into().expect("Monero returned an invalid sized hash") .try_into().expect("Monero returned an invalid sized hash")
).collect() ).collect::<Vec<_>>()
).await?; ).await?;
// TODO: Support time based lock times. These shouldn't be needed, and it may be painful to // 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 // get the median time for the given height, yet we do need to in order to be complete

View File

@@ -20,7 +20,7 @@ impl Input {
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
match self { match self {
Input::Gen(height) => { Input::Gen(height) => {
w.write_all(&[0])?; w.write_all(&[255])?;
write_varint(height, w) write_varint(height, w)
}, },
@@ -34,17 +34,17 @@ impl Input {
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<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)?; r.read_exact(&mut variant)?;
Ok( Ok(
match variant[0] { match variant[0] {
0 => Input::Gen(read_varint(r)?), 255 => Input::Gen(read_varint(r)?),
2 => Input::ToKey { 2 => Input::ToKey {
amount: read_varint(r)?, amount: read_varint(r)?,
key_offsets: read_vec(read_varint, r)?, key_offsets: read_vec(read_varint, r)?,
key_image: read_point(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> { pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Output> {
let amount = read_varint(r)?; let amount = read_varint(r)?;
let mut tag = [0; 1]; let mut tag = [0];
r.read_exact(&mut tag)?; r.read_exact(&mut tag)?;
if (tag[0] != 2) && (tag[0] != 3) { if (tag[0] != 2) && (tag[0] != 3) {
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 output type"))?;