darkfi/blockchain/
mod.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::{
20    slice,
21    sync::{Arc, Mutex},
22};
23
24use darkfi_sdk::tx::TransactionHash;
25use darkfi_serial::{deserialize, Decodable};
26use sled_overlay::{
27    sled,
28    sled::{IVec, Transactional},
29};
30use tracing::debug;
31
32#[cfg(feature = "async-serial")]
33use darkfi_serial::{deserialize_async, AsyncDecodable};
34
35use crate::{tx::Transaction, util::time::Timestamp, Error, Result};
36
37/// Block related definitions and storage implementations
38pub mod block_store;
39pub use block_store::{
40    Block, BlockDifficulty, BlockInfo, BlockStore, BlockStoreOverlay, SLED_BLOCK_DIFFICULTY_TREE,
41    SLED_BLOCK_ORDER_TREE, SLED_BLOCK_STATE_INVERSE_DIFF_TREE, SLED_BLOCK_TREE,
42};
43
44/// Header definition and storage implementation
45pub mod header_store;
46pub use header_store::{
47    Header, HeaderHash, HeaderStore, HeaderStoreOverlay, SLED_HEADER_TREE, SLED_SYNC_HEADER_TREE,
48};
49
50/// Transactions related storage implementations
51pub mod tx_store;
52pub use tx_store::{
53    TxStore, TxStoreOverlay, SLED_PENDING_TX_TREE, SLED_TX_LOCATION_TREE, SLED_TX_TREE,
54};
55
56/// Contracts and Wasm storage implementations
57pub mod contract_store;
58pub use contract_store::{
59    ContractStore, ContractStoreOverlay, SLED_BINCODE_TREE, SLED_CONTRACTS_TREE,
60    SLED_CONTRACTS_TREES_TREE,
61};
62
63/// Monero definitions needed for merge mining
64pub mod monero;
65
66/// Structure holding all sled trees that define the concept of Blockchain.
67#[derive(Clone)]
68pub struct Blockchain {
69    /// Main pointer to the sled db connection
70    pub sled_db: sled::Db,
71    /// Headers sled tree
72    pub headers: HeaderStore,
73    /// Blocks sled tree
74    pub blocks: BlockStore,
75    /// Transactions related sled trees
76    pub transactions: TxStore,
77    /// Contracts related sled trees
78    pub contracts: ContractStore,
79}
80
81impl Blockchain {
82    /// Instantiate a new `Blockchain` with the given `sled` database.
83    pub fn new(db: &sled::Db) -> Result<Self> {
84        let headers = HeaderStore::new(db)?;
85        let blocks = BlockStore::new(db)?;
86        let transactions = TxStore::new(db)?;
87        let contracts = ContractStore::new(db)?;
88
89        Ok(Self { sled_db: db.clone(), headers, blocks, transactions, contracts })
90    }
91
92    /// Insert a given [`BlockInfo`] into the blockchain database.
93    /// This functions wraps all the logic of separating the block into specific
94    /// data that can be fed into the different trees of the database.
95    /// Upon success, the functions returns the block hash that
96    /// were given and appended to the ledger.
97    pub fn add_block(&self, block: &BlockInfo) -> Result<HeaderHash> {
98        let mut trees = vec![];
99        let mut batches = vec![];
100
101        // Store header
102        let (headers_batch, _) = self.headers.insert_batch(slice::from_ref(&block.header));
103        trees.push(self.headers.main.clone());
104        batches.push(headers_batch);
105
106        // Store block
107        let blk: Block = Block::from_block_info(block);
108        let (bocks_batch, block_hashes) = self.blocks.insert_batch(&[blk]);
109        let block_hash = block_hashes[0];
110        let block_hash_vec = [block_hash];
111        trees.push(self.blocks.main.clone());
112        batches.push(bocks_batch);
113
114        // Store block order
115        let blocks_order_batch =
116            self.blocks.insert_batch_order(&[block.header.height], &block_hash_vec);
117        trees.push(self.blocks.order.clone());
118        batches.push(blocks_order_batch);
119
120        // Store transactions
121        let (txs_batch, txs_hashes) = self.transactions.insert_batch(&block.txs);
122        trees.push(self.transactions.main.clone());
123        batches.push(txs_batch);
124
125        // Store transactions_locations
126        let txs_locations_batch =
127            self.transactions.insert_batch_location(&txs_hashes, block.header.height);
128        trees.push(self.transactions.location.clone());
129        batches.push(txs_locations_batch);
130
131        // Perform an atomic transaction over the trees and apply the batches.
132        self.atomic_write(&trees, &batches)?;
133
134        Ok(block_hash)
135    }
136
137    /// Check if the given [`BlockInfo`] is in the database and all trees.
138    pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
139        let blockhash = match self.blocks.get_order(&[block.header.height], true) {
140            Ok(v) => v[0].unwrap(),
141            Err(_) => return Ok(false),
142        };
143
144        // Check if we have all transactions
145        let txs: Vec<TransactionHash> = block.txs.iter().map(|tx| tx.hash()).collect();
146        if self.transactions.get(&txs, true).is_err() {
147            return Ok(false)
148        }
149
150        // Check provided info produces the same hash
151        Ok(blockhash == block.hash())
152    }
153
154    /// Retrieve [`BlockInfo`]s by given hashes. Fails if any of them is not found.
155    pub fn get_blocks_by_hash(&self, hashes: &[HeaderHash]) -> Result<Vec<BlockInfo>> {
156        let blocks = self.blocks.get(hashes, true)?;
157        let blocks: Vec<Block> = blocks.iter().map(|x| x.clone().unwrap()).collect();
158        let ret = self.get_blocks_infos(&blocks)?;
159
160        Ok(ret)
161    }
162
163    /// Retrieve all [`BlockInfo`] for given slice of [`Block`].
164    /// Fails if any of them is not found
165    fn get_blocks_infos(&self, blocks: &[Block]) -> Result<Vec<BlockInfo>> {
166        let mut ret = Vec::with_capacity(blocks.len());
167        for block in blocks {
168            let headers = self.headers.get(&[block.header], true)?;
169            // Since we used strict get, its safe to unwrap here
170            let header = headers[0].clone().unwrap();
171
172            let txs = self.transactions.get(&block.txs, true)?;
173            let txs = txs.iter().map(|x| x.clone().unwrap()).collect();
174
175            let info = BlockInfo::new(header, txs, block.signature);
176            ret.push(info);
177        }
178
179        Ok(ret)
180    }
181
182    /// Retrieve [`BlockInfo`]s by given heights. Does not fail if any of them are not found.
183    pub fn get_blocks_by_heights(&self, heights: &[u32]) -> Result<Vec<BlockInfo>> {
184        debug!(target: "blockchain", "get_blocks_by_heights(): {heights:?}");
185        let blockhashes = self.blocks.get_order(heights, false)?;
186
187        let mut hashes = vec![];
188        for i in blockhashes.into_iter().flatten() {
189            hashes.push(i);
190        }
191
192        self.get_blocks_by_hash(&hashes)
193    }
194
195    /// Retrieve [`Header`]s by given hashes. Fails if any of them is not found.
196    pub fn get_headers_by_hash(&self, hashes: &[HeaderHash]) -> Result<Vec<Header>> {
197        let headers = self.headers.get(hashes, true)?;
198        let ret: Vec<Header> = headers.iter().map(|x| x.clone().unwrap()).collect();
199
200        Ok(ret)
201    }
202
203    /// Retrieve [`Header`]s by given heights. Fails if any of them is not found.
204    pub fn get_headers_by_heights(&self, heights: &[u32]) -> Result<Vec<Header>> {
205        debug!(target: "blockchain", "get_headers_by_heights(): {heights:?}");
206        let blockhashes = self.blocks.get_order(heights, true)?;
207
208        let mut hashes = vec![];
209        for i in blockhashes.into_iter().flatten() {
210            hashes.push(i);
211        }
212
213        self.get_headers_by_hash(&hashes)
214    }
215
216    /// Retrieve n headers before given block height.
217    pub fn get_headers_before(&self, height: u32, n: usize) -> Result<Vec<Header>> {
218        debug!(target: "blockchain", "get_headers_before(): {height} -> {n}");
219        let hashes = self.blocks.get_before(height, n)?;
220        let headers = self.headers.get(&hashes, true)?;
221        Ok(headers.iter().map(|h| h.clone().unwrap()).collect())
222    }
223
224    /// Retrieve stored blocks count
225    pub fn len(&self) -> usize {
226        self.blocks.len()
227    }
228
229    /// Retrieve stored txs count
230    pub fn txs_len(&self) -> usize {
231        self.transactions.len()
232    }
233
234    /// Check if blockchain contains any blocks
235    pub fn is_empty(&self) -> bool {
236        self.blocks.is_empty()
237    }
238
239    /// Retrieve genesis (first) block height and hash.
240    pub fn genesis(&self) -> Result<(u32, HeaderHash)> {
241        self.blocks.get_first()
242    }
243
244    /// Retrieve genesis (first) block info.
245    pub fn genesis_block(&self) -> Result<BlockInfo> {
246        let (_, hash) = self.genesis()?;
247        Ok(self.get_blocks_by_hash(&[hash])?[0].clone())
248    }
249
250    /// Retrieve the last block height and hash.
251    pub fn last(&self) -> Result<(u32, HeaderHash)> {
252        self.blocks.get_last()
253    }
254
255    /// Retrieve the last block header.
256    pub fn last_header(&self) -> Result<Header> {
257        let (_, hash) = self.last()?;
258        Ok(self.headers.get(&[hash], true)?[0].clone().unwrap())
259    }
260
261    /// Retrieve the last block info.
262    pub fn last_block(&self) -> Result<BlockInfo> {
263        let (_, hash) = self.last()?;
264        Ok(self.get_blocks_by_hash(&[hash])?[0].clone())
265    }
266
267    /// Retrieve the last block difficulty. If the tree is empty,
268    /// returns `BlockDifficulty::genesis` difficulty.
269    pub fn last_block_difficulty(&self) -> Result<BlockDifficulty> {
270        if let Some(found) = self.blocks.get_last_difficulty()? {
271            return Ok(found)
272        }
273
274        let genesis_block = self.genesis_block()?;
275        Ok(BlockDifficulty::genesis(genesis_block.header.timestamp))
276    }
277
278    /// Check if block order for the given height is in the database.
279    pub fn has_height(&self, height: u32) -> Result<bool> {
280        let vec = match self.blocks.get_order(&[height], true) {
281            Ok(v) => v,
282            Err(_) => return Ok(false),
283        };
284        Ok(!vec.is_empty())
285    }
286
287    /// Insert a given slice of pending transactions into the blockchain database.
288    /// On success, the function returns the transaction hashes in the same order
289    /// as the input transactions.
290    pub fn add_pending_txs(&self, txs: &[Transaction]) -> Result<Vec<TransactionHash>> {
291        self.transactions.insert_pending(txs)
292    }
293
294    /// Retrieve all transactions from the pending tx store.
295    /// Be careful as this will try to load everything in memory.
296    pub fn get_pending_txs(&self) -> Result<Vec<Transaction>> {
297        let txs = self.transactions.get_all_pending()?;
298
299        let mut ret = Vec::with_capacity(txs.len());
300        for (_, tx) in txs {
301            ret.push(tx);
302        }
303
304        Ok(ret)
305    }
306
307    /// Remove a given slice of pending transactions from the blockchain database.
308    pub fn remove_pending_txs(&self, txs: &[Transaction]) -> Result<()> {
309        let txs_hashes: Vec<TransactionHash> = txs.iter().map(|tx| tx.hash()).collect();
310        self.remove_pending_txs_hashes(&txs_hashes)
311    }
312
313    /// Remove a given slice of pending transactions hashes from the blockchain database.
314    pub fn remove_pending_txs_hashes(&self, txs: &[TransactionHash]) -> Result<()> {
315        self.transactions.remove_pending(txs)
316    }
317
318    /// Auxiliary function to write to multiple trees completely atomic.
319    fn atomic_write(&self, trees: &[sled::Tree], batches: &[sled::Batch]) -> Result<()> {
320        if trees.len() != batches.len() {
321            return Err(Error::InvalidInputLengths)
322        }
323
324        trees.transaction(|trees| {
325            for (index, tree) in trees.iter().enumerate() {
326                tree.apply_batch(&batches[index])?;
327            }
328
329            Ok::<(), sled::transaction::ConflictableTransactionError<sled::Error>>(())
330        })?;
331
332        Ok(())
333    }
334
335    /// Retrieve all blocks contained in the blockchain in order.
336    /// Be careful as this will try to load everything in memory.
337    pub fn get_all(&self) -> Result<Vec<BlockInfo>> {
338        let order = self.blocks.get_all_order()?;
339        let order: Vec<HeaderHash> = order.iter().map(|x| x.1).collect();
340        let blocks = self.get_blocks_by_hash(&order)?;
341
342        Ok(blocks)
343    }
344
345    /// Retrieve [`BlockInfo`]s by given heights range.
346    pub fn get_by_range(&self, start: u32, end: u32) -> Result<Vec<BlockInfo>> {
347        let blockhashes = self.blocks.get_order_by_range(start, end)?;
348        let hashes: Vec<HeaderHash> = blockhashes.into_iter().map(|(_, hash)| hash).collect();
349        self.get_blocks_by_hash(&hashes)
350    }
351
352    /// Retrieve last 'N' [`BlockInfo`]s from the blockchain.
353    pub fn get_last_n(&self, n: usize) -> Result<Vec<BlockInfo>> {
354        let records = self.blocks.get_last_n_orders(n)?;
355
356        let mut last_n = vec![];
357        for record in records {
358            let header_hash = record.1;
359            let blocks = self.get_blocks_by_hash(&[header_hash])?;
360            for block in blocks {
361                last_n.push(block.clone());
362            }
363        }
364
365        Ok(last_n)
366    }
367
368    /// Auxiliary function to reset the blockchain and consensus state
369    /// to the provided block height.
370    pub fn reset_to_height(&self, height: u32) -> Result<()> {
371        // First we grab the last block height
372        let (last, _) = self.last()?;
373
374        // Check if request height is after our last height
375        if height >= last {
376            return Ok(())
377        }
378
379        // Grab all state inverse diffs until requested height,
380        // going backwards.
381        let heights: Vec<u32> = (height + 1..=last).rev().collect();
382        let inverse_diffs = self.blocks.get_state_inverse_diff(&heights, true)?;
383
384        // Create an overlay to apply the reverse diffs
385        let overlay = BlockchainOverlay::new(self)?;
386
387        // Apply the inverse diffs sequence
388        let overlay_lock = overlay.lock().unwrap();
389        let mut lock = overlay_lock.overlay.lock().unwrap();
390        for inverse_diff in inverse_diffs {
391            // Since we used strict retrieval it's safe to unwrap here
392            let inverse_diff = inverse_diff.unwrap();
393            lock.add_diff(&inverse_diff)?;
394            lock.apply_diff(&inverse_diff)?;
395            self.sled_db.flush()?;
396        }
397        drop(lock);
398        drop(overlay_lock);
399
400        Ok(())
401    }
402
403    /// Grab the RandomX VM current and next key, based on provided key
404    /// changing height and delay. Optionally, a height can be provided
405    /// to get the keys before it.
406    ///
407    /// NOTE: the height calculation logic is verified using test:
408    //        test_randomx_keys_retrieval_logic
409    pub fn get_randomx_vm_keys(
410        &self,
411        key_change_height: &u32,
412        key_change_delay: &u32,
413        height: Option<u32>,
414    ) -> Result<(HeaderHash, Option<HeaderHash>)> {
415        // Grab last known block header
416        let last = match height {
417            Some(h) => &self.get_headers_by_heights(&[if h != 0 { h - 1 } else { 0 }])?[0],
418            None => &self.last_header()?,
419        };
420
421        // Check if we passed the first key change height
422        if &last.height <= key_change_height {
423            // Genesis is our current
424            let current = self.genesis()?.1;
425
426            // Check if last known block header is the next key
427            let next = if &last.height == key_change_height { Some(last.hash()) } else { None };
428
429            return Ok((current, next))
430        }
431
432        // Find the current and next key based on distance of last
433        // known block header height from the key change height.
434        let distance = last.height % key_change_height;
435
436        // When distance is 0, current key is the block header
437        // located at last_height - key_change_height height, while
438        // last known block header is the next key.
439        if distance == 0 {
440            return Ok((
441                self.get_headers_by_heights(&[last.height - key_change_height])?[0].hash(),
442                Some(last.hash()),
443            ))
444        }
445
446        // When distance is less than key change delay, current key
447        // is the block header located at last_height - (distance + key_change_height)
448        // height, while the block header located at last_height - distance
449        // height is the next key.
450        if &distance < key_change_delay {
451            return Ok((
452                self.get_headers_by_heights(&[last.height - (distance + key_change_height)])?[0]
453                    .hash(),
454                Some(self.get_headers_by_heights(&[last.height - distance])?[0].hash()),
455            ))
456        }
457
458        // When distance is greater or equal to key change delay,
459        // current key is the block header located at last_height - distance
460        // height and we don't know the next key.
461        let current = self.get_headers_by_heights(&[last.height - distance])?[0].hash();
462        Ok((current, None))
463    }
464}
465
466/// Atomic pointer to sled db overlay.
467pub type SledDbOverlayPtr = Arc<Mutex<sled_overlay::SledDbOverlay>>;
468
469/// Atomic pointer to blockchain overlay.
470pub type BlockchainOverlayPtr = Arc<Mutex<BlockchainOverlay>>;
471
472/// Overlay structure over a [`Blockchain`] instance.
473pub struct BlockchainOverlay {
474    /// Main [`sled_overlay::SledDbOverlay`] to the sled db connection
475    pub overlay: SledDbOverlayPtr,
476    /// Headers overlay
477    pub headers: HeaderStoreOverlay,
478    /// Blocks overlay
479    pub blocks: BlockStoreOverlay,
480    /// Transactions overlay
481    pub transactions: TxStoreOverlay,
482    /// Contract overlay
483    pub contracts: ContractStoreOverlay,
484}
485
486impl BlockchainOverlay {
487    /// Instantiate a new `BlockchainOverlay` over the given [`Blockchain`] instance.
488    pub fn new(blockchain: &Blockchain) -> Result<BlockchainOverlayPtr> {
489        // Here we configure all our blockchain sled trees to be protected in the overlay
490        let protected_trees = vec![
491            SLED_BLOCK_TREE,
492            SLED_BLOCK_ORDER_TREE,
493            SLED_BLOCK_DIFFICULTY_TREE,
494            SLED_BLOCK_STATE_INVERSE_DIFF_TREE,
495            SLED_HEADER_TREE,
496            SLED_SYNC_HEADER_TREE,
497            SLED_TX_TREE,
498            SLED_TX_LOCATION_TREE,
499            SLED_PENDING_TX_TREE,
500            SLED_CONTRACTS_TREE,
501            SLED_CONTRACTS_TREES_TREE,
502            SLED_BINCODE_TREE,
503        ];
504        let overlay = Arc::new(Mutex::new(sled_overlay::SledDbOverlay::new(
505            &blockchain.sled_db,
506            protected_trees,
507        )));
508        let headers = HeaderStoreOverlay::new(&overlay)?;
509        let blocks = BlockStoreOverlay::new(&overlay)?;
510        let transactions = TxStoreOverlay::new(&overlay)?;
511        let contracts = ContractStoreOverlay::new(&overlay)?;
512
513        Ok(Arc::new(Mutex::new(Self { overlay, headers, blocks, transactions, contracts })))
514    }
515
516    /// Check if blockchain contains any blocks
517    pub fn is_empty(&self) -> Result<bool> {
518        self.blocks.is_empty()
519    }
520
521    /// Retrieve the last block height and hash.
522    pub fn last(&self) -> Result<(u32, HeaderHash)> {
523        self.blocks.get_last()
524    }
525
526    /// Retrieve the last block info.
527    pub fn last_block(&self) -> Result<BlockInfo> {
528        let (_, hash) = self.last()?;
529        Ok(self.get_blocks_by_hash(&[hash])?[0].clone())
530    }
531
532    /// Retrieve the last block height.
533    pub fn last_block_height(&self) -> Result<u32> {
534        Ok(self.last()?.0)
535    }
536
537    /// Retrieve the last block timestamp.
538    pub fn last_block_timestamp(&self) -> Result<Timestamp> {
539        let (_, hash) = self.last()?;
540        Ok(self.get_blocks_by_hash(&[hash])?[0].header.timestamp)
541    }
542
543    /// Insert a given [`BlockInfo`] into the overlay.
544    /// This functions wraps all the logic of separating the block into specific
545    /// data that can be fed into the different trees of the overlay.
546    /// Upon success, the functions returns the block hash that
547    /// were given and appended to the overlay.
548    /// Since we are adding to the overlay, we don't need to exeucte
549    /// the writes atomically.
550    pub fn add_block(&self, block: &BlockInfo) -> Result<HeaderHash> {
551        // Store header
552        self.headers.insert(slice::from_ref(&block.header))?;
553
554        // Store block
555        let blk: Block = Block::from_block_info(block);
556        let txs_hashes = blk.txs.clone();
557        let block_hash = self.blocks.insert(&[blk])?[0];
558        let block_hash_vec = [block_hash];
559
560        // Store block order
561        self.blocks.insert_order(&[block.header.height], &block_hash_vec)?;
562
563        // Store transactions
564        self.transactions.insert(&block.txs)?;
565
566        // Store transactions locations
567        self.transactions.insert_location(&txs_hashes, block.header.height)?;
568
569        Ok(block_hash)
570    }
571
572    /// Check if the given [`BlockInfo`] is in the database and all trees.
573    pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
574        let blockhash = match self.blocks.get_order(&[block.header.height], true) {
575            Ok(v) => v[0].unwrap(),
576            Err(_) => return Ok(false),
577        };
578
579        // Check if we have all transactions
580        let txs: Vec<TransactionHash> = block.txs.iter().map(|tx| tx.hash()).collect();
581        if self.transactions.get(&txs, true).is_err() {
582            return Ok(false)
583        }
584
585        // Check provided info produces the same hash
586        Ok(blockhash == block.hash())
587    }
588
589    /// Retrieve [`Header`]s by given hashes. Fails if any of them is not found.
590    pub fn get_headers_by_hash(&self, hashes: &[HeaderHash]) -> Result<Vec<Header>> {
591        let headers = self.headers.get(hashes, true)?;
592        let ret: Vec<Header> = headers.iter().map(|x| x.clone().unwrap()).collect();
593
594        Ok(ret)
595    }
596
597    /// Retrieve [`BlockInfo`]s by given hashes. Fails if any of them is not found.
598    pub fn get_blocks_by_hash(&self, hashes: &[HeaderHash]) -> Result<Vec<BlockInfo>> {
599        let blocks = self.blocks.get(hashes, true)?;
600        let blocks: Vec<Block> = blocks.iter().map(|x| x.clone().unwrap()).collect();
601        let ret = self.get_blocks_infos(&blocks)?;
602
603        Ok(ret)
604    }
605
606    /// Retrieve all [`BlockInfo`] for given slice of [`Block`].
607    /// Fails if any of them is not found
608    fn get_blocks_infos(&self, blocks: &[Block]) -> Result<Vec<BlockInfo>> {
609        let mut ret = Vec::with_capacity(blocks.len());
610        for block in blocks {
611            let headers = self.headers.get(&[block.header], true)?;
612            // Since we used strict get, its safe to unwrap here
613            let header = headers[0].clone().unwrap();
614
615            let txs = self.transactions.get(&block.txs, true)?;
616            let txs = txs.iter().map(|x| x.clone().unwrap()).collect();
617
618            let info = BlockInfo::new(header, txs, block.signature);
619            ret.push(info);
620        }
621
622        Ok(ret)
623    }
624
625    /// Retrieve [`Block`]s by given hashes and return their transactions hashes.
626    pub fn get_blocks_txs_hashes(&self, hashes: &[HeaderHash]) -> Result<Vec<TransactionHash>> {
627        let blocks = self.blocks.get(hashes, true)?;
628        let mut ret = vec![];
629        for block in blocks {
630            ret.extend_from_slice(&block.unwrap().txs);
631        }
632
633        Ok(ret)
634    }
635
636    /// Checkpoint overlay so we can revert to it, if needed.
637    pub fn checkpoint(&self) {
638        self.overlay.lock().unwrap().checkpoint();
639    }
640
641    /// Revert to current overlay checkpoint.
642    pub fn revert_to_checkpoint(&self) {
643        self.overlay.lock().unwrap().revert_to_checkpoint();
644    }
645
646    /// Auxiliary function to create a full clone using SledDbOverlay::clone,
647    /// generating new pointers for the underlying overlays.
648    pub fn full_clone(&self) -> Result<BlockchainOverlayPtr> {
649        let overlay = Arc::new(Mutex::new(self.overlay.lock().unwrap().clone()));
650        let headers = HeaderStoreOverlay::new(&overlay)?;
651        let blocks = BlockStoreOverlay::new(&overlay)?;
652        let transactions = TxStoreOverlay::new(&overlay)?;
653        let contracts = ContractStoreOverlay::new(&overlay)?;
654
655        Ok(Arc::new(Mutex::new(Self { overlay, headers, blocks, transactions, contracts })))
656    }
657}
658
659/// Parse a sled record in the form of a tuple (`key`, `value`).
660pub fn parse_record<T1: Decodable, T2: Decodable>(record: (IVec, IVec)) -> Result<(T1, T2)> {
661    let key = deserialize(&record.0)?;
662    let value = deserialize(&record.1)?;
663
664    Ok((key, value))
665}
666
667/// Parse a sled record with a u32 key, encoded in Big Endian bytes,
668/// in the form of a tuple (`key`, `value`).
669pub fn parse_u32_key_record<T: Decodable>(record: (IVec, IVec)) -> Result<(u32, T)> {
670    let key_bytes: [u8; 4] = record.0.as_ref().try_into().unwrap();
671    let key = u32::from_be_bytes(key_bytes);
672    let value = deserialize(&record.1)?;
673
674    Ok((key, value))
675}
676
677/// Parse a sled record with a u64 key, encoded in Big Endian bytes,
678/// in the form of a tuple (`key`, `value`).
679pub fn parse_u64_key_record<T: Decodable>(record: (IVec, IVec)) -> Result<(u64, T)> {
680    let key_bytes: [u8; 8] = record.0.as_ref().try_into().unwrap();
681    let key = u64::from_be_bytes(key_bytes);
682    let value = deserialize(&record.1)?;
683
684    Ok((key, value))
685}
686
687#[cfg(feature = "async-serial")]
688/// Parse a sled record in the form of a tuple (`key`, `value`).
689pub async fn parse_record_async<T1: AsyncDecodable, T2: AsyncDecodable>(
690    record: (IVec, IVec),
691) -> Result<(T1, T2)> {
692    let key = deserialize_async(&record.0).await?;
693    let value = deserialize_async(&record.1).await?;
694
695    Ok((key, value))
696}
697
698#[cfg(feature = "async-serial")]
699/// Parse a sled record with a u32 key, encoded in Big Endian bytes,
700/// in the form of a tuple (`key`, `value`).
701pub async fn parse_u32_key_record_async<T: AsyncDecodable>(
702    record: (IVec, IVec),
703) -> Result<(u32, T)> {
704    let key_bytes: [u8; 4] = record.0.as_ref().try_into().unwrap();
705    let key = u32::from_be_bytes(key_bytes);
706    let value = deserialize_async(&record.1).await?;
707
708    Ok((key, value))
709}
710
711#[cfg(feature = "async-serial")]
712/// Parse a sled record with a u64 key, encoded in Big Endian bytes,
713/// in the form of a tuple (`key`, `value`).
714pub async fn parse_u64_key_record_async<T: AsyncDecodable>(
715    record: (IVec, IVec),
716) -> Result<(u64, T)> {
717    let key_bytes: [u8; 8] = record.0.as_ref().try_into().unwrap();
718    let key = u64::from_be_bytes(key_bytes);
719    let value = deserialize_async(&record.1).await?;
720
721    Ok((key, value))
722}
723
724#[cfg(test)]
725mod tests {
726    use crate::validator::pow::{RANDOMX_KEY_CHANGE_DELAY, RANDOMX_KEY_CHANGING_HEIGHT};
727
728    /// Compute the RandomX VM current and next key heights, based on
729    /// provided key changing height and delay.
730    fn get_randomx_vm_keys_heights(last: u32) -> (u32, Option<u32>) {
731        // Check if we passed the first key change height
732        if last <= RANDOMX_KEY_CHANGING_HEIGHT {
733            // Genesis is our current
734            let current = 0;
735
736            // Check if last height is the next key height
737            let next = if last == RANDOMX_KEY_CHANGING_HEIGHT { Some(last) } else { None };
738
739            return (current, next)
740        }
741
742        // Find the current and next key based on distance of last
743        // height from the key change height.
744        let distance = last % RANDOMX_KEY_CHANGING_HEIGHT;
745
746        // When distance is 0, current key is the last_height - RANDOMX_KEY_CHANGING_HEIGHT
747        // height, while last is the next key.
748        if distance == 0 {
749            return (last - RANDOMX_KEY_CHANGING_HEIGHT, Some(last))
750        }
751
752        // When distance is less than key change delay, current key
753        // is the last_height - (distance + RANDOMX_KEY_CHANGING_HEIGHT) height,
754        // while the last_height - distance height is the next key.
755        if distance < RANDOMX_KEY_CHANGE_DELAY {
756            return (last - (distance + RANDOMX_KEY_CHANGING_HEIGHT), Some(last - distance))
757        }
758
759        // When distance is greater or equal to key change delay,
760        // current key is the last_height - distance height and we
761        // don't know the next key height.
762        let current = last - distance;
763        (current, None)
764    }
765
766    #[test]
767    fn test_randomx_keys_retrieval_logic() {
768        // last < RANDOMX_KEY_CHANGING_HEIGHT(2048)
769        let (current, next) = get_randomx_vm_keys_heights(2047);
770        assert_eq!(current, 0);
771        assert!(next.is_none());
772
773        // last == RANDOMX_KEY_CHANGING_HEIGHT(2048)
774        let (current, next) = get_randomx_vm_keys_heights(2048);
775        assert_eq!(current, 0);
776        assert_eq!(next, Some(2048));
777
778        // last > RANDOMX_KEY_CHANGING_HEIGHT(2048)
779        // last % RANDOMX_KEY_CHANGING_HEIGHT(2048) == 0
780        let (current, next) = get_randomx_vm_keys_heights(4096);
781        assert_eq!(current, 2048);
782        assert_eq!(next, Some(4096));
783
784        // last % RANDOMX_KEY_CHANGING_HEIGHT(2048) < RANDOMX_KEY_CHANGE_DELAY(64)
785        let (current, next) = get_randomx_vm_keys_heights(4097);
786        assert_eq!(current, 2048);
787        assert_eq!(next, Some(4096));
788
789        // last % RANDOMX_KEY_CHANGING_HEIGHT(2048) == RANDOMX_KEY_CHANGE_DELAY(64)
790        let (current, next) = get_randomx_vm_keys_heights(4160);
791        assert_eq!(current, 4096);
792        assert!(next.is_none());
793
794        // last % RANDOMX_KEY_CHANGING_HEIGHT(2048) > RANDOMX_KEY_CHANGE_DELAY(64)
795        let (current, next) = get_randomx_vm_keys_heights(4161);
796        assert_eq!(current, 4096);
797        assert!(next.is_none());
798    }
799}