Skip to content

Commit eaf2939

Browse files
committed
implement RGB channels
1 parent f6a9382 commit eaf2939

24 files changed

+1063
-174
lines changed

lightning-invoice/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ secp256k1 = { version = "0.24.0", default-features = false, features = ["recover
2626
num-traits = { version = "0.2.8", default-features = false }
2727
bitcoin_hashes = { version = "0.11", default-features = false }
2828
hashbrown = { version = "0.8", optional = true }
29-
serde = { version = "1.0.118", optional = true }
29+
30+
# RGB and related
31+
hex = "0.4"
32+
rgb-std = "0.9.0"
33+
serde = { version = "1.0.118" }
34+
serde_json = { version = "1"}
3035

3136
[dev-dependencies]
3237
lightning = { version = "0.0.113", path = "../lightning", default-features = false, features = ["_test_utils"] }

lightning-invoice/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
compile_error!("at least one of the `std` or `no-std` features must be enabled");
2727

2828
pub mod payment;
29+
pub mod rgb_utils;
2930
pub mod utils;
3031

3132
pub(crate) mod time_utils;

lightning-invoice/src/payment.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ use bitcoin_hashes::Hash;
141141
use bitcoin_hashes::sha256::Hash as Sha256;
142142

143143
use crate::prelude::*;
144+
use crate::rgb_utils::{filter_first_hops, write_rgb_payment_info_file};
144145
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
145146
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
146147
use lightning::ln::msgs::LightningError;
@@ -150,6 +151,8 @@ use lightning::util::logger::Logger;
150151
use crate::time_utils::Time;
151152
use crate::sync::Mutex;
152153

154+
use rgb::ContractId;
155+
153156
use secp256k1::PublicKey;
154157

155158
use core::fmt;
@@ -158,6 +161,8 @@ use core::future::Future;
158161
use core::ops::Deref;
159162
use core::time::Duration;
160163
#[cfg(feature = "std")]
164+
use std::path::PathBuf;
165+
#[cfg(feature = "std")]
161166
use std::time::SystemTime;
162167

163168
/// A utility for paying [`Invoice`]s and sending spontaneous payments.
@@ -199,6 +204,7 @@ pub struct InvoicePayerUsingTime<
199204
/// Caches the overall attempts at making a payment, which is updated prior to retrying.
200205
payment_cache: Mutex<HashMap<PaymentHash, PaymentAttempts<T>>>,
201206
retry: Retry,
207+
ldk_data_dir: PathBuf,
202208
}
203209

204210
/// Storing minimal payment attempts information required for determining if a outbound payment can
@@ -327,7 +333,7 @@ where
327333
/// Will forward any [`Event::PaymentPathFailed`] events to the decorated `event_handler` once
328334
/// `retry` has been exceeded for a given [`Invoice`].
329335
pub fn new(
330-
payer: P, router: R, logger: L, event_handler: E, retry: Retry
336+
payer: P, router: R, logger: L, event_handler: E, retry: Retry, ldk_data_dir: PathBuf
331337
) -> Self {
332338
Self {
333339
payer,
@@ -336,6 +342,7 @@ where
336342
event_handler,
337343
payment_cache: Mutex::new(HashMap::new()),
338344
retry,
345+
ldk_data_dir,
339346
}
340347
}
341348

@@ -448,10 +455,11 @@ where
448455
/// ensure that a second payment with the same [`PaymentPreimage`] is never sent.
449456
pub fn pay_pubkey(
450457
&self, pubkey: PublicKey, payment_preimage: PaymentPreimage, amount_msats: u64,
451-
final_cltv_expiry_delta: u32
458+
final_cltv_expiry_delta: u32, contract_id: ContractId, amount_rgb: u64
452459
) -> Result<PaymentId, PaymentError> {
453460
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
454461
let payment_id = PaymentId(payment_hash.0);
462+
write_rgb_payment_info_file(&self.ldk_data_dir, &payment_hash, contract_id, amount_rgb);
455463
self.do_pay_pubkey(pubkey, payment_preimage, payment_hash, payment_id, amount_msats,
456464
final_cltv_expiry_delta)
457465
.map(|()| payment_id)
@@ -467,9 +475,10 @@ where
467475
/// [`PaymentHash`] has never been paid before.
468476
pub fn pay_pubkey_with_id(
469477
&self, pubkey: PublicKey, payment_preimage: PaymentPreimage, payment_id: PaymentId,
470-
amount_msats: u64, final_cltv_expiry_delta: u32
478+
amount_msats: u64, final_cltv_expiry_delta: u32, contract_id: ContractId, amount_rgb: u64
471479
) -> Result<(), PaymentError> {
472480
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
481+
write_rgb_payment_info_file(&self.ldk_data_dir, &payment_hash, contract_id, amount_rgb);
473482
self.do_pay_pubkey(pubkey, payment_preimage, payment_hash, payment_id, amount_msats,
474483
final_cltv_expiry_delta)
475484
}
@@ -507,10 +516,11 @@ where
507516
}
508517

509518
let payer = self.payer.node_id();
510-
let first_hops = self.payer.first_hops();
519+
let mut first_hops = self.payer.first_hops();
520+
let contract_id = filter_first_hops(&self.ldk_data_dir, &payment_hash, &mut first_hops);
511521
let inflight_htlcs = self.payer.inflight_htlcs();
512522
let route = self.router.find_route(
513-
&payer, &params, Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs
523+
&payer, &params, Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs, contract_id
514524
).map_err(|e| PaymentError::Routing(e))?;
515525

516526
match send_payment(&route) {
@@ -574,11 +584,12 @@ where
574584
}
575585

576586
let payer = self.payer.node_id();
577-
let first_hops = self.payer.first_hops();
587+
let mut first_hops = self.payer.first_hops();
588+
let contract_id = filter_first_hops(&self.ldk_data_dir, &payment_hash, &mut first_hops);
578589
let inflight_htlcs = self.payer.inflight_htlcs();
579590

580591
let route = self.router.find_route(
581-
&payer, &params, Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs
592+
&payer, &params, Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs, contract_id
582593
);
583594

584595
if route.is_err() {
@@ -727,6 +738,7 @@ where
727738
}
728739
}
729740

741+
/*
730742
#[cfg(test)]
731743
mod tests {
732744
use super::*;
@@ -2307,3 +2319,4 @@ mod tests {
23072319
assert!(expected_events.borrow().is_empty());
23082320
}
23092321
}
2322+
*/

lightning-invoice/src/rgb_utils.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! A module to provide RGB functionality
2+
3+
use lightning::ln::PaymentHash;
4+
use lightning::ln::channelmanager::ChannelDetails;
5+
use lightning::rgb_utils::{RgbInfo, RgbPaymentInfo};
6+
7+
use rgb::ContractId;
8+
9+
#[cfg(feature = "std")]
10+
use std::fs;
11+
#[cfg(feature = "std")]
12+
use std::path::PathBuf;
13+
14+
/// Write RGB payment info to file
15+
pub(crate) fn write_rgb_payment_info_file(ldk_data_dir: &PathBuf, payment_hash: &PaymentHash, contract_id: ContractId, amount_rgb: u64) {
16+
let rgb_payment_info_path = ldk_data_dir.clone().join(hex::encode(payment_hash.0));
17+
let rgb_payment_info = RgbPaymentInfo {
18+
contract_id,
19+
amount: amount_rgb,
20+
local_rgb_amount: 0,
21+
remote_rgb_amount: 0,
22+
};
23+
let serialized_info = serde_json::to_string(&rgb_payment_info).expect("valid rgb payment info");
24+
std::fs::write(rgb_payment_info_path, serialized_info).expect("able to write rgb payment info file");
25+
}
26+
27+
28+
/// Filter first_hops for contract_id
29+
pub(crate) fn filter_first_hops(ldk_data_dir: &PathBuf, payment_hash: &PaymentHash, first_hops: &mut Vec<ChannelDetails>) -> ContractId {
30+
let rgb_payment_info_path = ldk_data_dir.join(hex::encode(payment_hash.0));
31+
let serialized_info = fs::read_to_string(rgb_payment_info_path).expect("valid rgb payment info file");
32+
let rgb_payment_info: RgbPaymentInfo = serde_json::from_str(&serialized_info).expect("valid rgb payment info file");
33+
let contract_id = rgb_payment_info.contract_id;
34+
first_hops.retain(|h| {
35+
let info_file_path = ldk_data_dir.join(hex::encode(&h.channel_id));
36+
if !info_file_path.exists() {
37+
return false
38+
}
39+
let serialized_info = fs::read_to_string(info_file_path).expect("valid rgb info file");
40+
let rgb_info: RgbInfo = serde_json::from_str(&serialized_info).expect("valid rgb info file");
41+
rgb_info.contract_id == contract_id.clone()
42+
});
43+
contract_id
44+
}

lightning-persister/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl FilesystemPersister {
9595
));
9696
}
9797

98-
let index = filename.unwrap().split_at(65).1.parse();
98+
let index: Result<u16, _> = filename.unwrap().split_at(65).1.parse();
9999
if index.is_err() {
100100
return Err(std::io::Error::new(
101101
std::io::ErrorKind::InvalidData,

lightning/Cargo.toml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
1717

1818
[features]
1919
# Internal test utilities exposed to other repo crates
20-
_test_utils = ["hex", "regex", "bitcoin/bitcoinconsensus"]
20+
_test_utils = ["regex", "bitcoin/bitcoinconsensus"]
2121
# Unlog messages superior at targeted level.
2222
max_level_off = []
2323
max_level_error = []
@@ -42,12 +42,32 @@ default = ["std", "grind_signatures"]
4242
bitcoin = { version = "0.29.0", default-features = false, features = ["secp-recovery"] }
4343

4444
hashbrown = { version = "0.8", optional = true }
45-
hex = { version = "0.4", optional = true }
4645
regex = { version = "1.5.6", optional = true }
4746
backtrace = { version = "0.3", optional = true }
4847

4948
core2 = { version = "0.3.0", optional = true, default-features = false }
5049

50+
# RGB and related
51+
amplify = "3.13.0"
52+
base64 = "0.13.0"
53+
bp-core = { version = "0.9.0", features = ["psbt", "wallet"] }
54+
commit_verify = "0.9.0"
55+
futures = "0.3"
56+
hex = { version = "0.4" }
57+
internet2 = "0.9.0"
58+
lnpbp = "0.9.0"
59+
lnpbp-invoice = { version = "0.9.0", features = ["rgb"] }
60+
psbt = "0.9.0"
61+
reqwest = { version = "0.11", default-features = false, features = ["json", "blocking"] }
62+
rgb-std = "0.9.0"
63+
rgb20 = "0.9.0"
64+
rgb_core = { package = "rgb-core", version = "0.9.0" }
65+
rgb_rpc = "0.9.1"
66+
serde = { version = "^1.0", features = ["derive"] }
67+
serde_json = { version = "^1.0" }
68+
strict_encoding = "0.9.0"
69+
tokio = { version = "1.14.1", features = ["macros", "rt-multi-thread"] }
70+
5171
[dev-dependencies]
5272
hex = "0.4"
5373
regex = "1.5.6"

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use crate::util::events::{AnchorDescriptor, HTLCDescriptor, BumpTransactionEvent
5757

5858
use crate::prelude::*;
5959
use core::{cmp, mem};
60+
use std::path::PathBuf;
6061
use crate::io::{self, Error};
6162
use core::convert::TryInto;
6263
use core::ops::Deref;
@@ -1104,7 +1105,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
11041105
funding_redeemscript: Script, channel_value_satoshis: u64,
11051106
commitment_transaction_number_obscure_factor: u64,
11061107
initial_holder_commitment_tx: HolderCommitmentTransaction,
1107-
best_block: BestBlock, counterparty_node_id: PublicKey) -> ChannelMonitor<Signer> {
1108+
best_block: BestBlock, counterparty_node_id: PublicKey, ldk_data_dir: PathBuf) -> ChannelMonitor<Signer> {
11081109

11091110
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
11101111
let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize());
@@ -1140,7 +1141,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
11401141

11411142
let onchain_tx_handler =
11421143
OnchainTxHandler::new(destination_script.clone(), keys,
1143-
channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone());
1144+
channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone(), ldk_data_dir);
11441145

11451146
let mut outputs_to_watch = HashMap::new();
11461147
outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]);
@@ -3770,9 +3771,10 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K>
37703771
let cltv_expiry: u32 = Readable::read(reader)?;
37713772
let payment_hash: PaymentHash = Readable::read(reader)?;
37723773
let transaction_output_index: Option<u32> = Readable::read(reader)?;
3774+
let amount_rgb: u64 = Readable::read(reader)?;
37733775

37743776
HTLCOutputInCommitment {
3775-
offered, amount_msat, cltv_expiry, payment_hash, transaction_output_index
3777+
offered, amount_msat, cltv_expiry, payment_hash, transaction_output_index, amount_rgb
37763778
}
37773779
}
37783780
}

0 commit comments

Comments
 (0)