use std::convert::{TryFrom, TryInto};
use primitive_types::U512;
use tari_common_types::{chain_metadata::ChainMetadata, types::FixedHash};
use crate::proto::base_node as proto;
const ACCUMULATED_DIFFICULTY_BYTE_SIZE_U256: usize = 32;
const ACCUMULATED_DIFFICULTY_BYTE_SIZE_U512: usize = 64;
impl TryFrom<proto::ChainMetadata> for ChainMetadata {
type Error = String;
fn try_from(metadata: proto::ChainMetadata) -> Result<Self, Self::Error> {
if metadata.accumulated_difficulty_low.len() > ACCUMULATED_DIFFICULTY_BYTE_SIZE_U256 {
return Err(format!(
"Invalid accumulated difficulty low byte length. {} was expected but the actual length was {}",
ACCUMULATED_DIFFICULTY_BYTE_SIZE_U256,
metadata.accumulated_difficulty_low.len()
));
}
if metadata.accumulated_difficulty_high.len() > ACCUMULATED_DIFFICULTY_BYTE_SIZE_U256 {
return Err(format!(
"Invalid accumulated difficulty byte high length. {} was expected but the actual length was {}",
ACCUMULATED_DIFFICULTY_BYTE_SIZE_U256,
metadata.accumulated_difficulty_high.len()
));
}
let mut bytes = metadata.accumulated_difficulty_high.to_vec();
bytes.extend_from_slice(&metadata.accumulated_difficulty_low);
let accumulated_difficulty = U512::from_big_endian(&bytes);
let best_block_height = metadata.best_block_height;
let pruning_horizon = if metadata.pruned_height == 0 {
metadata.pruned_height
} else {
best_block_height.saturating_sub(metadata.pruned_height)
};
if metadata.best_block_hash.is_empty() {
return Err("Best block is missing".to_string());
}
let hash: FixedHash = metadata
.best_block_hash
.try_into()
.map_err(|e| format!("Malformed best block: {e}"))?;
ChainMetadata::new(
best_block_height,
hash,
pruning_horizon,
metadata.pruned_height,
accumulated_difficulty,
metadata.timestamp,
)
.map_err(|e| e.to_string())
}
}
impl From<ChainMetadata> for proto::ChainMetadata {
fn from(metadata: ChainMetadata) -> Self {
let mut accumulated_difficulty = [0u8; ACCUMULATED_DIFFICULTY_BYTE_SIZE_U512];
metadata
.accumulated_difficulty()
.to_big_endian(&mut accumulated_difficulty);
Self {
best_block_height: metadata.best_block_height(),
best_block_hash: metadata.best_block_hash().to_vec(),
pruned_height: metadata.pruned_height(),
accumulated_difficulty_low: accumulated_difficulty[32..=63].to_vec(),
accumulated_difficulty_high: accumulated_difficulty[0..=31].to_vec(),
timestamp: metadata.timestamp(),
}
}
}
impl proto::ChainMetadata {
pub fn best_block_height(&self) -> u64 {
self.best_block_height
}
}