1pub mod read;
2pub mod write;
3
4mod ledger_config;
5use ark_ff::fields::arithmetic::InvalidBigInt;
6pub use ledger_config::*;
7
8mod ledger_event;
9pub use ledger_event::*;
10
11mod ledger_actions;
12pub use ledger_actions::*;
13
14mod ledger_state;
15pub use ledger_state::*;
16
17mod ledger_reducer;
18
19mod ledger_service;
20pub use ledger_service::*;
21
22pub mod ledger_manager;
23
24pub use ledger::{AccountIndex as LedgerAccountIndex, Address as LedgerAddress};
25pub use ledger_manager::LedgerManager;
26
27use ledger::TreeVersion;
28use mina_p2p_messages::v2;
29
30pub const LEDGER_DEPTH: usize =
32 crate::core::network::mainnet::CONSTRAINT_CONSTANTS.ledger_depth as usize;
33
34lazy_static::lazy_static! {
35 static ref LEDGER_HASH_EMPTIES: [v2::LedgerHash; LEDGER_DEPTH + 1] = {
37 use ledger::TreeVersion;
38
39 std::array::from_fn(|i| {
40 let hash = ledger::V2::empty_hash_at_height(LEDGER_DEPTH.saturating_sub(i));
41 v2::MinaBaseLedgerHash0StableV1(hash.into()).into()
42 })
43 };
44}
45
46pub fn ledger_empty_hash_at_depth(depth: usize) -> v2::LedgerHash {
47 LEDGER_HASH_EMPTIES.get(depth).unwrap().clone()
48}
49
50pub fn complete_height_tree_with_empties(
54 content_hash: &v2::LedgerHash,
55 subtree_height: usize,
56) -> Result<v2::LedgerHash, InvalidBigInt> {
57 assert!(LEDGER_DEPTH >= subtree_height);
58 let content_hash = content_hash.0.to_field()?;
59
60 let computed_hash = (subtree_height..LEDGER_DEPTH).fold(content_hash, |prev_hash, height| {
61 let depth = LEDGER_DEPTH.saturating_sub(height);
62 let empty_right = ledger_empty_hash_at_depth(depth).0.to_field().unwrap(); ledger::V2::hash_node(height, prev_hash, empty_right)
64 });
65
66 Ok(v2::LedgerHash::from_fp(computed_hash))
67}
68
69pub fn tree_height_for_num_accounts(num_accounts: u64) -> usize {
71 if num_accounts == 1 {
72 1
73 } else if num_accounts.is_power_of_two() {
74 num_accounts.ilog2() as usize
75 } else {
76 num_accounts.next_power_of_two().ilog2() as usize
77 }
78}
79
80pub fn complete_num_accounts_tree_with_empties(
86 contents_hash: &v2::LedgerHash,
87 num_accounts: u64,
88) -> Result<v2::LedgerHash, InvalidBigInt> {
89 if num_accounts == 0 {
91 return Ok(ledger_empty_hash_at_depth(0));
92 }
93
94 let subtree_height = tree_height_for_num_accounts(num_accounts);
95
96 if subtree_height > LEDGER_DEPTH {
98 Ok(ledger_empty_hash_at_depth(0))
99 } else {
100 complete_height_tree_with_empties(contents_hash, subtree_height)
101 }
102}
103
104pub fn hash_node_at_depth(
105 depth: usize,
106 left: mina_curves::pasta::Fp,
107 right: mina_curves::pasta::Fp,
108) -> mina_curves::pasta::Fp {
109 let height = LEDGER_DEPTH.saturating_sub(depth).saturating_sub(1);
110 ledger::V2::hash_node(height, left, right)
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_complete_with_empties() {
119 let subtree_height = 14;
120 let expected_hash: v2::LedgerHash = "jwxdRe86RJV99CZbxZzb4JoDwEnvNQbc6Ha8iPx7pr3FxYpjHBG"
121 .parse()
122 .unwrap();
123 let contents_hash = "jwav4pBszibQqek634VUQEc5WZAbF3CnT7sMyhqXe3vucyXdjJs"
124 .parse()
125 .unwrap();
126
127 let actual_hash =
128 complete_height_tree_with_empties(&contents_hash, subtree_height).unwrap();
129
130 assert_eq!(expected_hash, actual_hash);
131 }
132
133 #[test]
134 fn test_complete_with_empties_with_num_accounts() {
135 let subtree_height = 8517;
136 let expected_hash: v2::LedgerHash = "jwxdRe86RJV99CZbxZzb4JoDwEnvNQbc6Ha8iPx7pr3FxYpjHBG"
137 .parse()
138 .unwrap();
139 let contents_hash = "jwav4pBszibQqek634VUQEc5WZAbF3CnT7sMyhqXe3vucyXdjJs"
140 .parse()
141 .unwrap();
142
143 let actual_hash =
144 complete_num_accounts_tree_with_empties(&contents_hash, subtree_height).unwrap();
145
146 assert_eq!(expected_hash, actual_hash);
147 }
148}