Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change(consensus): Add lockbox funding stream #8694

Merged
merged 34 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bf1278a
Addresses clippy lints
arya2 Jul 25, 2024
aa88979
checks network magic and returns early from `is_regtest()`
arya2 Jul 22, 2024
d9a53e6
Moves `subsidy.rs` to `zebra-chain`, refactors funding streams into …
arya2 Jul 23, 2024
124e249
Replaces Vec with HashMap, adds `ConfiguredFundingStreams` type and c…
arya2 Jul 24, 2024
cbf7ef3
Empties recipients list
arya2 Jul 24, 2024
54af589
Adds a comment on num_addresses calculation being invalid for configu…
arya2 Jul 24, 2024
db434c3
Documentation fixes, minor cleanup, renames a test, adds TODOs, and f…
arya2 Jul 24, 2024
7d7f606
Removes unnecessary `ParameterSubsidy` impl for &Network, adds docs a…
arya2 Jul 24, 2024
77a6f2c
Adds a "deferred" FundingStreamReceiver, adds a post-NU6 funding stre…
arya2 Jul 24, 2024
dbc7ca9
adds `lockbox_input_value()` fn
arya2 Jul 24, 2024
0f962c5
Adds TODOs for linking to relevant ZIPs and updating height ranges
arya2 Jul 24, 2024
9bca31f
Adds `nu6_lockbox_funding_stream` acceptance test
arya2 Jul 24, 2024
0d22b68
updates funding stream values test to check post-NU6 funding streams …
arya2 Jul 24, 2024
039c9a1
Reverts Mainnet/Testnet NU6 activation height definitions, updates `t…
arya2 Jul 24, 2024
2f14517
reverts unnecessary refactor
arya2 Jul 24, 2024
33a5545
appease clippy
arya2 Jul 24, 2024
1183d49
Adds a test for `lockbox_input_value()`
arya2 Jul 24, 2024
b523bf5
Applies suggestions from code review
arya2 Jul 25, 2024
7df2e28
Fixes potential panic
arya2 Jul 26, 2024
95378fd
Merge branch 'main' into deferred-pool
arya2 Jul 29, 2024
7173af7
Fixes bad merge
arya2 Jul 29, 2024
c6244e6
Update zebra-chain/src/parameters/network_upgrade.rs
arya2 Jul 29, 2024
166bc23
Updates acceptance test to check that invalid blocks are rejected
arya2 Jul 29, 2024
c113601
Checks that the original valid block template at height 2 is accepted…
arya2 Jul 29, 2024
4627c08
Reverts changes for coinbase should balance exactly ZIP
arya2 Jul 29, 2024
6aa2858
Merge branch 'main' into deferred-pool
mpguerra Jul 30, 2024
b82f2be
Merge branch 'main' into deferred-pool
arya2 Jul 31, 2024
126fdab
updates test name
arya2 Aug 1, 2024
bf49432
Updates deferred pool funding stream name to "Lockbox", moves post-NU…
arya2 Aug 1, 2024
14fbfb4
Updates `get_block_subsidy()` RPC method to exclude lockbox funding s…
arya2 Aug 1, 2024
7987c76
Adds a TODO for updating `FundingStreamReceiver::name()` method docs
arya2 Aug 1, 2024
e5eaf38
Updates `FundingStreamRecipient::new()` to accept an iterator of item…
arya2 Aug 1, 2024
8949301
Uses FPF Testnet address for post-NU6 testnet funding streams
arya2 Aug 1, 2024
cdb1684
Updates the NU6 consensus branch id
arya2 Aug 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions zebra-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,7 @@ required-features = ["bench"]
[[bench]]
name = "redpallas"
harness = false

[lints.rust]
upbqdn marked this conversation as resolved.
Show resolved Hide resolved
# TODO: Remove this once it's no longer needed for NU6.
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zcash_unstable, values("nu6"))'] }
69 changes: 52 additions & 17 deletions zebra-chain/src/parameters/network/subsidy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub enum FundingStreamReceiver {

/// The Major Grants (Zcash Community Grants) funding stream.
MajorGrants,
/// The deferred pool contribution.
// TODO: Add link to lockbox stream ZIP
Deferred,
}

impl FundingStreamReceiver {
Expand All @@ -74,6 +77,8 @@ impl FundingStreamReceiver {
FundingStreamReceiver::Ecc => "Electric Coin Company",
FundingStreamReceiver::ZcashFoundation => "Zcash Foundation",
FundingStreamReceiver::MajorGrants => "Major Grants",
// TODO: Find out what this should be called and update the funding stream name
FundingStreamReceiver::Deferred => "Deferred Fund",
arya2 marked this conversation as resolved.
Show resolved Hide resolved
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -144,21 +149,25 @@ pub struct FundingStreamRecipient {

impl FundingStreamRecipient {
/// Creates a new [`FundingStreamRecipient`].
pub fn new<I, T>(numerator: u64, addresses: I) -> Self
pub fn new<I, T>(numerator: u64, addresses: Option<I>) -> Self
where
T: ToString,
I: IntoIterator<Item = T>,
{
Self {
numerator,
addresses: addresses
.into_iter()
.map(|addr| {
let addr = addr.to_string();
addr.parse()
.expect("funding stream address must deserialize")
})
.collect(),
addresses: if let Some(addresses) = addresses {
addresses
.into_iter()
.map(|addr| {
let addr = addr.to_string();
addr.parse()
.expect("funding stream address must deserialize")
})
.collect()
} else {
vec![]
},
}
}

Expand All @@ -181,15 +190,15 @@ lazy_static! {
recipients: [
(
FundingStreamReceiver::Ecc,
FundingStreamRecipient::new(7, FUNDING_STREAM_ECC_ADDRESSES_MAINNET.iter()),
FundingStreamRecipient::new(7, Some(FUNDING_STREAM_ECC_ADDRESSES_MAINNET)),
),
(
FundingStreamReceiver::ZcashFoundation,
FundingStreamRecipient::new(5, FUNDING_STREAM_ZF_ADDRESSES_MAINNET),
FundingStreamRecipient::new(5, Some(FUNDING_STREAM_ZF_ADDRESSES_MAINNET)),
),
(
FundingStreamReceiver::MajorGrants,
FundingStreamRecipient::new(8, FUNDING_STREAM_MG_ADDRESSES_MAINNET),
FundingStreamRecipient::new(8, Some(FUNDING_STREAM_MG_ADDRESSES_MAINNET)),
),
]
.into_iter()
Expand All @@ -199,8 +208,21 @@ lazy_static! {
/// The post-NU6 funding streams for Mainnet
// TODO: Add a reference to lockbox stream ZIP, this is currently based on https://zips.z.cash/draft-nuttycom-funding-allocation
pub static ref POST_NU6_FUNDING_STREAMS_MAINNET: FundingStreams = FundingStreams {
// TODO: Adjust this height range and recipient list once a proposal is selected
height_range: Height(2_726_400)..Height(3_146_400),
recipients: HashMap::new()
recipients: [
(
FundingStreamReceiver::Deferred,
FundingStreamRecipient::new::<[&str; 0], &str>(12, None),
),
(
FundingStreamReceiver::MajorGrants,
// TODO: Update these addresses
FundingStreamRecipient::new(8, Some(FUNDING_STREAM_MG_ADDRESSES_MAINNET)),
),
]
.into_iter()
.collect()
};

/// The pre-NU6 funding streams for Testnet as described in [protocol specification §7.10.1][7.10.1]
Expand All @@ -210,15 +232,15 @@ lazy_static! {
recipients: [
(
FundingStreamReceiver::Ecc,
FundingStreamRecipient::new(7, FUNDING_STREAM_ECC_ADDRESSES_TESTNET),
FundingStreamRecipient::new(7, Some(FUNDING_STREAM_ECC_ADDRESSES_TESTNET)),
),
(
FundingStreamReceiver::ZcashFoundation,
FundingStreamRecipient::new(5, FUNDING_STREAM_ZF_ADDRESSES_TESTNET),
FundingStreamRecipient::new(5, Some(FUNDING_STREAM_ZF_ADDRESSES_TESTNET)),
),
(
FundingStreamReceiver::MajorGrants,
FundingStreamRecipient::new(8, FUNDING_STREAM_MG_ADDRESSES_TESTNET),
FundingStreamRecipient::new(8, Some(FUNDING_STREAM_MG_ADDRESSES_TESTNET)),
),
]
.into_iter()
Expand All @@ -229,8 +251,21 @@ lazy_static! {
// TODO: Add a reference to lockbox stream ZIP, this is currently based on the number of blocks between the
// start and end heights for Mainnet in https://zips.z.cash/draft-nuttycom-funding-allocation
pub static ref POST_NU6_FUNDING_STREAMS_TESTNET: FundingStreams = FundingStreams {
// TODO: Adjust this height range and recipient list once a proposal is selected
height_range: Height(2_942_000)..Height(3_362_000),
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
recipients: HashMap::new()
recipients: [
(
FundingStreamReceiver::Deferred,
FundingStreamRecipient::new::<[&str; 0], &str>(12, None),
),
(
FundingStreamReceiver::MajorGrants,
// TODO: Update these addresses
FundingStreamRecipient::new(8, Some(FUNDING_STREAM_MG_ADDRESSES_TESTNET)),
),
]
.into_iter()
.collect()
};
}

Expand Down
10 changes: 7 additions & 3 deletions zebra-chain/src/parameters/network/testnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub struct ConfiguredFundingStreamRecipient {
/// The numerator for each funding stream receiver category, see [`FundingStreamRecipient::numerator`] for more details.
pub numerator: u64,
/// Addresses for the funding stream recipient, see [`FundingStreamRecipient::addresses`] for more details.
pub addresses: Vec<String>,
pub addresses: Option<Vec<String>>,
}

impl ConfiguredFundingStreamRecipient {
Expand Down Expand Up @@ -133,8 +133,12 @@ impl ConfiguredFundingStreams {
))
.expect("no overflow should happen in this sub") as usize;

for recipient in funding_streams.recipients().values() {
// TODO: Make an exception for the `Deferred` receiver.
for (&receiver, recipient) in funding_streams.recipients() {
if receiver == FundingStreamReceiver::Deferred {
// The `Deferred` receiver doesn't need any addresses.
continue;
}

assert!(
recipient.addresses().len() >= expected_min_num_addresses,
"recipients must have a sufficient number of addresses for height range, \
Expand Down
34 changes: 21 additions & 13 deletions zebra-chain/src/parameters/network/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,19 +320,23 @@ fn check_configured_funding_stream_constraints() {
recipients: Some(vec![ConfiguredFundingStreamRecipient {
receiver: FundingStreamReceiver::Ecc,
numerator: 20,
addresses: FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
addresses: Some(
FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
),
}]),
..Default::default()
},
ConfiguredFundingStreams {
recipients: Some(vec![ConfiguredFundingStreamRecipient {
receiver: FundingStreamReceiver::Ecc,
numerator: 100,
addresses: FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
addresses: Some(
FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
),
}]),
..Default::default()
},
Expand Down Expand Up @@ -398,7 +402,7 @@ fn check_configured_funding_stream_constraints() {
recipients: Some(vec![ConfiguredFundingStreamRecipient {
receiver: FundingStreamReceiver::Ecc,
numerator: 10,
addresses: vec![],
addresses: Some(vec![]),
arya2 marked this conversation as resolved.
Show resolved Hide resolved
}]),
..Default::default()
});
Expand All @@ -410,9 +414,11 @@ fn check_configured_funding_stream_constraints() {
recipients: Some(vec![ConfiguredFundingStreamRecipient {
receiver: FundingStreamReceiver::Ecc,
numerator: 101,
addresses: FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
addresses: Some(
FUNDING_STREAM_ECC_ADDRESSES_TESTNET
.map(Into::into)
.to_vec(),
),
}]),
..Default::default()
});
Expand All @@ -424,9 +430,11 @@ fn check_configured_funding_stream_constraints() {
recipients: Some(vec![ConfiguredFundingStreamRecipient {
receiver: FundingStreamReceiver::Ecc,
numerator: 10,
addresses: FUNDING_STREAM_ECC_ADDRESSES_MAINNET
.map(Into::into)
.to_vec(),
addresses: Some(
FUNDING_STREAM_ECC_ADDRESSES_MAINNET
.map(Into::into)
.to_vec(),
),
}]),
..Default::default()
});
Expand Down
11 changes: 7 additions & 4 deletions zebra-chain/src/parameters/network_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ pub(super) const MAINNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)]
(block::Height(903_000), Heartwood),
(block::Height(1_046_400), Canopy),
(block::Height(1_687_104), Nu5),
// TODO: Add NU6.
// TODO: Add NU6
// (block::Height(2_726_400), Nu6),
];

/// Fake mainnet network upgrade activation heights, used in tests.
Expand Down Expand Up @@ -124,7 +125,8 @@ pub(super) const TESTNET_ACTIVATION_HEIGHTS: &[(block::Height, NetworkUpgrade)]
(block::Height(903_800), Heartwood),
(block::Height(1_028_500), Canopy),
(block::Height(1_842_420), Nu5),
// TODO: Add NU6.
// TODO: Add NU6
// (block::Height(2_942_000), Nu6),
arya2 marked this conversation as resolved.
Show resolved Hide resolved
];

/// Fake testnet network upgrade activation heights, used in tests.
Expand Down Expand Up @@ -214,8 +216,7 @@ pub(crate) const CONSENSUS_BRANCH_IDS: &[(NetworkUpgrade, ConsensusBranchId)] =
(Heartwood, ConsensusBranchId(0xf5b9230b)),
(Canopy, ConsensusBranchId(0xe9ff75a6)),
(Nu5, ConsensusBranchId(0xc2d6d0b4)),
// TODO: Use the real consensus branch ID once it's specified.
(Nu6, ConsensusBranchId(0xdeadc0de)),
(Nu6, ConsensusBranchId(0xc8e71055)),
arya2 marked this conversation as resolved.
Show resolved Hide resolved
];

/// The target block spacing before Blossom.
Expand Down Expand Up @@ -530,6 +531,8 @@ impl From<zcash_protocol::consensus::NetworkUpgrade> for NetworkUpgrade {
zcash_protocol::consensus::NetworkUpgrade::Heartwood => Self::Heartwood,
zcash_protocol::consensus::NetworkUpgrade::Canopy => Self::Canopy,
zcash_protocol::consensus::NetworkUpgrade::Nu5 => Self::Nu5,
#[cfg(zcash_unstable = "nu6")]
zcash_protocol::consensus::NetworkUpgrade::Nu6 => Self::Nu6,
}
}
}
Expand Down
36 changes: 30 additions & 6 deletions zebra-consensus/src/block/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use chrono::{DateTime, Utc};
use zebra_chain::{
amount::{Amount, Error as AmountError, NonNegative},
block::{Block, Hash, Header, Height},
parameters::{Network, NetworkUpgrade},
parameters::{subsidy::FundingStreamReceiver, Network, NetworkUpgrade},
transaction,
work::{
difficulty::{ExpandedDifficulty, ParameterDifficulty as _},
Expand Down Expand Up @@ -177,7 +177,7 @@ pub fn subsidy_is_valid(block: &Block, network: &Network) -> Result<(), BlockErr
// Founders rewards are paid up to Canopy activation, on both mainnet and testnet.
// But we checkpoint in Canopy so founders reward does not apply for Zebra.
unreachable!("we cannot verify consensus rules before Canopy activation");
} else if halving_div < 4 {
} else if halving_div < 8 {
// Funding streams are paid from Canopy activation to the second halving
// Note: Canopy activation is at the first halving on mainnet, but not on testnet
// ZIP-1014 only applies to mainnet, ZIP-214 contains the specific rules for testnet
Expand All @@ -194,8 +194,16 @@ 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 {
conradoplg marked this conversation as resolved.
Show resolved Hide resolved
// The deferred pool contribution is checked in `miner_fees_are_valid()`
// TODO: Add link to lockbox stream ZIP
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 @@ -237,6 +245,12 @@ 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");

// TODO: Add link to lockbox stream ZIP
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 @@ -246,9 +260,19 @@ 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)?;
arya2 marked this conversation as resolved.
Show resolved Hide resolved

// TODO: Add link to exact coinbase balance ZIP
let should_allow_unclaimed_subsidy =
NetworkUpgrade::current(network, height) <= NetworkUpgrade::Nu5;
arya2 marked this conversation as resolved.
Show resolved Hide resolved
let is_invalid_miner_fee = if should_allow_unclaimed_subsidy {
left > right
} else {
left != right
arya2 marked this conversation as resolved.
Show resolved Hide resolved
};

if left > right {
if is_invalid_miner_fee {
Err(SubsidyError::InvalidMinerFees)?;
}
arya2 marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
Loading
Loading