Skip to content

Commit

Permalink
Merge remote-tracking branch 'QED-it/zsa-integration-block-test' into…
Browse files Browse the repository at this point in the history
… zsa-issued-assets-tests
  • Loading branch information
arya2 committed Nov 15, 2024
2 parents e063729 + 4855c25 commit e040ae0
Show file tree
Hide file tree
Showing 30 changed files with 852 additions and 260 deletions.
4 changes: 2 additions & 2 deletions zebra-chain/src/block/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl Commitment {
// NetworkUpgrade::current() returns the latest network upgrade that's activated at the provided height, so
// on Regtest for heights above height 0, it could return NU6, and it's possible for the current network upgrade
// to be NU6 (or Canopy, or any network upgrade above Heartwood) at the Heartwood activation height.
(Canopy | Nu5 | Nu6, activation_height)
(Canopy | Nu5 | Nu6 | Nu7, activation_height)
if height == activation_height
&& Some(height) == Heartwood.activation_height(network) =>
{
Expand All @@ -136,7 +136,7 @@ impl Commitment {
}
}
(Heartwood | Canopy, _) => Ok(ChainHistoryRoot(ChainHistoryMmrRootHash(bytes))),
(Nu5 | Nu6, _) => Ok(ChainHistoryBlockTxAuthCommitment(
(Nu5 | Nu6 | Nu7, _) => Ok(ChainHistoryBlockTxAuthCommitment(
ChainHistoryBlockTxAuthCommitmentHash(bytes),
)),
}
Expand Down
4 changes: 2 additions & 2 deletions zebra-chain/src/history_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl NonEmptyHistoryTree {
)?;
InnerHistoryTree::PreOrchard(tree)
}
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => {
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => {
let tree = Tree::<OrchardOnward>::new_from_cache(
network,
network_upgrade,
Expand Down Expand Up @@ -156,7 +156,7 @@ impl NonEmptyHistoryTree {
)?;
(InnerHistoryTree::PreOrchard(tree), entry)
}
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 => {
NetworkUpgrade::Nu5 | NetworkUpgrade::Nu6 | NetworkUpgrade::Nu7 => {
let (tree, entry) = Tree::<OrchardOnward>::new_from_block(
network,
block,
Expand Down
3 changes: 3 additions & 0 deletions zebra-chain/src/orchard/shielded_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ bitflags! {
const ENABLE_SPENDS = 0b00000001;
/// Enable creating new non-zero valued Orchard notes.
const ENABLE_OUTPUTS = 0b00000010;
/// Enable ZSA transaction (otherwise all notes within actions must use native asset).
// FIXME: Should we use this flag explicitly anywhere in Zebra?
const ENABLE_ZSA = 0b00000100;
}
}

Expand Down
3 changes: 2 additions & 1 deletion zebra-chain/src/orchard_zsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#[cfg(any(test, feature = "proptest-impl"))]
pub(crate) mod arbitrary;

mod common;
#[cfg(test)]
mod tests;

mod asset_state;
mod burn;
Expand Down
20 changes: 18 additions & 2 deletions zebra-chain/src/orchard_zsa/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,28 @@ use std::io;

use crate::{
block::MAX_BLOCK_BYTES,
serialization::{SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashSerialize},
serialization::{
ReadZcashExt, SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashSerialize,
},
};

use orchard::{note::AssetBase, value::NoteValue};

use super::common::ASSET_BASE_SIZE;
// The size of the serialized AssetBase in bytes (used for TrustedPreallocate impls)
pub(super) const ASSET_BASE_SIZE: u64 = 32;

impl ZcashSerialize for AssetBase {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.to_bytes())
}
}

impl ZcashDeserialize for AssetBase {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Option::from(AssetBase::from_bytes(&reader.read_32_bytes()?))
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa AssetBase!"))
}
}

// Sizes of the serialized values for types in bytes (used for TrustedPreallocate impls)
const AMOUNT_SIZE: u64 = 8;
Expand Down
23 changes: 0 additions & 23 deletions zebra-chain/src/orchard_zsa/common.rs

This file was deleted.

215 changes: 17 additions & 198 deletions zebra-chain/src/orchard_zsa/issuance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,38 @@
use std::{fmt::Debug, io};

use nonempty::NonEmpty;

// FIXME: needed for "as_bool" only - consider to implement as_bool locally
use bitvec::macros::internal::funty::Fundamental;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use halo2::pasta::pallas;

// For pallas::Base::from_repr only
use group::ff::PrimeField;

use zcash_primitives::transaction::components::issuance::{read_v6_bundle, write_v6_bundle};

use orchard::{
issuance::{IssueAction, IssueBundle, Signed},
keys::IssuanceValidatingKey,
note::{ExtractedNoteCommitment, RandomSeed, Rho},
primitives::redpallas::{SigType, Signature, SpendAuth},
value::NoteValue,
Address, Note,
note::ExtractedNoteCommitment,
Note,
};

use crate::{
block::MAX_BLOCK_BYTES,
serialization::{
zcash_serialize_bytes, zcash_serialize_empty_list, ReadZcashExt, SerializationError,
TrustedPreallocate, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize,
},
serialization::{SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashSerialize},
};

use super::common::ASSET_BASE_SIZE;
use super::burn::ASSET_BASE_SIZE;

/// Wrapper for `IssueBundle` used in the context of Transaction V6. This allows the implementation of
/// a Serde serializer for unit tests within this crate.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IssueData(IssueBundle<Signed>);

impl IssueData {
/// Returns a reference to the inner `IssueBundle<Signed>`.
pub fn inner(&self) -> &IssueBundle<Signed> {
&self.0
}
}

impl From<IssueBundle<Signed>> for IssueData {
fn from(inner: IssueBundle<Signed>) -> Self {
Self(inner)
Expand Down Expand Up @@ -75,126 +71,6 @@ const RANDOM_SEED_SIZE: u64 = 32;
const NOTE_SIZE: u64 =
ADDRESS_SIZE + NOTE_VALUE_SIZE + ASSET_BASE_SIZE + NULLIFIER_SIZE + RANDOM_SEED_SIZE;

// FIXME: duplicates ZcashSerialize for reddsa::Signature in transaction/serialize.rs
// (as Signature from oechard_zsa is formally a different type)
impl<T: SigType> ZcashSerialize for Signature<T> {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&<[u8; 64]>::from(self))?;
Ok(())
}
}

// FIXME: duplicates ZcashDeserialize for reddsa::Signature in transaction/serialize.rs
// (as Signature from oechard_zsa is formally a different type)
impl<T: SigType> ZcashDeserialize for Signature<T> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Ok(reader.read_64_bytes()?.into())
}
}

impl ZcashDeserialize for Signed {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let signature = Signature::<SpendAuth>::zcash_deserialize(&mut reader)?;
Ok(Signed::from_data((&signature).into()))
}
}

impl ZcashSerialize for IssuanceValidatingKey {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.to_bytes())
}
}

impl ZcashDeserialize for IssuanceValidatingKey {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
IssuanceValidatingKey::from_bytes(&reader.read_32_bytes()?)
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa IssuanceValidatingKey!"))
}
}

impl ZcashSerialize for Address {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.to_raw_address_bytes())
}
}

impl ZcashDeserialize for Address {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let mut bytes = [0u8; ADDRESS_SIZE as usize];
reader.read_exact(&mut bytes)?;
Option::from(Address::from_raw_address_bytes(&bytes))
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Address!"))
}
}

impl ZcashSerialize for Rho {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.to_bytes())
}
}

impl ZcashDeserialize for Rho {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Option::from(Rho::from_bytes(&reader.read_32_bytes()?))
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Rho!"))
}
}

impl ZcashSerialize for RandomSeed {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(self.as_bytes())
}
}

// RandomSeed::zcash_deserialize can't be implemented and used as it requires Nullifier parameter.
// That's why we need to have this function.
fn zcash_deserialize_random_seed<R: io::Read>(
mut reader: R,
rho: &Rho,
) -> Result<RandomSeed, SerializationError> {
Option::from(RandomSeed::from_bytes(reader.read_32_bytes()?, rho))
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa RandomSeed!"))
}

impl ZcashSerialize for NoteValue {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
// FIXME: use Amount serializer/deserializer?
writer.write_u64::<LittleEndian>(self.inner())?;
Ok(())
}
}

impl ZcashDeserialize for NoteValue {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Ok(NoteValue::from_raw(reader.read_u64::<LittleEndian>()?))
}
}

impl ZcashSerialize for Note {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
self.recipient().zcash_serialize(&mut writer)?;
self.value().zcash_serialize(&mut writer)?;
self.asset().zcash_serialize(&mut writer)?;
self.rho().zcash_serialize(&mut writer)?;
self.rseed().zcash_serialize(&mut writer)?;

Ok(())
}
}

impl ZcashDeserialize for Note {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let recipient = (&mut reader).zcash_deserialize_into()?;
let value = (&mut reader).zcash_deserialize_into()?;
let asset = (&mut reader).zcash_deserialize_into()?;
let rho = (&mut reader).zcash_deserialize_into()?;
let rseed = zcash_deserialize_random_seed(&mut reader, &rho)?;

Option::from(Note::from_parts(recipient, value, asset, rho, rseed))
.ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Note components!"))
}
}

impl TrustedPreallocate for Note {
fn max_allocation() -> u64 {
// FIXME: is this a correct calculation way?
Expand All @@ -204,81 +80,24 @@ impl TrustedPreallocate for Note {
}
}

impl ZcashSerialize for IssueAction {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_u8(self.is_finalized().as_u8())?;
self.notes().to_vec().zcash_serialize(&mut writer)?;
zcash_serialize_bytes(&self.asset_desc().to_vec(), &mut writer)?;
Ok(())
}
}

impl ZcashDeserialize for IssueAction {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let finalize = reader.read_u8()?.as_bool();
let notes = (&mut reader).zcash_deserialize_into()?;
let asset_descr = (&mut reader).zcash_deserialize_into()?;
Ok(IssueAction::from_parts(asset_descr, notes, finalize))
}
}

impl TrustedPreallocate for IssueAction {
fn max_allocation() -> u64 {
// FIXME: impl correct calculation
10
}
}

impl ZcashSerialize for IssueBundle<Signed> {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
// FIXME: try to avoid transforming to Vec (consider implementation of ZcashSerialize for IntoIter generic,
// or use AtLeastOne).
// This is how does it work in librustzcash:
// Vector::write_nonempty(&mut writer, bundle.actions(), |w, action| write_action(action, w))?;
let actions: Vec<_> = self.actions().clone().into();

actions.zcash_serialize(&mut writer)?;
self.ik().zcash_serialize(&mut writer)?;
writer.write_all(&<[u8; 64]>::from(self.authorization().signature()))?;
Ok(())
}
}

impl ZcashSerialize for Option<IssueData> {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
match self {
None => {
// Denoted as `&Option<IssueData>` in the spec (ZIP 230).
zcash_serialize_empty_list(writer)?;
}
Some(issue_data) => {
issue_data.0.zcash_serialize(&mut writer)?;
}
}
Ok(())
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
write_v6_bundle(self.as_ref().map(|issue_data| &issue_data.0), writer)
}
}

// FIXME: We can't split IssueData out of Option<IssueData> deserialization,
// because the counts are read along with the arrays.
impl ZcashDeserialize for Option<IssueData> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let actions: Vec<_> = (&mut reader).zcash_deserialize_into()?;

if actions.is_empty() {
Ok(None)
} else {
let ik = (&mut reader).zcash_deserialize_into()?;
let authorization = (&mut reader).zcash_deserialize_into()?;

Ok(Some(IssueData(IssueBundle::from_parts(
ik,
NonEmpty::from_vec(actions).ok_or_else(|| {
SerializationError::Parse("Invalid orchard_zsa IssueData - no actions!")
})?,
authorization,
))))
}
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
Ok(read_v6_bundle(reader)?.map(IssueData))
}
}

Expand Down
2 changes: 2 additions & 0 deletions zebra-chain/src/orchard_zsa/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod issuance;
mod vectors;
Loading

0 comments on commit e040ae0

Please sign in to comment.