Move is_equihash_solution_valid to zebra-consensus
This commit is contained in:
parent
2a68ef5acb
commit
7118e4da3c
|
@ -1,6 +1,5 @@
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
|
|
||||||
use crate::serialization::ZcashSerialize;
|
|
||||||
use crate::work::{difficulty::CompactDifficulty, equihash::Solution};
|
use crate::work::{difficulty::CompactDifficulty, equihash::Solution};
|
||||||
|
|
||||||
use super::{merkle, Error, Hash};
|
use super::{merkle, Error, Hash};
|
||||||
|
@ -69,24 +68,6 @@ pub struct Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
/// Returns true if the header is valid based on its `EquihashSolution`
|
|
||||||
pub fn is_equihash_solution_valid(&self) -> Result<(), EquihashError> {
|
|
||||||
let n = 200;
|
|
||||||
let k = 9;
|
|
||||||
let nonce = &self.nonce;
|
|
||||||
let solution = &self.solution.0;
|
|
||||||
let mut input = Vec::new();
|
|
||||||
|
|
||||||
self.zcash_serialize(&mut input)
|
|
||||||
.expect("serialization into a vec can't fail");
|
|
||||||
|
|
||||||
let input = &input[0..Solution::INPUT_LENGTH];
|
|
||||||
|
|
||||||
equihash::is_valid_solution(n, k, input, nonce, solution)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if `self.time` is less than or equal to
|
/// Check if `self.time` is less than or equal to
|
||||||
/// 2 hours in the future, according to the node's local clock (`now`).
|
/// 2 hours in the future, according to the node's local clock (`now`).
|
||||||
///
|
///
|
||||||
|
@ -112,8 +93,3 @@ impl Header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
#[error("invalid equihash solution for BlockHeader")]
|
|
||||||
pub struct EquihashError(#[from] equihash::Error);
|
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
//! Equihash Solution and related items.
|
//! Equihash Solution and related items.
|
||||||
|
|
||||||
|
use crate::block::Header;
|
||||||
use crate::serialization::{
|
use crate::serialization::{
|
||||||
serde_helpers, ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize,
|
serde_helpers, ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize,
|
||||||
ZcashSerialize,
|
ZcashSerialize,
|
||||||
};
|
};
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
/// The error type for Equihash
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error("invalid equihash solution for BlockHeader")]
|
||||||
|
pub struct Error(#[from] equihash::Error);
|
||||||
|
|
||||||
/// The size of an Equihash solution in bytes (always 1344).
|
/// The size of an Equihash solution in bytes (always 1344).
|
||||||
pub(crate) const SOLUTION_SIZE: usize = 1344;
|
pub(crate) const SOLUTION_SIZE: usize = 1344;
|
||||||
|
|
||||||
|
@ -24,6 +31,25 @@ impl Solution {
|
||||||
/// The length of the portion of the header used as input when verifying
|
/// The length of the portion of the header used as input when verifying
|
||||||
/// equihash solutions, in bytes
|
/// equihash solutions, in bytes
|
||||||
pub const INPUT_LENGTH: usize = 4 + 32 * 3 + 4 * 2;
|
pub const INPUT_LENGTH: usize = 4 + 32 * 3 + 4 * 2;
|
||||||
|
|
||||||
|
/// Returns true if the header is valid based on its `EquihashSolution`
|
||||||
|
pub fn check(&self, block: &Header) -> Result<(), Error> {
|
||||||
|
let n = 200;
|
||||||
|
let k = 9;
|
||||||
|
let nonce = &block.nonce;
|
||||||
|
let solution = &self.0;
|
||||||
|
let mut input = Vec::new();
|
||||||
|
|
||||||
|
block
|
||||||
|
.zcash_serialize(&mut input)
|
||||||
|
.expect("serialization into a vec can't fail");
|
||||||
|
|
||||||
|
let input = &input[0..Solution::INPUT_LENGTH];
|
||||||
|
|
||||||
|
equihash::is_valid_solution(n, k, input, nonce, solution)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<Solution> for Solution {
|
impl PartialEq<Solution> for Solution {
|
||||||
|
|
|
@ -39,11 +39,11 @@ fn equihash_prop_test_solution() -> color_eyre::eyre::Result<()> {
|
||||||
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
||||||
let block = Block::zcash_deserialize(&block_bytes[..])
|
let block = Block::zcash_deserialize(&block_bytes[..])
|
||||||
.expect("block test vector should deserialize");
|
.expect("block test vector should deserialize");
|
||||||
block.header.is_equihash_solution_valid()?;
|
block.header.solution.check(&block.header)?;
|
||||||
|
|
||||||
proptest!(|(fake_header in randomized_solutions(block.header))| {
|
proptest!(|(fake_header in randomized_solutions(block.header))| {
|
||||||
fake_header
|
fake_header.solution
|
||||||
.is_equihash_solution_valid()
|
.check(&fake_header)
|
||||||
.expect_err("block header should not validate on randomized solution");
|
.expect_err("block header should not validate on randomized solution");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,11 @@ fn equihash_prop_test_nonce() -> color_eyre::eyre::Result<()> {
|
||||||
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
||||||
let block = Block::zcash_deserialize(&block_bytes[..])
|
let block = Block::zcash_deserialize(&block_bytes[..])
|
||||||
.expect("block test vector should deserialize");
|
.expect("block test vector should deserialize");
|
||||||
block.header.is_equihash_solution_valid()?;
|
block.header.solution.check(&block.header)?;
|
||||||
|
|
||||||
proptest!(|(fake_header in randomized_nonce(block.header))| {
|
proptest!(|(fake_header in randomized_nonce(block.header))| {
|
||||||
fake_header
|
fake_header.solution
|
||||||
.is_equihash_solution_valid()
|
.check(&fake_header)
|
||||||
.expect_err("block header should not validate on randomized nonce");
|
.expect_err("block header should not validate on randomized nonce");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -106,11 +106,11 @@ fn equihash_prop_test_input() -> color_eyre::eyre::Result<()> {
|
||||||
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
for block_bytes in zebra_test::vectors::TEST_BLOCKS.iter() {
|
||||||
let block = Block::zcash_deserialize(&block_bytes[..])
|
let block = Block::zcash_deserialize(&block_bytes[..])
|
||||||
.expect("block test vector should deserialize");
|
.expect("block test vector should deserialize");
|
||||||
block.header.is_equihash_solution_valid()?;
|
block.header.solution.check(&block.header)?;
|
||||||
|
|
||||||
proptest!(|(fake_header in randomized_input(block.header))| {
|
proptest!(|(fake_header in randomized_input(block.header))| {
|
||||||
fake_header
|
fake_header.solution
|
||||||
.is_equihash_solution_valid()
|
.check(&fake_header)
|
||||||
.expect_err("equihash solution should not validate on randomized input");
|
.expect_err("equihash solution should not validate on randomized input");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ fn equihash_solution_test_vector_is_valid() -> color_eyre::eyre::Result<()> {
|
||||||
|
|
||||||
let block = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])
|
let block = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])
|
||||||
.expect("block test vector should deserialize");
|
.expect("block test vector should deserialize");
|
||||||
block.header.is_equihash_solution_valid()?;
|
block.header.solution.check(&block.header)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ where
|
||||||
if hash > difficulty_threshold {
|
if hash > difficulty_threshold {
|
||||||
Err("Block failed the difficulty filter: hash must be less than or equal to the difficulty threshold.")?;
|
Err("Block failed the difficulty filter: hash must be less than or equal to the difficulty threshold.")?;
|
||||||
}
|
}
|
||||||
block.header.is_equihash_solution_valid()?;
|
check::is_equihash_solution_valid(&block.header)?;
|
||||||
|
|
||||||
// Since errors cause an early exit, try to do the
|
// Since errors cause an early exit, try to do the
|
||||||
// quick checks first.
|
// quick checks first.
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
//! Consensus check functions
|
//! Consensus check functions
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use zebra_chain::block::Block;
|
use zebra_chain::{
|
||||||
|
block::{Block, Header},
|
||||||
|
work::equihash,
|
||||||
|
};
|
||||||
|
|
||||||
/// Check that there is exactly one coinbase transaction in `Block`, and that
|
/// Check that there is exactly one coinbase transaction in `Block`, and that
|
||||||
/// the coinbase transaction is the first transaction in the block.
|
/// the coinbase transaction is the first transaction in the block.
|
||||||
|
@ -25,3 +28,7 @@ pub fn is_coinbase_first(block: &Block) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_equihash_solution_valid(header: &Header) -> Result<(), equihash::Error> {
|
||||||
|
header.solution.check(&header)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue