tycho_block_util/state/
shard_state_stuff.rs1use std::mem::ManuallyDrop;
2use std::sync::Arc;
3
4use anyhow::{Context, Result};
5use tycho_types::cell::Lazy;
6use tycho_types::merkle::MerkleUpdate;
7use tycho_types::models::*;
8use tycho_types::prelude::*;
9use tycho_util::FastHashSet;
10use tycho_util::mem::Reclaimer;
11
12use crate::dict::split_aug_dict_raw;
13use crate::state::RefMcStateHandle;
14
15#[derive(Clone)]
17#[repr(transparent)]
18pub struct ShardStateStuff {
19 inner: Arc<Inner>,
20}
21
22impl ShardStateStuff {
23 pub fn construct_split_root(left: Cell, right: Cell) -> Result<Cell> {
24 CellBuilder::build_from(ShardStateSplit {
25 left: Lazy::from_raw(left)?,
26 right: Lazy::from_raw(right)?,
27 })
28 .map_err(From::from)
29 }
30
31 pub fn from_root(block_id: &BlockId, root: Cell, handle: RefMcStateHandle) -> Result<Self> {
32 let shard_state = root.parse::<Box<ShardStateUnsplit>>()?;
33 Self::from_state_and_root(block_id, shard_state, root, handle)
34 }
35
36 pub fn from_state_and_root(
37 block_id: &BlockId,
38 shard_state: Box<ShardStateUnsplit>,
39 root: Cell,
40 handle: RefMcStateHandle,
41 ) -> Result<Self> {
42 anyhow::ensure!(
43 shard_state.shard_ident == block_id.shard,
44 "shard state shard_ident mismatch"
45 );
46
47 anyhow::ensure!(shard_state.seqno == block_id.seqno, "state seqno mismatch");
48
49 Ok(Self {
50 inner: Arc::new(Inner {
51 block_id: *block_id,
52 parts: ManuallyDrop::new(InnerParts {
53 shard_state_extra: shard_state.load_custom()?,
54 shard_state,
55 root,
56 handle,
57 }),
58 }),
59 })
60 }
61
62 pub fn block_id(&self) -> &BlockId {
63 &self.inner.block_id
64 }
65
66 pub fn state(&self) -> &ShardStateUnsplit {
67 &self.inner.shard_state
68 }
69
70 pub fn state_extra(&self) -> Result<&McStateExtra> {
71 let Some(extra) = self.inner.shard_state_extra.as_ref() else {
72 anyhow::bail!("given state is not a masterchain state");
73 };
74 Ok(extra)
75 }
76
77 pub fn ref_mc_state_handle(&self) -> &RefMcStateHandle {
78 &self.inner.handle
79 }
80
81 pub fn root_cell(&self) -> &Cell {
82 &self.inner.root
83 }
84
85 pub fn shards(&self) -> Result<&ShardHashes> {
86 Ok(&self.state_extra()?.shards)
87 }
88
89 pub fn config_params(&self) -> Result<&BlockchainConfig> {
90 Ok(&self.state_extra()?.config)
91 }
92
93 pub fn get_gen_chain_time(&self) -> u64 {
94 let state = self.state();
95 debug_assert!(state.gen_utime_ms < 1000);
96 state.gen_utime as u64 * 1000 + state.gen_utime_ms as u64
97 }
98
99 pub fn get_top_shards(&self) -> Result<Vec<ShardIdent>> {
100 let mut res = vec![self.block_id().shard];
101
102 for item in self.shards()?.latest_blocks() {
103 let block_id = item?;
104 res.push(block_id.shard);
105 }
106
107 Ok(res)
108 }
109
110 #[must_use = "this new state must be used to track cell usage"]
112 pub fn track_usage(&self, usage_mode: UsageTreeMode) -> Result<(UsageTree, Self)> {
113 let usage_tree = UsageTree::new(usage_mode);
114 let root = usage_tree.track(&Cell::untrack(self.inner.root.clone()));
115
116 let shard_state = root.parse::<Box<ShardStateUnsplit>>()?;
119
120 let shard_state = Self {
121 inner: Arc::new(Inner {
122 block_id: self.inner.block_id,
123 parts: ManuallyDrop::new(InnerParts {
124 shard_state_extra: shard_state.load_custom()?,
125 shard_state,
126 root,
127 handle: self.inner.handle.clone(),
128 }),
129 }),
130 };
131
132 Ok((usage_tree, shard_state))
133 }
134
135 pub fn par_make_next_state(
140 &self,
141 next_block_id: &BlockId,
142 merkle_update: &MerkleUpdate,
143 split_at_depth: Option<u8>,
144 ) -> Result<Self> {
145 let old_split_at = if let Some(depth) = split_at_depth {
146 let shard_accounts = self
147 .root_cell()
148 .reference_cloned(1)
149 .context("invalid shard state")?
150 .parse::<ShardAccounts>()
151 .context("failed to load shard accounts")?;
152
153 split_aug_dict_raw(shard_accounts, depth)
154 .context("failed to split shard accounts")?
155 .into_keys()
156 .collect::<FastHashSet<_>>()
157 } else {
158 Default::default()
159 };
160
161 let new_root = merkle_update
162 .par_apply(&self.inner.root, &old_split_at)
163 .context("failed to apply merkle update")?;
164
165 let shard_state = new_root.parse::<Box<ShardStateUnsplit>>()?;
166 anyhow::ensure!(
167 shard_state.shard_ident == next_block_id.shard,
168 "shard state shard_ident mismatch"
169 );
170 anyhow::ensure!(
171 shard_state.seqno == next_block_id.seqno,
172 "state seqno mismatch"
173 );
174
175 Ok(Self {
176 inner: Arc::new(Inner {
177 block_id: *next_block_id,
178 parts: ManuallyDrop::new(InnerParts {
179 shard_state_extra: shard_state.load_custom()?,
180 shard_state,
181 root: new_root,
182 handle: self.inner.handle.clone(),
183 }),
184 }),
185 })
186 }
187}
188
189impl AsRef<ShardStateUnsplit> for ShardStateStuff {
190 #[inline]
191 fn as_ref(&self) -> &ShardStateUnsplit {
192 &self.inner.shard_state
193 }
194}
195
196unsafe impl arc_swap::RefCnt for ShardStateStuff {
197 type Base = Inner;
198
199 fn into_ptr(me: Self) -> *mut Self::Base {
200 arc_swap::RefCnt::into_ptr(me.inner)
201 }
202
203 fn as_ptr(me: &Self) -> *mut Self::Base {
204 arc_swap::RefCnt::as_ptr(&me.inner)
205 }
206
207 unsafe fn from_ptr(ptr: *const Self::Base) -> Self {
208 Self {
209 inner: unsafe { arc_swap::RefCnt::from_ptr(ptr) },
210 }
211 }
212}
213
214#[doc(hidden)]
215pub struct Inner {
216 block_id: BlockId,
217 parts: ManuallyDrop<InnerParts>,
218}
219
220impl std::ops::Deref for Inner {
221 type Target = InnerParts;
222
223 #[inline]
224 fn deref(&self) -> &Self::Target {
225 &self.parts
226 }
227}
228
229impl Drop for Inner {
230 fn drop(&mut self) {
231 let parts = unsafe { ManuallyDrop::take(&mut self.parts) };
233 Reclaimer::instance().drop(parts);
234 }
235}
236
237#[doc(hidden)]
238pub struct InnerParts {
239 shard_state: Box<ShardStateUnsplit>,
240 shard_state_extra: Option<McStateExtra>,
241 root: Cell,
242 handle: RefMcStateHandle,
245}