Document part of the block header consensus rules (#3296)
* document header version consensus rule * document nbits threshold consensus rule * document difficulty filter consensus rule * document header solution consensus rule * document header time consensus rule * document upper time limit consensus rule * document max block size consensus rule * skip genesis in conesnsus rule check * remove fixed comment Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
parent
041a2693b7
commit
918a337d8b
|
@ -67,6 +67,12 @@ impl ZcashDeserialize for Header {
|
||||||
"high bit was set in version field",
|
"high bit was set in version field",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > The block version number MUST be greater than or equal to 4.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
if version < 4 {
|
if version < 4 {
|
||||||
return Err(SerializationError::Parse("version must be at least 4"));
|
return Err(SerializationError::Parse("version must be at least 4"));
|
||||||
}
|
}
|
||||||
|
@ -115,6 +121,12 @@ impl ZcashSerialize for Block {
|
||||||
|
|
||||||
impl ZcashDeserialize for Block {
|
impl ZcashDeserialize for Block {
|
||||||
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
|
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
|
||||||
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > The size of a block MUST be less than or equal to 2000000 bytes.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
|
//
|
||||||
// If the limit is reached, we'll get an UnexpectedEof error
|
// If the limit is reached, we'll get an UnexpectedEof error
|
||||||
let limited_reader = &mut reader.take(MAX_BLOCK_BYTES);
|
let limited_reader = &mut reader.take(MAX_BLOCK_BYTES);
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
|
|
|
@ -71,13 +71,13 @@ pub fn difficulty_is_valid(
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The difficulty filter is also context-free.
|
// # Consensus
|
||||||
//
|
//
|
||||||
// ZIP 205 and ZIP 208 incorrectly describe testnet minimum difficulty blocks
|
// > The block MUST pass the difficulty filter.
|
||||||
// as a change to the difficulty filter. But in `zcashd`, it is implemented
|
//
|
||||||
// as a change to the difficulty adjustment algorithm. So we don't need to
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
// do anything special for testnet here.
|
//
|
||||||
// For details, see https://github.com/zcash/zips/issues/416
|
// The difficulty filter is also context-free.
|
||||||
if hash > &difficulty_threshold {
|
if hash > &difficulty_threshold {
|
||||||
Err(BlockError::DifficultyFilter(
|
Err(BlockError::DifficultyFilter(
|
||||||
*height,
|
*height,
|
||||||
|
@ -92,6 +92,11 @@ pub fn difficulty_is_valid(
|
||||||
|
|
||||||
/// Returns `Ok(())` if the `EquihashSolution` is valid for `header`
|
/// Returns `Ok(())` if the `EquihashSolution` is valid for `header`
|
||||||
pub fn equihash_solution_is_valid(header: &Header) -> Result<(), equihash::Error> {
|
pub fn equihash_solution_is_valid(header: &Header) -> Result<(), equihash::Error> {
|
||||||
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > `solution` MUST represent a valid Equihash solution.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
header.solution.check(header)
|
header.solution.check(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,14 +229,31 @@ fn difficulty_threshold_is_valid(
|
||||||
let median_time_past = difficulty_adjustment.median_time_past();
|
let median_time_past = difficulty_adjustment.median_time_past();
|
||||||
let block_time_max =
|
let block_time_max =
|
||||||
median_time_past + Duration::seconds(difficulty::BLOCK_MAX_TIME_SINCE_MEDIAN);
|
median_time_past + Duration::seconds(difficulty::BLOCK_MAX_TIME_SINCE_MEDIAN);
|
||||||
if candidate_time <= median_time_past {
|
|
||||||
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > For each block other than the genesis block, `nTime` MUST be strictly greater
|
||||||
|
// than the median-time-past of that block.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
|
let genesis_height = NetworkUpgrade::Genesis
|
||||||
|
.activation_height(network)
|
||||||
|
.expect("Zebra always has a genesis height available");
|
||||||
|
|
||||||
|
if candidate_time <= median_time_past && candidate_height != genesis_height {
|
||||||
Err(ValidateContextError::TimeTooEarly {
|
Err(ValidateContextError::TimeTooEarly {
|
||||||
candidate_time,
|
candidate_time,
|
||||||
median_time_past,
|
median_time_past,
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
// The maximum time rule is only active on Testnet from a specific height
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > For each block at block height 2 or greater on Mainnet, or block height 653_606
|
||||||
|
// or greater on Testnet, `nTime` MUST be less than or equal to the median-time-past
|
||||||
|
// of that block plus 90*60 seconds.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
if NetworkUpgrade::is_max_block_time_enforced(network, candidate_height)
|
if NetworkUpgrade::is_max_block_time_enforced(network, candidate_height)
|
||||||
&& candidate_time > block_time_max
|
&& candidate_time > block_time_max
|
||||||
{
|
{
|
||||||
|
@ -246,6 +263,11 @@ fn difficulty_threshold_is_valid(
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// # Consensus
|
||||||
|
//
|
||||||
|
// > For a block at block height `Height`, `nBits` MUST be equal to `ThresholdBits(Height)`.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/protocol/protocol.pdf#blockheader
|
||||||
let expected_difficulty = difficulty_adjustment.expected_difficulty_threshold();
|
let expected_difficulty = difficulty_adjustment.expected_difficulty_threshold();
|
||||||
if difficulty_threshold != expected_difficulty {
|
if difficulty_threshold != expected_difficulty {
|
||||||
Err(ValidateContextError::InvalidDifficultyThreshold {
|
Err(ValidateContextError::InvalidDifficultyThreshold {
|
||||||
|
|
Loading…
Reference in New Issue