Skip to content

Commit

Permalink
fix: get_transaction does not work for non-wallet txs
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <gregorydhill@outlook.com>
  • Loading branch information
gregdhill committed Aug 2, 2023
1 parent eeb2fda commit 9492985
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 63 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ args.txt
vault-*-metadata
kv
*.wif
.idea/*
.idea/*
*.db
2 changes: 2 additions & 0 deletions bitcoin/src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ mod tests {
&self,
txid: Txid,
num_confirmations: u32,
block_hash: Option<BlockHash>,
is_wallet: bool,
) -> Result<TransactionMetadata, Error>;
async fn create_and_send_transaction(
&self,
Expand Down
64 changes: 43 additions & 21 deletions bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ pub use bitcoincore_rpc::{
Transaction, TxIn, TxOut, Txid, VarInt, WScriptHash,
},
bitcoincore_rpc_json::{
CreateRawTransactionInput, FundRawTransactionOptions, GetBlockchainInfoResult, GetTransactionResult,
GetTransactionResultDetailCategory, WalletTxInfo,
CreateRawTransactionInput, FundRawTransactionOptions, GetBlockchainInfoResult, GetRawTransactionResult,
GetTransactionResult, GetTransactionResultDetailCategory, WalletTxInfo,
},
json::{self, AddressType, GetBlockResult},
jsonrpc::{self, error::RpcError, Error as JsonRpcError},
Expand Down Expand Up @@ -128,7 +128,6 @@ pub struct SatPerVbyte(pub u64);
pub struct TransactionMetadata {
pub txid: Txid,
pub proof: RawTransactionProof,
pub block_height: u32,
pub block_hash: BlockHash,
pub fee: Option<SignedAmount>,
}
Expand Down Expand Up @@ -185,6 +184,8 @@ pub trait BitcoinCoreApi {
&self,
txid: Txid,
num_confirmations: u32,
block_hash: Option<BlockHash>,
is_wallet: bool,
) -> Result<TransactionMetadata, Error>;

async fn bump_fee(&self, txid: &Txid, address: Address, fee_rate: SatPerVbyte) -> Result<Txid, Error>;
Expand Down Expand Up @@ -867,27 +868,47 @@ impl BitcoinCoreApi for BitcoinCore {
/// # Arguments
/// * `txid` - transaction ID
/// * `num_confirmations` - how many confirmations we need to wait for
/// * `block_hash` - optional block hash
async fn wait_for_transaction_metadata(
&self,
txid: Txid,
num_confirmations: u32,
block_hash: Option<BlockHash>,
is_wallet: bool,
) -> Result<TransactionMetadata, Error> {
let (block_height, block_hash, fee) = retry(get_exponential_backoff(), || async {
Ok(match self.rpc.get_transaction(&txid, None) {
Ok(GetTransactionResult {
info:
WalletTxInfo {
confirmations,
blockhash: Some(hash),
blockheight: Some(height),
..
},
fee,
..
}) if confirmations >= 0 && confirmations as u32 >= num_confirmations => Ok((height, hash, fee)),
Ok(_) => Err(Error::ConfirmationError),
Err(e) => Err(e.into()),
}?)
let (block_hash, fee) = retry(get_exponential_backoff(), || async {
if is_wallet {
Ok(match self.rpc.get_transaction(&txid, None) {
Ok(GetTransactionResult {
info:
WalletTxInfo {
confirmations,
blockhash: Some(hash),
..
},
fee,
..
}) if confirmations >= 0 && confirmations as u32 >= num_confirmations => Ok((hash, fee)),
Ok(_) => Err(Error::ConfirmationError),
Err(e) => {
log::error!("{}", e);
Err(e.into())
}
}?)
} else {
Ok(match self.rpc.get_raw_transaction_info(&txid, block_hash.as_ref()) {
Ok(GetRawTransactionResult {
confirmations: Some(num),
blockhash: Some(hash),
..
}) if num >= num_confirmations => Ok((hash, None)),
Ok(_) => Err(Error::ConfirmationError),
Err(e) => {
log::error!("{}", e);
Err(e.into())
}
}?)
}
})
.await?;

Expand Down Expand Up @@ -915,7 +936,6 @@ impl BitcoinCoreApi for BitcoinCore {
Ok(TransactionMetadata {
txid,
proof,
block_height,
block_hash,
fee,
})
Expand Down Expand Up @@ -1005,7 +1025,9 @@ impl BitcoinCoreApi for BitcoinCore {
.create_and_send_transaction(address, sat, fee_rate, request_id)
.await?;

Ok(self.wait_for_transaction_metadata(txid, num_confirmations).await?)
Ok(self
.wait_for_transaction_metadata(txid, num_confirmations, None, true)
.await?)
}

/// Create or load a wallet on Bitcoin Core.
Expand Down
13 changes: 8 additions & 5 deletions bitcoin/src/light/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,17 @@ impl BitcoinCoreApi for BitcoinLight {
&self,
txid: Txid,
num_confirmations: u32,
_block_hash: Option<BlockHash>,
_is_wallet: bool,
) -> Result<TransactionMetadata, BitcoinError> {
let (block_height, block_hash, fee) = retry(get_exponential_backoff(), || async {
let (block_hash, fee) = retry(get_exponential_backoff(), || async {
Ok(match self.electrs.get_tx_info(&txid).await {
Ok(electrs::TxInfo {
confirmations,
height,
hash,
fee,
}) if confirmations >= num_confirmations => Ok((height, hash, fee)),
..
}) if confirmations >= num_confirmations => Ok((hash, fee)),
Ok(_) => Err(BitcoinError::ConfirmationError),
Err(_e) => Err(BitcoinError::ConnectionRefused),
}?)
Expand Down Expand Up @@ -262,7 +264,6 @@ impl BitcoinCoreApi for BitcoinLight {
Ok(TransactionMetadata {
txid,
proof,
block_height,
block_hash,
fee: Some(fee),
})
Expand Down Expand Up @@ -319,7 +320,9 @@ impl BitcoinCoreApi for BitcoinLight {
.create_and_send_transaction(address, sat, fee_rate, request_id)
.await?;

Ok(self.wait_for_transaction_metadata(txid, num_confirmations).await?)
Ok(self
.wait_for_transaction_metadata(txid, num_confirmations, None, true)
.await?)
}

async fn create_or_load_wallet(&self) -> Result<(), BitcoinError> {
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "3.8"
services:
interbtc:
image: "interlayhq/interbtc:1.25.0-rc4"
image: "interlayhq/interbtc:1.25.0-rc5"
command:
- --rpc-external
- --ws-external
Expand Down
Binary file modified runtime/metadata-parachain-interlay.scale
Binary file not shown.
Binary file modified runtime/metadata-parachain-kintsugi.scale
Binary file not shown.
7 changes: 4 additions & 3 deletions runtime/src/integration/bitcoin_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ impl MockBitcoinCore {
.await?;
let txid = self.send_transaction(&tx).await?;
let metadata = self
.wait_for_transaction_metadata(txid, num_confirmations)
.wait_for_transaction_metadata(txid, num_confirmations, None, true)
.await
.unwrap();
Ok(metadata)
Expand Down Expand Up @@ -454,6 +454,8 @@ impl BitcoinCoreApi for MockBitcoinCore {
&self,
txid: Txid,
_num_confirmations: u32,
_block_hash: Option<BlockHash>,
_is_wallet: bool,
) -> Result<TransactionMetadata, BitcoinError> {
let (block_height, block) = loop {
// we have to be careful not to deadlock, so limit the scope of the lock
Expand All @@ -480,7 +482,6 @@ impl BitcoinCoreApi for MockBitcoinCore {
raw_coinbase_tx,
},
txid,
block_height: block_height as u32,
fee: None,
})
}
Expand Down Expand Up @@ -508,7 +509,7 @@ impl BitcoinCoreApi for MockBitcoinCore {
.await
.unwrap();
let metadata = self
.wait_for_transaction_metadata(txid, num_confirmations)
.wait_for_transaction_metadata(txid, num_confirmations, None, true)
.await
.unwrap();
Ok(metadata)
Expand Down
63 changes: 33 additions & 30 deletions vault/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ impl Request {
}
});

let wait_for_transaction_metadata = btc_rpc.wait_for_transaction_metadata(txid, num_confirmations);
let wait_for_transaction_metadata =
btc_rpc.wait_for_transaction_metadata(txid, num_confirmations, None, true);
futures::pin_mut!(subscription);

let mut metadata_fut = wait_for_transaction_metadata;
Expand Down Expand Up @@ -811,7 +812,7 @@ mod tests {
async fn get_block(&self, hash: &BlockHash) -> Result<Block, BitcoinError>;
async fn get_block_header(&self, hash: &BlockHash) -> Result<BlockHeader, BitcoinError>;
async fn get_mempool_transactions<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<Transaction, BitcoinError>> + Send + 'a>, BitcoinError>;
async fn wait_for_transaction_metadata(&self, txid: Txid, num_confirmations: u32) -> Result<TransactionMetadata, BitcoinError>;
async fn wait_for_transaction_metadata(&self, txid: Txid, num_confirmations: u32, block_hash: Option<BlockHash>, is_wallet: bool) -> Result<TransactionMetadata, BitcoinError>;
async fn create_and_send_transaction(&self, address: Address, sat: u64, fee_rate: SatPerVbyte, request_id: Option<H256>) -> Result<Txid, BitcoinError>;
async fn send_to_address(&self, address: Address, sat: u64, request_id: Option<H256>, fee_rate: SatPerVbyte, num_confirmations: u32) -> Result<TransactionMetadata, BitcoinError>;
async fn create_or_load_wallet(&self) -> Result<(), BitcoinError>;
Expand Down Expand Up @@ -923,20 +924,21 @@ mod tests {
mock_bitcoin
.expect_create_and_send_transaction()
.returning(|_, _, _, _| Ok(Txid::all_zeros()));
mock_bitcoin.expect_wait_for_transaction_metadata().returning(|_, _| {
Ok(TransactionMetadata {
txid: Txid::all_zeros(),
proof: RawTransactionProof {
coinbase_tx_proof: vec![],
raw_coinbase_tx: vec![],
raw_user_tx: vec![],
user_tx_proof: vec![],
},
block_height: 0,
block_hash: BlockHash::all_zeros(),
fee: None,
})
});
mock_bitcoin
.expect_wait_for_transaction_metadata()
.returning(|_, _, _, _| {
Ok(TransactionMetadata {
txid: Txid::all_zeros(),
proof: RawTransactionProof {
coinbase_tx_proof: vec![],
raw_coinbase_tx: vec![],
raw_user_tx: vec![],
user_tx_proof: vec![],
},
block_hash: BlockHash::all_zeros(),
fee: None,
})
});
mock_bitcoin.expect_list_transactions().returning(|_| Ok(vec![]));
mock_bitcoin.expect_get_balance().returning(|_| Ok(Amount::ZERO));
let btc_rpc: DynBitcoinCoreApi = Arc::new(mock_bitcoin);
Expand Down Expand Up @@ -1058,20 +1060,21 @@ mod tests {
mock_bitcoin
.expect_create_and_send_transaction()
.returning(|_, _, _, _| Ok(Txid::all_zeros()));
mock_bitcoin.expect_wait_for_transaction_metadata().returning(|_, _| {
Ok(TransactionMetadata {
txid: Txid::all_zeros(),
proof: RawTransactionProof {
coinbase_tx_proof: vec![],
raw_coinbase_tx: vec![],
raw_user_tx: vec![],
user_tx_proof: vec![],
},
block_height: 0,
block_hash: BlockHash::all_zeros(),
fee: None,
})
});
mock_bitcoin
.expect_wait_for_transaction_metadata()
.returning(|_, _, _, _| {
Ok(TransactionMetadata {
txid: Txid::all_zeros(),
proof: RawTransactionProof {
coinbase_tx_proof: vec![],
raw_coinbase_tx: vec![],
raw_user_tx: vec![],
user_tx_proof: vec![],
},
block_hash: BlockHash::all_zeros(),
fee: None,
})
});
mock_bitcoin.expect_get_balance().returning(|_| Ok(Amount::ZERO));
let btc_rpc: DynBitcoinCoreApi = Arc::new(mock_bitcoin);

Expand Down
2 changes: 1 addition & 1 deletion vault/src/issue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ async fn process_transaction_and_execute_issue(
}

let tx_metadata = bitcoin_core
.wait_for_transaction_metadata(transaction.txid(), num_confirmations)
.wait_for_transaction_metadata(transaction.txid(), num_confirmations, Some(block_hash), false)
.await?;

tracing::info!(
Expand Down
2 changes: 1 addition & 1 deletion vault/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ mod tests {
async fn get_block(&self, hash: &BlockHash) -> Result<Block, BitcoinError>;
async fn get_block_header(&self, hash: &BlockHash) -> Result<BlockHeader, BitcoinError>;
async fn get_mempool_transactions<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<Transaction, BitcoinError>> + Send + 'a>, BitcoinError>;
async fn wait_for_transaction_metadata(&self, txid: Txid, num_confirmations: u32) -> Result<TransactionMetadata, BitcoinError>;
async fn wait_for_transaction_metadata(&self, txid: Txid, num_confirmations: u32, block_hash: Option<BlockHash>, is_wallet: bool) -> Result<TransactionMetadata, BitcoinError>;
async fn create_and_send_transaction(&self, address: Address, sat: u64, fee_rate: SatPerVbyte, request_id: Option<H256>) -> Result<Txid, BitcoinError>;
async fn send_to_address(&self, address: Address, sat: u64, request_id: Option<H256>, fee_rate: SatPerVbyte, num_confirmations: u32) -> Result<TransactionMetadata, BitcoinError>;
async fn create_or_load_wallet(&self) -> Result<(), BitcoinError>;
Expand Down
2 changes: 2 additions & 0 deletions vault/src/replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ mod tests {
&self,
txid: Txid,
num_confirmations: u32,
block_hash: Option<BlockHash>,
is_wallet: bool,
) -> Result<TransactionMetadata, BitcoinError>;
async fn create_and_send_transaction(
&self,
Expand Down

0 comments on commit 9492985

Please sign in to comment.