diff --git a/Cargo.lock b/Cargo.lock index 64ad8c2aee56..1a9aa9f9be17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7680,6 +7680,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-subscriber", "zksync_basic_types", "zksync_config", "zksync_da_client", diff --git a/core/lib/via_btc_client/Cargo.toml b/core/lib/via_btc_client/Cargo.toml index 2d72b3b27cd0..b5c481dd516e 100644 --- a/core/lib/via_btc_client/Cargo.toml +++ b/core/lib/via_btc_client/Cargo.toml @@ -35,16 +35,17 @@ inquire = "0.7.5" anyhow.workspace = true serde.workspace = true tracing.workspace = true +tracing-subscriber = { workspace = true, optional = true } [dev-dependencies] mockall = "0.13.0" [features] -regtest = [] +regtest = ["tracing-subscriber"] [[example]] -name = "bitcoin_client_example" -path = "examples/bitcoin_client_example.rs" +name = "indexer" +path = "examples/indexer_init_example.rs" required-features = ["regtest"] [[example]] diff --git a/core/lib/via_btc_client/examples/bitcoin_client_example.rs b/core/lib/via_btc_client/examples/bitcoin_client_example.rs deleted file mode 100644 index cf3da17d92d6..000000000000 --- a/core/lib/via_btc_client/examples/bitcoin_client_example.rs +++ /dev/null @@ -1,100 +0,0 @@ -#![cfg(feature = "regtest")] - -use anyhow::Result; -use bitcoin::{ - absolute::LockTime, address::NetworkUnchecked, transaction::Version, Address, Amount, Network, - OutPoint, Sequence, Transaction, TxIn, TxOut, Witness, -}; -use via_btc_client::{ - client::BitcoinClient, regtest::BitcoinRegtest, traits::BitcoinSigner, BitcoinOps, -}; - -#[tokio::main] -async fn main() -> Result<()> { - let context = BitcoinRegtest::new()?; - let client = BitcoinClient::new("http://localhost:18443", "regtest").await?; - - let miner_address = context.get_miner_address()?; - println!( - "Balance of miner {miner_address}: {:?} SAT", - client.get_balance(&miner_address).await? - ); - - let address = context.get_address(); - let private_key = context.get_private_key(); - println!("Testing account:"); - println!("Private key: {:?}", private_key.to_wif()); - println!("Address: {:?}", address); - println!("Balance: {:?} SAT", client.get_balance(&address).await?); - - let random_address = "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080" - .parse::>()? - .require_network(Network::Regtest)?; - println!("\nSending simple transfer to {}...\n", random_address); - - let amount_to_send = Amount::from_btc(20.0)?.to_sat(); - let fee = Amount::from_btc(0.00001)?.to_sat(); - let mut total_input = 0; - let mut inputs = Vec::new(); - - println!("Getting UTXOs of test address..."); - let utxos = client.fetch_utxos(&address).await?; - for (i, (utxo, txid, vout)) in utxos.into_iter().enumerate() { - println!("#{i} utxo:\nvout:{vout}\n{:?}\ntxid:{txid}\n", utxo); - inputs.push(TxIn { - previous_output: OutPoint::new(txid, vout), - script_sig: bitcoin::ScriptBuf::new(), - sequence: Sequence::MAX, - witness: Witness::new(), - }); - total_input += utxo.value.to_sat(); - if total_input > amount_to_send { - break; - } - } - - let mut outputs = vec![TxOut { - value: Amount::from_sat(amount_to_send), - script_pubkey: random_address.script_pubkey(), - }]; - if total_input.saturating_sub(amount_to_send) > Amount::from_btc(0.0002)?.to_sat() { - outputs.push(TxOut { - value: Amount::from_sat(total_input.saturating_sub(amount_to_send) - fee), - script_pubkey: address.script_pubkey(), - }) - } - println!("Outputs: {:?}", outputs); - let unsigned_tx = Transaction { - version: Version::TWO, - lock_time: LockTime::ZERO, - input: inputs, - output: outputs, - }; - - println!("Signing tx..."); - let signer = BasicSigner::new(private_key.to_wif().as_str(), client.get_rpc_client())?; - let mut signed_tx = unsigned_tx; - for i in 0..signed_tx.input.len() { - let witness = signer.sign_ecdsa(&signed_tx, i).await?; - signed_tx.input[i].witness = witness; - } - - let serialized_tx = bitcoin::consensus::encode::serialize(&signed_tx); - let txid = client - .broadcast_signed_transaction(&hex::encode(serialized_tx)) - .await?; - println!("\nTransaction sent: {:?}", txid); - - println!("Waiting for transaction to be mined..."); - tokio::time::sleep(std::time::Duration::from_secs(20)).await; - let i = client.check_tx_confirmation(&txid, 1).await?; - println!("Is {txid} confirmed (1 confirmation): {i}"); - - println!("Getting UTXOs of test address..."); - let utxos = client.fetch_utxos(&address).await?; - for (i, (utxo, txid, vout)) in utxos.into_iter().enumerate() { - println!("#{i} utxo:\nvout:{vout}\n{:?}\ntxid:{txid}\n", utxo); - } - - Ok(()) -} diff --git a/core/lib/via_btc_client/examples/indexer_init_example.rs b/core/lib/via_btc_client/examples/indexer_init_example.rs new file mode 100644 index 000000000000..7895da9958a1 --- /dev/null +++ b/core/lib/via_btc_client/examples/indexer_init_example.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use tracing_subscriber; +use via_btc_client::{indexer::BitcoinInscriptionIndexer, regtest::BitcoinRegtest, types::Network}; + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) + .init(); + + tracing::info!("starting Bitcoin client example"); + let context = BitcoinRegtest::new()?; + let miner = context.get_miner_address()?; + tracing::info!("miner address: {}", miner); + let indexer = + BitcoinInscriptionIndexer::new(&context.get_url(), Network::Regtest, vec![]).await; + + if let Err(e) = indexer { + tracing::error!("Failed to create indexer: {:?}", e); + } + Ok(()) +} diff --git a/core/lib/via_btc_client/tests/docker-compose-btc.yml b/core/lib/via_btc_client/resources/docker-compose-btc.yml similarity index 100% rename from core/lib/via_btc_client/tests/docker-compose-btc.yml rename to core/lib/via_btc_client/resources/docker-compose-btc.yml diff --git a/core/lib/via_btc_client/src/indexer/mod.rs b/core/lib/via_btc_client/src/indexer/mod.rs index 8651fbd2705f..8b03dad52a33 100644 --- a/core/lib/via_btc_client/src/indexer/mod.rs +++ b/core/lib/via_btc_client/src/indexer/mod.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use async_trait::async_trait; use bitcoin::{Address, BlockHash, KnownHrp, Network, Txid}; use bitcoincore_rpc::Auth; use tracing::{debug, error, info, instrument, warn}; @@ -10,7 +9,7 @@ use parser::MessageParser; use crate::{ client::BitcoinClient, - traits::{BitcoinIndexerOpt, BitcoinOps}, + traits::BitcoinOps, types, types::{BitcoinIndexerResult, CommonFields, FullInscriptionMessage, L1ToL2Message, Vote}, }; @@ -68,10 +67,9 @@ pub struct BitcoinInscriptionIndexer { network: Network, } -#[async_trait] -impl BitcoinIndexerOpt for BitcoinInscriptionIndexer { +impl BitcoinInscriptionIndexer { #[instrument(skip(rpc_url, network, bootstrap_txids), target = "bitcoin_indexer")] - async fn new( + pub async fn new( rpc_url: &str, network: Network, bootstrap_txids: Vec, @@ -103,7 +101,7 @@ impl BitcoinIndexerOpt for BitcoinInscriptionIndexer { } #[instrument(skip(self), target = "bitcoin_indexer")] - async fn process_blocks( + pub async fn process_blocks( &self, starting_block: u32, ending_block: u32, @@ -121,7 +119,7 @@ impl BitcoinIndexerOpt for BitcoinInscriptionIndexer { } #[instrument(skip(self), target = "bitcoin_indexer")] - async fn process_block( + pub async fn process_block( &self, block_height: u32, ) -> BitcoinIndexerResult> { @@ -149,7 +147,7 @@ impl BitcoinIndexerOpt for BitcoinInscriptionIndexer { } #[instrument(skip(self), target = "bitcoin_indexer")] - async fn are_blocks_connected( + pub async fn are_blocks_connected( &self, parent_hash: &BlockHash, child_hash: &BlockHash, @@ -320,6 +318,7 @@ impl BitcoinInscriptionIndexer { mod tests { use std::str::FromStr; + use async_trait::async_trait; use bitcoin::{ block::Header, hashes::Hash, Amount, Block, OutPoint, ScriptBuf, Transaction, TxMerkleNode, TxOut, diff --git a/core/lib/via_btc_client/src/lib.rs b/core/lib/via_btc_client/src/lib.rs index 8cbf83778c47..6397f7d7a64d 100644 --- a/core/lib/via_btc_client/src/lib.rs +++ b/core/lib/via_btc_client/src/lib.rs @@ -4,6 +4,7 @@ pub mod types; pub(crate) mod client; pub mod indexer; pub mod inscriber; -pub(crate) mod regtest; +#[cfg(feature = "regtest")] +pub mod regtest; pub(crate) mod signer; pub(crate) mod utils; diff --git a/core/lib/via_btc_client/src/regtest.rs b/core/lib/via_btc_client/src/regtest.rs index 9cf26859d37f..19e0af6ca37c 100644 --- a/core/lib/via_btc_client/src/regtest.rs +++ b/core/lib/via_btc_client/src/regtest.rs @@ -7,9 +7,11 @@ use std::{ use anyhow::Result; use bitcoin::{address::NetworkUnchecked, Address, Network, PrivateKey}; -const COMPOSE_FILE_PATH: &str = - concat!(env!("CARGO_MANIFEST_DIR"), "/tests/docker-compose-btc.yml"); -const CLI_CONTAINER_NAME: &str = "tests-bitcoin-cli-1"; +const COMPOSE_FILE_PATH: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/docker-compose-btc.yml" +); +const CLI_CONTAINER_NAME: &str = "resources-bitcoin-cli-1"; pub struct BitcoinRegtest { private_key: PrivateKey, @@ -105,23 +107,27 @@ mod tests { use secp256k1::Secp256k1; use super::*; - use crate::{client::BitcoinRpcClient, traits::BitcoinRpc}; + use crate::{client::BitcoinClient, traits::BitcoinOps}; #[tokio::test] async fn test_bitcoin_regtest() { let regtest = BitcoinRegtest::new().expect("Failed to create BitcoinRegtest"); - let rpc = BitcoinRpcClient::new(®test.get_url(), Auth::UserPass("rpcuser".to_string(), "rpcpassword".to_string())) - .expect("Failed create rpc client"); - - let block_count = rpc - .get_block_count() + let client = BitcoinClient::new( + ®test.get_url(), + Network::Regtest, + Auth::UserPass("rpcuser".to_string(), "rpcpassword".to_string()), + ) + .expect("Failed create rpc client"); + + let block_count = client + .fetch_block_height() .await .expect("Failed to get block count"); assert!(block_count > 100); let address = regtest.get_address(); let private_key = regtest.get_private_key(); - let balance = rpc + let balance = client .get_balance(address) .await .expect("Failed to get balance of test address"); diff --git a/core/lib/via_btc_client/src/traits.rs b/core/lib/via_btc_client/src/traits.rs index bec9e18fd0bd..1ab6125da58c 100644 --- a/core/lib/via_btc_client/src/traits.rs +++ b/core/lib/via_btc_client/src/traits.rs @@ -83,28 +83,3 @@ pub(crate) trait BitcoinSigner: Send + Sync { fn get_public_key(&self) -> PublicKey; } - -#[async_trait] -pub(crate) trait BitcoinIndexerOpt: Send + Sync { - async fn new( - rpc_url: &str, - network: Network, - bootstrap_txids: Vec, - ) -> BitcoinIndexerResult - where - Self: Sized; - async fn process_blocks( - &self, - starting_block: u32, - ending_block: u32, - ) -> BitcoinIndexerResult>; - async fn process_block( - &self, - block_height: u32, - ) -> BitcoinIndexerResult>; - async fn are_blocks_connected( - &self, - parent_hash: &BlockHash, - child_hash: &BlockHash, - ) -> BitcoinIndexerResult; -}