diff --git a/bin/darkfid2/src/tests/forks.rs b/bin/darkfid2/src/tests/forks.rs
new file mode 100644
index 000000000..591797c28
--- /dev/null
+++ b/bin/darkfid2/src/tests/forks.rs
@@ -0,0 +1,58 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+use darkfi::{blockchain::Blockchain, validator::consensus::Fork, Result};
+
+#[test]
+fn forks() -> Result<()> {
+ // Dummy records we will insert
+ let record0 = blake3::hash(b"Let there be dark!");
+ let record1 = blake3::hash(b"Never skip brain day.");
+
+ // Create a temporary blockchain
+ let blockchain = Blockchain::new(&sled::Config::new().temporary(true).open()?)?;
+
+ // Create a fork
+ let fork = Fork::new(&blockchain)?;
+
+ // Add a dummy record to fork
+ fork.overlay.lock().unwrap().order.insert(&[0], &[record0])?;
+
+ // Verify blockchain doesn't contain the record
+ assert_eq!(blockchain.order.get(&[0], false)?, [None]);
+ assert_eq!(fork.overlay.lock().unwrap().order.get(&[0], true)?, [Some(record0)]);
+
+ // Now we are going to clone the fork
+ let fork_clone = fork.full_clone()?;
+
+ // Verify it cointains the original record
+ assert_eq!(fork_clone.overlay.lock().unwrap().order.get(&[0], true)?, [Some(record0)]);
+
+ // Add another dummy record to cloned fork
+ fork_clone.overlay.lock().unwrap().order.insert(&[1], &[record1])?;
+
+ // Verify blockchain and original fork don't contain the record
+ assert_eq!(blockchain.order.get(&[0], false)?, [None]);
+ assert_eq!(fork.overlay.lock().unwrap().order.get(&[0, 1], false)?, [Some(record0), None]);
+ assert_eq!(
+ fork_clone.overlay.lock().unwrap().order.get(&[0, 1], true)?,
+ [Some(record0), Some(record1)]
+ );
+
+ Ok(())
+}
diff --git a/bin/darkfid2/src/tests/mod.rs b/bin/darkfid2/src/tests/mod.rs
index fde18e6f0..ce32ed782 100644
--- a/bin/darkfid2/src/tests/mod.rs
+++ b/bin/darkfid2/src/tests/mod.rs
@@ -25,6 +25,8 @@ use url::Url;
mod harness;
use harness::{generate_node, Harness, HarnessConfig};
+mod forks;
+
async fn sync_blocks_real(ex: Arc>) -> Result<()> {
init_logger();
diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs
index b7fbce605..c1a3529e4 100644
--- a/src/blockchain/mod.rs
+++ b/src/blockchain/mod.rs
@@ -540,6 +540,30 @@ impl BlockchainOverlay {
Ok(())
}
+
+ /// Auxiliary function to create a full clone using SledDbOverlay::clone,
+ /// and creating new pointers of underlying overlays.
+ pub fn full_clone(&self) -> Result {
+ let overlay = Arc::new(Mutex::new(self.overlay.lock().unwrap().clone()));
+ let headers = HeaderStoreOverlay::new(&overlay)?;
+ let blocks = BlockStoreOverlay::new(&overlay)?;
+ let order = BlockOrderStoreOverlay::new(&overlay)?;
+ let slots = SlotStoreOverlay::new(&overlay)?;
+ let transactions = TxStoreOverlay::new(&overlay)?;
+ let contracts = ContractStateStoreOverlay::new(&overlay)?;
+ let wasm_bincode = WasmStoreOverlay::new(&overlay)?;
+
+ Ok(Arc::new(Mutex::new(Self {
+ overlay,
+ headers,
+ blocks,
+ order,
+ slots,
+ transactions,
+ contracts,
+ wasm_bincode,
+ })))
+ }
}
/// Parse a sled record with a u64 keyin the form of a tuple (`key`, `value`).
diff --git a/src/validator/consensus/mod.rs b/src/validator/consensus/mod.rs
index 3e469ab89..966f84d58 100644
--- a/src/validator/consensus/mod.rs
+++ b/src/validator/consensus/mod.rs
@@ -95,6 +95,16 @@ impl Fork {
let overlay = BlockchainOverlay::new(blockchain)?;
Ok(Self { overlay, proposals: vec![] })
}
+
+ /// Auxiliary function to create a full clone using BlockchainOverlay::full_clone.
+ /// Changes to this clone don't affect original record, since underlying overlay
+ /// is cloned and pointers have been updated to the new one.
+ pub fn full_clone(&self) -> Result {
+ let overlay = self.overlay.lock().unwrap().full_clone()?;
+ let proposals = self.proposals.clone();
+
+ Ok(Self { overlay, proposals })
+ }
}
/// Block producer reward.