diff --git a/zcash_client_backend/proto/compact_formats.proto b/zcash_client_backend/proto/compact_formats.proto index eac2b2f2f..740d7f7f3 100644 --- a/zcash_client_backend/proto/compact_formats.proto +++ b/zcash_client_backend/proto/compact_formats.proto @@ -10,20 +10,27 @@ option swift_prefix = ""; // Remember that proto3 fields are all optional. A field that is not present will be set to its zero value. // bytes fields of hashes are in canonical little-endian format. +// BlockMetadata represents information about a block that may not be +// represented directly in the block data, but is instead derived from chain +// data or other external sources. +message BlockMetadata { + uint32 saplingCommitmentTreeSize = 1; // the size of the Sapling note commitment tree as of the end of this block + uint32 orchardCommitmentTreeSize = 2; // the size of the Orchard note commitment tree as of the end of this block +} + // CompactBlock is a packaging of ONLY the data from a block that's needed to: // 1. Detect a payment to your shielded Sapling address // 2. Detect a spend of your shielded Sapling notes // 3. Update your witnesses to generate new Sapling spend proofs. message CompactBlock { - uint32 protoVersion = 1; // the version of this wire format, for storage - uint64 height = 2; // the height of this block - bytes hash = 3; // the ID (hash) of this block, same as in block explorers - bytes prevHash = 4; // the ID (hash) of this block's predecessor - uint32 time = 5; // Unix epoch time when the block was mined - bytes header = 6; // (hash, prevHash, and time) OR (full header) - repeated CompactTx vtx = 7; // zero or more compact transactions from this block - uint32 saplingCommitmentTreeSize = 8; // the size of the Sapling note commitment tree as of the end of this block - uint32 orchardCommitmentTreeSize = 9; // the size of the Orchard note commitment tree as of the end of this block + uint32 protoVersion = 1; // the version of this wire format, for storage + uint64 height = 2; // the height of this block + bytes hash = 3; // the ID (hash) of this block, same as in block explorers + bytes prevHash = 4; // the ID (hash) of this block's predecessor + uint32 time = 5; // Unix epoch time when the block was mined + bytes header = 6; // (hash, prevHash, and time) OR (full header) + repeated CompactTx vtx = 7; // zero or more compact transactions from this block + BlockMetadata blockMetadata = 8; // information about this block derived from the chain or other sources } // CompactTx contains the minimum information for a wallet to know if this transaction diff --git a/zcash_client_backend/src/proto/compact_formats.rs b/zcash_client_backend/src/proto/compact_formats.rs index c8d45173c..bf023eacf 100644 --- a/zcash_client_backend/src/proto/compact_formats.rs +++ b/zcash_client_backend/src/proto/compact_formats.rs @@ -1,3 +1,16 @@ +/// BlockMetadata represents information about a block that may not be +/// represented directly in the block data, but is instead derived from chain +/// data or other external sources. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockMetadata { + /// the size of the Sapling note commitment tree as of the end of this block + #[prost(uint32, tag = "1")] + pub sapling_commitment_tree_size: u32, + /// the size of the Orchard note commitment tree as of the end of this block + #[prost(uint32, tag = "2")] + pub orchard_commitment_tree_size: u32, +} /// CompactBlock is a packaging of ONLY the data from a block that's needed to: /// 1. Detect a payment to your shielded Sapling address /// 2. Detect a spend of your shielded Sapling notes @@ -26,12 +39,9 @@ pub struct CompactBlock { /// zero or more compact transactions from this block #[prost(message, repeated, tag = "7")] pub vtx: ::prost::alloc::vec::Vec, - /// the size of the Sapling note commitment tree as of the end of this block - #[prost(uint32, tag = "8")] - pub sapling_commitment_tree_size: u32, - /// the size of the Orchard note commitment tree as of the end of this block - #[prost(uint32, tag = "9")] - pub orchard_commitment_tree_size: u32, + /// information about this block derived from the chain or other sources + #[prost(message, optional, tag = "8")] + pub block_metadata: ::core::option::Option, } /// CompactTx contains the minimum information for a wallet to know if this transaction /// is relevant to it (either pays to it or spends from it) via shielded elements diff --git a/zcash_client_backend/src/proto/service.rs b/zcash_client_backend/src/proto/service.rs index 38b15abdb..581762bb3 100644 --- a/zcash_client_backend/src/proto/service.rs +++ b/zcash_client_backend/src/proto/service.rs @@ -1,3 +1,16 @@ +/// BlockMetadata represents information about a block that may not be +/// represented directly in the block data, but is instead derived from chain +/// data or other external sources. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockMetadata { + /// the size of the Sapling note commitment tree as of the end of this block + #[prost(uint32, tag = "1")] + pub sapling_commitment_tree_size: u32, + /// the size of the Orchard note commitment tree as of the end of this block + #[prost(uint32, tag = "2")] + pub orchard_commitment_tree_size: u32, +} /// A BlockID message contains identifiers to select a block: a height or a /// hash. Specification by hash is not implemented, but may be in the future. #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 3266d4059..a9e7d3f56 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -218,16 +218,21 @@ pub(crate) fn scan_block_with_runner< // to use it. `block.sapling_commitment_tree_size` is expected to be correct as of the end of // the block, and we can't have a note of ours in a block with no outputs so treating the zero // default value from the protobuf as `None` is always correct. - let mut sapling_tree_position = if block.sapling_commitment_tree_size == 0 { - initial_commitment_tree_meta.map(|m| (m.sapling_tree_size() + 1).into()) - } else { - let end_position_exclusive = Position::from(u64::from(block.sapling_commitment_tree_size)); + let mut sapling_tree_position = if let Some(sapling_tree_size) = block + .block_metadata + .as_ref() + .map(|m| m.sapling_commitment_tree_size) + .filter(|s| *s != 0) + { + let end_position_exclusive = Position::from(u64::from(sapling_tree_size)); let output_count = block .vtx .iter() .map(|tx| u64::try_from(tx.outputs.len()).unwrap()) .sum(); Some(end_position_exclusive - output_count) + } else { + initial_commitment_tree_meta.map(|m| (m.sapling_tree_size() + 1).into()) }; for tx in block.vtx.into_iter() { @@ -404,11 +409,10 @@ pub(crate) fn scan_block_with_runner< block_hash, block_time: block.time, transactions: wtxs, - sapling_commitment_tree_size: if block.sapling_commitment_tree_size == 0 { - None - } else { - Some(block.sapling_commitment_tree_size) - }, + sapling_commitment_tree_size: block + .block_metadata + .map(|m| m.sapling_commitment_tree_size) + .filter(|s| *s != 0), sapling_commitments: sapling_note_commitments, }) } @@ -439,7 +443,7 @@ mod tests { use crate::{ data_api::chain::CommitmentTreeMeta, proto::compact_formats::{ - CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, + BlockMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, }, scan::BatchRunner, }; @@ -547,8 +551,11 @@ mod tests { cb.vtx.push(tx); } - cb.sapling_commitment_tree_size = initial_sapling_tree_size - + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(); + cb.block_metadata = Some(BlockMetadata { + sapling_commitment_tree_size: initial_sapling_tree_size + + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(), + ..Default::default() + }); cb } diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 1c4e887d2..60447a55e 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -964,7 +964,7 @@ mod tests { data_api::{WalletRead, WalletWrite}, keys::{sapling, UnifiedFullViewingKey}, proto::compact_formats::{ - CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, + BlockMetadata, CompactBlock, CompactSaplingOutput, CompactSaplingSpend, CompactTx, }, }; @@ -1109,8 +1109,11 @@ mod tests { }; cb.prev_hash.extend_from_slice(&prev_hash.0); cb.vtx.push(ctx); - cb.sapling_commitment_tree_size = initial_sapling_tree_size - + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(); + cb.block_metadata = Some(BlockMetadata { + sapling_commitment_tree_size: initial_sapling_tree_size + + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(), + ..Default::default() + }); (cb, note.nf(&dfvk.fvk().vk.nk, 0)) } @@ -1197,8 +1200,11 @@ mod tests { }; cb.prev_hash.extend_from_slice(&prev_hash.0); cb.vtx.push(ctx); - cb.sapling_commitment_tree_size = initial_sapling_tree_size - + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(); + cb.block_metadata = Some(BlockMetadata { + sapling_commitment_tree_size: initial_sapling_tree_size + + cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::(), + ..Default::default() + }); cb }