Skip to content

Commit

Permalink
[CLI] add command to rollback state to a special tx order (#2446)
Browse files Browse the repository at this point in the history
  • Loading branch information
jolestar authored Aug 17, 2024
1 parent 3a04190 commit 44a2682
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 8 deletions.
2 changes: 2 additions & 0 deletions crates/rooch/src/commands/db/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

pub mod revert_tx;
pub mod rollback;
6 changes: 2 additions & 4 deletions crates/rooch/src/commands/db/commands/revert_tx.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use std::path::PathBuf;
use std::time::SystemTime;

use anyhow::Error;
use clap::Parser;
use metrics::RegistryService;

use moveos_store::transaction_store::TransactionStore as TxExecutionInfoStore;
use moveos_store::MoveOSStore;
use moveos_types::moveos_std::object::ObjectMeta;
Expand All @@ -19,6 +15,8 @@ use rooch_store::RoochStore;
use rooch_types::error::{RoochError, RoochResult};
use rooch_types::rooch_network::RoochChainID;
use rooch_types::sequencer::SequencerInfo;
use std::path::PathBuf;
use std::time::SystemTime;

use crate::cli_types::WalletContextOptions;

Expand Down
171 changes: 171 additions & 0 deletions crates/rooch/src/commands/db/commands/rollback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use anyhow::Error;
use clap::Parser;
use metrics::RegistryService;
use moveos_store::config_store::ConfigStore;
use moveos_store::transaction_store::TransactionStore as TxExecutionInfoStore;
use moveos_store::MoveOSStore;
use moveos_types::moveos_std::object::ObjectMeta;
use moveos_types::startup_info;
use rooch_config::{RoochOpt, R_OPT_NET_HELP};
use rooch_db::RoochDB;
use rooch_genesis::RoochGenesis;
use rooch_store::RoochStore;
use rooch_types::error::{RoochError, RoochResult};
use rooch_types::rooch_network::RoochChainID;
use rooch_types::sequencer::SequencerInfo;
use std::path::PathBuf;
use std::time::SystemTime;

use crate::cli_types::WalletContextOptions;

/// Rollback the state to a specific transaction order.
#[derive(Debug, Parser)]
pub struct RollbackCommand {
#[clap(long, short = 'o')]
/// tx order which the state will rollback to
pub tx_order: u64,

#[clap(long = "data-dir", short = 'd')]
/// Path to data dir, this dir is base dir, the final data_dir is base_dir/chain_network_name
pub base_data_dir: Option<PathBuf>,

/// If local chainid, start the service with a temporary data store.
/// All data will be deleted when the service is stopped.
#[clap(long, short = 'n', help = R_OPT_NET_HELP)]
pub chain_id: Option<RoochChainID>,

#[clap(flatten)]
pub context_options: WalletContextOptions,
}

impl RollbackCommand {
pub async fn execute(self) -> RoochResult<()> {
let tx_order = self.tx_order;
let (_root, moveos_store, rooch_store, _start_time) = self.init();

let last_sequencer_info = rooch_store
.get_meta_store()
.get_sequencer_info()?
.ok_or_else(|| anyhow::anyhow!("Load sequencer info failed"))?;
let (last_order, last_accumulator_info) = (
last_sequencer_info.last_order,
last_sequencer_info.last_accumulator_info.clone(),
);
println!("Load latest sequencer order {:?}", last_order);
println!(
"Load latest sequencer accumulator info {:?}",
last_accumulator_info
);

if tx_order >= last_order {
return Err(RoochError::from(Error::msg(format!(
"tx order {} is greater or equals than last order {}",
tx_order, last_order
))));
}

let tx_hashes = rooch_store.transaction_store.get_tx_hashs(vec![tx_order])?;
// check tx hash exist via tx_order
if tx_hashes.is_empty() || tx_hashes[0].is_none() {
return Err(RoochError::from(Error::msg(format!(
"tx hash not exist via tx order {}",
tx_order
))));
}
let tx_hash = tx_hashes[0].unwrap();

let ledger_tx_opt = rooch_store
.transaction_store
.get_transaction_by_hash(tx_hash)?;
if ledger_tx_opt.is_none() {
println!("the ledger tx not exist via tx_hash {}", tx_hash);
return Ok(());
}
let sequencer_info = ledger_tx_opt.unwrap().sequence_info;
assert_eq!(sequencer_info.tx_order, tx_order);
let tx_order = sequencer_info.tx_order;

let execution_info = moveos_store
.transaction_store
.get_tx_execution_info(tx_hash)?;

if execution_info.is_none() {
return Err(RoochError::from(Error::msg(format!(
"the tx execution info not exist via tx_hash {}",
tx_hash
))));
}

let execution_info = execution_info.unwrap();
let start_order = tx_order + 1;
for order in (start_order..=last_order).rev() {
let tx_hashes = rooch_store.transaction_store.get_tx_hashs(vec![order])?;
if tx_hashes.is_empty() || tx_hashes[0].is_none() {
return Err(RoochError::from(Error::msg(format!(
"tx hash not exist via tx order {}",
order
))));
}
let tx_hash = tx_hashes[0].unwrap();
let ledger_tx_opt = rooch_store
.transaction_store
.get_transaction_by_hash(tx_hash)?;

if ledger_tx_opt.is_none() {
println!("the ledger tx not exist via tx_hash {}", tx_hash);
continue;
}

let sequencer_info = ledger_tx_opt.unwrap().sequence_info;
let tx_order = sequencer_info.tx_order;
rooch_store
.transaction_store
.remove_transaction(tx_hash, tx_order)?;
moveos_store
.transaction_store
.remove_tx_execution_info(tx_hash)?;
println!(
"remove tx succ, tx_hash: {:?}, tx_order {}",
tx_hash, tx_order
);
}

let rollback_sequencer_info = SequencerInfo {
last_order: tx_order,
last_accumulator_info: sequencer_info.tx_accumulator_info(),
};
rooch_store
.meta_store
.save_sequencer_info_ignore_check(rollback_sequencer_info)?;
let startup_info =
startup_info::StartupInfo::new(execution_info.state_root, execution_info.size);

moveos_store.save_startup_info(startup_info)?;

println!(
"rollback succ, tx_hash: {:?}, tx_order {}, state_root: {:?}",
tx_hash, tx_order, execution_info.state_root
);
Ok(())
}

fn init(self) -> (ObjectMeta, MoveOSStore, RoochStore, SystemTime) {
let start_time = SystemTime::now();

let opt = RoochOpt::new_with_default(self.base_data_dir, self.chain_id, None).unwrap();
let registry_service = RegistryService::default();
let rooch_db =
RoochDB::init(opt.store_config(), &registry_service.default_registry()).unwrap();
let genesis = RoochGenesis::load_or_init(opt.network(), &rooch_db).unwrap();
let root = genesis.genesis_root().clone();
(
root,
rooch_db.moveos_store,
rooch_db.rooch_store,
start_time,
)
}
}
11 changes: 7 additions & 4 deletions crates/rooch/src/commands/db/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::cli_types::CommandAction;
use crate::commands::db::commands::revert_tx::RevertTxCommand;
use async_trait::async_trait;
use clap::Parser;

use commands::rollback::RollbackCommand;
use rooch_types::error::RoochResult;

use crate::cli_types::CommandAction;
use crate::commands::db::commands::revert_tx::RevertTxCommand;

pub mod commands;

/// DB Commands
Expand All @@ -25,6 +24,9 @@ impl CommandAction<String> for DB {
DBCommand::RevertTx(revert_tx) => revert_tx.execute().await.map(|resp| {
serde_json::to_string_pretty(&resp).expect("Failed to serialize response")
}),
DBCommand::Rollback(rollback) => rollback.execute().await.map(|resp| {
serde_json::to_string_pretty(&resp).expect("Failed to serialize response")
}),
}
}
}
Expand All @@ -33,4 +35,5 @@ impl CommandAction<String> for DB {
#[clap(name = "db")]
pub enum DBCommand {
RevertTx(RevertTxCommand),
Rollback(RollbackCommand),
}
5 changes: 5 additions & 0 deletions moveos/moveos-store/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ impl TransactionStore for MoveOSStore {
self.get_transaction_store()
.multi_get_tx_execution_infos(tx_hashes)
}

fn remove_tx_execution_info(&self, tx_hash: H256) -> Result<()> {
self.get_transaction_store()
.remove_tx_execution_info(tx_hash)
}
}

impl ConfigStore for MoveOSStore {
Expand Down
5 changes: 5 additions & 0 deletions moveos/moveos-store/src/transaction_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub trait TransactionStore {
&self,
tx_hashes: Vec<H256>,
) -> Result<Vec<Option<TransactionExecutionInfo>>>;
fn remove_tx_execution_info(&self, tx_hash: H256) -> Result<()>;
}

impl TransactionStore for TransactionDBStore {
Expand All @@ -40,4 +41,8 @@ impl TransactionStore for TransactionDBStore {
) -> Result<Vec<Option<TransactionExecutionInfo>>> {
self.multiple_get(tx_hashes)
}

fn remove_tx_execution_info(&self, tx_hash: H256) -> Result<()> {
self.remove(tx_hash)
}
}

0 comments on commit 44a2682

Please sign in to comment.