use std::error::Error as StdError;
use std::sync::Arc;
pub use crate::bitcoin::error::{BitcoinError, BitcoinResult};
#[cfg(feature = "rust-bitcoin")]
pub use bitcoin::{Address, Block, Network, Transaction};
use crate::bitcoin::config::BitcoinConfig as ConfigBitcoinConfig;
use crate::bitcoin::config::BitcoinConfig as BitcoinInternalConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitcoinImplementationType {
Rust,
Core,
Electrum,
Custom,
Web3,
RPC,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BitcoinAddress {
pub address: String,
pub address_type: AddressType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressType {
P2PKH,
P2SH,
P2WPKH,
P2WSH,
P2TR,
}
#[derive(Debug, Clone)]
pub struct BitcoinTransaction {
pub txid: String,
pub version: u32,
pub inputs: Vec<TransactionInput>,
pub outputs: Vec<TransactionOutput>,
pub locktime: u32,
pub size: usize,
pub weight: usize,
pub fee: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct TransactionInput {
pub txid: String,
pub vout: u32,
pub script_sig: Vec<u8>,
pub sequence: u32,
pub witness: Option<Vec<Vec<u8>>>,
}
#[derive(Debug, Clone)]
pub struct TransactionOutput {
pub value: u64,
pub script_pubkey: Vec<u8>,
pub address: Option<String>,
}
#[derive(Debug, Clone)]
pub struct BlockHeader {
pub version: i32,
pub prev_blockhash: String,
pub merkle_root: String,
pub time: u32,
pub bits: u32,
pub nonce: u32,
}
#[async_trait::async_trait]
pub trait BitcoinInterface: Send + Sync {
async fn get_transaction(&self, txid: &str) -> BitcoinResult<Transaction>;
async fn get_block(&self, hash: &str) -> BitcoinResult<Block>;
async fn get_block_height(&self) -> BitcoinResult<u32>;
async fn generate_address(&self, address_type: AddressType) -> BitcoinResult<Address>;
async fn create_transaction(
&self,
outputs: Vec<(String, u64)>,
fee_rate: u64,
) -> BitcoinResult<Transaction>;
async fn broadcast_transaction(&self, transaction: &Transaction) -> BitcoinResult<String>;
async fn get_balance(&self, address: &Address) -> BitcoinResult<u64>;
async fn estimate_fee(&self, target_blocks: u8) -> BitcoinResult<u64>;
async fn get_block_header(&self, hash: &str) -> BitcoinResult<BlockHeader>;
async fn verify_merkle_proof(
&self,
tx_hash: &str,
block_header: &BlockHeader,
) -> BitcoinResult<bool>;
async fn send_transaction(&self, tx: &Transaction) -> BitcoinResult<String>;
fn implementation_type(&self) -> BitcoinImplementationType;
}
pub fn create_bitcoin_interface(
implementation_type: BitcoinImplementationType,
config: &ConfigBitcoinConfig,
) -> Result<Arc<dyn BitcoinInterface + 'static>, Box<dyn StdError>> {
let _internal_config = BitcoinInternalConfig {
enabled: true,
network: config.network.clone(),
rpc_url: Some(
config
.rpc_url
.clone()
.unwrap_or_else(|| "http://127.0.0.1:18332".to_string()),
),
auth: config.auth.clone(),
min_confirmations: 6,
default_fee_rate: 10,
wallet_path: None,
};
match implementation_type {
BitcoinImplementationType::Rust => {
#[cfg(feature = "rust-bitcoin")]
{
match crate::bitcoin::rust::RustBitcoinImplementation::new(&_internal_config) {
Ok(implementation) => {
Ok(Arc::new(implementation) as Arc<dyn BitcoinInterface + 'static>)
}
Err(e) => Err(Box::new(BitcoinError::ConfigError(e.to_string()))),
}
}
#[cfg(not(feature = "rust-bitcoin"))]
{
Err(Box::new(BitcoinError::ConfigError("Rust Bitcoin implementation requested but feature 'rust-bitcoin' is not enabled".to_string())))
}
}
_ => {
#[cfg(feature = "rust-bitcoin")]
{
match crate::bitcoin::rust::RustBitcoinImplementation::new(&_internal_config) {
Ok(implementation) => {
Ok(Arc::new(implementation) as Arc<dyn BitcoinInterface + 'static>)
}
Err(e) => Err(Box::new(BitcoinError::ConfigError(e.to_string()))),
}
}
#[cfg(not(feature = "rust-bitcoin"))]
{
Err(Box::new(BitcoinError::ConfigError(
"No Bitcoin implementation available for the requested type".to_string(),
)))
}
}
}
}
pub fn get_current_bitcoin_interface(
config: &ConfigBitcoinConfig,
) -> Result<Arc<dyn BitcoinInterface + 'static>, Box<dyn StdError>> {
let _internal_config = BitcoinInternalConfig {
enabled: true,
network: config.network.clone(),
rpc_url: Some(
config
.rpc_url
.clone()
.unwrap_or_else(|| "http://127.0.0.1:18332".to_string()),
),
auth: config.auth.clone(),
min_confirmations: 6,
default_fee_rate: 10,
wallet_path: None,
};
let implementation =
match crate::bitcoin::rust::RustBitcoinImplementation::new(&_internal_config) {
Ok(impl_instance) => impl_instance,
Err(e) => return Err(Box::new(BitcoinError::ConfigError(e.to_string()))),
};
Ok(Arc::new(implementation))
}