fixed equihash
This commit is contained in:
parent
d62342f3f1
commit
787a36549c
|
@ -5,6 +5,7 @@ use ser::{deserialize, serialize};
|
|||
use crypto::dhash256;
|
||||
use compact::Compact;
|
||||
use hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
use ser::{Error, Serializable, Deserializable, Stream, Reader};
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Clone)]
|
||||
|
@ -18,6 +19,7 @@ pub struct BlockHeader {
|
|||
pub time: u32,
|
||||
pub bits: Compact,
|
||||
pub nonce: BlockHeaderNonce,
|
||||
pub hash_final_sapling_root: Option<H256>,
|
||||
pub equihash_solution: Option<EquihashSolution>,
|
||||
}
|
||||
|
||||
|
@ -37,17 +39,44 @@ impl BlockHeader {
|
|||
pub fn hash(&self) -> H256 {
|
||||
dhash256(&serialize(self))
|
||||
}
|
||||
|
||||
pub fn equihash_input(&self) -> Bytes {
|
||||
let mut stream = Stream::new();
|
||||
stream
|
||||
.append(&self.version)
|
||||
.append(&self.previous_header_hash)
|
||||
.append(&self.merkle_root_hash);
|
||||
|
||||
if let Some(hash_final_sapling_root) = self.hash_final_sapling_root.as_ref() {
|
||||
stream.append(hash_final_sapling_root);
|
||||
}
|
||||
|
||||
stream
|
||||
.append(&self.time)
|
||||
.append(&self.bits);
|
||||
|
||||
match self.nonce {
|
||||
BlockHeaderNonce::U32(ref v) => stream.append(v),
|
||||
BlockHeaderNonce::H256(ref v) => stream.append(v),
|
||||
};
|
||||
|
||||
stream.out()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BlockHeader {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use rustc_serialize::hex::ToHex;
|
||||
|
||||
f.debug_struct("BlockHeader")
|
||||
.field("version", &self.version)
|
||||
.field("previous_header_hash", &self.previous_header_hash.reversed())
|
||||
.field("merkle_root_hash", &self.merkle_root_hash.reversed())
|
||||
.field("hash_final_sapling_root", &self.hash_final_sapling_root)
|
||||
.field("time", &self.time)
|
||||
.field("bits", &self.bits)
|
||||
.field("nonce", &self.nonce)
|
||||
.field("equihash_solution", &self.equihash_solution.as_ref().map(|s| s.0.to_hex()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -60,13 +89,12 @@ impl From<&'static str> for BlockHeader {
|
|||
|
||||
impl Serializable for BlockHeader {
|
||||
fn serialize(&self, stream: &mut Stream) {
|
||||
let is_zcash_format = stream.is_zcash_stream();
|
||||
stream
|
||||
.append(&self.version)
|
||||
.append(&self.previous_header_hash)
|
||||
.append(&self.merkle_root_hash);
|
||||
if is_zcash_format {
|
||||
stream.append(&H256::default());
|
||||
if let Some(hash_final_sapling_root) = self.hash_final_sapling_root.as_ref() {
|
||||
stream.append(hash_final_sapling_root);
|
||||
}
|
||||
stream
|
||||
.append(&self.time)
|
||||
|
@ -92,9 +120,11 @@ impl Deserializable for BlockHeader {
|
|||
let merkle_root_hash = reader.read()?;
|
||||
|
||||
// TODO: rename to transaction format - original, witness, zcash, must be enum, not flags
|
||||
if is_zcash_format {
|
||||
let _reserved_hash: H256 = reader.read()?;
|
||||
}
|
||||
let hash_final_sapling_root = if is_zcash_format {
|
||||
Some(reader.read()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let time = reader.read()?;
|
||||
let bits = reader.read()?;
|
||||
|
@ -113,6 +143,7 @@ impl Deserializable for BlockHeader {
|
|||
version,
|
||||
previous_header_hash,
|
||||
merkle_root_hash,
|
||||
hash_final_sapling_root,
|
||||
time,
|
||||
bits,
|
||||
nonce,
|
||||
|
|
|
@ -55,6 +55,20 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Push integer to the end of script
|
||||
pub fn push_i64(mut self, int: i64) -> Self {
|
||||
if int == -1 || (int >= 1 && int <= 16) {
|
||||
let shift: i64 = (Opcode::OP_1 as u8 - 1) as i64;
|
||||
self.data.push((int + shift) as u8);
|
||||
self
|
||||
} else if int == 0 {
|
||||
self.data.push(Opcode::OP_0 as u8);
|
||||
self
|
||||
} else {
|
||||
self.push_num(int.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends num push operation to the end of script
|
||||
pub fn push_num(self, num: Num) -> Self {
|
||||
self.push_data(&num.to_bytes())
|
||||
|
|
|
@ -269,7 +269,7 @@ impl<'a> BlockCoinbaseScript<'a> {
|
|||
}
|
||||
|
||||
let prefix = script::Builder::default()
|
||||
.push_num(self.height.into())
|
||||
.push_i64(self.height.into())
|
||||
.into_script();
|
||||
|
||||
let matches = self.block.transactions.first()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use network::ConsensusParams;
|
||||
use network::{ConsensusParams, ConsensusFork};
|
||||
use storage::BlockHeaderProvider;
|
||||
use canon::CanonHeader;
|
||||
use error::Error;
|
||||
|
@ -8,6 +8,7 @@ use deployments::Deployments;
|
|||
|
||||
pub struct HeaderAcceptor<'a> {
|
||||
pub version: HeaderVersion<'a>,
|
||||
pub equihash: HeaderEquihashSolution<'a>,
|
||||
pub work: HeaderWork<'a>,
|
||||
pub median_timestamp: HeaderMedianTimestamp<'a>,
|
||||
}
|
||||
|
@ -22,6 +23,7 @@ impl<'a> HeaderAcceptor<'a> {
|
|||
) -> Self {
|
||||
let csv_active = deployments.as_ref().csv(height, store, consensus);
|
||||
HeaderAcceptor {
|
||||
equihash: HeaderEquihashSolution::new(header, consensus),
|
||||
work: HeaderWork::new(header, store, height, consensus),
|
||||
median_timestamp: HeaderMedianTimestamp::new(header, store, csv_active),
|
||||
version: HeaderVersion::new(header, height, consensus),
|
||||
|
@ -29,6 +31,7 @@ impl<'a> HeaderAcceptor<'a> {
|
|||
}
|
||||
|
||||
pub fn check(&self) -> Result<(), Error> {
|
||||
try!(self.equihash.check());
|
||||
try!(self.version.check());
|
||||
try!(self.work.check());
|
||||
try!(self.median_timestamp.check());
|
||||
|
@ -64,6 +67,39 @@ impl<'a> HeaderVersion<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct HeaderEquihashSolution<'a> {
|
||||
header: CanonHeader<'a>,
|
||||
consensus: &'a ConsensusParams,
|
||||
}
|
||||
|
||||
impl<'a> HeaderEquihashSolution<'a> {
|
||||
fn new(header: CanonHeader<'a>, consensus: &'a ConsensusParams) -> Self {
|
||||
HeaderEquihashSolution {
|
||||
header: header,
|
||||
consensus: consensus,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), Error> {
|
||||
match self.consensus.fork {
|
||||
ConsensusFork::ZCash => (),
|
||||
_ => return Ok(()),
|
||||
}
|
||||
|
||||
use equihash;
|
||||
let is_solution_correct = equihash::verify_block_equihash_solution(&equihash::EquihashParams {
|
||||
N: 200,
|
||||
K: 9,
|
||||
}, &self.header.raw);
|
||||
|
||||
if is_solution_correct {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidEquihashSolution)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HeaderWork<'a> {
|
||||
header: CanonHeader<'a>,
|
||||
store: &'a BlockHeaderProvider,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use blake2_rfc::blake2b::Blake2b;
|
||||
use byteorder::{BigEndian, LittleEndian, ByteOrder, WriteBytesExt};
|
||||
use chain::BlockHeader;
|
||||
use primitives::hex::ToHex;
|
||||
|
||||
pub struct EquihashParams {
|
||||
|
@ -39,6 +40,16 @@ impl EquihashParams {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn verify_block_equihash_solution(params: &EquihashParams, header: &BlockHeader) -> bool {
|
||||
let equihash_solution = match header.equihash_solution.as_ref() {
|
||||
Some(equihash_solution) => equihash_solution,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let input = header.equihash_input();
|
||||
verify_equihash_solution(params, &input, &equihash_solution.0)
|
||||
}
|
||||
|
||||
pub fn verify_equihash_solution(params: &EquihashParams, input: &[u8], solution: &[u8]) -> bool {
|
||||
if solution.len() != params.solution_size() {
|
||||
return false;
|
||||
|
@ -117,12 +128,18 @@ fn merge_rows(row1: &[u8], row2: &[u8], len: usize, indices_len: usize, trim: us
|
|||
}
|
||||
|
||||
fn distinct_indices(row1: &[u8], row2: &[u8], len: usize, indices_len: usize) -> bool {
|
||||
for i in 0..indices_len / 4 {
|
||||
for j in 0..indices_len / 4 {
|
||||
let mut i = 0;
|
||||
let mut j = 0;
|
||||
while i < indices_len {
|
||||
while j < indices_len {
|
||||
if row1[len + i..len + i + 4] == row2[len + j..len + j + 4] {
|
||||
return false;
|
||||
}
|
||||
|
||||
j += 4;
|
||||
}
|
||||
|
||||
i += 4;
|
||||
}
|
||||
|
||||
true
|
||||
|
|
|
@ -59,6 +59,7 @@ pub enum Error {
|
|||
UnexpectedWitness,
|
||||
/// Database error
|
||||
Database(DBError),
|
||||
InvalidEquihashSolution,
|
||||
}
|
||||
|
||||
impl From<DBError> for Error {
|
||||
|
|
Loading…
Reference in New Issue