explorer: integrate reorg handling with block subscription and subscription sync

This commit integrates blockchain reorg functionality into the explorer’s block syncing and subscriptions, addressing inconsistencies and aligning the explorer state with a Darkfi node. Key improvements include reorg detection and handling in block synchronization and subscriptions, consolidated and refined logging for better observability, state reset methods to reliably handle reorg scenarios, and enhanced safeguards to ensure consistency before starting subscriptions.

Summary of Updates:

## Blocks Module
- Added `get_block_by_height` to retrieve blocks by height to support reorg handling
- Added `reset_to_height` function to reset blocks and related transactions to a specific height, enabling transactional resets. This function was introduced because the blockchain layer's equivalent function could not be reused due to the absence of `StateDiffs` on the explorer side.
- Changed the log level of `reset_blocks` to `debug` to streamline reorg-related logging

## Transaction Module
- Changed the log level of `reset_blocks` to `debug` to streamline reorg-related logging

## Binary Crate (main.rs)
- Added `reset_explorer_state` to reset the explorer state to a given height or to genesis. This ensures consistency across blocks, transactions, and metrics during resets or reorgs
- Updated logging to include transaction count during ExplorerDb initialization

## Rpc Blocks Module
- Refined variable and function names with "darkfid" for improved readability

### Block Sync Reorgs
- Implemented block sync reorg handling to detect and resolve inconsistencies between the Darkfid node and the explorer
- Introduced reorg detection logic based on mismatched block hashes and heights
- Added support for handling reorg scenarios, including genesis related cases
- Extended logging to report detected reorgs and re-alignments
- Updated the `reset` flag handling to purge and resync the explorer state from scratch when enabled
- Added `process_sync_blocks_reorg` to identify mismatched blocks and realign the explorer's blockchain state to the correct height

## Subscription Sync Reorgs
- Added reorg handling in the subscription process to detect reorgs through block height mismatches and reset the explorer state as needed
- Improved safeguards against mismatched last synced and last confirmed blocks before initiating the subscription process

These updates provide explorer nodes the ability to handle blockchain reorgs and ensure alignment with the canonical chain from Darkfi nodes.
This commit is contained in:
kalm
2025-02-17 23:03:06 -08:00
parent 26f69b3e16
commit ce5dc4988b
5 changed files with 351 additions and 81 deletions

View File

@@ -16,7 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use log::{debug, info};
use log::{debug, warn};
use sled_overlay::sled::{transaction::ConflictableTransactionError, Transactional};
use tinyjson::JsonValue;
use darkfi::{
@@ -27,7 +28,7 @@ use darkfi::{
util::time::Timestamp,
Error, Result,
};
use darkfi_sdk::crypto::schnorr::Signature;
use darkfi_sdk::{crypto::schnorr::Signature, tx::TransactionHash};
use crate::ExplorerService;
@@ -95,7 +96,7 @@ impl ExplorerService {
let tree = db.open_tree(tree_name)?;
tree.clear()?;
let tree_name_str = std::str::from_utf8(tree_name)?;
info!(target: "blockchain-explorer::blocks", "Successfully reset block tree: {tree_name_str}");
debug!(target: "blockchain-explorer::blocks", "Successfully reset block tree: {tree_name_str}");
}
Ok(())
@@ -167,7 +168,7 @@ impl ExplorerService {
// Fetch block by hash and handle encountered errors
match self.db.blockchain.get_blocks_by_hash(&[header_hash]) {
Ok(blocks) => Ok(Some(BlockRecord::from(&blocks[0]))),
Ok(blocks) => Ok(blocks.first().map(BlockRecord::from)),
Err(Error::BlockNotFound(_)) => Ok(None),
Err(e) => Err(Error::DatabaseError(format!(
"[get_block_by_hash] Block retrieval failed: {e:?}"
@@ -175,6 +176,18 @@ impl ExplorerService {
}
}
/// Fetch a block given its height from the database.
pub fn get_block_by_height(&self, height: u32) -> Result<Option<BlockRecord>> {
// Fetch block by height and handle encountered errors
match self.db.blockchain.get_blocks_by_heights(&[height]) {
Ok(blocks) => Ok(blocks.first().map(BlockRecord::from)),
Err(Error::BlockNotFound(_)) => Ok(None),
Err(e) => Err(Error::DatabaseError(format!(
"[get_block_by_height] Block retrieval failed: {e:?}"
))),
}
}
/// Fetch the last block from the database.
pub fn last_block(&self) -> Result<Option<(u32, String)>> {
let block_store = &self.db.blockchain.blocks;
@@ -218,4 +231,94 @@ impl ExplorerService {
Ok(block_records)
}
/// Resets the [`ExplorerDb::blockchain::blocks`] and [`ExplorerDb::blockchain::transactions`]
/// trees to a specified height by removing entries above the `reset_height`, returning a result
/// that indicates success or failure.
///
/// The function retrieves the last explorer block and iteratively rolls back entries
/// in the [`BlockStore::main`], [`BlockStore::order`], and [`BlockStore::difficulty`] trees
/// to the specified `reset_height`. It also resets the [`TxStore::main`] and
/// [`TxStore::location`] trees to reflect the transaction state at the given height.
///
/// This operation is performed atomically using a sled transaction applied across the affected sled
/// trees, ensuring consistency and avoiding partial updates.
pub fn reset_to_height(&self, reset_height: u32) -> Result<()> {
let block_store = &self.db.blockchain.blocks;
let tx_store = &self.db.blockchain.transactions;
debug!(target: "blockchain_explorer::blocks::reset_to_height", "Resetting to height {reset_height}: block_count={}, txs_count={}", block_store.len(), tx_store.len());
// Get the last block height
let (last_block_height, _) = block_store.get_last().map_err(|e| {
Error::DatabaseError(format!(
"[reset_to_height]: Failed to get the last block height: {e:?}"
))
})?;
// Skip resetting blocks if `reset_height` is greater than or equal to `last_block_height`
if reset_height >= last_block_height {
warn!(target: "blockchain_explorer::blocks::reset_to_height",
"Nothing to reset because reset_height is greater than or equal to last_block_height: {reset_height} >= {last_block_height}");
return Ok(());
}
// Get the associated block infos in order to obtain transactions to reset
let block_infos_to_reset =
&self.db.blockchain.get_by_range(reset_height, last_block_height).map_err(|e| {
Error::DatabaseError(format!(
"[reset_to_height]: Failed to get the transaction hashes to reset: {e:?}"
))
})?;
// Collect the transaction hashes from the blocks that need resetting
let txs_hashes_to_reset: Vec<TransactionHash> = block_infos_to_reset
.iter()
.flat_map(|block_info| block_info.txs.iter().map(|tx| tx.hash()))
.collect();
// Perform the reset operation atomically using a sled transaction
let tx_result = (&block_store.main, &block_store.order, &block_store.difficulty, &tx_store.main, &tx_store.location)
.transaction(|(block_main, block_order, block_difficulty, tx_main, tx_location)| {
// Traverse the block heights in reverse, removing each block up to (but not including) reset_height
for height in (reset_height + 1..=last_block_height).rev() {
let height_key = height.to_be_bytes();
// Fetch block from `order` tree to obtain the block hash needed to remove blocks from `main` tree
let order_header_hash = block_order.get(height_key).map_err(ConflictableTransactionError::Abort)?;
if let Some(header_hash) = order_header_hash {
// Remove block from the `main` tree
block_main.remove(&header_hash).map_err(ConflictableTransactionError::Abort)?;
// Remove block from the `difficulty` tree
block_difficulty.remove(&height_key).map_err(ConflictableTransactionError::Abort)?;
// Remove block from the `order` tree
block_order.remove(&height_key).map_err(ConflictableTransactionError::Abort)?;
}
debug!(target: "blockchain_explorer::blocks::reset_to_height", "Removed block at height: {height}");
}
// Iterate through the transaction hashes, removing the related transactions
for (tx_count, tx_hash) in txs_hashes_to_reset.iter().enumerate() {
// Remove transaction from the `main` tree
tx_main.remove(tx_hash.inner()).map_err(ConflictableTransactionError::Abort)?;
// Remove transaction from the `location` tree
tx_location.remove(tx_hash.inner()).map_err(ConflictableTransactionError::Abort)?;
debug!(target: "blockchain_explorer::blocks::reset_to_height", "Removed transaction ({tx_count}): {tx_hash}");
}
Ok(())
})
.map_err(|e| {
Error::DatabaseError(format!("[reset_to_height]: Resetting height failed: {e:?}"))
});
debug!(target: "blockchain_explorer::blocks::reset_to_height", "Successfully reset to height {reset_height}: block_count={}, txs_count={}", block_store.len(), tx_store.len());
tx_result
}
}

View File

@@ -51,7 +51,6 @@ pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
/// Handles a database error by formatting the output, logging it with target-specific context,
/// and returning a [`DatabaseError`].
#[allow(dead_code)] // TODO: Remove once code that uses this function is rebased into master
pub fn handle_database_error(target: &str, message: &str, error: impl std::fmt::Debug) -> Error {
let error_message = format!("{}: {:?}", message, error);
let formatted_target = format!("blockchain-explorer:: {target}");

View File

@@ -23,7 +23,7 @@ use std::{
};
use lazy_static::lazy_static;
use log::{error, info};
use log::{debug, error, info};
use rpc_blocks::subscribe_blocks;
use sled_overlay::sled;
use smol::{lock::Mutex, stream::StreamExt};
@@ -225,6 +225,36 @@ impl ExplorerService {
Ok(())
}
/// Resets the explorer state to the specified height. If a genesis block height is provided,
/// all blocks and transactions are purged from the database. Otherwise, the state is reverted
/// to the given height. The explorer metrics are updated to reflect the updated blocks and
/// transactions up to the reset height, ensuring consistency. Returns a result indicating
/// success or an error if the operation fails.
pub fn reset_explorer_state(&self, height: u32) -> Result<()> {
debug!(target: "blockchain-explorer::reset_explorer_state", "Resetting explorer state to height: {height}");
// Check if a genesis block reset or to a specific height
match height {
// Reset for genesis height 0, purge blocks and transactions
0 => {
self.reset_blocks()?;
self.reset_transactions()?;
debug!(target: "blockchain-explorer::reset_explorer_state", "Successfully reset explorer state to accept a new genesis block");
}
// Reset for all other heights
_ => {
self.reset_to_height(height)?;
debug!(target: "blockchain-explorer::reset_explorer_state", "Successfully reset blocks to height: {height}");
}
}
// Reset gas metrics to the specified height to reflect the updated blockchain state
self.db.metrics_store.reset_gas_metrics(height)?;
debug!(target: "blockchain-explorer::reset_explorer_state", "Successfully reset metrics store to height: {height}");
Ok(())
}
}
/// Represents the explorer database backed by a `sled` database connection, responsible for maintaining
@@ -249,8 +279,7 @@ impl ExplorerDb {
let blockchain = Blockchain::new(&sled_db)?;
let metrics_store = MetricsStore::new(&sled_db)?;
let contract_meta_store = ContractMetaStore::new(&sled_db)?;
info!(target: "blockchain-explorer", "Initialized explorer database {}, block count: {}", db_path.display(), blockchain.len());
info!(target: "blockchain-explorer", "Initialized explorer database {}: block count: {}, tx count: {}", db_path.display(), blockchain.len(), blockchain.txs_len());
Ok(Self { sled_db, blockchain, metrics_store, contract_meta_store })
}
}

View File

@@ -18,7 +18,7 @@
use std::sync::Arc;
use log::{error, info, warn};
use log::{debug, error, info, warn};
use tinyjson::JsonValue;
use url::Url;
@@ -37,11 +37,11 @@ use darkfi::{
};
use darkfi_serial::deserialize_async;
use crate::Explorerd;
use crate::{error::handle_database_error, Explorerd};
impl Explorerd {
// Queries darkfid for a block with given height.
async fn get_block_by_height(&self, height: u32) -> Result<BlockInfo> {
async fn get_darkfid_block_by_height(&self, height: u32) -> Result<BlockInfo> {
let params = self
.darkfid_daemon_request(
"blockchain.get_block",
@@ -54,64 +54,176 @@ impl Explorerd {
Ok(block)
}
/// Syncs the blockchain starting from the last synced block.
/// If reset flag is provided, all tables are reset, and start syncing from beginning.
/// Synchronizes blocks between the explorer and a Darkfi blockchain node, ensuring
/// the database remains consistent by syncing any missing or outdated blocks.
///
/// If provided `reset` is true, the explorer's blockchain-related and metric sled trees are purged
/// and syncing starts from the genesis block. The function also handles reorgs by re-aligning the
/// explorer state to the correct height when blocks are outdated. Returns a result indicating
/// success or failure.
///
/// Reorg handling is delegated to the [`Self::process_sync_blocks_reorg`] function, whose
/// documentation provides more details on the reorg process during block syncing.
pub async fn sync_blocks(&self, reset: bool) -> Result<()> {
// Grab last synced block height
let mut height = match self.service.last_block() {
Ok(Some((height, _))) => height,
Ok(None) => 0,
Err(e) => {
return Err(Error::DatabaseError(format!(
"[sync_blocks] Retrieving last synced block failed: {:?}",
e
)));
}
};
// If last synced block is genesis (0) or reset flag
// has been provided we reset, otherwise continue with
// the next block height
if height == 0 || reset {
self.service.reset_blocks()?;
height = 0;
} else {
height += 1;
};
loop {
// Grab last confirmed block
let (last_height, last_hash) = self.get_last_confirmed_block().await?;
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Requested to sync from block number: {height}");
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Last confirmed block number reported by darkfid: {last_height} - {last_hash}");
// Already synced last confirmed block
if height > last_height {
return Ok(())
}
while height <= last_height {
let block = match self.get_block_by_height(height).await {
Ok(r) => r,
Err(e) => {
let error_message =
format!("[sync_blocks] RPC client request failed: {:?}", e);
error!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "{}", error_message);
return Err(Error::DatabaseError(error_message));
}
};
if let Err(e) = self.service.put_block(&block).await {
let error_message = format!("[sync_blocks] Put block failed: {:?}", e);
error!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "{}", error_message);
return Err(Error::DatabaseError(error_message));
};
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Synced block {height}");
height += 1;
// Grab last synced block height from the explorer's database.
let last_synced_block = self.service.last_block().map_err(|e| {
handle_database_error(
"rpc_blocks::sync_blocks",
"[sync_blocks] Retrieving last synced block failed",
e,
)
})?;
// Grab the last confirmed block height and hash from the darkfi node
let (last_darkfid_height, last_darkfid_hash) = self.get_last_confirmed_block().await?;
// Initialize the current height to sync from, starting from genesis block if last sync block does not exist
let (last_synced_height, last_synced_hash) = last_synced_block
.map_or((0, "".to_string()), |(height, header_hash)| (height, header_hash));
// Declare a mutable variable to track the current sync height while processing blocks
let mut current_height = last_synced_height;
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Requested to sync from block number: {current_height}");
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Last confirmed block number reported by darkfid: {last_darkfid_height} - {last_darkfid_hash}");
// A reorg is detected if the hash of the last synced block differs from the hash of the last confirmed block,
// unless the reset flag is set or the current height is 0
let reorg_detected = last_synced_hash != last_darkfid_hash && !reset && current_height != 0;
// If the reset flag is set, reset the explorer state and start syncing from the genesis block height.
// Otherwise, handle reorgs if detected, or proceed to the next block if not at the genesis height.
if reset {
self.service.reset_explorer_state(0)?;
current_height = 0;
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Successfully reset explorer database based on set reset parameter");
} else if reorg_detected {
current_height =
self.process_sync_blocks_reorg(last_synced_height, last_darkfid_height).await?;
// Log only if a reorg occurred
if current_height != last_synced_height {
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Successfully completed reorg to height: {current_height}");
}
// Prepare to sync the next block after reorg
current_height += 1;
} else if current_height != 0 {
// Resume syncing from the block after the last synced height
current_height += 1;
}
// Sync blocks until the explorer is up to date with the last confirmed block
while current_height <= last_darkfid_height {
// Retrieve the block from darkfi node by height
let block = match self.get_darkfid_block_by_height(current_height).await {
Ok(r) => r,
Err(e) => {
return Err(handle_database_error(
"rpc_blocks::sync_blocks",
"[sync_blocks] RPC client request failed",
e,
))
}
};
// Store the retrieved block in the explorer's database
if let Err(e) = self.service.put_block(&block).await {
return Err(handle_database_error(
"rpc_blocks::sync_blocks",
"[sync_blocks] Put block failed",
e,
))
};
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Synced block {current_height}");
// Increment the current height to sync the next block
current_height += 1;
}
info!(target: "blockchain-explorer::rpc_blocks::sync_blocks", "Completed sync, total number of explorer blocks: {}", self.service.db.blockchain.blocks.len());
Ok(())
}
/// Handles blockchain reorganizations (reorgs) during the explorer node's startup synchronization
/// with Darkfi nodes, ensuring the explorer provides a consistent and accurate view of the blockchain.
///
/// A reorg occurs when the blocks stored by the blockchain nodes diverge from those stored by the explorer.
/// This function resolves inconsistencies by identifying the point of divergence, searching backward through
/// block heights, and comparing block hashes between the explorer database and the blockchain node. Once a
/// common block height is found, the explorer is re-aligned to that height.
///
/// If no common block can be found, the explorer resets to the "genesis height," removing all blocks,
/// transactions, and metrics from its database to resynchronize with the canonical chain from the nodes.
///
/// Returns the last height at which the explorer's state was successfully re-aligned with the blockchain.
async fn process_sync_blocks_reorg(
&self,
last_synced_height: u32,
last_darkfid_height: u32,
) -> Result<u32> {
// Log reorg detection in the case that explorer height is greater or equal to height of darkfi node
if last_synced_height >= last_darkfid_height {
info!(target: "blockchain-explorer::rpc_blocks::process_sync_blocks_reorg",
"Reorg detected with heights: explorer.{last_synced_height} >= darkfid.{last_darkfid_height}");
}
// Declare a mutable variable to track the current height while searching for a common block
let mut cur_height = last_synced_height;
// Search for an explorer block that matches a darkfi node block
while cur_height > 0 {
let synced_block = self.service.get_block_by_height(cur_height)?;
debug!(target: "blockchain-explorer::rpc_blocks::process_sync_blocks_reorg", "Searching for common block: {}", cur_height);
// Check if we found a synced block for current height being searched
if let Some(synced_block) = synced_block {
// Fetch the block from darkfi node to check for a match
match self.get_darkfid_block_by_height(cur_height).await {
Ok(darkfid_block) => {
// If hashes match, we've found the point of divergence
if synced_block.header_hash == darkfid_block.hash().to_string() {
// If hashes match but the cur_height differs from the last synced height, reset the explorer state
if cur_height != last_synced_height {
self.service.reset_explorer_state(cur_height)?;
debug!(target: "blockchain-explorer::rpc_blocks::process_sync_blocks_reorg", "Successfully completed reorg to height: {cur_height}");
}
break;
} else {
// Log reorg detection with height and header hash mismatch details
if cur_height == last_synced_height {
info!(
target: "blockchain-explorer::rpc_blocks::process_sync_blocks_reorg",
"Reorg detected at height {}: explorer.{} != darkfid.{}",
cur_height,
synced_block.header_hash,
darkfid_block.hash().to_string()
);
}
}
}
// Continue searching for blocks that do not exist on darkfi nodes
Err(Error::JsonRpcError((-32121, _))) => (),
Err(e) => {
return Err(handle_database_error(
"rpc_blocks::process_sync_blocks_reorg",
"[process_sync_blocks_reorg] RPC client request failed",
e,
))
}
}
}
// Move to previous block to search for a match
cur_height = cur_height.saturating_sub(1);
}
// Check if genesis block reorg is needed
if cur_height == 0 {
self.service.reset_explorer_state(0)?;
}
// Return the last height we reorged to
Ok(cur_height)
}
// RPCAPI:
@@ -269,12 +381,12 @@ pub async fn subscribe_blocks(
ex: Arc<smol::Executor<'static>>,
) -> Result<(StoppableTaskPtr, StoppableTaskPtr)> {
// Grab last confirmed block
let (last_confirmed, _) = explorer.get_last_confirmed_block().await?;
let (last_darkfid_height, last_darkfid_hash) = explorer.get_last_confirmed_block().await?;
// Grab last synced block
let last_synced = match explorer.service.last_block() {
Ok(Some((height, _))) => height,
Ok(None) => 0,
let (mut height, hash) = match explorer.service.last_block() {
Ok(Some((height, hash))) => (height, hash),
Ok(None) => (0, "".to_string()),
Err(e) => {
return Err(Error::DatabaseError(format!(
"[subscribe_blocks] Retrieving last synced block failed: {e:?}"
@@ -282,12 +394,20 @@ pub async fn subscribe_blocks(
}
};
if last_confirmed != last_synced {
warn!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Warning: Last synced block is not the last confirmed block.");
// Evaluates whether there is a mismatch between the last confirmed block and the last synced block
let blocks_mismatch = (last_darkfid_height != height || last_darkfid_hash != hash) &&
last_darkfid_height != 0 &&
height != 0;
// Check if there is a mismatch, throwing an error to prevent operating in a potentially inconsistent state
if blocks_mismatch {
warn!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks",
"Warning: Last synced block is not the last confirmed block: \
last_darkfid_height={last_darkfid_height}, last_synced_height={height}, last_darkfid_hash={last_darkfid_hash}, last_synced_hash={hash}");
warn!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "You should first fully sync the blockchain, and then subscribe");
return Err(Error::DatabaseError(
"[subscribe_blocks] Blockchain not fully synced".to_string(),
))
));
}
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Subscribing to receive notifications of incoming blocks");
@@ -322,7 +442,7 @@ pub async fn subscribe_blocks(
loop {
match subscription.receive().await {
JsonResult::Notification(n) => {
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Got Block notification from darkfid subscription");
debug!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Got Block notification from darkfid subscription");
if n.method != "blockchain.subscribe_blocks" {
return Err(Error::UnexpectedJsonRpc(format!(
"Got foreign notification from darkfid: {}",
@@ -347,7 +467,7 @@ pub async fn subscribe_blocks(
let param = param.get::<String>().unwrap();
let bytes = base64::decode(param).unwrap();
let block_data: BlockInfo = match deserialize_async(&bytes).await {
let darkfid_block: BlockInfo = match deserialize_async(&bytes).await {
Ok(b) => b,
Err(e) => {
return Err(Error::UnexpectedJsonRpc(format!(
@@ -355,17 +475,36 @@ pub async fn subscribe_blocks(
)))
},
};
let header_hash = block_data.hash().to_string();
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "=======================================");
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Block header: {header_hash}");
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Block Notification: {}", darkfid_block.hash().to_string());
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "=======================================");
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Deserialized successfully. Storing block...");
if let Err(e) = explorer.service.put_block(&block_data).await {
// Store darkfi node block height for later use
let darkfid_block_height = darkfid_block.header.height;
// Check if we need to perform a reorg due to mismatch in block heights
if darkfid_block_height <= height {
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks",
"Reorg detected with heights: darkfid.{darkfid_block_height} <= explorer.{height}");
// Calculate the reset height
let reset_height = darkfid_block_height.saturating_sub(1);
// Execute the reorg by resetting the explorer state to reset height
explorer.service.reset_explorer_state(reset_height)?;
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Successfully completed reorg to height: {reset_height}");
}
if let Err(e) = explorer.service.put_block(&darkfid_block).await {
return Err(Error::DatabaseError(format!(
"[subscribe_blocks] Put block failed: {e:?}"
)))
}
info!(target: "blockchain-explorer::rpc_blocks::subscribe_blocks", "Successfully stored new block at height: {}", darkfid_block.header.height );
// Process the next block
height = darkfid_block.header.height;
}
}

View File

@@ -18,7 +18,7 @@
use std::collections::HashMap;
use log::{debug, error, info};
use log::{debug, error};
use smol::io::Cursor;
use tinyjson::JsonValue;
@@ -98,7 +98,7 @@ impl ExplorerService {
let tree = &self.db.blockchain.sled_db.open_tree(tree_name)?;
tree.clear()?;
let tree_name_str = std::str::from_utf8(tree_name)?;
info!(target: "blockchain-explorer::blocks", "Successfully reset transaction tree: {tree_name_str}");
debug!(target: "blockchain-explorer::blocks", "Successfully reset transaction tree: {tree_name_str}");
}
Ok(())