1use serde::{Deserialize, Serialize};
4use sha2::{Digest, Sha256};
5
6use crate::types::Chain;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct HeightRange {
16 pub low: u32,
17 pub high: u32,
18}
19
20impl HeightRange {
21 pub fn new(low: u32, high: u32) -> Self {
22 Self { low, high }
23 }
24
25 pub fn count(&self) -> u32 {
27 self.high - self.low + 1
28 }
29
30 pub fn contains(&self, height: u32) -> bool {
32 height >= self.low && height <= self.high
33 }
34
35 pub fn overlaps(&self, other: &HeightRange) -> bool {
37 self.low <= other.high && other.low <= self.high
38 }
39
40 pub fn merge(&self, other: &HeightRange) -> Option<HeightRange> {
43 let self_adj = self.high.saturating_add(1);
45 let other_adj = other.high.saturating_add(1);
46 if self_adj >= other.low && other_adj >= self.low {
47 Some(HeightRange::new(
48 self.low.min(other.low),
49 self.high.max(other.high),
50 ))
51 } else {
52 None
53 }
54 }
55
56 pub fn subtract(&self, other: &HeightRange) -> Vec<HeightRange> {
58 if !self.overlaps(other) {
60 return vec![self.clone()];
61 }
62
63 let mut result = Vec::new();
64
65 if other.low > self.low {
67 result.push(HeightRange::new(self.low, other.low - 1));
68 }
69
70 if other.high < self.high {
72 result.push(HeightRange::new(other.high + 1, self.high));
73 }
74
75 result
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(rename_all = "camelCase")]
86pub struct BaseBlockHeader {
87 pub version: u32,
88 pub previous_hash: String,
90 pub merkle_root: String,
92 pub time: u32,
93 pub bits: u32,
94 pub nonce: u32,
95}
96
97fn display_hex_to_internal(hex_str: &str) -> [u8; 32] {
100 let mut bytes = [0u8; 32];
101 let decoded = hex::decode(hex_str).unwrap_or_else(|_| vec![0u8; 32]);
102 let len = decoded.len().min(32);
103 bytes[..len].copy_from_slice(&decoded[..len]);
104 bytes.reverse();
105 bytes
106}
107
108impl BaseBlockHeader {
109 pub fn to_bytes(&self) -> [u8; 80] {
111 let mut buf = [0u8; 80];
112 let mut offset = 0;
113
114 buf[offset..offset + 4].copy_from_slice(&self.version.to_le_bytes());
116 offset += 4;
117
118 let prev = display_hex_to_internal(&self.previous_hash);
120 buf[offset..offset + 32].copy_from_slice(&prev);
121 offset += 32;
122
123 let merkle = display_hex_to_internal(&self.merkle_root);
125 buf[offset..offset + 32].copy_from_slice(&merkle);
126 offset += 32;
127
128 buf[offset..offset + 4].copy_from_slice(&self.time.to_le_bytes());
130 offset += 4;
131
132 buf[offset..offset + 4].copy_from_slice(&self.bits.to_le_bytes());
134 offset += 4;
135
136 buf[offset..offset + 4].copy_from_slice(&self.nonce.to_le_bytes());
138
139 buf
140 }
141
142 pub fn to_block_header_at_height(&self, height: u32) -> BlockHeader {
144 let bytes = self.to_bytes();
145 let hash = compute_block_hash(&bytes);
146 BlockHeader {
147 version: self.version,
148 previous_hash: self.previous_hash.clone(),
149 merkle_root: self.merkle_root.clone(),
150 time: self.time,
151 bits: self.bits,
152 nonce: self.nonce,
153 height,
154 hash,
155 }
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
165#[serde(rename_all = "camelCase")]
166pub struct BlockHeader {
167 pub version: u32,
168 pub previous_hash: String,
169 pub merkle_root: String,
170 pub time: u32,
171 pub bits: u32,
172 pub nonce: u32,
173 pub height: u32,
174 pub hash: String,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
183#[serde(rename_all = "camelCase")]
184pub struct LiveBlockHeader {
185 pub version: u32,
186 pub previous_hash: String,
187 pub merkle_root: String,
188 pub time: u32,
189 pub bits: u32,
190 pub nonce: u32,
191 pub height: u32,
192 pub hash: String,
193 pub chain_work: String,
194 pub is_chain_tip: bool,
195 pub is_active: bool,
196 pub header_id: Option<u64>,
197 pub previous_header_id: Option<u64>,
198}
199
200impl From<LiveBlockHeader> for BlockHeader {
201 fn from(live: LiveBlockHeader) -> Self {
202 BlockHeader {
203 version: live.version,
204 previous_hash: live.previous_hash,
205 merkle_root: live.merkle_root,
206 time: live.time,
207 bits: live.bits,
208 nonce: live.nonce,
209 height: live.height,
210 hash: live.hash,
211 }
212 }
213}
214
215#[derive(Debug, Clone, Default, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct InsertHeaderResult {
223 pub added: bool,
224 pub dupe: bool,
225 pub is_active_tip: bool,
226 pub reorg_depth: u32,
227 pub prior_tip: Option<BlockHeader>,
228 pub deactivated_headers: Vec<BlockHeader>,
229 pub no_prev: bool,
230 pub bad_prev: bool,
231 pub no_active_ancestor: bool,
232 pub no_tip: bool,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
241#[serde(rename_all = "camelCase")]
242pub struct ChaintracksInfo {
243 pub chain: Option<Chain>,
244 pub storage_type: String,
245 pub ingestor_count: u32,
246 pub tip_height: Option<u32>,
247 pub live_range: Option<HeightRange>,
248 pub is_listening: bool,
249 pub is_synchronized: bool,
250}
251
252pub fn compute_block_hash(header_bytes: &[u8; 80]) -> String {
259 let first = Sha256::digest(header_bytes);
260 let second = Sha256::digest(&first);
261 let mut hash_bytes: [u8; 32] = second.into();
262 hash_bytes.reverse();
263 hex::encode(hash_bytes)
264}
265
266pub fn calculate_work(bits: u32) -> String {
271 let exponent = ((bits >> 24) & 0xff) as usize;
273 let mantissa = bits & 0x007fffff;
274
275 let mut target = [0u8; 32];
276 if exponent > 0 && exponent <= 32 {
277 let start = 32usize.saturating_sub(exponent);
278 if start + 2 < 32 {
279 target[start] = ((mantissa >> 16) & 0xff) as u8;
280 target[start + 1] = ((mantissa >> 8) & 0xff) as u8;
281 target[start + 2] = (mantissa & 0xff) as u8;
282 }
283 }
284
285 let (t_hi, t_lo) = bytes32_to_u128pair(&target);
287
288 let (not_hi, not_lo) = (!t_hi, !t_lo);
290
291 let (t1_lo, carry) = t_lo.overflowing_add(1u128);
293 let t1_hi = t_hi.wrapping_add(carry as u128);
294
295 let (div_hi, div_lo) = div256(not_hi, not_lo, t1_hi, t1_lo);
297
298 let (result_lo, carry2) = div_lo.overflowing_add(1u128);
300 let result_hi = div_hi.wrapping_add(carry2 as u128);
301
302 format!(
304 "{:016x}{:016x}{:016x}{:016x}",
305 (result_hi >> 64) as u64,
306 result_hi as u64,
307 (result_lo >> 64) as u64,
308 result_lo as u64,
309 )
310}
311
312fn bytes32_to_u128pair(b: &[u8; 32]) -> (u128, u128) {
313 let hi = u128::from_be_bytes(b[0..16].try_into().unwrap());
314 let lo = u128::from_be_bytes(b[16..32].try_into().unwrap());
315 (hi, lo)
316}
317
318fn div256(a_hi: u128, a_lo: u128, b_hi: u128, b_lo: u128) -> (u128, u128) {
321 if b_hi == 0 && b_lo == 0 {
322 panic!("division by zero");
323 }
324
325 if b_hi == 0 {
327 let (q_hi, r) = div128_by_u128(a_hi, 0, b_lo);
328 let (q_lo, _) = div128_by_u128(a_lo, r, b_lo);
329 return (q_hi, q_lo);
330 }
331
332 let a = u128pair_to_bytes32(a_hi, a_lo);
334 let b = u128pair_to_bytes32(b_hi, b_lo);
335 let (q, _r) = bytes32_divmod(&a, &b);
336 bytes32_to_u128pair(&q)
337}
338
339fn u128pair_to_bytes32(hi: u128, lo: u128) -> [u8; 32] {
340 let mut b = [0u8; 32];
341 b[0..16].copy_from_slice(&hi.to_be_bytes());
342 b[16..32].copy_from_slice(&lo.to_be_bytes());
343 b
344}
345
346fn bytes32_divmod(a: &[u8; 32], b: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
349 let mut q = [0u8; 32];
350 let mut r = [0u8; 32];
351
352 for i in 0..256usize {
353 shl1_bytes32(&mut r);
355 let byte_idx = i / 8;
357 let bit_idx = 7 - (i % 8);
358 let bit = (a[byte_idx] >> bit_idx) & 1;
359 r[31] |= bit;
360
361 if cmp_bytes32(&r, b) >= 0 {
363 sub_bytes32(&mut r, b);
364 let q_byte = i / 8;
365 let q_bit = 7 - (i % 8);
366 q[q_byte] |= 1 << q_bit;
367 }
368 }
369
370 (q, r)
371}
372
373fn shl1_bytes32(b: &mut [u8; 32]) {
374 let mut carry = 0u8;
375 for i in (0..32).rev() {
376 let new_carry = b[i] >> 7;
377 b[i] = (b[i] << 1) | carry;
378 carry = new_carry;
379 }
380}
381
382fn cmp_bytes32(a: &[u8; 32], b: &[u8; 32]) -> i32 {
383 for i in 0..32 {
384 if a[i] < b[i] {
385 return -1;
386 }
387 if a[i] > b[i] {
388 return 1;
389 }
390 }
391 0
392}
393
394fn sub_bytes32(a: &mut [u8; 32], b: &[u8; 32]) {
395 let mut borrow = 0i16;
396 for i in (0..32).rev() {
397 let diff = a[i] as i16 - b[i] as i16 - borrow;
398 if diff < 0 {
399 a[i] = (diff + 256) as u8;
400 borrow = 1;
401 } else {
402 a[i] = diff as u8;
403 borrow = 0;
404 }
405 }
406}
407
408fn div128_by_u128(hi: u128, lo: u128, d: u128) -> (u128, u128) {
411 let limbs = [
413 (hi >> 64) as u64,
414 hi as u64,
415 (lo >> 64) as u64,
416 lo as u64,
417 ];
418
419 let mut r: u128 = 0;
420 let mut q_limbs = [0u64; 4];
421 for (i, &limb) in limbs.iter().enumerate() {
422 let cur = (r << 64) | limb as u128;
423 q_limbs[i] = (cur / d) as u64;
424 r = cur % d;
425 }
426
427 let q = ((q_limbs[2] as u128) << 64) | q_limbs[3] as u128;
428 (q, r)
429}
430
431#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_height_range_count() {
441 let r = HeightRange::new(10, 20);
442 assert_eq!(r.count(), 11);
443 let r = HeightRange::new(5, 5);
444 assert_eq!(r.count(), 1);
445 }
446
447 #[test]
448 fn test_height_range_contains() {
449 let r = HeightRange::new(10, 20);
450 assert!(r.contains(10));
451 assert!(r.contains(15));
452 assert!(r.contains(20));
453 assert!(!r.contains(9));
454 assert!(!r.contains(21));
455 }
456
457 #[test]
458 fn test_height_range_merge() {
459 let a = HeightRange::new(10, 20);
460 let b = HeightRange::new(15, 30);
461 assert_eq!(a.merge(&b), Some(HeightRange::new(10, 30)));
462 let a = HeightRange::new(10, 20);
463 let b = HeightRange::new(21, 30);
464 assert_eq!(a.merge(&b), Some(HeightRange::new(10, 30)));
465 let a = HeightRange::new(10, 20);
466 let b = HeightRange::new(25, 30);
467 assert_eq!(a.merge(&b), None);
468 }
469
470 #[test]
471 fn test_height_range_subtract() {
472 let a = HeightRange::new(10, 30);
473 let b = HeightRange::new(15, 20);
474 assert_eq!(
475 a.subtract(&b),
476 vec![HeightRange::new(10, 14), HeightRange::new(21, 30)]
477 );
478 let a = HeightRange::new(10, 30);
479 let b = HeightRange::new(10, 20);
480 assert_eq!(a.subtract(&b), vec![HeightRange::new(21, 30)]);
481 let a = HeightRange::new(10, 20);
482 let b = HeightRange::new(25, 30);
483 assert_eq!(a.subtract(&b), vec![HeightRange::new(10, 20)]);
484 }
485
486 #[test]
487 fn test_base_block_header_to_bytes() {
488 let genesis = BaseBlockHeader {
489 version: 1,
490 previous_hash: "0000000000000000000000000000000000000000000000000000000000000000"
491 .to_string(),
492 merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
493 .to_string(),
494 time: 1231006505,
495 bits: 0x1d00ffff,
496 nonce: 2083236893,
497 };
498 let bytes = genesis.to_bytes();
499 assert_eq!(bytes.len(), 80);
500 }
501
502 #[test]
503 fn test_compute_block_hash_genesis() {
504 let genesis = BaseBlockHeader {
505 version: 1,
506 previous_hash: "0000000000000000000000000000000000000000000000000000000000000000"
507 .to_string(),
508 merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
509 .to_string(),
510 time: 1231006505,
511 bits: 0x1d00ffff,
512 nonce: 2083236893,
513 };
514 let bytes = genesis.to_bytes();
515 let hash = compute_block_hash(&bytes);
516 assert_eq!(
517 hash,
518 "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
519 );
520 }
521
522 #[test]
523 fn test_to_block_header_at_height() {
524 let base = BaseBlockHeader {
525 version: 1,
526 previous_hash: "0000000000000000000000000000000000000000000000000000000000000000"
527 .to_string(),
528 merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
529 .to_string(),
530 time: 1231006505,
531 bits: 0x1d00ffff,
532 nonce: 2083236893,
533 };
534 let header = base.to_block_header_at_height(0);
535 assert_eq!(header.height, 0);
536 assert_eq!(
537 header.hash,
538 "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
539 );
540 }
541
542 #[test]
543 fn test_calculate_work() {
544 let work = calculate_work(0x1d00ffff);
545 assert!(!work.is_empty());
546 assert_eq!(work.len(), 64);
547 }
548
549 #[test]
550 fn test_block_header_serialization_roundtrip() {
551 let header = BlockHeader {
552 version: 1,
553 previous_hash: "abc".to_string(),
554 merkle_root: "def".to_string(),
555 time: 12345,
556 bits: 0x1d00ffff,
557 nonce: 99,
558 height: 10,
559 hash: "ghi".to_string(),
560 };
561 let json = serde_json::to_string(&header).unwrap();
562 assert!(json.contains("\"previousHash\""));
563 assert!(json.contains("\"merkleRoot\""));
564 let deserialized: BlockHeader = serde_json::from_str(&json).unwrap();
565 assert_eq!(deserialized.height, 10);
566 }
567}