crate::ix!();
pub const BLOCK_INDEX_N_MEDIAN_TIME_SPAN: i32 = 11;
#[inline] pub fn invert_lowest_one(n: i32) -> i32 {
n & (n - 1)
}
#[inline] pub fn get_skip_height(height: i32) -> i32 {
if height < 2 {
return 0;
}
match (height & 1) != 0 {
true => invert_lowest_one(invert_lowest_one(height - 1)) + 1,
false => invert_lowest_one(height)
}
}
#[derive(PartialEq,Eq,Clone,Debug)]
pub struct BlockIndex {
pub phash_block: Option<u256>,
pub pprev: Option<Arc<BlockIndex>>,
pub pskip: Option<Arc<BlockIndex>>,
pub n_height: i32,
pub n_file: i32,
pub n_data_pos: u32,
pub n_undo_pos: u32,
pub n_chain_work: ArithU256,
pub n_tx: u32,
pub n_chain_tx: u32,
pub n_status: u32,
pub n_version: i32,
pub hash_merkle_root: u256,
pub n_time: u32,
pub n_bits: u32,
pub n_nonce: u32,
pub n_sequence_id: i32,
pub n_time_max: u32,
}
unsafe impl Send for BlockIndex {}
unsafe impl Sync for BlockIndex {}
pub type BlockIndexRef = Option<Arc<BlockIndex>>;
impl Default for BlockIndex {
fn default() -> Self {
Self {
phash_block: None,
pprev: None,
pskip: None,
n_height: 0,
n_file: 0,
n_data_pos: 0,
n_undo_pos: 0,
n_chain_work: ArithU256::default(),
n_tx: 0,
n_chain_tx: 0,
n_status: 0,
n_version: 0,
hash_merkle_root: u256::default(),
n_time: 0,
n_bits: 0,
n_nonce: 0,
n_sequence_id: 0,
n_time_max: 0,
}
}
}
impl BlockIndex {
pub fn new(block: &BlockHeader) -> Self {
Self {
n_version: block.n_version,
hash_merkle_root: block.hash_merkle_root.clone(),
n_time: block.n_time,
n_bits: block.n_bits,
n_nonce: block.n_nonce,
..Default::default()
}
}
pub fn get_block_pos(&self) -> FlatFilePos {
let mut ret = FlatFilePos::default();
if (self.n_status & BlockStatus::BLOCK_HAVE_DATA.bits()) != 0 {
ret.n_file = self.n_file;
ret.n_pos = self.n_data_pos;
}
ret
}
pub fn get_undo_pos(&self) -> FlatFilePos {
let mut ret = FlatFilePos::default();
if (self.n_status & BlockStatus::BLOCK_HAVE_UNDO.bits()) != 0 {
ret.n_file = self.n_file;
ret.n_pos = self.n_undo_pos;
}
ret
}
pub fn get_block_header(&self) -> BlockHeader {
let mut block = BlockHeader::default();
block.n_version = self.n_version;
if self.pprev.is_some() {
block.hash_prev_block = unsafe {
self.pprev.as_ref().unwrap().get_block_hash()
};
}
block.hash_merkle_root = self.hash_merkle_root.clone();
block.n_time = self.n_time;
block.n_bits = self.n_bits;
block.n_nonce = self.n_nonce;
block
}
pub fn get_block_hash(&self) -> u256 {
self.phash_block.as_ref().unwrap().clone()
}
pub fn have_txs_downloaded(&self) -> bool {
self.n_chain_tx != 0
}
pub fn get_block_time(&self) -> i64 {
self.n_time as i64
}
pub fn get_block_time_max(&self) -> i64 {
self.n_time_max as i64
}
pub fn get_median_time_past(self: Arc<Self>) -> i64 {
unsafe {
let mut pmedian = [0_i64; BLOCK_INDEX_N_MEDIAN_TIME_SPAN as usize];
let mut pbegin: *mut i64 = pmedian.as_mut_ptr().offset(BLOCK_INDEX_N_MEDIAN_TIME_SPAN as isize);
let pend: *mut i64 = pmedian.as_mut_ptr().offset(BLOCK_INDEX_N_MEDIAN_TIME_SPAN as isize);
let mut pindex: Option<Arc<BlockIndex>> = Some(self.clone());
let mut i: i32 = 0;
while i < BLOCK_INDEX_N_MEDIAN_TIME_SPAN && pindex.is_some() {
pbegin = pbegin.offset(-1);
*pbegin = pindex.as_ref().unwrap().get_block_time();
i += 1;
pindex = Some(pindex.as_ref().unwrap().pprev.clone().unwrap());
}
let len: usize = pend.offset_from(pbegin).try_into().unwrap();
let mut slice = std::slice::from_raw_parts_mut(pbegin, len);
slice.sort();
let idx: usize = ((pend.offset_from(pbegin)) / 2)
.try_into()
.unwrap();
slice[idx]
}
}
pub fn to_string(&self) -> String {
format!(
"BlockIndex(pprev={:?}, nHeight={:?}, merkle={:?}, hashBlock={:?})",
self.pprev,
self.n_height,
self.hash_merkle_root,
self.get_block_hash()
)
}
pub fn is_valid(&self, n_up_to: Option<BlockStatus>) -> bool {
let n_up_to: BlockStatus
= n_up_to.unwrap_or(BlockStatus::BLOCK_VALID_TRANSACTIONS);
assert!((n_up_to.bits() & !BlockStatus::BLOCK_VALID_MASK.bits()) == 0);
if (self.n_status & BlockStatus::BLOCK_FAILED_MASK.bits()) != 0 {
return false;
}
((self.n_status & BlockStatus::BLOCK_VALID_MASK.bits()) >= n_up_to.bits())
}
pub fn is_assumed_valid(&self) -> bool {
(self.n_status & BlockStatus::BLOCK_ASSUMED_VALID.bits()) != 0
}
pub fn raise_validity(&mut self, n_up_to: BlockStatus) -> bool {
assert!((n_up_to & !BlockStatus::BLOCK_VALID_MASK).bits() == 0);
if (self.get_n_status() & BlockStatus::BLOCK_FAILED_MASK).bits() != 0 {
return false;
}
if (self.get_n_status() & BlockStatus::BLOCK_VALID_MASK) < n_up_to {
if (self.n_status & BlockStatus::BLOCK_ASSUMED_VALID.bits()) != 0
&& n_up_to >= BlockStatus::BLOCK_VALID_SCRIPTS {
self.n_status &= !BlockStatus::BLOCK_ASSUMED_VALID.bits();
}
self.n_status =
((self.get_n_status() & !BlockStatus::BLOCK_VALID_MASK) | n_up_to).bits();
return true;
}
false
}
pub fn get_n_status(&self) -> BlockStatus {
BlockStatus::from_bits(self.n_status).unwrap()
}
pub fn get_ancestor(self: Arc<Self>, height: i32) -> Option<Arc<BlockIndex>> {
if height > self.n_height || height < 0 {
return None;
}
let mut pindex_walk: Option<Arc<BlockIndex>> = Some(self.clone());
let mut height_walk: i32 = self.n_height;
while height_walk > height{
let height_skip: i32 = get_skip_height(height_walk);
let height_skip_prev: i32 = get_skip_height(height_walk - 1);
unsafe {
if pindex_walk.as_ref().unwrap().pskip.is_some()
&& (
height_skip == height
|| (height_skip > height && !(height_skip_prev < height_skip - 2 && height_skip_prev >= height))
) {
pindex_walk = Some(
pindex_walk.as_ref().unwrap().pskip.as_ref().unwrap().clone()
);
height_walk = height_skip;
} else {
assert!(pindex_walk.as_ref().unwrap().pprev.is_some());
let pprev = pindex_walk.as_ref().unwrap().pprev.clone();
pindex_walk = Some(pprev.unwrap().clone());
{
let old = height_walk;
height_walk -= 1;
old
};
}
}
}
pindex_walk
}
pub fn build_skip(&mut self) {
if let Some(ref pprev) = self.pprev {
let pprev = pprev.clone();
let skip_height = get_skip_height(self.n_height);
self.pskip = pprev.get_ancestor(skip_height);
}
}
}
pub fn get_block_proof(block: &BlockIndex) -> ArithU256 {
todo!();
}
pub fn last_common_ancestor(
pa: Option<Arc<BlockIndex>>,
pb: Option<Arc<BlockIndex>>) -> Option<Arc<BlockIndex>> {
todo!();
}