use bitcoin::hashes::Hash;
use bitcoin::{BlockHash as CoreHash, CompactTarget, TxMerkleNode};
use sidestr_core::block::{FamilyBlock, HeaderFamily};
use sidestr_core::parents::Family;
use sidestr_core::rules::RuleResult;
use sidestr_core::sighash::SighashRules;
use sidestr_core::{Error, Result};
use crate::{Blake2bV2Header, BlockHash, StockHeader, VERSION_HEADER_V2_FLAG};
pub const BLAKE2B_V2_VERSION: u32 = 0xa000_0000;
fn to_core(h: BlockHash) -> CoreHash {
CoreHash::from_byte_array(h.to_wire())
}
fn from_core(h: CoreHash) -> BlockHash {
BlockHash::from_wire(h.to_byte_array())
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Blake2bV2;
impl HeaderFamily for Blake2bV2 {
type Header = Blake2bV2Header;
type Block = FamilyBlock<Blake2bV2>;
const FAMILY: Family = Family::Blake2b;
const HEADER_LEN: usize = Blake2bV2Header::WIRE_SIZE;
fn encode_header(&self, header: &Blake2bV2Header) -> Vec<u8> {
header.encode().to_vec()
}
fn decode_header(&self, bytes: &[u8]) -> Result<Blake2bV2Header> {
Blake2bV2Header::decode(bytes).map_err(|e| Error::Encoding(format!("v2 header: {e}")))
}
fn block_hash(&self, header: &Blake2bV2Header) -> CoreHash {
to_core(header.hash())
}
fn signed_prefix(&self, header: &Blake2bV2Header) -> Vec<u8> {
header.signet_preimage(header.merkle_root).to_vec()
}
fn header_height(&self, header: &Blake2bV2Header) -> Option<u32> {
Some(header.height)
}
fn new_header(
&self,
prev: CoreHash,
merkle_root: TxMerkleNode,
time: u32,
bits: CompactTarget,
height: u32,
tx_count: usize,
) -> Blake2bV2Header {
Blake2bV2Header {
version: BLAKE2B_V2_VERSION,
prev_block_hash: from_core(prev),
merkle_root: merkle_root.to_byte_array(),
time_on_wire: time,
bits: bits.to_consensus(),
nonce: 0,
nonce2: 0,
nonce3: 0,
extranonce: [0u8; 16],
time_offset: 0,
tx_count: u16::try_from(tx_count).unwrap_or(u16::MAX),
flags: 0,
xor_key_mask_clear_bits: 0,
xor_key: [0u8; 16],
height,
mm_rhs: [0u8; 32],
}
}
fn version(&self, header: &Blake2bV2Header) -> u32 {
header.version
}
fn version_number(&self, header: &Blake2bV2Header) -> i64 {
i64::from(header.version)
}
fn prev(&self, header: &Blake2bV2Header) -> CoreHash {
to_core(header.prev_block_hash)
}
fn merkle_root(&self, header: &Blake2bV2Header) -> TxMerkleNode {
TxMerkleNode::from_byte_array(header.merkle_root)
}
fn time(&self, header: &Blake2bV2Header) -> u32 {
header.time()
}
fn bits(&self, header: &Blake2bV2Header) -> CompactTarget {
CompactTarget::from_consensus(header.bits)
}
fn nonce(&self, header: &Blake2bV2Header) -> u32 {
header.nonce
}
fn set_merkle_root(&self, header: &mut Blake2bV2Header, root: TxMerkleNode) {
header.merkle_root = root.to_byte_array();
}
fn set_nonce(&self, header: &mut Blake2bV2Header, nonce: u32) {
header.nonce = nonce;
}
fn header_rules(&self, header: &Blake2bV2Header, height: u32) -> Vec<RuleResult> {
vec![
RuleResult::new("knots:rule-header-v1-until-fork", Some(true)),
RuleResult::new(
"knots:rule-header-v2-from-fork",
Some(header.version & VERSION_HEADER_V2_FLAG != 0),
),
RuleResult::new("knots:rule-header-height", Some(header.height == height)),
RuleResult::new(
"knots:rule-header-flags-reserved",
Some(header.check_flags().is_ok()),
),
]
}
fn block_rules(&self, header: &Blake2bV2Header, tx_count: usize) -> Vec<RuleResult> {
vec![
RuleResult::new(
"knots:rule-block-txcount",
Some(usize::from(header.tx_count) == tx_count),
),
RuleResult::new("knots:rule-block-headline", Some(true)),
]
}
fn sighash_rules(&self, _height: u32) -> SighashRules {
SighashRules::KnotsUnified
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Stock;
impl HeaderFamily for Stock {
type Header = StockHeader;
type Block = FamilyBlock<Stock>;
const FAMILY: Family = Family::Stock;
const HEADER_LEN: usize = StockHeader::WIRE_SIZE;
fn encode_header(&self, header: &StockHeader) -> Vec<u8> {
header.encode().to_vec()
}
fn decode_header(&self, bytes: &[u8]) -> Result<StockHeader> {
StockHeader::decode(bytes).map_err(|e| Error::Encoding(format!("stock header: {e}")))
}
fn block_hash(&self, header: &StockHeader) -> CoreHash {
to_core(header.hash())
}
fn signed_prefix(&self, header: &StockHeader) -> Vec<u8> {
header.signet_preimage(header.merkle_root).to_vec()
}
fn header_height(&self, _header: &StockHeader) -> Option<u32> {
None
}
fn new_header(
&self,
prev: CoreHash,
merkle_root: TxMerkleNode,
time: u32,
bits: CompactTarget,
_height: u32,
_tx_count: usize,
) -> StockHeader {
StockHeader {
version: 0x2000_0000,
prev_block_hash: from_core(prev),
merkle_root: merkle_root.to_byte_array(),
time,
bits: bits.to_consensus(),
nonce: 0,
}
}
fn version(&self, header: &StockHeader) -> u32 {
header.version
}
fn version_number(&self, header: &StockHeader) -> i64 {
i64::from(header.version as i32)
}
fn prev(&self, header: &StockHeader) -> CoreHash {
to_core(header.prev_block_hash)
}
fn merkle_root(&self, header: &StockHeader) -> TxMerkleNode {
TxMerkleNode::from_byte_array(header.merkle_root)
}
fn time(&self, header: &StockHeader) -> u32 {
header.time
}
fn bits(&self, header: &StockHeader) -> CompactTarget {
CompactTarget::from_consensus(header.bits)
}
fn nonce(&self, header: &StockHeader) -> u32 {
header.nonce
}
fn set_merkle_root(&self, header: &mut StockHeader, root: TxMerkleNode) {
header.merkle_root = root.to_byte_array();
}
fn set_nonce(&self, header: &mut StockHeader, nonce: u32) {
header.nonce = nonce;
}
}