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"),
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 {

View File

@ -67,7 +67,7 @@ impl From<NullifierSeed> 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 {

View File

@ -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<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.
pub fn contains_coinbase_input(&self) -> bool {
self.inputs()

View File

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

View File

@ -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)

View File

@ -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<Self, BoxError> {
let array = bytes.as_ref().try_into().unwrap();