mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
script/research/tx-replayer: a tool to replay a transaction by resetting the blockchain database to a height before the transaction was added at
This commit is contained in:
6
script/research/tx-replayer/.gitignore
vendored
Normal file
6
script/research/tx-replayer/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
rustfmt.toml
|
||||||
|
tx-replayer
|
||||||
|
*.zst
|
||||||
|
*.json.gz
|
||||||
24
script/research/tx-replayer/Cargo.toml
Normal file
24
script/research/tx-replayer/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "tx-replayer"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "CLI-utility to replay transactions for analysis"
|
||||||
|
authors = ["Dyne.org foundation <foundation@dyne.org>"]
|
||||||
|
repository = "https://codeberg.org/darkrenaissance/darkfi"
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
darkfi = {path = "../../../", features = ["validator"]}
|
||||||
|
darkfi-sdk = {path = "../../../src/sdk"}
|
||||||
|
sled-overlay = {version = "0.1.10"}
|
||||||
|
smol = {version = "2.0.2"}
|
||||||
|
clap = {version = "4.4.11", features = ["derive"]}
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||||
|
halo2_gadgets = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
37
script/research/tx-replayer/Makefile
Normal file
37
script/research/tx-replayer/Makefile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.POSIX:
|
||||||
|
|
||||||
|
# Install prefix
|
||||||
|
PREFIX = $(HOME)/.cargo
|
||||||
|
|
||||||
|
# Cargo binary
|
||||||
|
CARGO = cargo
|
||||||
|
|
||||||
|
# Compile target
|
||||||
|
RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
|
||||||
|
# Uncomment when doing musl static builds
|
||||||
|
#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
|
||||||
|
|
||||||
|
SRC = \
|
||||||
|
Cargo.toml \
|
||||||
|
$(shell find src -type f -name '*.rs') \
|
||||||
|
|
||||||
|
BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
$(BIN): $(SRC)
|
||||||
|
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
|
||||||
|
cp -f target/$(RUST_TARGET)/release/$@ $@
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
$(CARGO) +nightly fmt --all
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clippy --target=$(RUST_TARGET) \
|
||||||
|
--release --all-features --workspace --tests
|
||||||
|
|
||||||
|
clean:
|
||||||
|
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
|
||||||
|
rm -f $(BIN)
|
||||||
|
|
||||||
|
.PHONY: all fmt clippy clean
|
||||||
78
script/research/tx-replayer/src/main.rs
Normal file
78
script/research/tx-replayer/src/main.rs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use darkfi::{
|
||||||
|
blockchain::{Blockchain, BlockchainOverlay, BlockchainOverlayPtr},
|
||||||
|
cli_desc,
|
||||||
|
util::path::expand_path,
|
||||||
|
validator::verification::verify_transaction,
|
||||||
|
zk::VerifyingKey,
|
||||||
|
};
|
||||||
|
use darkfi_sdk::{crypto::MerkleTree, tx::TransactionHash};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(about = cli_desc!())]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
database_path: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
tx_hash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
smol::block_on(async {
|
||||||
|
let args = Args::parse();
|
||||||
|
replay_tx(args).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn replay_tx(args: Args) {
|
||||||
|
let db_path = expand_path(&args.database_path).unwrap();
|
||||||
|
let sled_db = sled_overlay::sled::open(&db_path).unwrap();
|
||||||
|
|
||||||
|
let blockchain = Blockchain::new(&sled_db).unwrap();
|
||||||
|
let txh: TransactionHash = args.tx_hash.parse().unwrap();
|
||||||
|
let tx = blockchain.transactions.get(&[txh], true).unwrap().first().unwrap().clone().unwrap();
|
||||||
|
|
||||||
|
let (overlay, new_height) = rollback_database(&blockchain, txh).await;
|
||||||
|
|
||||||
|
let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
|
||||||
|
for call in &tx.calls {
|
||||||
|
vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let result =
|
||||||
|
verify_transaction(&overlay, new_height, 2, &tx, &mut MerkleTree::new(1), &mut vks, true)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("Verify Transaction Result: {:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets the blockchain in memory to a height before the transaction.
|
||||||
|
async fn rollback_database(
|
||||||
|
blockchain: &Blockchain,
|
||||||
|
txh: TransactionHash,
|
||||||
|
) -> (BlockchainOverlayPtr, u32) {
|
||||||
|
let (tx_height, _) =
|
||||||
|
blockchain.transactions.get_location(&[txh], true).unwrap().first().unwrap().unwrap();
|
||||||
|
|
||||||
|
let new_height = tx_height - 1;
|
||||||
|
println!("Rolling back database to Height: {new_height}");
|
||||||
|
|
||||||
|
let (last, _) = blockchain.last().unwrap();
|
||||||
|
let heights: Vec<u32> = (new_height + 1..=last).rev().collect();
|
||||||
|
let inverse_diffs = blockchain.blocks.get_state_inverse_diff(&heights, true).unwrap();
|
||||||
|
|
||||||
|
let overlay = BlockchainOverlay::new(blockchain).unwrap();
|
||||||
|
|
||||||
|
let overlay_lock = overlay.lock().unwrap();
|
||||||
|
let mut lock = overlay_lock.overlay.lock().unwrap();
|
||||||
|
for inverse_diff in inverse_diffs {
|
||||||
|
let inverse_diff = inverse_diff.unwrap();
|
||||||
|
lock.add_diff(&inverse_diff).unwrap();
|
||||||
|
}
|
||||||
|
drop(lock);
|
||||||
|
drop(overlay_lock);
|
||||||
|
|
||||||
|
(overlay, new_height)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user