state: insert into nullifier trees

This commit is contained in:
Jane Lusby 2020-10-23 15:29:52 -07:00 committed by Henry de Valence
parent 6758fdbd1c
commit 2095b4f0d3
6 changed files with 109 additions and 16 deletions

View File

@ -31,7 +31,7 @@ fn prf_nf(nk: [u8; 32], rho: [u8; 32]) -> [u8; 32] {
any(test, feature = "proptest-impl"), any(test, feature = "proptest-impl"),
derive(proptest_derive::Arbitrary) derive(proptest_derive::Arbitrary)
)] )]
pub struct Nullifier([u8; 32]); pub struct Nullifier(pub [u8; 32]);
impl From<[u8; 32]> for Nullifier { impl From<[u8; 32]> for Nullifier {
fn from(buf: [u8; 32]) -> Self { fn from(buf: [u8; 32]) -> Self {

View File

@ -67,7 +67,7 @@ impl From<NullifierSeed> for [u8; 32] {
any(test, feature = "proptest-impl"), any(test, feature = "proptest-impl"),
derive(proptest_derive::Arbitrary) derive(proptest_derive::Arbitrary)
)] )]
pub struct Nullifier(pub(crate) [u8; 32]); pub struct Nullifier(pub [u8; 32]);
impl From<[u8; 32]> for Nullifier { impl From<[u8; 32]> for Nullifier {
fn from(bytes: [u8; 32]) -> Self { fn from(bytes: [u8; 32]) -> Self {

View File

@ -27,7 +27,7 @@ use crate::{
block, block,
parameters::NetworkUpgrade, parameters::NetworkUpgrade,
primitives::{Bctv14Proof, Groth16Proof}, primitives::{Bctv14Proof, Groth16Proof},
transparent, sapling, sprout, transparent,
}; };
/// A Zcash transaction. /// 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<dyn Iterator<Item = &sprout::Nullifier> + '_> {
// 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<dyn Iterator<Item = &sapling::Nullifier> + '_> {
// 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. /// Returns `true` if transaction contains any coinbase inputs.
pub fn contains_coinbase_input(&self) -> bool { pub fn contains_coinbase_input(&self) -> bool {
self.inputs() self.inputs()

View File

@ -65,13 +65,13 @@ impl ShieldedData {
/// Collect the [`Nullifier`]s for this transaction, if it contains /// Collect the [`Nullifier`]s for this transaction, if it contains
/// [`Spend`]s. /// [`Spend`]s.
pub fn nullifiers(&self) -> Vec<Nullifier> { pub fn nullifiers(&self) -> impl Iterator<Item = &Nullifier> {
self.spends().map(|spend| spend.nullifier).collect() self.spends().map(|spend| &spend.nullifier)
} }
/// Collect the cm_u's for this transaction, if it contains [`Output`]s. /// Collect the cm_u's for this transaction, if it contains [`Output`]s.
pub fn note_commitments(&self) -> Vec<jubjub::Fq> { pub fn note_commitments(&self) -> impl Iterator<Item = &jubjub::Fq> {
self.outputs().map(|output| output.cm_u).collect() self.outputs().map(|output| &output.cm_u)
} }
/// Calculate the Spend/Output binding verification key. /// Calculate the Spend/Output binding verification key.

View File

@ -41,8 +41,8 @@ pub struct FinalizedState {
block_by_height: sled::Tree, block_by_height: sled::Tree,
tx_by_hash: sled::Tree, tx_by_hash: sled::Tree,
utxo_by_outpoint: sled::Tree, utxo_by_outpoint: sled::Tree,
// sprout_nullifiers: sled::Tree, sprout_nullifiers: sled::Tree,
// sapling_nullifiers: sled::Tree, sapling_nullifiers: sled::Tree,
// sprout_anchors: sled::Tree, // sprout_anchors: sled::Tree,
// sapling_anchors: sled::Tree, // sapling_anchors: sled::Tree,
/// Commit blocks to the finalized state up to this height, then exit Zebra. /// 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(), block_by_height: db.open_tree(b"block_by_height").unwrap(),
tx_by_hash: db.open_tree(b"tx_by_hash").unwrap(), tx_by_hash: db.open_tree(b"tx_by_hash").unwrap(),
utxo_by_outpoint: db.open_tree(b"utxo_by_outpoint").unwrap(), utxo_by_outpoint: db.open_tree(b"utxo_by_outpoint").unwrap(),
// sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(), sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(),
// sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(), sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(),
debug_stop_at_height: config.debug_stop_at_height.map(block::Height), 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.block_by_height.flush()?;
total_flushed += self.tx_by_hash.flush()?; total_flushed += self.tx_by_hash.flush()?;
total_flushed += self.utxo_by_outpoint.flush()?; total_flushed += self.utxo_by_outpoint.flush()?;
// total_flushed += self.sprout_nullifiers.flush()?; total_flushed += self.sprout_nullifiers.flush()?;
// total_flushed += self.sapling_nullifiers.flush()?; total_flushed += self.sapling_nullifiers.flush()?;
Ok(total_flushed) Ok(total_flushed)
} }
@ -221,6 +221,8 @@ impl FinalizedState {
&self.block_by_height, &self.block_by_height,
&self.utxo_by_outpoint, &self.utxo_by_outpoint,
&self.tx_by_hash, &self.tx_by_hash,
&self.sprout_nullifiers,
&self.sapling_nullifiers,
) )
.transaction( .transaction(
move |( move |(
@ -229,6 +231,8 @@ impl FinalizedState {
block_by_height, block_by_height,
utxo_by_outpoint, utxo_by_outpoint,
tx_by_hash, tx_by_hash,
sprout_nullifiers,
sapling_nullifiers,
)| { )| {
// TODO: check highest entry of hash_by_height as in RFC // TODO: check highest entry of hash_by_height as in RFC
@ -248,9 +252,14 @@ impl FinalizedState {
utxo_by_outpoint.zs_insert(outpoint, output)?; 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 // for some reason type inference fails here
Ok::<_, sled::transaction::ConflictableTransactionError>(hash) Ok::<_, sled::transaction::ConflictableTransactionError>(hash)

View File

@ -4,8 +4,9 @@ use std::{convert::TryInto, sync::Arc};
use zebra_chain::{ use zebra_chain::{
block, block,
block::Block, block::Block,
sapling,
serialization::{ZcashDeserialize, ZcashSerialize}, serialization::{ZcashDeserialize, ZcashSerialize},
transaction, sprout, transaction,
transaction::Transaction, transaction::Transaction,
transparent, 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 { impl FromSled for block::Hash {
fn from_ivec(bytes: sled::IVec) -> Result<Self, BoxError> { fn from_ivec(bytes: sled::IVec) -> Result<Self, BoxError> {
let array = bytes.as_ref().try_into().unwrap(); let array = bytes.as_ref().try_into().unwrap();