2018-10-12 10:22:58 -07:00
|
|
|
//! Generated code for handling light client protobuf structs.
|
|
|
|
|
2023-08-16 10:15:10 -07:00
|
|
|
use std::io;
|
|
|
|
|
|
|
|
use incrementalmerkletree::frontier::CommitmentTree;
|
2020-08-05 13:08:58 -07:00
|
|
|
use zcash_primitives::{
|
|
|
|
block::{BlockHash, BlockHeader},
|
|
|
|
consensus::BlockHeight,
|
2023-08-16 10:15:10 -07:00
|
|
|
merkle_tree::read_commitment_tree,
|
|
|
|
sapling::{note::ExtractedNoteCommitment, Node, Nullifier, NOTE_COMMITMENT_TREE_DEPTH},
|
2022-02-16 18:44:20 -08:00
|
|
|
transaction::{components::sapling, TxId},
|
2020-08-05 13:08:58 -07:00
|
|
|
};
|
2019-05-01 05:21:48 -07:00
|
|
|
|
2021-08-09 13:28:42 -07:00
|
|
|
use zcash_note_encryption::{EphemeralKeyBytes, COMPACT_NOTE_SIZE};
|
2021-04-05 10:51:07 -07:00
|
|
|
|
2022-11-01 17:42:41 -07:00
|
|
|
#[rustfmt::skip]
|
2022-11-04 12:17:54 -07:00
|
|
|
#[allow(unknown_lints)]
|
|
|
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
2018-10-12 10:22:58 -07:00
|
|
|
pub mod compact_formats;
|
2019-05-01 05:21:48 -07:00
|
|
|
|
2022-09-16 10:24:14 -07:00
|
|
|
#[rustfmt::skip]
|
2022-11-04 12:17:54 -07:00
|
|
|
#[allow(unknown_lints)]
|
|
|
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
2022-09-16 10:24:14 -07:00
|
|
|
pub mod service;
|
|
|
|
|
2019-05-01 05:21:48 -07:00
|
|
|
impl compact_formats::CompactBlock {
|
|
|
|
/// Returns the [`BlockHash`] for this block.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// This function will panic if [`CompactBlock.header`] is not set and
|
|
|
|
/// [`CompactBlock.hash`] is not exactly 32 bytes.
|
|
|
|
///
|
|
|
|
/// [`CompactBlock.header`]: #structfield.header
|
|
|
|
/// [`CompactBlock.hash`]: #structfield.hash
|
|
|
|
pub fn hash(&self) -> BlockHash {
|
|
|
|
if let Some(header) = self.header() {
|
|
|
|
header.hash()
|
|
|
|
} else {
|
|
|
|
BlockHash::from_slice(&self.hash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the [`BlockHash`] for this block's parent.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// This function will panic if [`CompactBlock.header`] is not set and
|
|
|
|
/// [`CompactBlock.prevHash`] is not exactly 32 bytes.
|
|
|
|
///
|
|
|
|
/// [`CompactBlock.header`]: #structfield.header
|
|
|
|
/// [`CompactBlock.prevHash`]: #structfield.prevHash
|
|
|
|
pub fn prev_hash(&self) -> BlockHash {
|
|
|
|
if let Some(header) = self.header() {
|
|
|
|
header.prev_block
|
|
|
|
} else {
|
2022-11-01 17:42:41 -07:00
|
|
|
BlockHash::from_slice(&self.prev_hash)
|
2019-05-01 05:21:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
/// Returns the [`BlockHeight`] value for this block
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// This function will panic if [`CompactBlock.height`] is not
|
|
|
|
/// representable within a u32.
|
|
|
|
pub fn height(&self) -> BlockHeight {
|
|
|
|
self.height.try_into().unwrap()
|
|
|
|
}
|
|
|
|
|
2019-05-01 05:21:48 -07:00
|
|
|
/// Returns the [`BlockHeader`] for this block if present.
|
|
|
|
///
|
|
|
|
/// A convenience method that parses [`CompactBlock.header`] if present.
|
|
|
|
///
|
|
|
|
/// [`CompactBlock.header`]: #structfield.header
|
|
|
|
pub fn header(&self) -> Option<BlockHeader> {
|
|
|
|
if self.header.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
BlockHeader::read(&self.header[..]).ok()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-26 03:59:07 -07:00
|
|
|
|
2021-05-11 09:54:39 -07:00
|
|
|
impl compact_formats::CompactTx {
|
|
|
|
/// Returns the transaction Id
|
|
|
|
pub fn txid(&self) -> TxId {
|
|
|
|
let mut hash = [0u8; 32];
|
|
|
|
hash.copy_from_slice(&self.hash);
|
|
|
|
TxId::from_bytes(hash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 18:44:20 -08:00
|
|
|
impl compact_formats::CompactSaplingOutput {
|
2019-08-26 03:59:07 -07:00
|
|
|
/// Returns the note commitment for this output.
|
|
|
|
///
|
|
|
|
/// A convenience method that parses [`CompactOutput.cmu`].
|
|
|
|
///
|
|
|
|
/// [`CompactOutput.cmu`]: #structfield.cmu
|
2023-01-06 09:01:05 -08:00
|
|
|
pub fn cmu(&self) -> Result<ExtractedNoteCommitment, ()> {
|
2020-07-01 13:26:54 -07:00
|
|
|
let mut repr = [0; 32];
|
2020-04-22 22:32:04 -07:00
|
|
|
repr.as_mut().copy_from_slice(&self.cmu[..]);
|
2023-01-06 09:01:05 -08:00
|
|
|
Option::from(ExtractedNoteCommitment::from_bytes(&repr)).ok_or(())
|
2019-08-26 03:59:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the ephemeral public key for this output.
|
|
|
|
///
|
|
|
|
/// A convenience method that parses [`CompactOutput.epk`].
|
|
|
|
///
|
|
|
|
/// [`CompactOutput.epk`]: #structfield.epk
|
2021-08-09 13:28:42 -07:00
|
|
|
pub fn ephemeral_key(&self) -> Result<EphemeralKeyBytes, ()> {
|
2022-11-01 17:42:41 -07:00
|
|
|
self.ephemeral_key[..]
|
2021-08-09 13:28:42 -07:00
|
|
|
.try_into()
|
|
|
|
.map(EphemeralKeyBytes)
|
|
|
|
.map_err(|_| ())
|
2019-08-26 03:59:07 -07:00
|
|
|
}
|
|
|
|
}
|
2021-01-19 09:09:36 -08:00
|
|
|
|
2023-09-21 17:09:00 -07:00
|
|
|
impl<Proof> From<&sapling::OutputDescription<Proof>> for compact_formats::CompactSaplingOutput {
|
|
|
|
fn from(out: &sapling::OutputDescription<Proof>) -> compact_formats::CompactSaplingOutput {
|
2022-11-01 17:42:41 -07:00
|
|
|
compact_formats::CompactSaplingOutput {
|
2023-01-06 09:01:05 -08:00
|
|
|
cmu: out.cmu().to_bytes().to_vec(),
|
2022-12-10 14:27:09 -08:00
|
|
|
ephemeral_key: out.ephemeral_key().as_ref().to_vec(),
|
|
|
|
ciphertext: out.enc_ciphertext()[..COMPACT_NOTE_SIZE].to_vec(),
|
2022-11-01 17:42:41 -07:00
|
|
|
}
|
2021-04-05 10:51:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 18:44:20 -08:00
|
|
|
impl TryFrom<compact_formats::CompactSaplingOutput> for sapling::CompactOutputDescription {
|
2021-04-05 10:51:07 -07:00
|
|
|
type Error = ();
|
|
|
|
|
2022-02-16 18:44:20 -08:00
|
|
|
fn try_from(value: compact_formats::CompactSaplingOutput) -> Result<Self, Self::Error> {
|
|
|
|
Ok(sapling::CompactOutputDescription {
|
2021-04-05 10:51:07 -07:00
|
|
|
cmu: value.cmu()?,
|
2021-08-06 08:54:48 -07:00
|
|
|
ephemeral_key: value.ephemeral_key()?,
|
2021-12-16 21:34:45 -08:00
|
|
|
enc_ciphertext: value.ciphertext.try_into().map_err(|_| ())?,
|
2021-04-05 10:51:07 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 18:44:20 -08:00
|
|
|
impl compact_formats::CompactSaplingSpend {
|
2021-01-19 09:09:36 -08:00
|
|
|
pub fn nf(&self) -> Result<Nullifier, ()> {
|
|
|
|
Nullifier::from_slice(&self.nf).map_err(|_| ())
|
|
|
|
}
|
|
|
|
}
|
2023-08-16 10:15:10 -07:00
|
|
|
|
2023-09-21 17:09:00 -07:00
|
|
|
impl<A: sapling::Authorization> From<&sapling::SpendDescription<A>>
|
|
|
|
for compact_formats::CompactSaplingSpend
|
|
|
|
{
|
|
|
|
fn from(spend: &sapling::SpendDescription<A>) -> compact_formats::CompactSaplingSpend {
|
|
|
|
compact_formats::CompactSaplingSpend {
|
|
|
|
nf: spend.nullifier().to_vec(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<SpendAuth> From<&orchard::Action<SpendAuth>> for compact_formats::CompactOrchardAction {
|
|
|
|
fn from(action: &orchard::Action<SpendAuth>) -> compact_formats::CompactOrchardAction {
|
|
|
|
compact_formats::CompactOrchardAction {
|
|
|
|
nullifier: action.nullifier().to_bytes().to_vec(),
|
|
|
|
cmx: action.cmx().to_bytes().to_vec(),
|
|
|
|
ephemeral_key: action.encrypted_note().epk_bytes.to_vec(),
|
|
|
|
ciphertext: action.encrypted_note().enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-16 10:15:10 -07:00
|
|
|
impl service::TreeState {
|
2023-09-01 09:06:19 -07:00
|
|
|
/// Deserializes and returns the Sapling note commitment tree field of the tree state.
|
2023-08-16 10:15:10 -07:00
|
|
|
pub fn sapling_tree(&self) -> io::Result<CommitmentTree<Node, NOTE_COMMITMENT_TREE_DEPTH>> {
|
|
|
|
let sapling_tree_bytes = hex::decode(&self.sapling_tree).map_err(|e| {
|
|
|
|
io::Error::new(
|
|
|
|
io::ErrorKind::InvalidData,
|
|
|
|
format!("Hex decoding of Sapling tree bytes failed: {:?}", e),
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
read_commitment_tree::<Node, _, NOTE_COMMITMENT_TREE_DEPTH>(&sapling_tree_bytes[..])
|
|
|
|
}
|
|
|
|
}
|