dig_network_block/
body.rs1use crate::dig_l2_definition as definitions;
11use crate::emission::Emission;
12use serde::{Deserialize, Serialize};
13use thiserror::Error;
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
17pub struct L2BlockBody {
18 #[serde(with = "crate::serde_hex::hex_vec")]
20 pub data: Vec<u8>,
21 pub emissions: Vec<Emission>,
23}
24
25impl L2BlockBody {
26 pub fn calculate_data_root(&self) -> definitions::Hash32 {
29 let mut leaves: Vec<definitions::Hash32> = self
30 .data
31 .iter()
32 .map(|b| definitions::COMPUTE_DATA_HASH(*b))
33 .collect();
34 leaves.sort_unstable();
35 definitions::MERKLE_ROOT(&leaves)
36 }
37
38 pub fn calculate_emissions_root(&self) -> definitions::Hash32 {
41 let mut leaves: Vec<definitions::Hash32> =
42 self.emissions.iter().map(|e| e.calculate_root()).collect();
43 leaves.sort_unstable();
44 definitions::MERKLE_ROOT(&leaves)
45 }
46
47 pub fn calculate_root(&self) -> definitions::Hash32 {
49 let d = self.calculate_data_root();
50 let e = self.calculate_emissions_root();
51 definitions::COMPUTE_BODY_ROOT(&d, &e)
52 }
53}
54
55#[derive(Debug, Error)]
57pub enum BodyError {
58 #[error("body error: {0}")]
60 Generic(String),
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::emission::Emission;
67
68 #[test]
69 fn data_root_does_not_depend_on_input_order() {
70 let b1 = L2BlockBody {
71 data: vec![3, 1, 2],
72 emissions: vec![],
73 };
74 let b2 = L2BlockBody {
75 data: vec![2, 3, 1],
76 emissions: vec![],
77 };
78 assert_eq!(b1.calculate_data_root(), b2.calculate_data_root());
79 }
80
81 #[test]
82 fn emissions_root_does_not_depend_on_input_order() {
83 let e1 = Emission {
84 pubkey: [1u8; 48],
85 weight: 5,
86 };
87 let e2 = Emission {
88 pubkey: [2u8; 48],
89 weight: 5,
90 };
91 let e3 = Emission {
92 pubkey: [3u8; 48],
93 weight: 6,
94 };
95 let b1 = L2BlockBody {
96 data: vec![],
97 emissions: vec![e1.clone(), e2.clone(), e3.clone()],
98 };
99 let b2 = L2BlockBody {
100 data: vec![],
101 emissions: vec![e3, e1, e2],
102 };
103 assert_eq!(b1.calculate_emissions_root(), b2.calculate_emissions_root());
104 }
105
106 #[test]
107 fn body_root_changes_when_subroots_change() {
108 let e = Emission {
109 pubkey: [9u8; 48],
110 weight: 1,
111 };
112 let b1 = L2BlockBody {
113 data: vec![1, 2],
114 emissions: vec![e.clone()],
115 };
116 let b2 = L2BlockBody {
117 data: vec![1],
118 emissions: vec![e],
119 };
120 assert_ne!(b1.calculate_root(), b2.calculate_root());
121 }
122}