Repository: vinteumorg/Floresta
Pull request #215: Feat/enable backfill
Author: login: Davidson-Souza
Created: 2024-08-12T17:42:38Z | Merged: 2025-03-17T21:45:05Z



Diff:
diff --git a/README.md b/README.md
index 7e7327246..bb163f21d 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ For developers, detailed documentation for `libfloresta` is available [here](htt
   - [Building with Nix](#building-with-nix)
 - [Running](#running)
   - [Assume Utreexo](#assume-utreexo)
+  - [Backfill](#backfill)
   - [Compact Filters](#compact-filters)
   - [Getting Help](#getting-help)
   - [Wallet](#wallet)
@@ -70,7 +71,7 @@ git clone https://github.com/vinteumorg/Floresta.git
 go to the Floresta directory
 
 ```bash
-cd Floresta/
+$ cd Floresta/
 ```
 
 and build with cargo build
@@ -151,9 +152,9 @@ pkgs.floresta-node
 
 After building, florestad and floresta-cli will be available in the target directory. You can run the full node with
 ```bash
-./target/release/florestad
+$ ./target/release/florestad
 # or, if you installed it with cargo install
-florestad
+$ florestad
 ```
 
 You may run it as a background process with the `--daemon` flag.
@@ -165,20 +166,29 @@ florestad --daemon
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/vinteumorg/Floresta/blob/master/crates/floresta-cli/README.md).
 
 Before running you can create the SSL certificates. If you don't do it, it will display a logging `Failed to load SSL certificates, ignoring SSL`. However, it is not mandatory to have the certificates to run the full node.
 
-### Assume Utreexo
-If you want to skip the IBD process, you can use the `--assume-utreexo` flag. This flag will start the node at a given height, with the state
-provided by this implementation. Therefore, you're trusting that we are giving you the correct state. Everything after that height will be
-verified by the node just like any other node.
+#### Assume Utreexo
+
+If you want to start your node and get up and running quickly, you can use the Assume Utreexo feature. This is enabled by defalt, but you can disable it with the `--no-assume-utreexo` flag.
+
+```bash
+$ florestad --no-assume-utreexo
+```
+
+#### Backfill
+
+After the node starts it will validate everything in the background, downloading blocks from genesis to the assumed height, validating them and compare with the provided value. This way, you can start using the node right away, but still validate everything. This option, however, will take some time to complete, using a lot of CPU and bandwidth.
+
+This is the default behavior of the `florestad` if no flags are provided. You can disable it using:
 
 ```bash
-florestad --assume-utreexo
+$ florestad --no-backfill
 ```
 
 ### Compact Filters
@@ -186,7 +196,7 @@ florestad --assume-utreexo
 Floresta supports compact block filters, which can be used to scan for transactions in a block without downloading the entire block. You can start the node with the `--cfilters` flag to download the filters for the blocks that you're interested in. You can also use the `--filters-start-height` flag to specify the block height that you want to start downloading the filters from. This is useful if you want to download only the filters for a specific range of blocks.
 
 ```bash
-florestad --cfilters --filters-start-height 800000
+$ florestad --cfilters --filters-start-height 800000
 ```
 
 ### Getting Help
@@ -194,12 +204,12 @@ florestad --cfilters --filters-start-height 800000
 You can get a list of all the available commands by running
 
 ```bash
-floresta-cli help
+$ floresta-cli help
 ```
 
 and you can get the cli parameters by running
 ```bash
-floresta-cli help <command>
+$ floresta-cli help <command>
 ```
 
 ### Wallet
@@ -211,7 +221,7 @@ call the `rescan` rpc after adding the wallet.
 You can add new descriptors to the wallet with the `importdescriptor` rpc.
 
 ```bash
-floresta-cli importdescriptor "wpkh(xpub6CFy3kRXorC3NMTt8qrsY9ucUfxVLXyFQ49JSLm3iEG5gfAmWewYFzjNYFgRiCjoB9WWEuJQiyYGCdZvUTwPEUPL9pPabT8bkbiD9Po47XG/<0;1>/*)"
+$ floresta-cli importdescriptor "wpkh(xpub6CFy3kRXorC3NMTt8qrsY9ucUfxVLXyFQ49JSLm3iEG5gfAmWewYFzjNYFgRiCjoB9WWEuJQiyYGCdZvUTwPEUPL9pPabT8bkbiD9Po47XG/<0;1>/*)"
 ```
 
 The rescan assumes that you have compact block filters for the blocks that you're scanning. You can either download all the filters
@@ -219,13 +229,13 @@ The rescan assumes that you have compact block filters for the blocks that you'r
 using the `--filters-start-height` option. Let's you know that none of your wallets are older than block 800,000. Just start the node with.
 
 ```bash
-./target/release/florestad --cfilters --filters-start-height 800000
+$ ./target/release/florestad --cfilters --filters-start-height 800000
 ```
 
 if you add a wallet and want to rescan the blocks from 800,000 to the current height, you can use the `rescan` rpc.
 
 ```bash
-floresta-cli rescan 800000
+$ floresta-cli rescan 800000
 ```
 
 Once you have a transaction cached in your watch-only, you can use either the rpc or integrated electrum server to retrieve information about your wallet. You can use wallets like Electrum or Sparrow to connect to your node and retrieve information about your wallet. Just connect with the server running at `127.0.0.1:50001:t`. On electrum you may want to use the `--oneserver` flag to connect to a single server, for better privacy.
@@ -237,7 +247,7 @@ Once you have a transaction cached in your watch-only, you can use either the rp
 The tests in `floresta-cli` depend on the compiled `florestad` binary. Make sure to build the entire project first by running:
 
 ```bash
-cargo build
+$ cargo build
 ```
 
 ### Testing Options
@@ -245,7 +255,7 @@ cargo build
 There's a set of tests that you can run with:
 
 ```bash
-cargo test
+$ cargo test
 ```
 
 For the full test suite, including long-running tests, use:
diff --git a/crates/floresta-chain/src/pruned_utreexo/chain_state.rs b/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
index a6f1e29da..1aeb73150 100644
--- a/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
@@ -1017,6 +1017,10 @@ impl<PersistedState: ChainStore> UpdatableChainstate for ChainState<PersistedSta
         self.reorg(new_tip)
     }
 
+    fn get_acc(&self) -> Stump {
+        self.acc()
+    }
+
     fn mark_block_as_valid(&self, block: BlockHash) -> Result<(), BlockchainError> {
         let header = self.get_disk_block_header(&block)?;
         let height = header.height().unwrap();
@@ -1196,16 +1200,14 @@ impl<PersistedState: ChainStore> UpdatableChainstate for ChainState<PersistedSta
         final_height: u32,
         acc: Stump,
     ) -> Result<super::partial_chain::PartialChainState, BlockchainError> {
-        let blocks = (initial_height..=final_height)
-            .flat_map(|height| {
+        let blocks = (0..=final_height)
+            .map(|height| {
                 let hash = self
                     .get_block_hash(height)
                     .expect("Block should be present");
-                self.get_disk_block_header(&hash)
-            })
-            .filter_map(|header| match header {
-                DiskBlockHeader::FullyValid(header, _) => Some(header),
-                _ => None,
+                *self
+                    .get_disk_block_header(&hash)
+                    .expect("Block should be present")
             })
             .collect();
 
@@ -1218,7 +1220,6 @@ impl<PersistedState: ChainStore> UpdatableChainstate for ChainState<PersistedSta
             current_acc: acc,
             final_height,
             assume_valid: false,
-            initial_height,
             current_height: initial_height,
         };
 
diff --git a/crates/floresta-chain/src/pruned_utreexo/mod.rs b/crates/floresta-chain/src/pruned_utreexo/mod.rs
index 87161174c..d1d92438e 100644
--- a/crates/floresta-chain/src/pruned_utreexo/mod.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/mod.rs
@@ -151,7 +151,6 @@ pub trait UpdatableChainstate {
     /// [PartialChainState] to completion by downloading blocks inside that chainstate's range.
     /// If all goes right, it'll end without error, and you should mark blocks in this range as
     /// valid.
-    ///
     /// Since this chainstate may start from a height with an existing UTXO set, you need to
     /// provide a [Stump] for that block.
     fn get_partial_chain(
@@ -165,6 +164,8 @@ pub trait UpdatableChainstate {
     /// This mimics the behaviour of checking every block before this block, and continues
     /// from this point
     fn mark_chain_as_assumed(&self, acc: Stump, tip: BlockHash) -> Result<bool, BlockchainError>;
+    /// Returns the current accumulator
+    fn get_acc(&self) -> Stump;
 }
 
 /// This trait is defining how we interact with our chain database. This definitions
@@ -215,6 +216,10 @@ impl<T: UpdatableChainstate> UpdatableChainstate for Arc<T> {
         T::flush(self)
     }
 
+    fn get_acc(&self) -> Stump {
+        T::get_acc(self)
+    }
+
     fn toggle_ibd(&self, is_ibd: bool) {
         T::toggle_ibd(self, is_ibd)
     }
diff --git a/crates/floresta-chain/src/pruned_utreexo/partial_chain.rs b/crates/floresta-chain/src/pruned_utreexo/partial_chain.rs
index 7ae5f57a8..0117b742a 100644
--- a/crates/floresta-chain/src/pruned_utreexo/partial_chain.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/partial_chain.rs
@@ -51,11 +51,6 @@ pub(crate) struct PartialChainStateInner {
     /// and to build the accumulator. We assume this is sorted by height, and
     /// should contains all blocks in this interval.
     pub(crate) blocks: Vec<BlockHeader>,
-    /// The height this interval starts at. This [initial_height, final_height), so
-    /// if we break the interval at height 100, the first interval will be [0, 100)
-    /// and the second interval will be [100, 200). And the initial height of the
-    /// second interval will be 99.
-    pub(crate) initial_height: u32,
     /// The height we are on right now, this is used to keep track of the progress
     /// of the sync.
     pub(crate) current_height: u32,
@@ -97,19 +92,17 @@ unsafe impl Send for PartialChainState {}
 unsafe impl Sync for PartialChainState {}
 
 impl PartialChainStateInner {
-    /// Returns the height we have synced up to so far
-    pub fn current_height(&self) -> u32 {
-        self.current_height
-    }
-
     /// Whether or not we have synced up to the final height
     pub fn is_sync(&self) -> bool {
         self.current_height == self.final_height
     }
 
     pub fn get_block(&self, height: u32) -> Option<&BlockHeader> {
-        let index = height - self.initial_height;
-        self.blocks.get(index as usize)
+        if height >= self.blocks.len() as u32 {
+            return None;
+        }
+
+        self.blocks.get(height as usize)
     }
 
     #[cfg(feature = "bitcoinconsensus")]
@@ -199,6 +192,7 @@ impl PartialChainStateInner {
                 block.block_hash()
             );
         }
+
         self.update_state(height, acc);
 
         Ok(height)
@@ -214,6 +208,7 @@ impl PartialChainStateInner {
         if !block.check_merkle_root() {
             return Err(BlockValidationErrors::BadMerkleRoot)?;
         }
+
         if height >= self.chain_params().params.bip34_height
             && block.bip34_block_height() != Ok(height as u64)
         {
@@ -316,6 +311,10 @@ impl UpdatableChainstate for PartialChainState {
         self.inner().current_acc.roots.clone()
     }
 
+    fn get_acc(&self) -> Stump {
+        self.inner().current_acc.clone()
+    }
+
     //these are no-ops, you can call them, but they won't do anything
 
     fn flush(&self) -> Result<(), BlockchainError> {
@@ -375,7 +374,6 @@ impl BlockchainInterface for PartialChainState {
     }
 
     fn get_block_hash(&self, height: u32) -> Result<bitcoin::BlockHash, BlockchainError> {
-        let height = height - self.inner().initial_height;
         self.inner()
             .blocks
             .get(height as usize)
@@ -385,8 +383,8 @@ impl BlockchainInterface for PartialChainState {
 
     fn get_best_block(&self) -> Result<(u32, bitcoin::BlockHash), Self::Error> {
         Ok((
-            self.inner().current_height(),
-            self.get_block_hash(self.inner().current_height())?,
+            self.inner().final_height,
+            self.get_block_hash(self.inner().final_height)?,
         ))
     }
 
@@ -409,6 +407,22 @@ impl BlockchainInterface for PartialChainState {
         !self.inner().is_sync()
     }
 
+    fn get_block_locator(&self) -> Result<Vec<bitcoin::BlockHash>, Self::Error> {
+        let mut hashes = vec![];
+        let mut step = 1;
+        let mut height = self.inner().current_height;
+
+        while height > 0 {
+            hashes.push(self.get_block_hash(height)?);
+            if hashes.len() > 10 {
+                step *= 2;
+            }
+            height = height.saturating_sub(step);
+        }
+
+        Ok(hashes)
+    }
+
     // partial chain states are only used for IBD, so we don't need to implement these
 
     fn get_block_header(&self, _height: &BlockHash) -> Result<BlockHeader, Self::Error> {
@@ -479,10 +493,6 @@ impl BlockchainInterface for PartialChainState {
     fn get_unbroadcasted(&self) -> Vec<bitcoin::Transaction> {
         unimplemented!("partialChainState::get_unbroadcasted")
     }
-
-    fn get_block_locator(&self) -> Result<Vec<bitcoin::BlockHash>, Self::Error> {
-        unimplemented!("partialChainState::get_block_locator")
-    }
 }
 
 // mainly for tests
@@ -543,7 +553,6 @@ mod tests {
             final_height: 1,
             blocks,
             error: None,
-            initial_height: 0,
         }
         .into()
     }
@@ -569,7 +578,6 @@ mod tests {
             final_height: 100,
             blocks: parsed_blocks.iter().map(|block| block.header).collect(),
             error: None,
-            initial_height: 0,
         }
         .into();
         parsed_blocks.remove(0);
@@ -595,7 +603,8 @@ mod tests {
             parsed_blocks.push(block);
         }
         // The file contains 150 blocks, we split them into two chains.
-        let (blocks1, blocks2) = parsed_blocks.split_at(101);
+        let split = parsed_blocks.clone();
+        let (blocks1, blocks2) = split.split_at(101);
         let mut chainstate1 = PartialChainStateInner {
             assume_valid: true,
             consensus: Consensus {
@@ -604,21 +613,18 @@ mod tests {
             current_height: 0,
             current_acc: Stump::default(),
             final_height: 100,
-            blocks: blocks1.iter().map(|block| block.header).collect(),
+            blocks: parsed_blocks.iter().map(|block| block.header).collect(),
             error: None,
-            initial_height: 0,
         };
+
         // We need to add the last block of the first chain to the second chain, so that
         // the second chain can validate all its blocks.
-        let mut blocks2_headers = vec![blocks1.last().unwrap()];
-        blocks2_headers.extend(blocks2);
-
-        let blocks2_headers = blocks2_headers.iter().map(|block| block.header).collect();
-
-        let mut blocks1 = blocks1.iter();
-        blocks1.next();
+        for (height, block) in blocks1.iter().enumerate() {
+            // skip the genesis block
+            if height == 0 {
+                continue;
+            }
 
-        for block in blocks1 {
             let proof = Proof::default();
             let inputs = HashMap::new();
             let del_hashes = vec![];
@@ -626,6 +632,7 @@ mod tests {
                 .process_block(block, proof, inputs, del_hashes)
                 .unwrap();
         }
+
         // The state after 100 blocks, computed ahead of time.
         let roots = [
             "a2f1e6db842e13c7480c8d80f29ca2db5f9b96e1b428ebfdbd389676d7619081",
@@ -651,9 +658,8 @@ mod tests {
             current_height: 100,
             current_acc: acc2,
             final_height: 150,
-            blocks: blocks2_headers,
+            blocks: parsed_blocks.iter().map(|block| block.header).collect(),
             error: None,
-            initial_height: 100,
         }
         .into();
 
diff --git a/crates/floresta-electrum/src/electrum_protocol.rs b/crates/floresta-electrum/src/electrum_protocol.rs
index 1efae5885..a0fa7f341 100644
--- a/crates/floresta-electrum/src/electrum_protocol.rs
+++ b/crates/floresta-electrum/src/electrum_protocol.rs
@@ -912,6 +912,7 @@ mod test {
     use floresta_watch_only::kv_database::KvDatabase;
     use floresta_watch_only::merkle::MerkleProof;
     use floresta_watch_only::AddressCache;
+    use floresta_wire::address_man::AddressMan;
     use floresta_wire::mempool::Mempool;
     use floresta_wire::node::UtreexoNode;
     use floresta_wire::running_node::RunningNode;
@@ -928,6 +929,7 @@ mod test {
     use tokio::net::TcpListener;
     use tokio::net::TcpStream;
     use tokio::sync::Mutex;
+    use tokio::sync::RwLock;
     use tokio::task;
     use tokio::time::timeout;
     use tokio_rustls::rustls::Certificate;
@@ -1066,6 +1068,8 @@ mod test {
                 chain.clone(),
                 Arc::new(Mutex::new(Mempool::new(Pollard::default(), 0))),
                 None,
+                Arc::new(RwLock::new(false)),
+                AddressMan::default(),
             )
             .unwrap();
 
diff --git a/crates/floresta-wire/src/p2p_wire/address_man.rs b/crates/floresta-wire/src/p2p_wire/address_man.rs
index 9d805be12..f9b2b4052 100644
--- a/crates/floresta-wire/src/p2p_wire/address_man.rs
+++ b/crates/floresta-wire/src/p2p_wire/address_man.rs
@@ -158,7 +158,7 @@ impl LocalAddress {
 }
 
 /// A module that keeps track of know addresses and serve them to our node to connect
-#[derive(Default)]
+#[derive(Default, Clone)]
 pub struct AddressMan {
     addresses: HashMap<usize, LocalAddress>,
     good_addresses: Vec<usize>,
@@ -200,7 +200,6 @@ impl AddressMan {
                 }
 
                 self.push_if_has_service(address, service_flags::UTREEXO.into());
-                self.push_if_has_service(address, service_flags::UTREEXO.into()); // UTREEXO_FILTER
                 self.push_if_has_service(address, ServiceFlags::NONE); // this means any peer
                 self.push_if_has_service(address, ServiceFlags::COMPACT_FILTERS);
             }
@@ -373,7 +372,7 @@ impl AddressMan {
                 .or_else(|| self.get_random_address(required_service))?;
 
             match peer.state {
-                AddressState::NeverTried | AddressState::Tried(_) => {
+                AddressState::NeverTried | AddressState::Tried(_) | AddressState::Connected => {
                     return Some((id, peer));
                 }
 
@@ -393,8 +392,6 @@ impl AddressMan {
 
                     self.good_addresses.retain(|&x| x != id);
                 }
-
-                AddressState::Connected => {}
             }
         }
 
@@ -437,6 +434,7 @@ impl AddressMan {
 
         let idx = rand::random::<usize>() % peers.len();
         let utreexo_peer = peers.get(idx)?;
+
         Some((*utreexo_peer, self.addresses.get(utreexo_peer)?.to_owned()))
     }
 
diff --git a/crates/floresta-wire/src/p2p_wire/chain_selector.rs b/crates/floresta-wire/src/p2p_wire/chain_selector.rs
index b49ce0eac..22dce25fd 100644
--- a/crates/floresta-wire/src/p2p_wire/chain_selector.rs
+++ b/crates/floresta-wire/src/p2p_wire/chain_selector.rs
@@ -45,7 +45,6 @@
 //! downloading the actual blocks and validating them.
 use std::collections::HashMap;
 use std::collections::HashSet;
-use std::sync::Arc;
 use std::time::Duration;
 use std::time::Instant;
 
@@ -63,7 +62,6 @@ use log::info;
 use log::warn;
 use rustreexo::accumulator::node_hash::BitcoinNodeHash;
 use rustreexo::accumulator::stump::Stump;
-use tokio::sync::RwLock;
 use tokio::time::timeout;
 
 use super::error::WireError;
@@ -174,8 +172,7 @@ where
             .and_modify(|e| *e = last)
             .or_insert(last);
 
-        self.request_headers(headers.last().unwrap().block_hash(), peer)
-            .await
+        self.request_headers(last, peer).await
     }
 
     /// Takes a serialized accumulator and parses it into a Stump
@@ -690,7 +687,7 @@ where
         Ok(())
     }
 
-    pub async fn run(&mut self, stop_signal: Arc<RwLock<bool>>) -> Result<(), WireError> {
+    pub async fn run(&mut self) -> Result<(), WireError> {
         info!("Starting ibd, selecting the best chain");
 
         loop {
@@ -750,7 +747,7 @@ where
 
             try_and_log!(self.check_for_timeout().await);
 
-            if *stop_signal.read().await {
+            if *self.kill_signal.read().await {
                 break;
             }
         }
diff --git a/crates/floresta-wire/src/p2p_wire/node.rs b/crates/floresta-wire/src/p2p_wire/node.rs
index f6fae6969..d543307a9 100644
--- a/crates/floresta-wire/src/p2p_wire/node.rs
+++ b/crates/floresta-wire/src/p2p_wire/node.rs
@@ -193,6 +193,7 @@ pub struct NodeCommon<Chain: BlockchainInterface + UpdatableChainstate> {
     pub(crate) config: UtreexoNodeConfig,
     pub(crate) datadir: String,
     pub(crate) network: Network,
+    pub(crate) kill_signal: Arc<tokio::sync::RwLock<bool>>,
 
     // 7. Stuff used by the node handle
     pub(crate) user_requests: Arc<NodeInterface>,
@@ -234,6 +235,8 @@ where
         chain: Chain,
         mempool: Arc<Mutex<Mempool>>,
         block_filters: Option<Arc<NetworkFilters<FlatFiltersStore>>>,
+        kill_signal: Arc<tokio::sync::RwLock<bool>>,
+        address_man: AddressMan,
     ) -> Result<Self, WireError> {
         let (node_tx, node_rx) = unbounded_channel();
         let socks5 = config.proxy.map(Socks5StreamBuilder::new);
@@ -262,7 +265,7 @@ where
                 network: config.network.into(),
                 node_rx,
                 node_tx,
-                address_man: AddressMan::default(),
+                address_man,
                 last_headers_request: Instant::now(),
                 last_tip_update: Instant::now(),
                 last_connection: Instant::now(),
@@ -273,13 +276,14 @@ where
                 last_get_address_request: Instant::now(),
                 last_send_addresses: Instant::now(),
                 datadir: config.datadir.clone(),
-                socks5,
                 max_banscore: config.max_banscore,
+                socks5,
                 fixed_peer,
                 config,
                 user_requests: Arc::new(NodeInterface {
                     requests: std::sync::Mutex::new(Vec::new()),
                 }),
+                kill_signal,
             },
             context: T::default(),
         })
diff --git a/crates/floresta-wire/src/p2p_wire/running_node.rs b/crates/floresta-wire/src/p2p_wire/running_node.rs
index 8b6e6427e..319252c23 100644
--- a/crates/floresta-wire/src/p2p_wire/running_node.rs
+++ b/crates/floresta-wire/src/p2p_wire/running_node.rs
@@ -3,7 +3,6 @@
 /// CPU to run, being bound by the number of blocks found in a given period.
 use std::collections::BTreeMap;
 use std::collections::HashMap;
-use std::sync::Arc;
 use std::time::Duration;
 use std::time::Instant;
 
@@ -28,7 +27,6 @@ use rand::random;
 use rustreexo::accumulator::node_hash::BitcoinNodeHash;
 use rustreexo::accumulator::pollard::PollardAddition;
 use rustreexo::accumulator::stump::Stump;
-use tokio::sync::RwLock;
 use tokio::time::timeout;
 
 use super::error::WireError;
@@ -73,7 +71,7 @@ impl NodeContext for RunningNode {
 impl<Chain> UtreexoNode<Chain, RunningNode>
 where
     WireError: From<<Chain as BlockchainInterface>::Error>,
-    Chain: BlockchainInterface + UpdatableChainstate + 'static,
+    Chain: BlockchainInterface + UpdatableChainstate + Sync + Send + Clone + 'static,
 {
     async fn send_addresses(&mut self) -> Result<(), WireError> {
         let addresses = self
@@ -160,17 +158,28 @@ where
         Ok(())
     }
 
-    async fn catch_up(self, kill_signal: Arc<RwLock<bool>>) -> Self {
-        let mut sync = UtreexoNode::<Chain, SyncNode> {
-            context: SyncNode::default(),
-            common: self.common,
-        };
-        sync.run(kill_signal, |_| {}).await;
+    /// Every time we restart the node, we'll be a few blocks behind the tip. This function
+    /// will start a sync node that will request, download and validate all blocks from the
+    /// last validation index to the tip. This function will block until the sync node is
+    /// finished.
+    ///
+    /// On the first startup, if we use either assumeutreexo or pow fraud proofs, this function
+    /// will only download the blocks that are after the one that got assumed. So, for PoW fraud
+    /// proofs, this means the last 100 blocks, and for assumeutreexo, this means however many
+    /// blocks from the hard-coded value in the config file.
+    pub async fn catch_up(&self) -> Result<(), WireError> {
+        let sync = UtreexoNode::<Chain, SyncNode>::new(
+            self.config.clone(),
+            self.chain.clone(),
+            self.mempool.clone(),
+            None,
+            self.kill_signal.clone(),
+            self.address_man.clone(),
+        )?;
+
+        sync.run(|_| {}).await;
 
-        UtreexoNode {
-            common: sync.common,
-            context: self.context,
-        }
+        Ok(())
     }
 
     /// This function is called periodically to check if we have:
@@ -228,77 +237,166 @@ where
         Ok(())
     }
 
-    pub async fn run(
-        mut self,
-        kill_signal: Arc<RwLock<bool>>,
-        stop_signal: futures::channel::oneshot::Sender<()>,
-    ) {
+    /// If either PoW fraud proofs or assumeutreexo are enabled, we will "skip" IBD for all
+    /// historical blocks. This allow us to start the node faster, making it usable in a few
+    /// minutes. If you still want to validate all blocks, you can enable the backfill option.
+    ///
+    /// This function will spawn a background task that will download and validate all blocks
+    /// that got assumed. After completion, the task will shutdown and the node will continue
+    /// running normally. If we ever assume an invalid chain, the node will [halt and catch fire].
+    ///
+    /// [halt and catch fire]: https://en.wikipedia.org/wiki/Halt_and_Catch_Fire_(computing)
+    pub fn backfill(&self, done_flag: std::sync::mpsc::Sender<()>) -> Result<bool, WireError> {
+        // try finding the last state of the sync node
+        let state = std::fs::read(self.config.datadir.clone() + "/.sync_node_state");
+        // try to recover from the disk state, if it exists. Otherwise, start from genesis
+        let (chain, end) = match state {
+            Ok(state) => {
+                // if this file is empty, this means we've finished backfilling
+                if state.is_empty() {
+                    return Ok(false);
+                }
+
+                let acc = Stump::deserialize(&state[..(state.len() - 8)]).unwrap();
+                let tip = u32::from_le_bytes(
+                    state[(state.len() - 8)..(state.len() - 4)]
+                        .try_into()
+                        .unwrap(),
+                );
+
+                let end = u32::from_le_bytes(state[(state.len() - 4)..].try_into().unwrap());
+                info!(
+                    "Recovering backfill node from state tip={}, end={}",
+                    tip, end
+                );
+                (
+                    self.chain
+                        .get_partial_chain(tip, end, acc)
+                        .expect("Failed to get partial chain"),
+                    end,
+                )
+            }
+            Err(_) => {
+                // if the file doesn't exist or got corrupted, start from genesis
+                let end = self
+                    .chain
+                    .get_validation_index()
+                    .expect("can get the validation index");
+                (
+                    self.chain
+                        .get_partial_chain(0, end, Stump::default())
+                        .unwrap(),
+                    end,
+                )
+            }
+        };
+
+        let backfill = UtreexoNode::<PartialChainState, SyncNode>::new(
+            self.config.clone(),
+            chain,
+            self.mempool.clone(),
+            None,
+            self.kill_signal.clone(),
+            self.address_man.clone(),
+        )
+        .unwrap();
+
+        let datadir = self.config.datadir.clone();
+        let outer_chain = self.chain.clone();
+
+        let fut = UtreexoNode::<PartialChainState, SyncNode>::run(
+            backfill,
+            move |chain: &PartialChainState| {
+                if chain.has_invalid_blocks() {
+                    panic!("We assumed a chain with invalid blocks, something went really wrong");
+                }
+
+                done_flag.send(()).unwrap();
+
+                // we haven't finished the backfill yet, save the current state for the next run
+                if chain.is_in_idb() {
+                    let acc = chain.get_acc();
+                    let tip = chain.get_height().unwrap();
+                    let mut ser_acc = Vec::new();
+                    acc.serialize(&mut ser_acc).unwrap();
+                    ser_acc.extend_from_slice(&tip.to_le_bytes());
+                    ser_acc.extend_from_slice(&end.to_le_bytes());
+                    std::fs::write(datadir + "/.sync_node_state", ser_acc)
+                        .expect("Failed to write sync node state");
+                    return;
+                }
+
+                // empty the file if we're done
+                std::fs::write(datadir + "/.sync_node_state", Vec::new())
+                    .expect("Failed to write sync node state");
+
+                for block in chain.list_valid_blocks() {
+                    outer_chain
+                        .mark_block_as_valid(block.block_hash())
+                        .expect("Failed to mark block as valid");
+                }
+
+                info!("Backfilling task shutting down...");
+            },
+        );
+
+        tokio::task::spawn(fut);
+        Ok(true)
+    }
+
+    pub async fn run(mut self, stop_signal: futures::channel::oneshot::Sender<()>) {
         try_and_log!(self.init_peers().await);
-        let startup_tip = self.chain.get_height().unwrap();
 
         // Use this node state to Initial Block download
         let mut ibd = UtreexoNode {
             common: self.common,
             context: ChainSelector::default(),
         };
-        try_and_log!(UtreexoNode::<Chain, ChainSelector>::run(&mut ibd, kill_signal.clone()).await);
 
-        if *kill_signal.read().await {
-            self = UtreexoNode {
-                common: ibd.common,
-                context: self.context,
-            };
-            self.shutdown().await;
-            try_and_log!(stop_signal.send(()));
-            return;
-        }
+        try_and_log!(UtreexoNode::<Chain, ChainSelector>::run(&mut ibd).await);
 
         self = UtreexoNode {
             common: ibd.common,
             context: self.context,
         };
 
-        // download all blocks from the network
-        if self.config.backfill && startup_tip == 0 {
-            let end = self.common.chain.get_validation_index().unwrap();
-            let chain = self
-                .chain
-                .get_partial_chain(startup_tip, end, Stump::default())
-                .unwrap();
+        if *self.kill_signal.read().await {
+            self.shutdown().await;
+            try_and_log!(stop_signal.send(()));
+            return;
+        }
 
-            let mut backfill = UtreexoNode::<PartialChainState, SyncNode>::new(
-                self.config.clone(),
-                chain,
-                self.mempool.clone(),
-                None,
-            )
-            .expect("Failed to create backfill node"); // expect is fine here, because we already
-                                                       // validated this config before creating the RunningNode
-
-            UtreexoNode::<PartialChainState, SyncNode>::run(
-                &mut backfill,
-                kill_signal.clone(),
-                |chain: &PartialChainState| {
-                    if chain.has_invalid_blocks() {
-                        panic!(
-                            "We assumed a chain with invalid blocks, something went really wrong"
-                        );
-                    }
+        // download blocks from the network before our validation index, probably because we've
+        // assumed it somehow.
+        let (sender, recv) = std::sync::mpsc::channel();
+        let is_backfilling = match self.config.backfill {
+            true => {
+                info!("Starting backfill task...");
+                self.backfill(sender)
+                    .expect("Failed to spawn backfill thread")
+            }
+            false => false,
+        };
 
-                    for block in chain.list_valid_blocks() {
-                        self.chain
-                            .mark_block_as_valid(block.block_hash())
-                            .expect("Failed to mark block as valid");
-                    }
-                },
-            )
-            .await;
-        }
+        // Catch up with the network, donloading blocks from our last validation index onwnwards
+        info!("Catching up with the network...");
+        try_and_log!(self.catch_up().await);
 
-        self = self.catch_up(kill_signal.clone()).await;
+        if *self.kill_signal.read().await {
+            self.shutdown().await;
+            stop_signal.send(()).unwrap();
+            return;
+        }
 
         self.last_block_request = self.chain.get_validation_index().unwrap_or(0);
+        if let Some(ref cfilters) = self.block_filters {
+            self.last_filter = self
+                .chain
+                .get_block_hash(cfilters.get_height().unwrap_or(1))
+                .unwrap();
+        }
 
+        self.last_block_request = self.chain.get_validation_index().unwrap_or(0);
         if let Some(ref cfilters) = self.block_filters {
             self.last_filter = self
                 .chain
@@ -308,16 +406,16 @@ where
 
         info!("starting running node...");
         loop {
+            if *self.kill_signal.read().await {
+                break;
+            }
+
             while let Ok(Some(notification)) =
                 timeout(Duration::from_millis(100), self.node_rx.recv()).await
             {
                 try_and_log!(self.handle_notification(notification).await);
             }
 
-            if *kill_signal.read().await {
-                self.shutdown().await;
-                break;
-            }
             // Jobs that don't need a connected peer
 
             // Save our peers db
@@ -406,6 +504,13 @@ where
             }
         }
 
+        // ignore the error here because if the backfill task already
+        // finished, this channel will be closed
+        if is_backfilling {
+            let _ = recv.recv();
+        }
+
+        self.shutdown().await;
         stop_signal.send(()).unwrap();
     }
 
diff --git a/crates/floresta-wire/src/p2p_wire/sync_node.rs b/crates/floresta-wire/src/p2p_wire/sync_node.rs
index a5f1e6ab0..a378e61f6 100644
--- a/crates/floresta-wire/src/p2p_wire/sync_node.rs
+++ b/crates/floresta-wire/src/p2p_wire/sync_node.rs
@@ -1,6 +1,5 @@
 //! A node that downloads and validates the blockchain.
 
-use std::sync::Arc;
 use std::time::Duration;
 use std::time::Instant;
 
@@ -17,7 +16,6 @@ use log::debug;
 use log::error;
 use log::info;
 use log::warn;
-use tokio::sync::RwLock;
 use tokio::time::timeout;
 
 use super::error::WireError;
@@ -63,7 +61,7 @@ impl NodeContext for SyncNode {
 impl<Chain> UtreexoNode<Chain, SyncNode>
 where
     WireError: From<<Chain as BlockchainInterface>::Error>,
-    Chain: BlockchainInterface + UpdatableChainstate + 'static,
+    Chain: BlockchainInterface + UpdatableChainstate + 'static + Send + Sync,
 {
     /// Checks if we have the next 10 missing blocks until the tip, and request missing ones for a peer.
     async fn get_blocks_to_download(&mut self) {
@@ -112,7 +110,7 @@ where
     ///     - Checks if our tip is obsolete and requests a new one, creating a new connection.
     ///     - Handles timeouts for inflight requests.
     ///     - If were low on inflights, requests new blocks to validate.
-    pub async fn run(&mut self, kill_signal: Arc<RwLock<bool>>, done_cb: impl FnOnce(&Chain)) {
+    pub async fn run(mut self, done_cb: impl FnOnce(&Chain)) {
         info!("Starting sync node");
         self.context.last_block_requested = self.chain.get_validation_index().unwrap();
 
@@ -121,12 +119,23 @@ where
                 try_and_log!(self.handle_message(msg).await);
             }
 
-            if *kill_signal.read().await {
+            if *self.kill_signal.read().await {
                 break;
             }
 
-            if self.chain.get_validation_index().unwrap() == self.chain.get_best_block().unwrap().0
-            {
+            let validation_index = self
+                .chain
+                .get_validation_index()
+                .expect("validation index block should present");
+
+            let best_block = self
+                .chain
+                .get_best_block()
+                .expect("best block should present")
+                .0;
+
+            if validation_index == best_block {
+                info!("ibd finished, switching to normal operation mode");
                 self.chain.toggle_ibd(false);
                 break;
             }
@@ -171,7 +180,6 @@ where
                 self.get_blocks_to_download().await;
             }
         }
-
         done_cb(&self.chain);
     }
 
@@ -340,6 +348,10 @@ where
         }
 
         if self.inflight.len() < 4 {
+            if *self.kill_signal.read().await {
+                return Ok(());
+            }
+
             self.get_blocks_to_download().await;
         }
 
diff --git a/crates/floresta-wire/src/p2p_wire/tests/sync_node.rs b/crates/floresta-wire/src/p2p_wire/tests/sync_node.rs
index dde063360..ef6666609 100644
--- a/crates/floresta-wire/src/p2p_wire/tests/sync_node.rs
+++ b/crates/floresta-wire/src/p2p_wire/tests/sync_node.rs
@@ -1,6 +1,5 @@
 #[cfg(test)]
 mod tests_utils {
-    use std::mem::ManuallyDrop;
     use std::sync::Arc;
     use std::time::Duration;
 
@@ -13,6 +12,7 @@ mod tests_utils {
     use tokio::sync::RwLock;
     use tokio::time::timeout;
 
+    use crate::address_man::AddressMan;
     use crate::mempool::Mempool;
     use crate::node::UtreexoNode;
     use crate::p2p_wire::sync_node::SyncNode;
@@ -46,11 +46,14 @@ mod tests_utils {
 
         let config = get_node_config(datadir, network, pow_fraud_proofs);
 
+        let kill_signal = Arc::new(RwLock::new(false));
         let mut node = UtreexoNode::<Arc<ChainState<KvChainStore>>, SyncNode>::new(
             config,
             chain.clone(),
             mempool,
             None,
+            kill_signal.clone(),
+            AddressMan::default(),
         )
         .unwrap();
 
@@ -71,15 +74,7 @@ mod tests_utils {
             node.peers.insert(i as u32, peer);
         }
 
-        let mut node = ManuallyDrop::new(Box::new(node));
-        let kill_signal = Arc::new(RwLock::new(false));
-
-        // FIXME: This doesn't look very safe, but we need to coerce a &mut reference of the node
-        //        to live for the static lifetime, or it can't be spawn-ed by tokio::task
-        let _node: &'static mut UtreexoNode<Arc<ChainState<KvChainStore>>, SyncNode> =
-            unsafe { std::mem::transmute(&mut **node) };
-
-        timeout(Duration::from_secs(100), _node.run(kill_signal, |_| {}))
+        timeout(Duration::from_secs(100), node.run(|_| {}))
             .await
             .unwrap();
 
diff --git a/crates/floresta/examples/node.rs b/crates/floresta/examples/node.rs
index 00fb86db4..ac82472d0 100644
--- a/crates/floresta/examples/node.rs
+++ b/crates/floresta/examples/node.rs
@@ -16,12 +16,12 @@ use floresta::chain::Network;
 use floresta::wire::mempool::Mempool;
 use floresta::wire::node::UtreexoNode;
 use floresta_chain::AssumeValidArg;
+use floresta_wire::address_man::AddressMan;
 use floresta_wire::node_interface::NodeMethods;
 use floresta_wire::running_node::RunningNode;
 use floresta_wire::UtreexoNodeConfig;
 use rustreexo::accumulator::pollard::Pollard;
 use tokio::sync::Mutex;
-use tokio::sync::RwLock;
 
 const DATA_DIR: &str = "./tmp-db";
 
@@ -64,6 +64,8 @@ async fn main() {
         chain.clone(),
         Arc::new(Mutex::new(Mempool::new(Pollard::default(), 1000))),
         None,
+        Arc::new(tokio::sync::RwLock::new(false)),
+        AddressMan::default(),
     )
     .unwrap();
     // A handle is a simple way to interact with the node. It implements a queue of requests
@@ -76,7 +78,7 @@ async fn main() {
     // It will also start the mempool, which will start rebroadcasting our transactions every hour.
     // The node will keep running until the process is killed, by setting kill_signal to true. In
     // this example, we don't kill the node, so it will keep running forever.
-    p2p.run(Arc::new(RwLock::new(false)), sender).await;
+    p2p.run(sender).await;
 
     // That's it! The node is now running, and will keep running until the process is killed.
     // You can now use the chain state to query the current state of the accumulator, or the
diff --git a/florestad/src/cli.rs b/florestad/src/cli.rs
index 5da4481f5..840481d7b 100644
--- a/florestad/src/cli.rs
+++ b/florestad/src/cli.rs
@@ -150,14 +150,14 @@ pub struct Cli {
     /// Download block filters starting at this height. Negative numbers are relative to the current tip.
     pub filters_start_height: Option<i32>,
 
-    #[arg(long)]
+    #[arg(long, default_value_t = false)]
     /// Whether we should assume a utreexo state for a given height
     ///
     /// This option will significantly speed up the initial block download, by skipping the
     /// validation of the first hundreds of thousands of blocks. However, there's an inherent
     /// trust in the developer that the utreexo state is correct. Everything after the assumed
     /// height will be fully validated.
-    pub assume_utreexo: bool,
+    pub no_assume_utreexo: bool,
 
     #[arg(long, value_name = "PATH")]
     /// Path to the SSL certificate file
@@ -188,4 +188,17 @@ pub struct Cli {
     /// write it to a file. This option should be an absolute path to a file. Usually, you'd
     /// write it to $DATA_DIR/florestad.pid
     pub pid_file: Option<String>,
+
+    #[arg(long, default_value_t = false)]
+    /// Whehter we should backfill
+    ///
+    /// If we assumeutreexo or use pow fraud proofs, you have the option to download and validate
+    /// the blocks that were skipped. This will take a long time, but will run on the background
+    /// and won't affect the node's operation. You may notice that this will take a lot of CPU
+    /// and bandwidth to run.
+    ///
+    /// The default behavior is verifying the blocks that were skipped during node startup.
+    /// This will run in the background and wont't affect node's operation. However,
+    /// to disable backfilling, run floresta using this flag.
+    pub no_backfill: bool,
 }
diff --git a/florestad/src/florestad.rs b/florestad/src/florestad.rs
index a8ee3a5c8..cf22f38e7 100644
--- a/florestad/src/florestad.rs
+++ b/florestad/src/florestad.rs
@@ -33,8 +33,10 @@ use floresta_electrum::electrum_protocol::ElectrumServer;
 use floresta_watch_only::kv_database::KvDatabase;
 use floresta_watch_only::AddressCache;
 use floresta_watch_only::AddressCacheDatabase;
+use floresta_wire::address_man::AddressMan;
 use floresta_wire::mempool::Mempool;
 use floresta_wire::node::UtreexoNode;
+use floresta_wire::running_node::RunningNode;
 use floresta_wire::UtreexoNodeConfig;
 use futures::channel::oneshot;
 use futures::executor::block_on;
@@ -166,6 +168,13 @@ pub struct Config {
     pub no_ssl: bool,
     /// Whether to allow fallback to v1 transport if v2 connection fails.
     pub allow_v1_fallback: bool,
+    /// Whehter we should backfill
+    ///
+    /// If we assumeutreexo or use pow fraud proofs, you have the option to download and validate
+    /// the blocks that were skipped. This will take a long time, but will run on the background
+    /// and won't affect the node's operation. You may notice that this will take a lot of CPU
+    /// and bandwidth to run.
+    pub backfill: bool,
 }
 
 pub struct Florestad {
@@ -400,19 +409,23 @@ impl Florestad {
             max_outbound: 10,
             max_inflight: 20,
             assume_utreexo: self.config.assumeutreexo_value.clone().or(assume_utreexo),
-            backfill: false,
+            backfill: self.config.backfill,
             filter_start_height: self.config.filters_start_height,
             user_agent: self.config.user_agent.clone(),
             allow_v1_fallback: self.config.allow_v1_fallback,
         };
 
         let acc = Pollard::new();
+        let kill_signal = self.stop_signal.clone();
+
         // Chain Provider (p2p)
-        let chain_provider = UtreexoNode::new(
+        let chain_provider = UtreexoNode::<_, RunningNode>::new(
             config,
             blockchain_state.clone(),
             Arc::new(tokio::sync::Mutex::new(Mempool::new(acc, 300_000_000))),
             cfilters.clone(),
+            kill_signal.clone(),
+            AddressMan::default(),
         )
         .expect("Could not create a chain provider");
 
@@ -541,13 +554,12 @@ impl Florestad {
         }
 
         // Chain provider
-        let kill_signal = self.stop_signal.clone();
         let (sender, receiver) = oneshot::channel();
 
         let mut recv = self.stop_notify.lock().unwrap();
         *recv = Some(receiver);
 
-        task::spawn(chain_provider.run(kill_signal, sender));
+        task::spawn(chain_provider.run(sender));
 
         // Metrics
         #[cfg(feature = "metrics")]
diff --git a/florestad/src/main.rs b/florestad/src/main.rs
index ca550eb21..451004a7f 100644
--- a/florestad/src/main.rs
+++ b/florestad/src/main.rs
@@ -41,7 +41,7 @@ fn main() {
         data_dir: params.data_dir.clone(),
         cfilters: params.cfilters,
         proxy: params.proxy,
-        assume_utreexo: params.assume_utreexo,
+        assume_utreexo: !params.no_assume_utreexo,
         connect: params.connect,
         wallet_xpub: params.wallet_xpub,
         config_file: params.config_file,
@@ -65,6 +65,7 @@ fn main() {
         ssl_key_path: params.ssl_key_path,
         no_ssl: params.no_ssl,
         allow_v1_fallback: !params.no_v1_fallback,
+        backfill: !params.no_backfill,
     };
 
     #[cfg(unix)]
@@ -79,6 +80,8 @@ fn main() {
     let _rt = tokio::runtime::Builder::new_multi_thread()
         .enable_all()
         .worker_threads(4)
+        .max_blocking_threads(2)
+        .thread_keep_alive(Duration::from_secs(60))
         .thread_name("florestad")
         .build()
         .unwrap();


Reviews:
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-08-12T19:02:17Z
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-08-12T19:07:39Z
user: login: luca0x46
body: The flags on read me must be updated to match the actual call on florestad.

Also, there are a couple warnings on clippy, so as #386 is on the way, I believe the warnings could also be handled before merging. After fixing these two observations, ACK.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-27T14:54:52Z
user: login: luca0x46
body: As the CI broke I checked out the PR to see the problem and there are a few `UtreexoNode::new()` calls with missing params. 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T13:16:05Z
user: login: luca0x46
body: It now works as expected! 

Just a couple of suggested changes on the documentation to match the expected behavior and usage of the CLI.

Also, during execution, one thing that bothered me was the double equal logs.

```
[2025-03-17 14:31:16 INFO floresta_wire::p2p_wire::running_node] Starting backfill task...
[2025-03-17 14:31:16 INFO floresta_wire::p2p_wire::running_node] Recovering backfill node from state tip=0, end=861955
[2025-03-17 14:31:26 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-17 14:31:26 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
[2025-03-17 14:31:26 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
```

I checked the implementation and it is correct, however, these logs just bother me. But nothing that should prevent merging.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T17:55:22Z
user: login: Davidson-Souza
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-17T19:20:34Z
user: login: luca0x46
body: ACK [9f358f](https://github.com/vinteumorg/Floresta/commit/9f358f307b197092442f628a108df2d802e399d3)
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T20:14:10Z

Review comments:
diff_hunk: @@ -100,47 +101,58 @@ $ nix run github:Davidson-Souza/Floresta
 
 After building, florestad and floresta-cli will be available in the target directory. You can run the full node with
 ```bash
-./target/release/florestad
+$ ./target/release/florestad
 # or, if you installed it with cargo install
-florestad
+$ florestad
 ```
 
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/Davidson-Souza/Floresta/blob/master/crates/floresta-cli/README.md).
 
 #### Assume Utreexo
+
 If you want to skip the IBD process, you can use the `--assumeutreexo` flag. This flag will start the node at a given height, with the state
 provided by this implementation. Therefore, you're trusting that we are giving you the correct state. Everything after that height will be
 verified by the node just like any other node.
 
 ```bash
-florestad --assumeutreexo
+$ florestad --assumeutreexo
+```
+
+#### Backfill
+
+If you want to get a node up and running in a few minutes, but still want to validate everything, you can start `florestad` with `assumeutree` and pass the `--backfill` flag. This will download the blocks from genesis to the assumed height, validate them and compare with the provided value, all in the background. This way, you can start using the node right away, and it will be fully validated in a few hours/days.
+
path: README.md
user: login: jaoleal
body: 
```suggestion
If you want to get a node up and running in a few minutes, but still want to validate everything, you can start `florestad` with `assumeutreexo` and pass the `--backfill` flag. This will download the blocks from genesis to the assumed height, validate them and compare with the provided value, all in the background. This way, you can start using the node right away, and it will be fully validated in a few hours/days depending on your hardware.
```
created_at: 2024-08-12T19:02:16Z
author_association: MEMBER
diff_hunk: @@ -157,9 +156,11 @@ pub trait UpdatableChainstate {
     ) -> Result<PartialChainState, BlockchainError>;
     /// Marks a chain as fully-valid
     ///
-    /// This mimics the behavour of checking every block before this block, and continues
+    /// This mimics the behavour of checking every block before this block, and continuesjjj
     /// from this point
path: crates/floresta-chain/src/pruned_utreexo/mod.rs
user: login: jaoleal
body: 
```suggestion
    /// This mimics the behavour of checking every block before this block, and continues
```
created_at: 2024-08-12T19:07:38Z
author_association: MEMBER
diff_hunk: @@ -165,41 +166,53 @@ florestad --daemon
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/vinteumorg/Floresta/blob/master/crates/floresta-cli/README.md).
 
 Before running you can create the SSL certificates. If you don't do it, it will display a logging `Failed to load SSL certificates, ignoring SSL`. However, it is not mandatory to have the certificates to run the full node.
 
-### Assume Utreexo
-If you want to skip the IBD process, you can use the `--assume-utreexo` flag. This flag will start the node at a given height, with the state
+#### Assume Utreexo
+
+If you want to skip the IBD process, you can use the `--assumeutreexo` flag. This flag will start the node at a given height, with the state
path: README.md
user: login: luca0x46
body: it should be `--assume-utreexo` 
created_at: 2025-02-27T14:46:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -165,41 +166,53 @@ florestad --daemon
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/vinteumorg/Floresta/blob/master/crates/floresta-cli/README.md).
 
 Before running you can create the SSL certificates. If you don't do it, it will display a logging `Failed to load SSL certificates, ignoring SSL`. However, it is not mandatory to have the certificates to run the full node.
 
-### Assume Utreexo
-If you want to skip the IBD process, you can use the `--assume-utreexo` flag. This flag will start the node at a given height, with the state
+#### Assume Utreexo
+
+If you want to skip the IBD process, you can use the `--assumeutreexo` flag. This flag will start the node at a given height, with the state
 provided by this implementation. Therefore, you're trusting that we are giving you the correct state. Everything after that height will be
 verified by the node just like any other node.
 
 ```bash
-florestad --assume-utreexo
+$ florestad --assumeutreexo
path: README.md
user: login: luca0x46
body: same here. `--assume-utreexo`
created_at: 2025-02-27T14:47:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -165,41 +166,53 @@ florestad --daemon
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/vinteumorg/Floresta/blob/master/crates/floresta-cli/README.md).
 
 Before running you can create the SSL certificates. If you don't do it, it will display a logging `Failed to load SSL certificates, ignoring SSL`. However, it is not mandatory to have the certificates to run the full node.
 
-### Assume Utreexo
-If you want to skip the IBD process, you can use the `--assume-utreexo` flag. This flag will start the node at a given height, with the state
+#### Assume Utreexo
+
+If you want to skip the IBD process, you can use the `--assumeutreexo` flag. This flag will start the node at a given height, with the state
 provided by this implementation. Therefore, you're trusting that we are giving you the correct state. Everything after that height will be
 verified by the node just like any other node.
 
 ```bash
-florestad --assume-utreexo
+$ florestad --assumeutreexo
+```
+
+#### Backfill
+
+If you want to get a node up and running in a few minutes, but still want to validate everything, you can start `florestad` with `assumeutreexo` and pass the `--backfill` flag. This will download the blocks from genesis to the assumed height, validate them and compare with the provided value, all in the background. This way, you can start using the node right away, and it will be fully validated in a few hours/days depending on your hardware.
+
+This is the default behavior of `florestad` if no flags are provided.
+
+```bash
+$ florestad --assumeutreexo --backfill
path: README.md
user: login: luca0x46
body: replace for:
`$ florestad --assume-utreexo --backfill`
created_at: 2025-02-27T14:49:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,6 +63,7 @@ async fn main() {
         chain.clone(),
         Arc::new(Mutex::new(Mempool::new(Pollard::default(), 1000))),
         None,
+        Arc::new(tokio::sync::RwLock::new(false)),
path: crates/floresta/examples/node.rs
user: login: luca0x46
body: Missing `AddressMan` argument to method `new()`
created_at: 2025-03-17T13:09:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1066,6 +1067,7 @@ mod test {
                 chain.clone(),
                 Arc::new(Mutex::new(Mempool::new(Pollard::default(), 0))),
                 None,
+                Arc::new(RwLock::new(false)),
path: crates/floresta-electrum/src/electrum_protocol.rs
user: login: luca0x46
body: argument 6 of type `AddressMan` is missing
created_at: 2025-03-17T13:10:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,11 +45,13 @@ mod tests_utils {
 
         let config = get_node_config(datadir, network, pow_fraud_proofs);
 
+        let kill_signal = Arc::new(RwLock::new(false));
         let mut node = UtreexoNode::<Arc<ChainState<KvChainStore>>, SyncNode>::new(
             config,
             chain.clone(),
             mempool,
             None,
+            kill_signal.clone(),
path: crates/floresta-wire/src/p2p_wire/tests/sync_node.rs
user: login: luca0x46
body: argument 6 of type `AddressMan` is missing
created_at: 2025-03-17T13:11:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -165,41 +166,52 @@ florestad --daemon
 This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool.
 
 ```bash
-floresta-cli getblockchaininfo
+$ floresta-cli getblockchaininfo
 ```
 
 For more information on how to use the `floresta-cli` tool, you can check the [api documentation](https://github.com/vinteumorg/Floresta/blob/master/crates/floresta-cli/README.md).
 
 Before running you can create the SSL certificates. If you don't do it, it will display a logging `Failed to load SSL certificates, ignoring SSL`. However, it is not mandatory to have the certificates to run the full node.
 
-### Assume Utreexo
+#### Assume Utreexo
+
 If you want to skip the IBD process, you can use the `--assume-utreexo` flag. This flag will start the node at a given height, with the state
 provided by this implementation. Therefore, you're trusting that we are giving you the correct state. Everything after that height will be
 verified by the node just like any other node.
 
 ```bash
-florestad --assume-utreexo
+$ florestad --assume-utreexo
+```
+
+#### Backfill
+
+If you want to get a node up and running in a few minutes, but still want to validate everything, you can start `florestad` with `assumeutreexo` and pass the `--backfill` flag. This will download the blocks from genesis to the assumed height, validate them and compare with the provided value, all in the background. This way, you can start using the node right away, and it will be fully validated in a few hours/days depending on your hardware.
+
+This is the default behavior of `florestad` if no flags are provided.
+
+```bash
+$ florestad --assume-utreexo --backfill
path: README.md
user: login: luca0x46
body: As the behavior of the `backfill` is now the standard procedure, I believe this part of the read me could be modified to match the usage. 

Something like:
```
After the node starts it will validate everything in the background using a backfill. It will download the blocks from genesis to the assumed height, validate them and compare with the provided value, all in the background. This way, you can start using the node right away, and it will be validated in a few hours/days depending on your hardware. You might notice this uses a lot of CPU and bandwith. 

This is the default behavior of the `florestad` if no flags are provided. You can disable it using:
```bash
$ florestad --no-backfill```
```   
created_at: 2025-03-17T17:44:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -188,4 +188,15 @@ pub struct Cli {
     /// write it to a file. This option should be an absolute path to a file. Usually, you'd
     /// write it to $DATA_DIR/florestad.pid
     pub pid_file: Option<String>,
+
+    #[arg(long, default_value_t = false)]
+    /// Whehter we should backfill
+    ///
+    /// If we assumeutreexo or use pow fraud proofs, you have the option to download and validate
+    /// the blocks that were skipped. This will take a long time, but will run on the background
+    /// and won't affect the node's operation. You may notice that this will take a lot of CPU
+    /// and bandwidth to run.
+    ///
+    /// This is the default behavior if either assumeutreexo or pow fraud proofs are enabled.
path: florestad/src/cli.rs
user: login: luca0x46
body: I would also suggest updating this to:
```
Whether we should backfill.

The default behavior is verifying the blocks that were skipped during node startup. This will run in the background and wont't affect node's operation. However, to disable the backfill, run the node using this flag.
```
created_at: 2025-03-17T17:50:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -166,6 +168,13 @@ pub struct Config {
     pub no_ssl: bool,
     /// Whether to allow fallback to v1 transport if v2 connection fails.
     pub allow_v1_fallback: bool,
+    /// Whehter we should backfill
+    ///
+    /// If we assumeutreexo or use pow fraud proofs, you have the option to download and validate
+    /// the blocks that were skipped. This will take a long time, but will run on the background
+    /// and won't affect the node's operation. You may notice that this will take a lot of CPU
+    /// and bandwidth to run.
path: florestad/src/florestad.rs
user: login: luca0x46
body: Same here. Updating to match the expected behavior.
created_at: 2025-03-17T17:52:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -166,6 +168,13 @@ pub struct Config {
     pub no_ssl: bool,
     /// Whether to allow fallback to v1 transport if v2 connection fails.
     pub allow_v1_fallback: bool,
+    /// Whehter we should backfill
+    ///
+    /// If we assumeutreexo or use pow fraud proofs, you have the option to download and validate
+    /// the blocks that were skipped. This will take a long time, but will run on the background
+    /// and won't affect the node's operation. You may notice that this will take a lot of CPU
+    /// and bandwidth to run.
path: florestad/src/florestad.rs
user: login: Davidson-Souza
body: We didn't negate this one. Only the CLI version
created_at: 2025-03-17T19:20:34Z
author_association: MEMBER

PR comments:
user: login: Davidson-Souza
created_at: 2024-08-15T21:13:01Z
body: Rebased with #172 and updated with @jaoleal suggestions.
author_association: MEMBER
user: login: jaoleal
created_at: 2024-11-23T14:11:34Z
body: Is this ready to merge ?
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2024-11-23T14:42:48Z
body: I don't remember the state of this 😆 . I'll rebase and see if it still works
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2024-11-23T16:39:26Z
body: @jaoleal pushed a rebase. The tests are green, but I haven't tried to run yet
author_association: MEMBER
user: login: luca0x46
created_at: 2025-02-24T13:59:47Z
body: I am reviewing it rn, it seems to me to be working, however it has not finished the idb yet. Is there a specific reason why it hasn't been merged yet?
author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-02-26T00:18:46Z
body: For the review, the only problem I encountered when using the backfill up to now (except for the bugs that will be fixed on rebase) is on checking the status of the backfill. I believe there should be an easy way to check the progress even while running on daemon. Maybe a follow-up PR?
author_association: CONTRIBUTOR
user: login: Davidson-Souza
created_at: 2025-02-26T14:04:42Z
body: > For the review, the only problem I encountered when using the backfill up to now (except for the bugs that will be fixed on rebase) is on checking the status of the backfill. I believe there should be an easy way to check the progress even while running on daemon. Maybe a follow-up PR?

This is a very good observation. I do think a follow-up would be better, this is already huge on its own.
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2025-02-26T14:05:20Z
body: Rebased with master

CC: @jaoleal  @lucad70
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2025-02-26T19:16:42Z
body: Force-pushed 7183d219adb4be24176111d9802f6ac0f9c3abe5 fixing a small bug with recovery
author_association: MEMBER
user: login: luca0x46
created_at: 2025-03-11T16:02:16Z
body: While I build a floresta-cli call to check the development during the backfill, I tried to force it true and noticed that starting the node using the command `florestad --assume-utreexo --backfill` is not setting the `self.config.backfill` to `true`. 

Basically I first ran the `florestad` and compared the logs with `florestad --assume-utreexo --backfill`. I noticed that there wasn't any change. Then I modified the code to hardcode activate the backfill by changing this condition to always being true. On this code snipet at `running_node.rs`

```
        if self.config.backfill {
            info!("Starting backfill task...");
            self.backfill(sender)
                .expect("Failed to spawn backfill thread");
        }
```

To:
```
        if true {
...
        }
```

Then I ran `florestad` to see if there was any change on the logs as I had expected, it did. It now enabled the backfill. 
- Step 1: Running without any args
```
~Laptop Floresta % florestad
[2025-03-11 12:18:26 WARN florestad::florestad] Could not read config file, ignoring it
…
[2025-03-11 12:19:24 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-11 12:19:24 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
…
```
- Step 2: Running using `--assume-utreexo --backfill`
```
~Laptop Floresta % florestad --assume-utreexo --backfill
[2025-03-11 12:20:47 WARN florestad::florestad] Could not read config file, ignoring it
…
[2025-03-11 12:21:47 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-11 12:21:47 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
…
```

- Step 3: running again without args
```
~Laptop Floresta % florestad
[2025-03-11 12:24:38 WARN florestad::florestad] Could not read config file, ignoring it
…
[2025-03-11 12:25:16 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-11 12:25:16 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
...
```

- Step 4: Forcing the logic to `self.config.backfill == true`

```
~Laptop Floresta % florestad
[2025-03-11 12:27:27 WARN florestad::florestad] Could not read config file, ignoring it
…
[2025-03-11 12:28:17 INFO floresta_wire::p2p_wire::chain_selector] Finished downloading headers from peer=0, checking if our peers agree
_[2025-03-11 12:28:18 INFO floresta_wire::p2p_wire::running_node] Starting backfill task...
[2025-03-11 12:28:18 INFO floresta_wire::p2p_wire::running_node] Recovering backfill node from state tip=0, end=861955_
[2025-03-11 12:28:28 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-11 12:28:28 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
[2025-03-11 12:28:28 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
…
```

- Step 5: To check if it was a problem of config consistency, I performed a cargo clean after these runs and ran first the `florestad --assume-utreexo --backfill` and got the following

```
Floresta % florestad --assume-utreexo --backfill
[2025-03-11 12:44:27 WARN florestad::florestad] Could not read config file, ignoring it
…
[2025-03-11 12:45:31 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-11 12:45:31 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
…
```

So in my review, running `florestad --assume-utreexo --backfill` is not starting the backfill. If it is a misunderstanding of the code and of the README.md please let me know. 

PS: after these I tried running `florestad --backfill` only and got the same logs as running only `florestad` without args.


author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-03-12T18:20:22Z
body: @qlrd suggested that maybe the logic is inverted somewhere... He added the `!` and the backfill started

- Adding a `println!("BACKFILL: {}", params.backfill)` on the florestad `main.rs` CLI returns:
```
     Running `target/debug/florestad --assume-utreexo --backfill`
BACKFILL: true
```

- Adding the `!` on the logic starts the backfill:

Code changed:
```
        if !self.config.backfill {
            info!("Starting backfill task...");
            self.backfill(sender)
                .expect("Failed to spawn backfill thread");
        }
```

Result:

```
     Running `target/debug/florestad --assume-utreexo --backfill`
BACKFILL: true
[2025-03-12 15:12:34 WARN florestad::florestad] Could not read config file, ignoring it
...
[2025-03-12 15:13:57 INFO floresta_wire::p2p_wire::chain_selector] Finished downloading headers from peer=0, checking if our peers agree
[2025-03-12 15:13:59 INFO floresta_wire::p2p_wire::running_node] Starting backfill task...
[2025-03-12 15:13:59 INFO floresta_wire::p2p_wire::running_node] Recovering backfill node from state tip=0, end=861955
[2025-03-12 15:14:28 INFO floresta_wire::p2p_wire::running_node] Catching up with the network...
[2025-03-12 15:14:28 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
[2025-03-12 15:14:28 INFO floresta_wire::p2p_wire::sync_node] Starting sync node
```

As a note: I don't believe there should be two `Starting sync node` logs
author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-03-12T18:47:47Z
body: @qlrd helped and we found were it is hardcoded to `false`

Line 408 at `florestad.rs` reads: `backfill: false,`

Full code snipet here:

```
        let config = UtreexoNodeConfig {
            network: Self::get_net(&self.config.network),
            pow_fraud_proofs,
            proxy: self
                .config
                .proxy
                .as_ref()
                .map(|host| Self::get_ip_address(host, 9050)),
            datadir: data_dir.clone(),
            fixed_peer: self.config.connect.clone(),
            max_banscore: 50,
            compact_filters: self.config.cfilters,
            max_outbound: 10,
            max_inflight: 20,
            assume_utreexo: self.config.assumeutreexo_value.clone().or(assume_utreexo),
            backfill: false,
            filter_start_height: self.config.filters_start_height,
            user_agent: self.config.user_agent.clone(),
        };
```

Thanks @qlrd !
author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-03-12T18:49:41Z
body: - Changing line `backfill: false,` to `self.config.backfill` resulted on correctly activating the backfill

```
[2025-03-12 15:55:39 INFO floresta_wire::p2p_wire::running_node] Starting backfill task...
[2025-03-12 15:55:39 INFO floresta_wire::p2p_wire::running_node] Recovering backfill node from state tip=0, end=861955
```
author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-03-13T12:33:59Z
body: I was thinking about the fact in this concept the `--backfill` is true even if the user does not set the flag. However, shouldn't there be a way for the user to set it to false? Maybe the CLI could be `florestad --assume-utreexo --backfill true/false` 

In this way, the CLI should be modified to take an arg of true or false. Or it could be just 1 (true) and 0 (false)
What do you think @Davidson-Souza ?
author_association: CONTRIBUTOR
user: login: qlrd
created_at: 2025-03-13T13:49:58Z
body: >  Maybe the CLI could be florestad --assume-utreexo --backfill true/false

Maybe just a `florestad --assume-utreexo --no-backfill` would suffice, in this case?
author_association: CONTRIBUTOR
user: login: luca0x46
created_at: 2025-03-14T02:00:16Z
body: > >  Maybe the CLI could be florestad --assume-utreexo --backfill true/false
> 
> 
> 
> Maybe just a `florestad --assume-utreexo --no-backfill` would suffice, in this case?

I believe it could. So the user only uses the flag if he wants to disable the standard procedure of backfill. But then would it still `assume utreexo`?
author_association: CONTRIBUTOR
user: login: Davidson-Souza
created_at: 2025-03-14T14:27:14Z
body: @qlrd @lucad70 thanks for spotting this.

> Maybe just a florestad --assume-utreexo --no-backfill would suffice, in this case?

I think this is the way to go. I want backfill to be default on, so a flag to disable it should be enough.
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2025-03-17T16:52:21Z
body: After a little CI fight, I think this is ready to go. I've repeated the process many times and it works just fine
author_association: MEMBER
user: login: Davidson-Souza
created_at: 2025-03-17T20:58:36Z
body: Just realized we also need to flip the `--assume-utreexo` switch as well, or it won't do anything.
author_association: MEMBER