Skip to content

Commit

Permalink
DRAFT: Adds a "deferred" FundingStreamReceiver, adds a `POST_NU6_FUND…
Browse files Browse the repository at this point in the history
…ING_STREAM_RECEIVER_NUMERATORS` lazy static, updates `funding_stream_values()`, updates the `miner_fees_are_valid()` function to check that the deferred pool contribution is valid and that there are no unclaimed block subsidies after NU6 activation, and adds some TODOs
  • Loading branch information
arya2 committed Jul 17, 2024
1 parent e6e69fb commit 014ff8c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 21 deletions.
30 changes: 25 additions & 5 deletions zebra-consensus/src/block/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use zebra_chain::{
},
};

use crate::error::*;
use crate::{error::*, FundingStreamReceiver};

use super::subsidy;

Expand Down Expand Up @@ -193,8 +193,15 @@ pub fn subsidy_is_valid(block: &Block, network: &Network) -> Result<(), BlockErr
//
// https://zips.z.cash/protocol/protocol.pdf#fundingstreams
for (receiver, expected_amount) in funding_streams {
let address =
subsidy::funding_streams::funding_stream_address(height, network, receiver);
if receiver == FundingStreamReceiver::Deferred {
// The deferred pool contribution is checked in `miner_fees_are_valid()`
continue;
}

let address = subsidy::funding_streams::funding_stream_address(
height, network, receiver,
)
.expect("funding stream receivers other than the deferred pool must have an address");

let has_expected_output =
subsidy::funding_streams::filter_outputs_by_address(coinbase, &address)
Expand Down Expand Up @@ -236,6 +243,11 @@ pub fn miner_fees_are_valid(
let block_subsidy = subsidy::general::block_subsidy(height, network)
.expect("a valid block subsidy for this height and network");

let expected_deferred_amount = subsidy::funding_streams::funding_stream_values(height, network)
.expect("we always expect a funding stream hashmap response even if empty")
.remove(&FundingStreamReceiver::Deferred)
.unwrap_or_default();

// # Consensus
//
// > The total value in zatoshi of transparent outputs from a coinbase transaction,
Expand All @@ -245,9 +257,17 @@ pub fn miner_fees_are_valid(
// https://zips.z.cash/protocol/protocol.pdf#txnconsensus
let left = (transparent_value_balance - sapling_value_balance - orchard_value_balance)
.map_err(|_| SubsidyError::SumOverflow)?;
let right = (block_subsidy + block_miner_fees).map_err(|_| SubsidyError::SumOverflow)?;
let right = (block_subsidy + block_miner_fees - expected_deferred_amount)
.map_err(|_| SubsidyError::SumOverflow)?;

let should_allow_unclaimed_subsidy =
NetworkUpgrade::current(network, height) <= NetworkUpgrade::Nu5;

if left > right {
if if should_allow_unclaimed_subsidy {
left > right
} else {
left != right
} {
Err(SubsidyError::InvalidMinerFees)?;
}

Expand Down
25 changes: 17 additions & 8 deletions zebra-consensus/src/block/subsidy/funding_streams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use std::{collections::HashMap, str::FromStr};
use zebra_chain::{
amount::{Amount, Error, NonNegative},
block::Height,
parameters::{Network, NetworkUpgrade::*},
parameters::{
Network,
NetworkUpgrade::{self, *},
},
transaction::Transaction,
transparent::{self, Script},
};
Expand All @@ -25,14 +28,20 @@ pub fn funding_stream_values(
height: Height,
network: &Network,
) -> Result<HashMap<FundingStreamReceiver, Amount<NonNegative>>, Error> {
let canopy_height = Canopy.activation_height(network).unwrap();
let current_network_upgrade = NetworkUpgrade::current(network, height);
let mut results = HashMap::new();

if height >= canopy_height {
if current_network_upgrade >= Canopy {
let range = FUNDING_STREAM_HEIGHT_RANGES.get(&network.kind()).unwrap();
if range.contains(&height) {
let block_subsidy = block_subsidy(height, network)?;
for (&receiver, &numerator) in FUNDING_STREAM_RECEIVER_NUMERATORS.iter() {
let funding_stream_numerators = if current_network_upgrade <= Nu5 {
PRE_NU6_FUNDING_STREAM_RECEIVER_NUMERATORS.iter()
} else {
POST_NU6_FUNDING_STREAM_RECEIVER_NUMERATORS.iter()
};

for (&receiver, &numerator) in funding_stream_numerators {
// - Spec equation: `fs.value = floor(block_subsidy(height)*(fs.numerator/fs.denominator))`:
// https://zips.z.cash/protocol/protocol.pdf#subsidies
// - In Rust, "integer division rounds towards zero":
Expand Down Expand Up @@ -105,14 +114,14 @@ pub fn funding_stream_address(
height: Height,
network: &Network,
receiver: FundingStreamReceiver,
) -> transparent::Address {
) -> Option<transparent::Address> {
let index = funding_stream_address_index(height, network);
let address = &FUNDING_STREAM_ADDRESSES
.get(&network.kind())
.expect("there is always another hash map as value for a given valid network")
.get(&receiver)
.expect("in the inner hash map there is always a vector of strings with addresses")[index];
transparent::Address::from_str(address).expect("address should deserialize")
.get(&receiver)?
.get(index)?;
Some(transparent::Address::from_str(address).expect("address should deserialize"))
}

/// Return a human-readable name and a specification URL for the funding stream `receiver`.
Expand Down
25 changes: 23 additions & 2 deletions zebra-consensus/src/parameters/subsidy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ pub enum FundingStreamReceiver {

/// The Major Grants (Zcash Community Grants) funding stream.
MajorGrants,

/// The deferred pool contribution.
Deferred,
}

/// Denominator as described in [protocol specification §7.10.1][7.10.1].
Expand All @@ -72,29 +75,45 @@ lazy_static! {
hash_map.insert(FundingStreamReceiver::Ecc, "Electric Coin Company");
hash_map.insert(FundingStreamReceiver::ZcashFoundation, "Zcash Foundation");
hash_map.insert(FundingStreamReceiver::MajorGrants, "Major Grants");
hash_map.insert(FundingStreamReceiver::Deferred, "Deferred Fund");
hash_map
};


/// The numerator for each funding stream receiver category
/// The numerator for each funding stream receiver category until NU6
/// as described in [protocol specification §7.10.1][7.10.1].
///
/// [7.10.1]: https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams
pub static ref FUNDING_STREAM_RECEIVER_NUMERATORS: HashMap<FundingStreamReceiver, u64> = {
pub static ref PRE_NU6_FUNDING_STREAM_RECEIVER_NUMERATORS: HashMap<FundingStreamReceiver, u64> = {
let mut hash_map = HashMap::new();
hash_map.insert(FundingStreamReceiver::Ecc, 7);
hash_map.insert(FundingStreamReceiver::ZcashFoundation, 5);
hash_map.insert(FundingStreamReceiver::MajorGrants, 8);
hash_map
};

/// The numerator for each funding stream receiver category after NU6
/// as described in [protocol specification §7.10.1][7.10.1].
///
/// [7.10.1]: https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams
pub static ref POST_NU6_FUNDING_STREAM_RECEIVER_NUMERATORS: HashMap<FundingStreamReceiver, u64> = {
let mut hash_map = HashMap::new();
hash_map.insert(FundingStreamReceiver::Deferred, 12);

// TODO: Remove MajorGrants if the full lockbox dev fund proposal is selected, or
// add more funding stream addresses for MajorGrants on all networks if the hybrid proposal is selected.
hash_map.insert(FundingStreamReceiver::MajorGrants, 8);
hash_map
};

/// Start and end Heights for funding streams
/// as described in [protocol specification §7.10.1][7.10.1].
///
/// [7.10.1]: https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams
// TODO: Move the value here to a field on `testnet::Parameters` (#8367)
pub static ref FUNDING_STREAM_HEIGHT_RANGES: HashMap<NetworkKind, std::ops::Range<Height>> = {
let mut hash_map = HashMap::new();
// TODO: Adjust these values once a proposal is selected
hash_map.insert(NetworkKind::Mainnet, Height(1_046_400)..Height(2_726_400));
hash_map.insert(NetworkKind::Testnet, Height(1_028_500)..Height(2_796_000));
hash_map.insert(NetworkKind::Regtest, Height(1_028_500)..Height(2_796_000));
Expand Down Expand Up @@ -144,6 +163,7 @@ pub const FUNDING_STREAM_ADDRESS_CHANGE_INTERVAL: HeightDiff = POST_BLOSSOM_HALV
/// however we know this value beforehand so we prefer to make it a constant instead.
///
/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams
// TODO: Update this once a dev fund proposal is selected.
pub const FUNDING_STREAMS_NUM_ADDRESSES_MAINNET: usize = 48;

/// List of addresses for the ECC funding stream in the Mainnet.
Expand Down Expand Up @@ -246,6 +266,7 @@ pub const FUNDING_STREAM_MG_ADDRESSES_MAINNET: [&str; FUNDING_STREAMS_NUM_ADDRES
/// however we know this value beforehand so we prefer to make it a constant instead.
///
/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams
// TODO: Update this once a dev fund proposal is selected.
pub const FUNDING_STREAMS_NUM_ADDRESSES_TESTNET: usize = 51;

/// List of addresses for the ECC funding stream in the Testnet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,11 @@ pub fn standard_coinbase_outputs(
(Amount<NonNegative>, transparent::Address),
> = funding_streams
.into_iter()
.map(|(receiver, amount)| {
(
.filter_map(|(receiver, amount)| {
Some((
receiver,
(amount, funding_stream_address(height, network, receiver)),
)
(amount, funding_stream_address(height, network, receiver)?),
))
})
.collect();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ pub struct FundingStream {
///
/// The current Zcash funding streams only use transparent addresses,
/// so Zebra doesn't support Sapling addresses in this RPC.
pub address: transparent::Address,
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<transparent::Address>,
}

impl FundingStream {
/// Convert a `receiver`, `value`, and `address` into a `FundingStream` response.
pub fn new(
receiver: FundingStreamReceiver,
value: Amount<NonNegative>,
address: transparent::Address,
address: Option<transparent::Address>,
) -> FundingStream {
let (recipient, specification) = funding_stream_recipient_info(receiver);

Expand Down

0 comments on commit 014ff8c

Please sign in to comment.