Skip to content

Commit 5586b69

Browse files
authored
Merge pull request #519 from Camillarhi/validate-onchain-address
feat: add onchain address validation for network-specific addresses
2 parents b914731 + 94b32c9 commit 5586b69

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ fn build_with_store_internal(
10291029
Arc::clone(&tx_broadcaster),
10301030
Arc::clone(&fee_estimator),
10311031
Arc::clone(&payment_store),
1032+
Arc::clone(&config),
10321033
Arc::clone(&logger),
10331034
));
10341035

src/wallet/mod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use persist::KVStoreWalletPersister;
99

10+
use crate::config::Config;
1011
use crate::logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
1112

1213
use crate::fee_estimator::{ConfirmationTarget, FeeEstimator};
@@ -34,6 +35,7 @@ use lightning_invoice::RawBolt11Invoice;
3435
use bdk_chain::spk_client::{FullScanRequest, SyncRequest};
3536
use bdk_wallet::{Balance, KeychainKind, PersistedWallet, SignOptions, Update};
3637

38+
use bitcoin::address::NetworkUnchecked;
3739
use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
3840
use bitcoin::blockdata::locktime::absolute::LockTime;
3941
use bitcoin::hashes::Hash;
@@ -43,11 +45,12 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
4345
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
4446
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, Signing};
4547
use bitcoin::{
46-
Amount, FeeRate, ScriptBuf, Transaction, TxOut, Txid, WPubkeyHash, WitnessProgram,
47-
WitnessVersion,
48+
Address, Amount, FeeRate, Network, ScriptBuf, Transaction, TxOut, Txid, WPubkeyHash,
49+
WitnessProgram, WitnessVersion,
4850
};
4951

5052
use std::ops::Deref;
53+
use std::str::FromStr;
5154
use std::sync::{Arc, Mutex};
5255

5356
pub(crate) enum OnchainSendAmount {
@@ -71,6 +74,7 @@ where
7174
broadcaster: B,
7275
fee_estimator: E,
7376
payment_store: Arc<PaymentStore<Arc<Logger>>>,
77+
config: Arc<Config>,
7478
logger: L,
7579
}
7680

@@ -83,11 +87,11 @@ where
8387
pub(crate) fn new(
8488
wallet: bdk_wallet::PersistedWallet<KVStoreWalletPersister>,
8589
wallet_persister: KVStoreWalletPersister, broadcaster: B, fee_estimator: E,
86-
payment_store: Arc<PaymentStore<Arc<Logger>>>, logger: L,
90+
payment_store: Arc<PaymentStore<Arc<Logger>>>, config: Arc<Config>, logger: L,
8791
) -> Self {
8892
let inner = Mutex::new(wallet);
8993
let persister = Mutex::new(wallet_persister);
90-
Self { inner, persister, broadcaster, fee_estimator, payment_store, logger }
94+
Self { inner, persister, broadcaster, fee_estimator, payment_store, config, logger }
9195
}
9296

9397
pub(crate) fn get_full_scan_request(&self) -> FullScanRequest<KeychainKind> {
@@ -327,10 +331,21 @@ where
327331
self.get_balances(total_anchor_channels_reserve_sats).map(|(_, s)| s)
328332
}
329333

334+
fn parse_and_validate_address(
335+
&self, network: Network, address: &Address,
336+
) -> Result<Address, Error> {
337+
Address::<NetworkUnchecked>::from_str(address.to_string().as_str())
338+
.map_err(|_| Error::InvalidAddress)?
339+
.require_network(network)
340+
.map_err(|_| Error::InvalidAddress)
341+
}
342+
330343
pub(crate) fn send_to_address(
331344
&self, address: &bitcoin::Address, send_amount: OnchainSendAmount,
332345
fee_rate: Option<FeeRate>,
333346
) -> Result<Txid, Error> {
347+
self.parse_and_validate_address(self.config.network, &address)?;
348+
334349
// Use the set fee_rate or default to fee estimation.
335350
let confirmation_target = ConfirmationTarget::OnchainPayment;
336351
let fee_rate =

tests/integration_tests_rust.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ use lightning::util::persist::KVStore;
3030

3131
use lightning_invoice::{Bolt11InvoiceDescription, Description};
3232

33+
use bitcoin::address::NetworkUnchecked;
3334
use bitcoin::hashes::Hash;
35+
use bitcoin::Address;
3436
use bitcoin::Amount;
35-
3637
use log::LevelFilter;
3738

39+
use std::str::FromStr;
3840
use std::sync::Arc;
3941

4042
#[test]
@@ -302,6 +304,10 @@ fn onchain_send_receive() {
302304

303305
let addr_a = node_a.onchain_payment().new_address().unwrap();
304306
let addr_b = node_b.onchain_payment().new_address().unwrap();
307+
// This is a Bitcoin Testnet address. Sending funds to this address from the Regtest network will fail
308+
let static_address = "tb1q0d40e5rta4fty63z64gztf8c3v20cvet6v2jdh";
309+
let unchecked_address = Address::<NetworkUnchecked>::from_str(static_address).unwrap();
310+
let addr_c = unchecked_address.assume_checked();
305311

306312
let premine_amount_sat = 1_100_000;
307313
premine_and_distribute_funds(
@@ -366,6 +372,16 @@ fn onchain_send_receive() {
366372
node_a.onchain_payment().send_to_address(&addr_b, expected_node_a_balance + 1, None)
367373
);
368374

375+
assert_eq!(
376+
Err(NodeError::InvalidAddress),
377+
node_a.onchain_payment().send_to_address(&addr_c, expected_node_a_balance + 1, None)
378+
);
379+
380+
assert_eq!(
381+
Err(NodeError::InvalidAddress),
382+
node_a.onchain_payment().send_all_to_address(&addr_c, true, None)
383+
);
384+
369385
let amount_to_send_sats = 54321;
370386
let txid =
371387
node_b.onchain_payment().send_to_address(&addr_a, amount_to_send_sats, None).unwrap();

0 commit comments

Comments
 (0)