From 2095b4f0d3cc2aae58b5716f9ad3473ee514fe6b Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 23 Oct 2020 15:29:52 -0700 Subject: [PATCH] state: insert into nullifier trees --- zebra-chain/src/sapling/note/nullifiers.rs | 2 +- zebra-chain/src/sprout/note/nullifiers.rs | 2 +- zebra-chain/src/transaction.rs | 49 +++++++++++++++++++- zebra-chain/src/transaction/shielded_data.rs | 8 ++-- zebra-state/src/sled_state.rs | 25 ++++++---- zebra-state/src/sled_state/sled_format.rs | 39 +++++++++++++++- 6 files changed, 109 insertions(+), 16 deletions(-) diff --git a/zebra-chain/src/sapling/note/nullifiers.rs b/zebra-chain/src/sapling/note/nullifiers.rs index 7bd00e99..d7fc1418 100644 --- a/zebra-chain/src/sapling/note/nullifiers.rs +++ b/zebra-chain/src/sapling/note/nullifiers.rs @@ -31,7 +31,7 @@ fn prf_nf(nk: [u8; 32], rho: [u8; 32]) -> [u8; 32] { any(test, feature = "proptest-impl"), derive(proptest_derive::Arbitrary) )] -pub struct Nullifier([u8; 32]); +pub struct Nullifier(pub [u8; 32]); impl From<[u8; 32]> for Nullifier { fn from(buf: [u8; 32]) -> Self { diff --git a/zebra-chain/src/sprout/note/nullifiers.rs b/zebra-chain/src/sprout/note/nullifiers.rs index e2365b35..cdf74841 100644 --- a/zebra-chain/src/sprout/note/nullifiers.rs +++ b/zebra-chain/src/sprout/note/nullifiers.rs @@ -67,7 +67,7 @@ impl From for [u8; 32] { any(test, feature = "proptest-impl"), derive(proptest_derive::Arbitrary) )] -pub struct Nullifier(pub(crate) [u8; 32]); +pub struct Nullifier(pub [u8; 32]); impl From<[u8; 32]> for Nullifier { fn from(bytes: [u8; 32]) -> Self { diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 5d05e080..96ea1df0 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -27,7 +27,7 @@ use crate::{ block, parameters::NetworkUpgrade, primitives::{Bctv14Proof, Groth16Proof}, - transparent, + sapling, sprout, transparent, }; /// A Zcash transaction. @@ -147,6 +147,53 @@ impl Transaction { } } + /// Access the sprout::Nullifiers in this transaction, regardless of version. + pub fn sprout_nullifiers(&self) -> Box + '_> { + // This function returns a boxed iterator because the different + // transaction variants end up having different iterator types + match self { + // JoinSplits with Bctv14 Proofs + Transaction::V2 { + joinsplit_data: Some(joinsplit_data), + .. + } + | Transaction::V3 { + joinsplit_data: Some(joinsplit_data), + .. + } => Box::new( + joinsplit_data + .joinsplits() + .flat_map(|joinsplit| joinsplit.nullifiers.iter()), + ), + // JoinSplits with Groth Proofs + Transaction::V4 { + joinsplit_data: Some(joinsplit_data), + .. + } => Box::new( + joinsplit_data + .joinsplits() + .flat_map(|joinsplit| joinsplit.nullifiers.iter()), + ), + // No JoinSplits + _ => Box::new(std::iter::empty()), + } + } + + /// Access the sapling::Nullifiers in this transaction, regardless of version. + pub fn sapling_nullifiers(&self) -> Box + '_> { + // This function returns a boxed iterator because the different + // transaction variants end up having different iterator types + match self { + // JoinSplits with Groth Proofs + Transaction::V4 { + shielded_data: Some(shielded_data), + .. + } => Box::new(shielded_data.nullifiers()), + // No JoinSplits + _ => Box::new(std::iter::empty()), + } + } + /// Returns `true` if transaction contains any coinbase inputs. pub fn contains_coinbase_input(&self) -> bool { self.inputs() diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index 2237ada4..769daab7 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -65,13 +65,13 @@ impl ShieldedData { /// Collect the [`Nullifier`]s for this transaction, if it contains /// [`Spend`]s. - pub fn nullifiers(&self) -> Vec { - self.spends().map(|spend| spend.nullifier).collect() + pub fn nullifiers(&self) -> impl Iterator { + self.spends().map(|spend| &spend.nullifier) } /// Collect the cm_u's for this transaction, if it contains [`Output`]s. - pub fn note_commitments(&self) -> Vec { - self.outputs().map(|output| output.cm_u).collect() + pub fn note_commitments(&self) -> impl Iterator { + self.outputs().map(|output| &output.cm_u) } /// Calculate the Spend/Output binding verification key. diff --git a/zebra-state/src/sled_state.rs b/zebra-state/src/sled_state.rs index 210e45f1..9b7eaf66 100644 --- a/zebra-state/src/sled_state.rs +++ b/zebra-state/src/sled_state.rs @@ -41,8 +41,8 @@ pub struct FinalizedState { block_by_height: sled::Tree, tx_by_hash: sled::Tree, utxo_by_outpoint: sled::Tree, - // sprout_nullifiers: sled::Tree, - // sapling_nullifiers: sled::Tree, + sprout_nullifiers: sled::Tree, + sapling_nullifiers: sled::Tree, // sprout_anchors: sled::Tree, // sapling_anchors: sled::Tree, /// Commit blocks to the finalized state up to this height, then exit Zebra. @@ -69,8 +69,8 @@ impl FinalizedState { block_by_height: db.open_tree(b"block_by_height").unwrap(), tx_by_hash: db.open_tree(b"tx_by_hash").unwrap(), utxo_by_outpoint: db.open_tree(b"utxo_by_outpoint").unwrap(), - // sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(), - // sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(), + sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(), + sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(), debug_stop_at_height: config.debug_stop_at_height.map(block::Height), }; @@ -97,8 +97,8 @@ impl FinalizedState { total_flushed += self.block_by_height.flush()?; total_flushed += self.tx_by_hash.flush()?; total_flushed += self.utxo_by_outpoint.flush()?; - // total_flushed += self.sprout_nullifiers.flush()?; - // total_flushed += self.sapling_nullifiers.flush()?; + total_flushed += self.sprout_nullifiers.flush()?; + total_flushed += self.sapling_nullifiers.flush()?; Ok(total_flushed) } @@ -221,6 +221,8 @@ impl FinalizedState { &self.block_by_height, &self.utxo_by_outpoint, &self.tx_by_hash, + &self.sprout_nullifiers, + &self.sapling_nullifiers, ) .transaction( move |( @@ -229,6 +231,8 @@ impl FinalizedState { block_by_height, utxo_by_outpoint, tx_by_hash, + sprout_nullifiers, + sapling_nullifiers, )| { // TODO: check highest entry of hash_by_height as in RFC @@ -248,9 +252,14 @@ impl FinalizedState { utxo_by_outpoint.zs_insert(outpoint, output)?; } + + for sprout_nullifier in transaction.sprout_nullifiers() { + sprout_nullifiers.zs_insert(sprout_nullifier, ())?; + } + for sapling_nullifier in transaction.sapling_nullifiers() { + sapling_nullifiers.zs_insert(sapling_nullifier, ())?; + } } - // sprout_nullifiers - // sapling_nullifiers // for some reason type inference fails here Ok::<_, sled::transaction::ConflictableTransactionError>(hash) diff --git a/zebra-state/src/sled_state/sled_format.rs b/zebra-state/src/sled_state/sled_format.rs index 1fe7ef89..df1ab83a 100644 --- a/zebra-state/src/sled_state/sled_format.rs +++ b/zebra-state/src/sled_state/sled_format.rs @@ -4,8 +4,9 @@ use std::{convert::TryInto, sync::Arc}; use zebra_chain::{ block, block::Block, + sapling, serialization::{ZcashDeserialize, ZcashSerialize}, - transaction, + sprout, transaction, transaction::Transaction, transparent, }; @@ -89,6 +90,42 @@ impl IntoSled for block::Hash { } } +impl IntoSled for &sprout::Nullifier { + type Bytes = [u8; 32]; + + fn as_bytes(&self) -> Self::Bytes { + self.0 + } + + fn into_ivec(self) -> sled::IVec { + self.as_bytes().as_ref().into() + } +} + +impl IntoSled for &sapling::Nullifier { + type Bytes = [u8; 32]; + + fn as_bytes(&self) -> Self::Bytes { + self.0 + } + + fn into_ivec(self) -> sled::IVec { + self.as_bytes().as_ref().into() + } +} + +impl IntoSled for () { + type Bytes = [u8; 0]; + + fn as_bytes(&self) -> Self::Bytes { + [] + } + + fn into_ivec(self) -> sled::IVec { + sled::IVec::default() + } +} + impl FromSled for block::Hash { fn from_ivec(bytes: sled::IVec) -> Result { let array = bytes.as_ref().try_into().unwrap();