Skip to content

Commit

Permalink
[bitcoin] Improve the block 790964 testcase (#2514)
Browse files Browse the repository at this point in the history
* [bitcoin] Improve the block 790964 testcase

* fixup

* fixup
  • Loading branch information
jolestar authored Aug 27, 2024
1 parent cc96287 commit 0c056b0
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 28 deletions.
8 changes: 6 additions & 2 deletions crates/rooch-benchmarks/src/tx_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,12 @@ pub fn tx_exec_benchmark(c: &mut Criterion) {
.execute_l1_block(l1_block_with_body.clone())
.unwrap();
}
LedgerTxData::L1Tx(tx) => binding_test.execute_l1_tx(tx).unwrap(),
LedgerTxData::L2Tx(tx) => binding_test.execute(tx).unwrap(),
LedgerTxData::L1Tx(tx) => {
binding_test.execute_l1_tx(tx).unwrap();
}
LedgerTxData::L2Tx(tx) => {
binding_test.execute(tx).unwrap();
}
}
});
});
Expand Down
2 changes: 1 addition & 1 deletion crates/rooch-framework-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
## How to build a bitcoin block tester genesis?

```bash
cargo run -p rooch-framework-tests -- --btc-rpc-url http://localhost:9332 --btc-rpc-username your_username --btc-rpc-password your_pwd --block-hash 000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506
cargo run -p rooch-framework-tests -- --btc-rpc-url http://localhost:9332 --btc-rpc-username your_username --btc-rpc-password your_pwd --blocks 790964 --blocks 855396
```
24 changes: 18 additions & 6 deletions crates/rooch-framework-tests/src/binding_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use std::path::Path;
use std::sync::Arc;
use tempfile::TempDir;
use tokio::runtime::Runtime;
use tracing::info;

pub fn get_data_dir() -> DataDirPath {
match env::var("ROOCH_TEST_DATA_DIR") {
Expand Down Expand Up @@ -139,22 +140,30 @@ impl RustBindingTest {
}

//TODO let the module bundle to execute the function
pub fn execute(&mut self, tx: RoochTransaction) -> Result<()> {
pub fn execute(&mut self, tx: RoochTransaction) -> Result<ExecuteTransactionResult> {
let execute_result = self.execute_as_result(tx)?;
if execute_result.transaction_info.status != KeptVMStatus::Executed {
bail!(
"tx should success, error: {:?}",
execute_result.transaction_info.status
);
}
Ok(())
Ok(execute_result)
}

pub fn execute_l1_block_and_tx(&mut self, l1_block: L1BlockWithBody) -> Result<()> {
let l1_txs = self.execute_l1_block(l1_block.clone())?;
let tx_len = l1_txs.len();
let mut total_gas_used = 0;
for l1_tx in l1_txs {
self.execute_l1_tx(l1_tx)?;
let resut = self.execute_l1_tx(l1_tx)?;
total_gas_used += resut.output.gas_used;
}
let avg_gas_used = total_gas_used / tx_len as u64;
info!(
"execute l1 block total gas used: {}, avg gas used: {}",
total_gas_used, avg_gas_used
);
Ok(())
}

Expand Down Expand Up @@ -186,7 +195,7 @@ impl RustBindingTest {
}
}

pub fn execute_l1_tx(&mut self, l1_tx: L1Transaction) -> Result<()> {
pub fn execute_l1_tx(&mut self, l1_tx: L1Transaction) -> Result<ExecuteTransactionResult> {
let verified_tx = self.executor.validate_l1_tx(l1_tx)?;
self.execute_verified_tx(verified_tx)
}
Expand All @@ -196,15 +205,18 @@ impl RustBindingTest {
self.execute_verified_tx_as_result(verified_tx)
}

pub fn execute_verified_tx(&mut self, tx: VerifiedMoveOSTransaction) -> Result<()> {
pub fn execute_verified_tx(
&mut self,
tx: VerifiedMoveOSTransaction,
) -> Result<ExecuteTransactionResult> {
let execute_result = self.execute_verified_tx_as_result(tx)?;
if execute_result.transaction_info.status != KeptVMStatus::Executed {
bail!(
"tx should success, error: {:?}",
execute_result.transaction_info.status
);
}
Ok(())
Ok(execute_result)
}

pub fn execute_verified_tx_as_result(
Expand Down
66 changes: 55 additions & 11 deletions crates/rooch-framework-tests/src/bitcoin_block_tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

use crate::binding_test::RustBindingTest;
use anyhow::{anyhow, ensure, Result};
use bitcoin::{hashes::Hash, Block, BlockHash, Txid};
use anyhow::{anyhow, bail, ensure, Result};
use bitcoin::{hashes::Hash, Block, OutPoint, TxOut, Txid};
use framework_builder::stdlib_version::StdlibVersion;
use moveos_types::{
moveos_std::{
Expand All @@ -17,7 +17,7 @@ use rooch_relayer::actor::bitcoin_client_proxy::BitcoinClientProxy;
use rooch_types::{
bitcoin::{
ord::InscriptionID,
utxo::{BitcoinUTXOStore, UTXO},
utxo::{self, BitcoinUTXOStore, UTXO},
},
genesis_config,
into_address::IntoAddress,
Expand All @@ -37,6 +37,7 @@ use tracing::{debug, info};
pub struct BitcoinBlockTester {
genesis: BitcoinTesterGenesis,
binding_test: RustBindingTest,
executed_block: Option<Block>,
}

impl BitcoinBlockTester {
Expand All @@ -49,19 +50,61 @@ impl BitcoinBlockTester {
Ok(Self {
genesis,
binding_test,
executed_block: None,
})
}

/// Execute one block from genesis blocks
pub fn execute(&mut self) -> Result<()> {
for (height, block) in &self.genesis.blocks {
let l1_block = L1BlockWithBody::new_bitcoin_block(*height as u64, block.clone());
self.binding_test.execute_l1_block_and_tx(l1_block)?;
if self.genesis.blocks.is_empty() {
bail!("No block to execute");
}
let (height, block) = self.genesis.blocks.remove(0);
info!("Execute block: {}", height);
let l1_block = L1BlockWithBody::new_bitcoin_block(height as u64, block.clone());
self.binding_test.execute_l1_block_and_tx(l1_block)?;
self.executed_block = Some(block);
Ok(())
}

pub fn verify_utxo(&self) -> Result<()> {
//TODO verify utxo in state with block output
ensure!(
self.executed_block.is_some(),
"No block executed, please execute block first"
);
let mut utxo_set = HashMap::<OutPoint, TxOut>::new();
let block = self.executed_block.as_ref().unwrap();
for tx in block.txdata.as_slice() {
let txid = tx.txid();
for (index, tx_out) in tx.output.iter().enumerate() {
let vout = index as u32;
let out_point = OutPoint::new(txid, vout);
utxo_set.insert(out_point, tx_out.clone());
}
//remove spent utxo
for tx_in in tx.input.iter() {
utxo_set.remove(&tx_in.previous_output);
}
}

for (outpoint, tx_out) in utxo_set.into_iter() {
let utxo_object_id = utxo::derive_utxo_id(&outpoint.into());
let utxo_obj = self.binding_test.get_object(&utxo_object_id)?;
ensure!(
utxo_obj.is_some(),
"Missing utxo object: {}, {}",
utxo_object_id,
outpoint
);
let utxo_obj = utxo_obj.unwrap();
let utxo_state = utxo_obj.value_as::<UTXO>()?;
ensure!(
utxo_state.value == tx_out.value.to_sat(),
"UTXO not match: {:?}, {:?}",
utxo_state,
tx_out
);
}
Ok(())
}

Expand Down Expand Up @@ -119,13 +162,14 @@ impl TesterGenesisBuilder {
})
}

pub async fn add_block(mut self, block_hash: BlockHash) -> Result<Self> {
pub async fn add_block(mut self, block_height: u64) -> Result<Self> {
let block_hash = self.bitcoin_client.get_block_hash(block_height).await?;
let block = self.bitcoin_client.get_block(block_hash).await?;
let block_header_result = self
.bitcoin_client
.get_block_header_info(block_hash)
.await?;
debug!("Add block: {:?}", block_header_result);
info!("Add block: {:?}", block_header_result);
if !self.blocks.is_empty() {
let last_block = self.blocks.last().unwrap();
ensure!(
Expand Down Expand Up @@ -159,7 +203,7 @@ impl TesterGenesisBuilder {
if self.block_txids.contains(&txid) {
continue;
}
debug!("Get tx: {:?}", txid);
info!("Get tx: {:?}", txid);
let tx = self.bitcoin_client.get_raw_transaction(txid).await?;
depdent_txs.insert(txid, tx);
}
Expand Down Expand Up @@ -193,7 +237,7 @@ impl TesterGenesisBuilder {
SimpleMultiMap::create(),
);
let object_id = utxo.object_id();
debug!("Add utxo: {}, {:?}", object_id, utxo);
info!("Add utxo: {}, {:?}", object_id, utxo);
let mut object_meta = ObjectMeta::genesis_meta(object_id, UTXO::type_tag());
object_meta.owner = rooch_pre_output.recipient_address.to_rooch_address().into();
let utxo_obj = ObjectState::new_with_struct(object_meta, utxo)?;
Expand Down
14 changes: 9 additions & 5 deletions crates/rooch-framework-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use bitcoin::BlockHash;
use clap::Parser;
use coerce::actor::{system::ActorSystem, IntoActor};
use rooch_framework_tests::bitcoin_block_tester::TesterGenesisBuilder;
Expand All @@ -27,8 +26,9 @@ struct TestBuilderOpts {
#[clap(long, id = "btc-rpc-password", env = "BTC_RPC_PASSWORD")]
pub btc_rpc_password: String,

#[clap(long, id = "block-hash", env = "BLOCK_HASH")]
pub block_hash: BlockHash,
/// Block heights to execute
#[clap(long, id = "blocks")]
pub blocks: Vec<u64>,
}

#[tokio::main]
Expand All @@ -45,8 +45,12 @@ async fn main() -> Result<()> {
.into_actor(Some("bitcoin_client_for_rpc_service"), &actor_system)
.await?;
let bitcoin_client_proxy = BitcoinClientProxy::new(bitcoin_client_actor_ref.into());
let builder = TesterGenesisBuilder::new(bitcoin_client_proxy)?;
let builder = builder.add_block(opts.block_hash).await?;
let mut builder = TesterGenesisBuilder::new(bitcoin_client_proxy)?;
let mut blocks = opts.blocks;
blocks.sort();
for block in blocks {
builder = builder.add_block(block).await?;
}
let genesis = builder.build().await?;
genesis.save()?;
Ok(())
Expand Down
24 changes: 23 additions & 1 deletion crates/rooch-framework-tests/src/tests/bitcoin_tester_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::str::FromStr;

use rooch_types::bitcoin::ord::{Inscription, InscriptionID};
use rooch_types::bitcoin::ord::{Inscription, InscriptionID, SatPoint};
use tracing::{debug, warn};

use crate::bitcoin_block_tester::BitcoinBlockTester;
Expand All @@ -18,6 +18,11 @@ async fn test_block_100000() {
tester.verify_inscriptions().unwrap();
}

// cargo run -p rooch-framework-tests -- --btc-rpc-url http://localhost:9332 --btc-rpc-username your_username --btc-rpc-password your_pwd --blocks 790964 --blocks 855396
// This test contains two block: 790964 and 855396
// The inscription 8706753 inscribed in block 790964 and spend as fee in block 855396
// https://ordiscan.com/inscription/8706753
// https://ordinals.com/inscription/8706753
#[tokio::test]
async fn test_block_790964() {
let _ = tracing_subscriber::fmt::try_init();
Expand All @@ -28,6 +33,7 @@ async fn test_block_790964() {
}

let mut tester = BitcoinBlockTester::new(790964).unwrap();
//Execute the first block 790964
tester.execute().unwrap();
tester.verify_utxo().unwrap();
tester.verify_inscriptions().unwrap();
Expand All @@ -47,4 +53,20 @@ async fn test_block_790964() {
// assert_eq!(inscription.inscription_number, expected_inscription_number);
// assert_eq!(inscription.sequence_number, expected_sequence_number);
assert_eq!(inscription.location.offset, 0u64);

//Execute the second block 855396
tester.execute().unwrap();
tester.verify_utxo().unwrap();
tester.verify_inscriptions().unwrap();

let inscription_obj = tester.get_inscription(&inscription_id).unwrap().unwrap();
let inscription = inscription_obj.value_as::<Inscription>().unwrap();
debug!("Inscription: {:?}", inscription);
assert_eq!(
inscription.location,
SatPoint::from_str(
"4a61ddc33e4a0b99fa69aac4d2d5de9efe7c7cc44d5d28a9ac1734f8c3317964:0:316084756"
)
.unwrap()
);
}
Binary file modified crates/rooch-framework-tests/tester/790964.tester.genesis
Binary file not shown.
27 changes: 27 additions & 0 deletions crates/rooch-types/src/bitcoin/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,33 @@ impl MoveStructState for SatPoint {
}
}

impl FromStr for SatPoint {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self> {
let mut parts = s.split(':');
let txid = parts
.next()
.ok_or_else(|| anyhow::anyhow!("missing txid"))?;
let vout = parts
.next()
.ok_or_else(|| anyhow::anyhow!("missing vout"))?;
let offset = parts
.next()
.ok_or_else(|| anyhow::anyhow!("missing offset"))?;
let txid = bitcoin::Txid::from_str(txid)?;
let vout = u32::from_str(vout)?;
let offset = u64::from_str(offset)?;
Ok(SatPoint {
outpoint: OutPoint {
txid: txid.into_address(),
vout,
},
offset,
})
}
}

/// Rust bindings for BitcoinMove ord module
pub struct OrdModule<'a> {
caller: &'a dyn MoveFunctionCaller,
Expand Down
7 changes: 5 additions & 2 deletions crates/rooch-types/src/bitcoin/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::into_address::FromAddress;
use crate::{address::BitcoinAddress, addresses::BITCOIN_MOVE_ADDRESS, into_address::IntoAddress};
use anyhow::Result;
use bitcoin::Txid;
use bitcoin::{hashes::Hash, BlockHash};
use bitcoincore_rpc::bitcoincore_rpc_json::GetBlockHeaderResult;
use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr};
Expand Down Expand Up @@ -274,7 +275,7 @@ impl MoveStructState for Witness {
}
}

#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, PartialEq, Eq, Hash)]
pub struct OutPoint {
/// The referenced transaction's txid.
/// Use address to represent sha256d hash
Expand Down Expand Up @@ -327,7 +328,9 @@ impl MoveStructState for OutPoint {

impl Display for OutPoint {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}:{}", self.txid, self.vout)
//We use bitcoin txid hex to display
let txid = Txid::from_address(self.txid);
write!(f, "{}:{}", txid, self.vout)
}
}

Expand Down

0 comments on commit 0c056b0

Please sign in to comment.