Skip to main content

zebra_consensus/block/
subsidy.rs

1//! Funding Streams calculations [§7.10]
2//!
3//! [§7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams
4
5use zebra_chain::{
6    block::Height,
7    parameters::{subsidy::*, Network},
8    transparent::{self},
9};
10
11#[cfg(test)]
12mod tests;
13
14/// Returns the position in the address slice for each funding stream
15/// as described in [protocol specification §7.10][7.10]
16///
17/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams
18fn funding_stream_address_index(
19    height: Height,
20    network: &Network,
21    receiver: FundingStreamReceiver,
22) -> Option<usize> {
23    if receiver == FundingStreamReceiver::Deferred {
24        return None;
25    }
26
27    let funding_streams = network.funding_streams(height)?;
28    let num_addresses = funding_streams.recipient(receiver)?.addresses().len();
29
30    let index = 1u32
31        .checked_add(funding_stream_address_period(height, network))?
32        .checked_sub(funding_stream_address_period(
33            funding_streams.height_range().start,
34            network,
35        ))? as usize;
36
37    assert!(index > 0 && index <= num_addresses);
38    // spec formula will output an index starting at 1 but
39    // Zebra indices for addresses start at zero, return converted.
40    Some(index - 1)
41}
42
43/// Return the address corresponding to given height, network and funding stream receiver.
44///
45/// This function only returns transparent addresses, because the current Zcash funding streams
46/// only use transparent addresses,
47pub fn funding_stream_address(
48    height: Height,
49    network: &Network,
50    receiver: FundingStreamReceiver,
51) -> Option<&transparent::Address> {
52    let index = funding_stream_address_index(height, network, receiver)?;
53    let funding_streams = network.funding_streams(height)?;
54    funding_streams.recipient(receiver)?.addresses().get(index)
55}