mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-11-16 15:58:14 +00:00
From
serai types
This commit is contained in:
parent
4a1821e5e7
commit
a5316ad331
5 changed files with 226 additions and 18 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -885,9 +885,11 @@ dependencies = [
|
||||||
name = "cuprate-types"
|
name = "cuprate-types"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cuprate-epee-encoding",
|
"cuprate-epee-encoding",
|
||||||
"cuprate-fixed-bytes",
|
"cuprate-fixed-bytes",
|
||||||
|
"cuprate-helper",
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"hex",
|
"hex",
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
|
|
|
@ -13,14 +13,17 @@ default = ["blockchain", "epee", "serde", "json", "hex"]
|
||||||
blockchain = []
|
blockchain = []
|
||||||
epee = ["dep:cuprate-epee-encoding"]
|
epee = ["dep:cuprate-epee-encoding"]
|
||||||
serde = ["dep:serde"]
|
serde = ["dep:serde"]
|
||||||
|
bytemuck = ["dep:bytemuck"]
|
||||||
proptest = ["dep:proptest", "dep:proptest-derive"]
|
proptest = ["dep:proptest", "dep:proptest-derive"]
|
||||||
json = ["hex"]
|
json = ["hex", "bytemuck", "dep:cuprate-helper"]
|
||||||
hex = ["dep:hex", "dep:paste"]
|
hex = ["dep:hex", "dep:paste"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cuprate-epee-encoding = { path = "../net/epee-encoding", optional = true }
|
cuprate-epee-encoding = { path = "../net/epee-encoding", optional = true }
|
||||||
|
cuprate-helper = { path = "../helper", optional = true, features = ["cast"] }
|
||||||
cuprate-fixed-bytes = { path = "../net/fixed-bytes" }
|
cuprate-fixed-bytes = { path = "../net/fixed-bytes" }
|
||||||
|
|
||||||
|
bytemuck = { workspace = true, features = ["derive"], optional = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
curve25519-dalek = { workspace = true }
|
curve25519-dalek = { workspace = true }
|
||||||
monero-serai = { workspace = true }
|
monero-serai = { workspace = true }
|
||||||
|
|
|
@ -3,6 +3,16 @@
|
||||||
//! This module provides transparent wrapper types for
|
//! This module provides transparent wrapper types for
|
||||||
//! arrays that (de)serialize from hexadecimal input/output.
|
//! arrays that (de)serialize from hexadecimal input/output.
|
||||||
|
|
||||||
|
#![cfg_attr(
|
||||||
|
feature = "bytemuck",
|
||||||
|
expect(
|
||||||
|
clippy::allow_attributes,
|
||||||
|
reason = "bytemuck uses allow in its derive macros"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
|
||||||
|
#[cfg(feature = "bytemuck")]
|
||||||
|
use bytemuck::{Pod, TransparentWrapper, Zeroable};
|
||||||
#[cfg(feature = "epee")]
|
#[cfg(feature = "epee")]
|
||||||
use cuprate_epee_encoding::{error, macros::bytes, EpeeValue, Marker};
|
use cuprate_epee_encoding::{error, macros::bytes, EpeeValue, Marker};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -19,6 +29,7 @@ macro_rules! generate_hex_array {
|
||||||
$(
|
$(
|
||||||
#[doc = concat!("Wrapper type that (de)serializes from/to a ", stringify!($array_len), "-byte array.")]
|
#[doc = concat!("Wrapper type that (de)serializes from/to a ", stringify!($array_len), "-byte array.")]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable, TransparentWrapper))]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
|
@ -3,7 +3,14 @@
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{hex::HexBytes32, json::output::Output};
|
use monero_serai::{block, transaction};
|
||||||
|
|
||||||
|
use cuprate_helper::cast::usize_to_u64;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
hex::{HexBytes1, HexBytes32},
|
||||||
|
json::output::{Output, TaggedKey, Target},
|
||||||
|
};
|
||||||
|
|
||||||
/// JSON representation of a block.
|
/// JSON representation of a block.
|
||||||
///
|
///
|
||||||
|
@ -21,19 +28,25 @@ pub struct Block {
|
||||||
pub tx_hashes: Vec<HexBytes32>,
|
pub tx_hashes: Vec<HexBytes32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl From<monero_serai::block::Block> for Block {
|
impl From<block::Block> for Block {
|
||||||
// fn from(b: monero_serai::block::Block) -> Self {
|
fn from(b: block::Block) -> Self {
|
||||||
// Self {
|
let Ok(miner_tx) = MinerTransaction::try_from(b.miner_transaction) else {
|
||||||
// major_version: todo!(),
|
unreachable!("input is a miner tx, this should never fail");
|
||||||
// minor_version: todo!(),
|
};
|
||||||
// timestamp: todo!(),
|
|
||||||
// prev_id: todo!(),
|
let tx_hashes = b.transactions.into_iter().map(HexBytes32).collect();
|
||||||
// nonce: todo!(),
|
|
||||||
// miner_tx: todo!(),
|
Self {
|
||||||
// tx_hashes: todo!(),
|
major_version: b.header.hardfork_version,
|
||||||
// }
|
minor_version: b.header.hardfork_signal,
|
||||||
// }
|
timestamp: b.header.timestamp,
|
||||||
// }
|
prev_id: HexBytes32(b.header.previous),
|
||||||
|
nonce: b.header.nonce,
|
||||||
|
miner_tx,
|
||||||
|
tx_hashes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// [`Block::miner_tx`].
|
/// [`Block::miner_tx`].
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -54,6 +67,98 @@ pub enum MinerTransaction {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<transaction::Transaction> for MinerTransaction {
|
||||||
|
type Error = transaction::Transaction;
|
||||||
|
|
||||||
|
/// # Errors
|
||||||
|
/// This function errors if the input is not a miner transaction.
|
||||||
|
fn try_from(tx: transaction::Transaction) -> Result<Self, transaction::Transaction> {
|
||||||
|
fn map_prefix(
|
||||||
|
prefix: transaction::TransactionPrefix,
|
||||||
|
version: u8,
|
||||||
|
) -> Result<MinerTransactionPrefix, transaction::TransactionPrefix> {
|
||||||
|
let Some(input) = prefix.inputs.first() else {
|
||||||
|
return Err(prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
let height = match input {
|
||||||
|
transaction::Input::Gen(height) => usize_to_u64(*height),
|
||||||
|
transaction::Input::ToKey { .. } => return Err(prefix),
|
||||||
|
};
|
||||||
|
|
||||||
|
let vin = {
|
||||||
|
let r#gen = Gen { height };
|
||||||
|
let input = Input { r#gen };
|
||||||
|
[input]
|
||||||
|
};
|
||||||
|
|
||||||
|
let vout = prefix
|
||||||
|
.outputs
|
||||||
|
.into_iter()
|
||||||
|
.map(|o| {
|
||||||
|
let amount = o.amount.unwrap_or(0);
|
||||||
|
|
||||||
|
let target = match o.view_tag {
|
||||||
|
Some(view_tag) => {
|
||||||
|
let tagged_key = TaggedKey {
|
||||||
|
key: HexBytes32(o.key.0),
|
||||||
|
view_tag: HexBytes1([view_tag]),
|
||||||
|
};
|
||||||
|
|
||||||
|
Target::TaggedKey { tagged_key }
|
||||||
|
}
|
||||||
|
None => Target::Key {
|
||||||
|
key: HexBytes32(o.key.0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Output { amount, target }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// TODO: use cuprate_constants target time
|
||||||
|
let unlock_time = match prefix.additional_timelock {
|
||||||
|
transaction::Timelock::None => height,
|
||||||
|
transaction::Timelock::Block(height_lock) => height + usize_to_u64(height_lock),
|
||||||
|
transaction::Timelock::Time(seconds) => height + (seconds * 120),
|
||||||
|
} + 60;
|
||||||
|
|
||||||
|
Ok(MinerTransactionPrefix {
|
||||||
|
version,
|
||||||
|
unlock_time,
|
||||||
|
vin,
|
||||||
|
vout,
|
||||||
|
extra: prefix.extra,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(match tx {
|
||||||
|
transaction::Transaction::V1 { prefix, signatures } => {
|
||||||
|
let prefix = match map_prefix(prefix, 1) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(prefix) => return Err(transaction::Transaction::V1 { prefix, signatures }),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::V1 {
|
||||||
|
prefix,
|
||||||
|
signatures: [(); 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transaction::Transaction::V2 { prefix, proofs } => {
|
||||||
|
let prefix = match map_prefix(prefix, 2) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(prefix) => return Err(transaction::Transaction::V2 { prefix, proofs }),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::V2 {
|
||||||
|
prefix,
|
||||||
|
rct_signatures: MinerTransactionRctSignatures { r#type: 0 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for MinerTransaction {
|
impl Default for MinerTransaction {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::V1 {
|
Self::V1 {
|
||||||
|
@ -69,7 +174,7 @@ impl Default for MinerTransaction {
|
||||||
pub struct MinerTransactionPrefix {
|
pub struct MinerTransactionPrefix {
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub unlock_time: u64,
|
pub unlock_time: u64,
|
||||||
pub vin: Vec<Input>,
|
pub vin: [Input; 1],
|
||||||
pub vout: Vec<Output>,
|
pub vout: Vec<Output>,
|
||||||
pub extra: Vec<u8>,
|
pub extra: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,13 @@
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_helper::cast::usize_to_u64;
|
||||||
|
|
||||||
|
use monero_serai::transaction;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hex::{HexBytes32, HexBytes64, HexBytes8},
|
hex::{HexBytes1, HexBytes32, HexBytes64, HexBytes8},
|
||||||
json::output::Output,
|
json::output::{Output, TaggedKey, Target},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// JSON representation of a non-miner transaction.
|
/// JSON representation of a non-miner transaction.
|
||||||
|
@ -48,6 +52,89 @@ pub struct TransactionPrefix {
|
||||||
pub extra: Vec<u8>,
|
pub extra: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<transaction::Transaction> for Transaction {
|
||||||
|
fn from(tx: transaction::Transaction) -> Self {
|
||||||
|
fn map_prefix(prefix: transaction::TransactionPrefix, version: u8) -> TransactionPrefix {
|
||||||
|
let mut height = 0;
|
||||||
|
|
||||||
|
let vin = prefix
|
||||||
|
.inputs
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|input| match input {
|
||||||
|
transaction::Input::ToKey {
|
||||||
|
amount,
|
||||||
|
key_offsets,
|
||||||
|
key_image,
|
||||||
|
} => {
|
||||||
|
let key = Key {
|
||||||
|
amount: amount.unwrap_or(0),
|
||||||
|
key_offsets,
|
||||||
|
k_image: HexBytes32(key_image.compress().0),
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Input { key })
|
||||||
|
}
|
||||||
|
transaction::Input::Gen(h) => {
|
||||||
|
height = usize_to_u64(h);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vout = prefix
|
||||||
|
.outputs
|
||||||
|
.into_iter()
|
||||||
|
.map(|o| {
|
||||||
|
let amount = o.amount.unwrap_or(0);
|
||||||
|
|
||||||
|
let target = match o.view_tag {
|
||||||
|
Some(view_tag) => {
|
||||||
|
let tagged_key = TaggedKey {
|
||||||
|
key: HexBytes32(o.key.0),
|
||||||
|
view_tag: HexBytes1([view_tag]),
|
||||||
|
};
|
||||||
|
|
||||||
|
Target::TaggedKey { tagged_key }
|
||||||
|
}
|
||||||
|
None => Target::Key {
|
||||||
|
key: HexBytes32(o.key.0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Output { amount, target }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// TODO: use cuprate_constants target time
|
||||||
|
let unlock_time = match prefix.additional_timelock {
|
||||||
|
transaction::Timelock::None => height,
|
||||||
|
transaction::Timelock::Block(height_lock) => height + usize_to_u64(height_lock),
|
||||||
|
transaction::Timelock::Time(seconds) => height + (seconds * 120),
|
||||||
|
} + 60;
|
||||||
|
|
||||||
|
TransactionPrefix {
|
||||||
|
version,
|
||||||
|
unlock_time,
|
||||||
|
vin,
|
||||||
|
vout,
|
||||||
|
extra: prefix.extra,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match tx {
|
||||||
|
transaction::Transaction::V1 { prefix, signatures } => Self::V1 {
|
||||||
|
prefix: map_prefix(prefix, 1),
|
||||||
|
signatures: todo!(),
|
||||||
|
},
|
||||||
|
transaction::Transaction::V2 { prefix, proofs } => Self::V2 {
|
||||||
|
prefix: map_prefix(prefix, 2),
|
||||||
|
rct_signatures: todo!(),
|
||||||
|
rctsig_prunable: todo!(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// [`Transaction::V2::rct_signatures`].
|
/// [`Transaction::V2::rct_signatures`].
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
|
Loading…
Reference in a new issue