|
1 | 1 | use crate::convert::{
|
2 |
| - BlockchainInfo, FeeResponse, FundedTx, MempoolMinFeeResponse, NewAddress, RawTx, SignedTx, |
| 2 | + BlockchainInfo, FeeResponse, FundedTx, ListUnspentResponse, MempoolMinFeeResponse, NewAddress, |
| 3 | + RawTx, SignedTx, |
3 | 4 | };
|
4 | 5 | use crate::disk::FilesystemLogger;
|
| 6 | +use crate::hex_utils; |
5 | 7 | use base64;
|
| 8 | +use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR; |
6 | 9 | use bitcoin::blockdata::transaction::Transaction;
|
7 |
| -use bitcoin::consensus::encode; |
| 10 | +use bitcoin::consensus::{encode, Decodable, Encodable}; |
8 | 11 | use bitcoin::hash_types::{BlockHash, Txid};
|
9 |
| -use bitcoin::util::address::Address; |
| 12 | +use bitcoin::hashes::Hash; |
| 13 | +use bitcoin::util::address::{Address, Payload, WitnessVersion}; |
| 14 | +use bitcoin::{OutPoint, Script, TxOut, WPubkeyHash, XOnlyPublicKey}; |
10 | 15 | use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
|
| 16 | +use lightning::events::bump_transaction::{Utxo, WalletSource}; |
11 | 17 | use lightning::log_error;
|
12 | 18 | use lightning::routing::utxo::{UtxoLookup, UtxoResult};
|
13 | 19 | use lightning::util::logger::Logger;
|
@@ -250,6 +256,13 @@ impl BitcoindClient {
|
250 | 256 | .await
|
251 | 257 | .unwrap()
|
252 | 258 | }
|
| 259 | + |
| 260 | + pub async fn list_unspent(&self) -> ListUnspentResponse { |
| 261 | + self.bitcoind_rpc_client |
| 262 | + .call_method::<ListUnspentResponse>("listunspent", &vec![]) |
| 263 | + .await |
| 264 | + .unwrap() |
| 265 | + } |
253 | 266 | }
|
254 | 267 |
|
255 | 268 | impl FeeEstimator for BitcoindClient {
|
@@ -308,3 +321,55 @@ impl UtxoLookup for BitcoindClient {
|
308 | 321 | todo!();
|
309 | 322 | }
|
310 | 323 | }
|
| 324 | + |
| 325 | +impl WalletSource for BitcoindClient { |
| 326 | + fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()> { |
| 327 | + let utxos = tokio::task::block_in_place(move || { |
| 328 | + self.handle.block_on(async move { self.list_unspent().await }).0 |
| 329 | + }); |
| 330 | + Ok(utxos |
| 331 | + .into_iter() |
| 332 | + .filter_map(|utxo| { |
| 333 | + let outpoint = OutPoint { txid: utxo.txid, vout: utxo.vout }; |
| 334 | + match utxo.address.payload { |
| 335 | + Payload::WitnessProgram { version, ref program } => match version { |
| 336 | + WitnessVersion::V0 => WPubkeyHash::from_slice(program) |
| 337 | + .map(|wpkh| Utxo::new_v0_p2wpkh(outpoint, utxo.amount, &wpkh)) |
| 338 | + .ok(), |
| 339 | + // TODO: Add `Utxo::new_v1_p2tr` upstream. |
| 340 | + WitnessVersion::V1 => XOnlyPublicKey::from_slice(program) |
| 341 | + .map(|_| Utxo { |
| 342 | + outpoint, |
| 343 | + output: TxOut { |
| 344 | + value: utxo.amount, |
| 345 | + script_pubkey: Script::new_witness_program(version, program), |
| 346 | + }, |
| 347 | + satisfaction_weight: 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64 + |
| 348 | + 1 /* witness items */ + 1 /* schnorr sig len */ + 64, /* schnorr sig */ |
| 349 | + }) |
| 350 | + .ok(), |
| 351 | + _ => None, |
| 352 | + }, |
| 353 | + _ => None, |
| 354 | + } |
| 355 | + }) |
| 356 | + .collect()) |
| 357 | + } |
| 358 | + |
| 359 | + fn get_change_script(&self) -> Result<Script, ()> { |
| 360 | + tokio::task::block_in_place(move || { |
| 361 | + Ok(self.handle.block_on(async move { self.get_new_address().await.script_pubkey() })) |
| 362 | + }) |
| 363 | + } |
| 364 | + |
| 365 | + fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()> { |
| 366 | + let mut tx_bytes = Vec::new(); |
| 367 | + let _ = tx.consensus_encode(&mut tx_bytes).map_err(|_| ()); |
| 368 | + let tx_hex = hex_utils::hex_str(&tx_bytes); |
| 369 | + let signed_tx = tokio::task::block_in_place(move || { |
| 370 | + self.handle.block_on(async move { self.sign_raw_transaction_with_wallet(tx_hex).await }) |
| 371 | + }); |
| 372 | + let signed_tx_bytes = hex_utils::to_vec(&signed_tx.hex).ok_or(())?; |
| 373 | + Transaction::consensus_decode(&mut signed_tx_bytes.as_slice()).map_err(|_| ()) |
| 374 | + } |
| 375 | +} |
0 commit comments