bitcoin_hashes = { version = "0.11", default-features = false }
hashbrown = { version = "0.8", optional = true }
serde = { version = "1.0.118", optional = true }
+bitcoin = { version = "0.29.0", default-features = false }
[dev-dependencies]
lightning = { version = "0.0.113", path = "../lightning", default-features = false, features = ["_test_utils"] }
#[cfg(feature = "std")]
use std::error;
+use core::convert::TryFrom;
use core::fmt;
use core::fmt::{Display, Formatter};
use core::num::ParseIntError;
use bech32;
use bech32::{u5, FromBase32};
+use bitcoin::{PubkeyHash, ScriptHash};
+use bitcoin::util::address::WitnessVersion;
use bitcoin_hashes::Hash;
use bitcoin_hashes::sha256;
use crate::prelude::*;
if bytes.len() < 2 || bytes.len() > 40 {
return Err(ParseError::InvalidSegWitProgramLength);
}
-
+ let version = WitnessVersion::try_from(version).expect("0 through 16 are valid SegWit versions");
Ok(Fallback::SegWitProgram {
version: version,
program: bytes
})
},
17 => {
- if bytes.len() != 20 {
- return Err(ParseError::InvalidPubKeyHashLength);
- }
- //TODO: refactor once const generics are available
- let mut pkh = [0u8; 20];
- pkh.copy_from_slice(&bytes);
+ let pkh = match PubkeyHash::from_slice(&bytes) {
+ Ok(pkh) => pkh,
+ Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidPubKeyHashLength),
+ };
Ok(Fallback::PubKeyHash(pkh))
}
18 => {
- if bytes.len() != 20 {
- return Err(ParseError::InvalidScriptHashLength);
- }
- let mut sh = [0u8; 20];
- sh.copy_from_slice(&bytes);
+ let sh = match ScriptHash::from_slice(&bytes) {
+ Ok(sh) => sh,
+ Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(ParseError::InvalidScriptHashLength),
+ };
Ok(Fallback::ScriptHash(sh))
}
_ => Err(ParseError::Skip)
fn test_parse_fallback() {
use crate::Fallback;
use bech32::FromBase32;
+ use bitcoin::{PubkeyHash, ScriptHash};
+ use bitcoin::util::address::WitnessVersion;
+ use bitcoin_hashes::Hash;
let cases = vec![
(
from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
- Ok(Fallback::PubKeyHash([
+ Ok(Fallback::PubKeyHash(PubkeyHash::from_slice(&[
0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
- ]))
+ ]).unwrap()))
),
(
from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
- Ok(Fallback::ScriptHash([
+ Ok(Fallback::ScriptHash(ScriptHash::from_slice(&[
0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
- ]))
+ ]).unwrap()))
),
(
from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
Ok(Fallback::SegWitProgram {
- version: u5::try_from_u8(0).unwrap(),
+ version: WitnessVersion::V0,
program: Vec::from(&[
0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
use std::time::SystemTime;
use bech32::u5;
-use bitcoin_hashes::Hash;
-use bitcoin_hashes::sha256;
+use bitcoin::{Address, Network, PubkeyHash, ScriptHash};
+use bitcoin::util::address::{Payload, WitnessVersion};
+use bitcoin_hashes::{Hash, sha256};
use lightning::ln::PaymentSecret;
use lightning::ln::features::InvoiceFeatures;
#[cfg(any(doc, test))]
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct MinFinalCltvExpiryDelta(pub u64);
-// TODO: better types instead onf byte arrays
/// Fallback address in case no LN payment is possible
#[allow(missing_docs)]
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub enum Fallback {
SegWitProgram {
- version: u5,
+ version: WitnessVersion,
program: Vec<u8>,
},
- PubKeyHash([u8; 20]),
- ScriptHash([u8; 20]),
+ PubKeyHash(PubkeyHash),
+ ScriptHash(ScriptHash),
}
/// Recoverable signature
self.signed_invoice.fallbacks()
}
+ /// Returns a list of all fallback addresses as [`Address`]es
+ pub fn fallback_addresses(&self) -> Vec<Address> {
+ self.fallbacks().iter().map(|fallback| {
+ let network = match self.currency() {
+ Currency::Bitcoin => Network::Bitcoin,
+ Currency::BitcoinTestnet => Network::Testnet,
+ Currency::Regtest => Network::Regtest,
+ Currency::Simnet => Network::Regtest,
+ Currency::Signet => Network::Signet,
+ };
+
+ let payload = match fallback {
+ Fallback::SegWitProgram { version, program } => {
+ Payload::WitnessProgram { version: *version, program: program.to_vec() }
+ }
+ Fallback::PubKeyHash(pkh) => {
+ Payload::PubkeyHash(*pkh)
+ }
+ Fallback::ScriptHash(sh) => {
+ Payload::ScriptHash(*sh)
+ }
+ };
+
+ Address { payload, network }
+ }).collect()
+ }
+
/// Returns a list of all routes included in the invoice
pub fn private_routes(&self) -> Vec<&PrivateRoute> {
self.signed_invoice.private_routes()
#[cfg(test)]
mod test {
+ use bitcoin::Script;
use bitcoin_hashes::hex::FromHex;
use bitcoin_hashes::sha256;
.payee_pub_key(public_key.clone())
.expiry_time(Duration::from_secs(54321))
.min_final_cltv_expiry_delta(144)
- .fallback(Fallback::PubKeyHash([0;20]))
+ .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[0;20]).unwrap()))
.private_route(route_1.clone())
.private_route(route_2.clone())
.description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
assert_eq!(invoice.payee_pub_key(), Some(&public_key));
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
- assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
+ assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0;20]).unwrap())]);
+ let address = Address::from_script(&Script::new_p2pkh(&PubkeyHash::from_slice(&[0;20]).unwrap()), Network::Testnet).unwrap();
+ assert_eq!(invoice.fallback_addresses(), vec![address]);
assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
assert_eq!(
invoice.description(),
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
match *self {
Fallback::SegWitProgram {version: v, program: ref p} => {
- writer.write_u5(v)?;
+ writer.write_u5(Into::<u5>::into(v))?;
p.write_base32(writer)
},
Fallback::PubKeyHash(ref hash) => {
extern crate secp256k1;
extern crate hex;
+use bitcoin::util::address::WitnessVersion;
+use bitcoin::{PubkeyHash, ScriptHash};
use bitcoin_hashes::hex::FromHex;
use bitcoin_hashes::{sha256, Hash};
-use bech32::u5;
use lightning::ln::PaymentSecret;
use lightning::routing::gossip::RoutingFees;
use lightning::routing::router::{RouteHint, RouteHintHop};
.payment_hash(sha256::Hash::from_hex(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap())
- .fallback(Fallback::PubKeyHash([49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]))
+ .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]).unwrap()))
.build_raw()
.unwrap()
.sign(|_| {
.payment_hash(sha256::Hash::from_hex(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap())
- .fallback(Fallback::PubKeyHash([4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]))
+ .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]).unwrap()))
.private_route(RouteHint(vec![RouteHintHop {
src_node_id: PublicKey::from_slice(&hex::decode(
"029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
.payment_hash(sha256::Hash::from_hex(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap())
- .fallback(Fallback::ScriptHash([143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]))
+ .fallback(Fallback::ScriptHash(ScriptHash::from_slice(&[143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]).unwrap()))
.build_raw()
.unwrap()
.sign(|_| {
.payment_hash(sha256::Hash::from_hex(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap())
- .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
+ .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
program: vec![117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214]
})
.build_raw()
.payment_hash(sha256::Hash::from_hex(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap())
- .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
+ .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
program: vec![24, 99, 20, 60, 20, 197, 22, 104, 4, 189, 25, 32, 51, 86, 218, 19, 108, 152, 86, 120, 205, 77, 39, 161, 184, 198, 50, 150, 4, 144, 50, 98]
})
.build_raw()