Skip to content

Commit

Permalink
feat(rooch): add tx anomaly detection in rollback
Browse files Browse the repository at this point in the history
Implement anomaly detection for duplicate transactions during rollback. Introduce utility to derive genesis namespace from chain ID and integrate it with rollback command.
  • Loading branch information
popcnt1 committed Feb 25, 2025
1 parent 9cb444d commit 4f99a42
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 7 deletions.
32 changes: 25 additions & 7 deletions crates/rooch/src/commands/db/commands/rollback.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::utils::open_rooch_db;
use crate::utils::{derive_builtin_genesis_namespace_from_rooch_chain_id, open_rooch_db};
use anyhow::Error;
use clap::Parser;
use moveos_common::utils::to_bytes;
Expand All @@ -12,6 +12,7 @@ use moveos_types::startup_info;
use raw_store::rocks::batch::WriteBatch;
use raw_store::traits::DBStore;
use rooch_config::R_OPT_NET_HELP;
use rooch_pipeline_processor::actor::load_tx_anomalies;
use rooch_store::meta_store::SEQUENCER_INFO_KEY;
use rooch_store::META_SEQUENCER_INFO_COLUMN_FAMILY_NAME;
use rooch_types::error::{RoochError, RoochResult};
Expand All @@ -33,6 +34,14 @@ pub struct RollbackCommand {

impl RollbackCommand {
pub async fn execute(self) -> RoochResult<()> {
let tx_anomalies = if let Some(genesis_namespace) =
derive_builtin_genesis_namespace_from_rooch_chain_id(self.chain_id.clone())?
{
load_tx_anomalies(genesis_namespace)?
} else {
None
};

let tx_order = self.tx_order;
if tx_order == 0 {
return Err(RoochError::from(Error::msg(
Expand All @@ -42,7 +51,7 @@ impl RollbackCommand {
let (_root, rooch_db, _start_time) = open_rooch_db(self.base_data_dir, self.chain_id);

// check
// 1. tx_hash exist via tx_order
// 1. tx_hash exists via tx_order
let tx_hashes = rooch_db
.rooch_store
.transaction_store
Expand All @@ -54,7 +63,16 @@ impl RollbackCommand {
))));
}
let tx_hash = tx_hashes[0].unwrap();
// 2. tx_order must be less than last_order
// 2. tx_hash is not duplicate
if let Some(anomalies) = tx_anomalies {
if anomalies.is_dup_hash(&tx_hash) {
return Err(RoochError::from(Error::msg(format!(
"rollback tx failed: tx_hash {:?} is duplicate, try to rollback previous tx",
tx_hash
))));
}
}
// 3. tx_order must be less than last_order
let last_sequencer_info = rooch_db
.rooch_store
.get_meta_store()
Expand All @@ -67,8 +85,8 @@ impl RollbackCommand {
tx_order, last_order
))));
}
// 3. tx saved, sequenced, executed
// 3.1 tx saved
// 4. tx saved, sequenced, executed
// 4.1 tx saved
let ledger_tx_opt = rooch_db
.rooch_store
.transaction_store
Expand All @@ -79,10 +97,10 @@ impl RollbackCommand {
tx_hash
))));
}
// 3.2 tx sequenced
// 4.2 tx sequenced
let sequencer_info = ledger_tx_opt.unwrap().sequence_info;
assert_eq!(sequencer_info.tx_order, tx_order);
// 3.3 tx executed
// 4.3 tx executed
let execution_info = rooch_db
.moveos_store
.transaction_store
Expand Down
16 changes: 16 additions & 0 deletions crates/rooch/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,22 @@ pub fn open_inner_rocks(
}
}

pub fn derive_builtin_genesis_namespace_from_rooch_chain_id(
chain_id: Option<RoochChainID>,
) -> anyhow::Result<Option<String>> {
if chain_id.is_none() {
return Ok(None);
}

match chain_id.unwrap() {
RoochChainID::Builtin(builtin_chain_id) => {
let namespace = derive_builtin_genesis_namespace(builtin_chain_id)?;
Ok(Some(namespace))
}
RoochChainID::Custom(_) => Ok(None),
}
}

pub fn derive_builtin_genesis_namespace(chain_id: BuiltinChainID) -> anyhow::Result<String> {
let genesis = load_genesis_from_binary(chain_id)?.expect("Genesis not found");
let genesis_hash = genesis.genesis_hash();
Expand Down

0 comments on commit 4f99a42

Please sign in to comment.