1use super::*;
2
3pub trait Entry: Sized {
4 type Value;
5
6 fn load(value: Self::Value) -> Self;
7
8 fn store(self) -> Self::Value;
9}
10
11pub type HeaderValue = [u8; 80];
12
13impl Entry for Header {
14 type Value = HeaderValue;
15
16 fn load(value: Self::Value) -> Self {
17 consensus::encode::deserialize(&value).unwrap()
18 }
19
20 fn store(self) -> Self::Value {
21 let mut buffer = Cursor::new([0; 80]);
22 let len = self
23 .consensus_encode(&mut buffer)
24 .expect("in-memory writers don't error");
25 let buffer = buffer.into_inner();
26 debug_assert_eq!(len, buffer.len());
27 buffer
28 }
29}
30
31impl Entry for Rune {
32 type Value = u128;
33
34 fn load(value: Self::Value) -> Self {
35 Self(value)
36 }
37
38 fn store(self) -> Self::Value {
39 self.0
40 }
41}
42
43#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
44pub struct RuneEntry {
45 pub block: u64,
46 pub burned: u128,
47 pub divisibility: u8,
48 pub etching: Txid,
49 pub mints: u128,
50 pub number: u64,
51 pub premine: u128,
52 pub spaced_rune: SpacedRune,
53 pub symbol: Option<char>,
54 pub terms: Option<Terms>,
55 pub timestamp: u64,
56 pub turbo: bool,
57}
58
59impl RuneEntry {
60 pub fn mintable(&self, height: u64) -> Result<u128, MintError> {
61 let Some(terms) = self.terms else {
62 return Err(MintError::Unmintable);
63 };
64
65 if let Some(start) = self.start() {
66 if height < start {
67 return Err(MintError::Start(start));
68 }
69 }
70
71 if let Some(end) = self.end() {
72 if height >= end {
73 return Err(MintError::End(end));
74 }
75 }
76
77 let cap = terms.cap.unwrap_or_default();
78
79 if self.mints >= cap {
80 return Err(MintError::Cap(cap));
81 }
82
83 Ok(terms.amount.unwrap_or_default())
84 }
85
86 pub fn supply(&self) -> u128 {
87 self.premine
88 + self.mints
89 * self
90 .terms
91 .and_then(|terms| terms.amount)
92 .unwrap_or_default()
93 }
94
95 pub fn pile(&self, amount: u128) -> Pile {
96 Pile {
97 amount,
98 divisibility: self.divisibility,
99 symbol: self.symbol,
100 }
101 }
102
103 pub fn start(&self) -> Option<u64> {
104 let terms = self.terms?;
105
106 let relative = terms
107 .offset
108 .0
109 .map(|offset| self.block.saturating_add(offset));
110
111 let absolute = terms.height.0;
112
113 relative
114 .zip(absolute)
115 .map(|(relative, absolute)| relative.max(absolute))
116 .or(relative)
117 .or(absolute)
118 }
119
120 pub fn end(&self) -> Option<u64> {
121 let terms = self.terms?;
122
123 let relative = terms
124 .offset
125 .1
126 .map(|offset| self.block.saturating_add(offset));
127
128 let absolute = terms.height.1;
129
130 relative
131 .zip(absolute)
132 .map(|(relative, absolute)| relative.min(absolute))
133 .or(relative)
134 .or(absolute)
135 }
136}
137
138type TermsEntryValue = (
139 Option<u128>, (Option<u64>, Option<u64>), Option<u128>, (Option<u64>, Option<u64>), );
144
145pub(super) type RuneEntryValue = (
146 u64, u128, u8, (u128, u128), u128, u64, u128, (u128, u32), Option<char>, Option<TermsEntryValue>, u64, bool, );
159
160impl Default for RuneEntry {
161 fn default() -> Self {
162 Self {
163 block: 0,
164 burned: 0,
165 divisibility: 0,
166 etching: Txid::all_zeros(),
167 mints: 0,
168 number: 0,
169 premine: 0,
170 spaced_rune: SpacedRune::default(),
171 symbol: None,
172 terms: None,
173 timestamp: 0,
174 turbo: false,
175 }
176 }
177}
178
179impl Entry for RuneEntry {
180 type Value = RuneEntryValue;
181
182 fn load(
183 (
184 block,
185 burned,
186 divisibility,
187 etching,
188 mints,
189 number,
190 premine,
191 (rune, spacers),
192 symbol,
193 terms,
194 timestamp,
195 turbo,
196 ): RuneEntryValue,
197 ) -> Self {
198 Self {
199 block,
200 burned,
201 divisibility,
202 etching: {
203 let low = etching.0.to_le_bytes();
204 let high = etching.1.to_le_bytes();
205 Txid::from_byte_array([
206 low[0], low[1], low[2], low[3], low[4], low[5], low[6], low[7], low[8], low[9], low[10],
207 low[11], low[12], low[13], low[14], low[15], high[0], high[1], high[2], high[3], high[4],
208 high[5], high[6], high[7], high[8], high[9], high[10], high[11], high[12], high[13],
209 high[14], high[15],
210 ])
211 },
212 mints,
213 number,
214 premine,
215 spaced_rune: SpacedRune {
216 rune: Rune(rune),
217 spacers,
218 },
219 symbol,
220 terms: terms.map(|(cap, height, amount, offset)| Terms {
221 cap,
222 height,
223 amount,
224 offset,
225 }),
226 timestamp,
227 turbo,
228 }
229 }
230
231 fn store(self) -> Self::Value {
232 (
233 self.block,
234 self.burned,
235 self.divisibility,
236 {
237 let bytes = self.etching.to_byte_array();
238 (
239 u128::from_le_bytes([
240 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
241 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
242 ]),
243 u128::from_le_bytes([
244 bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
245 bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31],
246 ]),
247 )
248 },
249 self.mints,
250 self.number,
251 self.premine,
252 (self.spaced_rune.rune.0, self.spaced_rune.spacers),
253 self.symbol,
254 self.terms.map(
255 |Terms {
256 cap,
257 height,
258 amount,
259 offset,
260 }| (cap, height, amount, offset),
261 ),
262 self.timestamp,
263 self.turbo,
264 )
265 }
266}
267
268pub(super) type RuneIdValue = (u64, u32);
269
270impl Entry for RuneId {
271 type Value = RuneIdValue;
272
273 fn load((block, tx): Self::Value) -> Self {
274 Self { block, tx }
275 }
276
277 fn store(self) -> Self::Value {
278 (self.block, self.tx)
279 }
280}
281
282#[derive(Debug, Eq, PartialEq, Clone)]
283pub struct InscriptionEntry {
284 pub charms: u16,
285 pub fee: u64,
286 pub height: u32,
287 pub id: InscriptionId,
288 pub inscription_number: i32,
289 pub parents: Vec<u32>,
290 pub sat: Option<Sat>,
291 pub sequence_number: u32,
292 pub timestamp: u32,
293}
294
295pub type InscriptionEntryValue = (
296 u16, u64, u32, InscriptionIdValue, i32, Vec<u32>, Option<u64>, u32, u32, );
306
307impl Entry for InscriptionEntry {
308 type Value = InscriptionEntryValue;
309
310 #[rustfmt::skip]
311 fn load(
312 (
313 charms,
314 fee,
315 height,
316 id,
317 inscription_number,
318 parents,
319 sat,
320 sequence_number,
321 timestamp,
322 ): InscriptionEntryValue,
323 ) -> Self {
324 Self {
325 charms,
326 fee,
327 height,
328 id: InscriptionId::load(id),
329 inscription_number,
330 parents,
331 sat: sat.map(Sat),
332 sequence_number,
333 timestamp,
334 }
335 }
336
337 fn store(self) -> Self::Value {
338 (
339 self.charms,
340 self.fee,
341 self.height,
342 self.id.store(),
343 self.inscription_number,
344 self.parents,
345 self.sat.map(Sat::n),
346 self.sequence_number,
347 self.timestamp,
348 )
349 }
350}
351
352pub type InscriptionIdValue = (u128, u128, u32);
353
354impl Entry for InscriptionId {
355 type Value = InscriptionIdValue;
356
357 fn load(value: Self::Value) -> Self {
358 let (head, tail, index) = value;
359 let head_array = head.to_le_bytes();
360 let tail_array = tail.to_le_bytes();
361 let array = [
362 head_array[0],
363 head_array[1],
364 head_array[2],
365 head_array[3],
366 head_array[4],
367 head_array[5],
368 head_array[6],
369 head_array[7],
370 head_array[8],
371 head_array[9],
372 head_array[10],
373 head_array[11],
374 head_array[12],
375 head_array[13],
376 head_array[14],
377 head_array[15],
378 tail_array[0],
379 tail_array[1],
380 tail_array[2],
381 tail_array[3],
382 tail_array[4],
383 tail_array[5],
384 tail_array[6],
385 tail_array[7],
386 tail_array[8],
387 tail_array[9],
388 tail_array[10],
389 tail_array[11],
390 tail_array[12],
391 tail_array[13],
392 tail_array[14],
393 tail_array[15],
394 ];
395
396 Self {
397 txid: Txid::from_byte_array(array),
398 index,
399 }
400 }
401
402 fn store(self) -> Self::Value {
403 let txid_entry = self.txid.store();
404 let little_end = u128::from_le_bytes(txid_entry[..16].try_into().unwrap());
405 let big_end = u128::from_le_bytes(txid_entry[16..].try_into().unwrap());
406 (little_end, big_end, self.index)
407 }
408}
409
410pub type OutPointValue = [u8; 36];
411
412impl Entry for OutPoint {
413 type Value = OutPointValue;
414
415 fn load(value: Self::Value) -> Self {
416 Decodable::consensus_decode(&mut Cursor::new(value)).unwrap()
417 }
418
419 fn store(self) -> Self::Value {
420 let mut value = [0; 36];
421 self.consensus_encode(&mut value.as_mut_slice()).unwrap();
422 value
423 }
424}
425
426pub type SatPointValue = [u8; 44];
427
428impl Entry for SatPoint {
429 type Value = SatPointValue;
430
431 fn load(value: Self::Value) -> Self {
432 Decodable::consensus_decode(&mut Cursor::new(value)).unwrap()
433 }
434
435 fn store(self) -> Self::Value {
436 let mut value = [0; 44];
437 self.consensus_encode(&mut value.as_mut_slice()).unwrap();
438 value
439 }
440}
441
442pub type SatRange = (u64, u64);
443
444impl Entry for SatRange {
445 type Value = [u8; 11];
446
447 fn load([b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10]: Self::Value) -> Self {
448 let raw_base = u64::from_le_bytes([b0, b1, b2, b3, b4, b5, b6, 0]);
449
450 let base = raw_base & ((1 << 51) - 1);
452
453 let raw_delta = u64::from_le_bytes([b6, b7, b8, b9, b10, 0, 0, 0]);
454
455 let delta = raw_delta >> 3;
457
458 (base, base + delta)
459 }
460
461 fn store(self) -> Self::Value {
462 let base = self.0;
463 let delta = self.1 - self.0;
464 let n = u128::from(base) | u128::from(delta) << 51;
465 n.to_le_bytes()[0..11].try_into().unwrap()
466 }
467}
468
469pub type TxidValue = [u8; 32];
470
471impl Entry for Txid {
472 type Value = TxidValue;
473
474 fn load(value: Self::Value) -> Self {
475 Txid::from_byte_array(value)
476 }
477
478 fn store(self) -> Self::Value {
479 Txid::to_byte_array(self)
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use super::*;
486
487 #[test]
488 fn inscription_entry() {
489 let id = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefi0"
490 .parse::<InscriptionId>()
491 .unwrap();
492
493 let entry = InscriptionEntry {
494 charms: 0,
495 fee: 1,
496 height: 2,
497 id,
498 inscription_number: 3,
499 parents: vec![4, 5, 6],
500 sat: Some(Sat(7)),
501 sequence_number: 8,
502 timestamp: 9,
503 };
504
505 let value = (0, 1, 2, id.store(), 3, vec![4, 5, 6], Some(7), 8, 9);
506
507 assert_eq!(entry.clone().store(), value);
508 assert_eq!(InscriptionEntry::load(value), entry);
509 }
510
511 #[test]
512 fn inscription_id_entry() {
513 let inscription_id = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefi0"
514 .parse::<InscriptionId>()
515 .unwrap();
516
517 assert_eq!(
518 inscription_id.store(),
519 (
520 0x0123456789abcdef0123456789abcdef,
521 0x0123456789abcdef0123456789abcdef,
522 0
523 )
524 );
525
526 assert_eq!(
527 InscriptionId::load((
528 0x0123456789abcdef0123456789abcdef,
529 0x0123456789abcdef0123456789abcdef,
530 0
531 )),
532 inscription_id
533 );
534 }
535
536 #[test]
537 fn parent_entry_index() {
538 let inscription_id = "0000000000000000000000000000000000000000000000000000000000000000i1"
539 .parse::<InscriptionId>()
540 .unwrap();
541
542 assert_eq!(inscription_id.store(), (0, 0, 1));
543
544 assert_eq!(InscriptionId::load((0, 0, 1)), inscription_id);
545
546 let inscription_id = "0000000000000000000000000000000000000000000000000000000000000000i256"
547 .parse::<InscriptionId>()
548 .unwrap();
549
550 assert_eq!(inscription_id.store(), (0, 0, 256));
551
552 assert_eq!(InscriptionId::load((0, 0, 256)), inscription_id);
553 }
554
555 #[test]
556 fn rune_entry() {
557 let entry = RuneEntry {
558 block: 12,
559 burned: 1,
560 divisibility: 3,
561 etching: Txid::from_byte_array([
562 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
563 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
564 0x1E, 0x1F,
565 ]),
566 terms: Some(Terms {
567 cap: Some(1),
568 height: (Some(2), Some(3)),
569 amount: Some(4),
570 offset: (Some(5), Some(6)),
571 }),
572 mints: 11,
573 number: 6,
574 premine: 12,
575 spaced_rune: SpacedRune {
576 rune: Rune(7),
577 spacers: 8,
578 },
579 symbol: Some('a'),
580 timestamp: 10,
581 turbo: true,
582 };
583
584 let value = (
585 12,
586 1,
587 3,
588 (
589 0x0F0E0D0C0B0A09080706050403020100,
590 0x1F1E1D1C1B1A19181716151413121110,
591 ),
592 11,
593 6,
594 12,
595 (7, 8),
596 Some('a'),
597 Some((Some(1), (Some(2), Some(3)), Some(4), (Some(5), Some(6)))),
598 10,
599 true,
600 );
601
602 assert_eq!(entry.store(), value);
603 assert_eq!(RuneEntry::load(value), entry);
604 }
605
606 #[test]
607 fn rune_id_entry() {
608 assert_eq!(RuneId { block: 1, tx: 2 }.store(), (1, 2),);
609
610 assert_eq!(RuneId { block: 1, tx: 2 }, RuneId::load((1, 2)),);
611 }
612
613 #[test]
614 fn header() {
615 let expected = [
616 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
617 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
618 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
619 72, 73, 74, 75, 76, 77, 78, 79,
620 ];
621
622 let header = Header::load(expected);
623 let actual = header.store();
624
625 assert_eq!(actual, expected);
626 }
627
628 #[test]
629 fn mintable_default() {
630 assert_eq!(RuneEntry::default().mintable(0), Err(MintError::Unmintable));
631 }
632
633 #[test]
634 fn mintable_cap() {
635 assert_eq!(
636 RuneEntry {
637 terms: Some(Terms {
638 cap: Some(1),
639 amount: Some(1000),
640 ..default()
641 }),
642 mints: 0,
643 ..default()
644 }
645 .mintable(0),
646 Ok(1000),
647 );
648
649 assert_eq!(
650 RuneEntry {
651 terms: Some(Terms {
652 cap: Some(1),
653 amount: Some(1000),
654 ..default()
655 }),
656 mints: 1,
657 ..default()
658 }
659 .mintable(0),
660 Err(MintError::Cap(1)),
661 );
662
663 assert_eq!(
664 RuneEntry {
665 terms: Some(Terms {
666 cap: None,
667 amount: Some(1000),
668 ..default()
669 }),
670 mints: 0,
671 ..default()
672 }
673 .mintable(0),
674 Err(MintError::Cap(0)),
675 );
676 }
677
678 #[test]
679 fn mintable_offset_start() {
680 assert_eq!(
681 RuneEntry {
682 block: 1,
683 terms: Some(Terms {
684 cap: Some(1),
685 amount: Some(1000),
686 offset: (Some(1), None),
687 ..default()
688 }),
689 mints: 0,
690 ..default()
691 }
692 .mintable(1),
693 Err(MintError::Start(2)),
694 );
695
696 assert_eq!(
697 RuneEntry {
698 block: 1,
699 terms: Some(Terms {
700 cap: Some(1),
701 amount: Some(1000),
702 offset: (Some(1), None),
703 ..default()
704 }),
705 mints: 0,
706 ..default()
707 }
708 .mintable(2),
709 Ok(1000),
710 );
711 }
712
713 #[test]
714 fn mintable_offset_end() {
715 assert_eq!(
716 RuneEntry {
717 block: 1,
718 terms: Some(Terms {
719 cap: Some(1),
720 amount: Some(1000),
721 offset: (None, Some(1)),
722 ..default()
723 }),
724 mints: 0,
725 ..default()
726 }
727 .mintable(1),
728 Ok(1000),
729 );
730
731 assert_eq!(
732 RuneEntry {
733 block: 1,
734 terms: Some(Terms {
735 cap: Some(1),
736 amount: Some(1000),
737 offset: (None, Some(1)),
738 ..default()
739 }),
740 mints: 0,
741 ..default()
742 }
743 .mintable(2),
744 Err(MintError::End(2)),
745 );
746 }
747
748 #[test]
749 fn mintable_height_start() {
750 assert_eq!(
751 RuneEntry {
752 terms: Some(Terms {
753 cap: Some(1),
754 amount: Some(1000),
755 height: (Some(1), None),
756 ..default()
757 }),
758 mints: 0,
759 ..default()
760 }
761 .mintable(0),
762 Err(MintError::Start(1)),
763 );
764
765 assert_eq!(
766 RuneEntry {
767 terms: Some(Terms {
768 cap: Some(1),
769 amount: Some(1000),
770 height: (Some(1), None),
771 ..default()
772 }),
773 mints: 0,
774 ..default()
775 }
776 .mintable(1),
777 Ok(1000),
778 );
779 }
780
781 #[test]
782 fn mintable_height_end() {
783 assert_eq!(
784 RuneEntry {
785 terms: Some(Terms {
786 cap: Some(1),
787 amount: Some(1000),
788 height: (None, Some(1)),
789 ..default()
790 }),
791 mints: 0,
792 ..default()
793 }
794 .mintable(0),
795 Ok(1000),
796 );
797
798 assert_eq!(
799 RuneEntry {
800 terms: Some(Terms {
801 cap: Some(1),
802 amount: Some(1000),
803 height: (None, Some(1)),
804 ..default()
805 }),
806 mints: 0,
807 ..default()
808 }
809 .mintable(1),
810 Err(MintError::End(1)),
811 );
812 }
813
814 #[test]
815 fn mintable_multiple_terms() {
816 let entry = RuneEntry {
817 terms: Some(Terms {
818 cap: Some(1),
819 amount: Some(1000),
820 height: (Some(10), Some(20)),
821 offset: (Some(0), Some(10)),
822 }),
823 block: 10,
824 mints: 0,
825 ..default()
826 };
827
828 assert_eq!(entry.mintable(10), Ok(1000));
829
830 {
831 let mut entry = entry;
832 entry.terms.as_mut().unwrap().cap = None;
833 assert_eq!(entry.mintable(10), Err(MintError::Cap(0)));
834 }
835
836 {
837 let mut entry = entry;
838 entry.terms.as_mut().unwrap().height.0 = Some(11);
839 assert_eq!(entry.mintable(10), Err(MintError::Start(11)));
840 }
841
842 {
843 let mut entry = entry;
844 entry.terms.as_mut().unwrap().height.1 = Some(10);
845 assert_eq!(entry.mintable(10), Err(MintError::End(10)));
846 }
847
848 {
849 let mut entry = entry;
850 entry.terms.as_mut().unwrap().offset.0 = Some(1);
851 assert_eq!(entry.mintable(10), Err(MintError::Start(11)));
852 }
853
854 {
855 let mut entry = entry;
856 entry.terms.as_mut().unwrap().offset.1 = Some(0);
857 assert_eq!(entry.mintable(10), Err(MintError::End(10)));
858 }
859 }
860
861 #[test]
862 fn supply() {
863 assert_eq!(
864 RuneEntry {
865 terms: Some(Terms {
866 amount: Some(1000),
867 ..default()
868 }),
869 mints: 0,
870 ..default()
871 }
872 .supply(),
873 0
874 );
875
876 assert_eq!(
877 RuneEntry {
878 terms: Some(Terms {
879 amount: Some(1000),
880 ..default()
881 }),
882 mints: 1,
883 ..default()
884 }
885 .supply(),
886 1000
887 );
888
889 assert_eq!(
890 RuneEntry {
891 terms: Some(Terms {
892 amount: Some(1000),
893 ..default()
894 }),
895 mints: 0,
896 premine: 1,
897 ..default()
898 }
899 .supply(),
900 1
901 );
902
903 assert_eq!(
904 RuneEntry {
905 terms: Some(Terms {
906 amount: Some(1000),
907 ..default()
908 }),
909 mints: 1,
910 premine: 1,
911 ..default()
912 }
913 .supply(),
914 1001
915 );
916 }
917}