zebra_consensus/block/subsidy/
funding_streams.rs

1//! Funding Streams calculations. - [§7.8][7.8]
2//!
3//! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
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        .expect("no overflow should happen in this sum")
33        .checked_sub(funding_stream_address_period(
34            funding_streams.height_range().start,
35            network,
36        ))
37        .expect("no overflow should happen in this sub") as usize;
38
39    assert!(index > 0 && index <= num_addresses);
40    // spec formula will output an index starting at 1 but
41    // Zebra indices for addresses start at zero, return converted.
42    Some(index - 1)
43}
44
45/// Return the address corresponding to given height, network and funding stream receiver.
46///
47/// This function only returns transparent addresses, because the current Zcash funding streams
48/// only use transparent addresses,
49pub fn funding_stream_address(
50    height: Height,
51    network: &Network,
52    receiver: FundingStreamReceiver,
53) -> Option<&transparent::Address> {
54    let index = funding_stream_address_index(height, network, receiver)?;
55    let funding_streams = network.funding_streams(height)?;
56    funding_streams.recipient(receiver)?.addresses().get(index)
57}