@@ -79,8 +79,8 @@ use crate::ln::LN_MAX_MSG_LEN;
7979use crate::offers::static_invoice::StaticInvoice;
8080use crate::rgb_utils::{
8181 color_closing, color_commitment, color_htlc, get_rgb_channel_info_path,
82- get_rgb_channel_info_pending, parse_rgb_channel_info, rename_rgb_files,
83- update_rgb_channel_amount_pending,
82+ get_rgb_channel_info_pending, parse_rgb_channel_info,
83+ read_rgb_channel_info_kv, rename_rgb_files, update_rgb_channel_amount_pending,
8484};
8585use crate::routing::gossip::NodeId;
8686use crate::sign::ecdsa::EcdsaChannelSigner;
@@ -104,6 +104,8 @@ use crate::prelude::*;
104104use crate::sign::type_resolver::ChannelSignerType;
105105#[cfg(any(test, fuzzing, debug_assertions))]
106106use crate::sync::Mutex;
107+ use crate::sync::Arc;
108+ use crate::util::persist::KVStoreSync;
107109use core::ops::Deref;
108110use core::time::Duration;
109111use core::{cmp, fmt, mem};
@@ -3132,6 +3134,9 @@ where
31323134 pub(super) consignment_endpoint: Option<RgbTransport>,
31333135
31343136 pub(crate) ldk_data_dir: PathBuf,
3137+
3138+ /// Optional KVStore for RGB data persistence
3139+ pub(crate) rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
31353140}
31363141
31373142/// A channel struct implementing this trait can receive an initial counterparty commitment
@@ -3232,7 +3237,7 @@ where
32323237 let temporary_channel_id = context.channel_id;
32333238 context.channel_id = channel_id;
32343239 if context.is_colored() {
3235- rename_rgb_files(&context.channel_id, &temporary_channel_id, &context.ldk_data_dir);
3240+ rename_rgb_files(&context.channel_id, &temporary_channel_id, &context.ldk_data_dir, context.rgb_kv_store.as_ref() );
32363241 }
32373242
32383243 assert!(!context.channel_state.is_monitor_update_in_progress()); // We have not had any monitor(s) yet to fail update!
@@ -3401,6 +3406,7 @@ where
34013406 msg_push_msat: u64,
34023407 open_channel_fields: msgs::CommonOpenChannelFields,
34033408 ldk_data_dir: PathBuf,
3409+ rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
34043410 ) -> Result<(FundingScope, ChannelContext<SP>), ChannelError>
34053411 where
34063412 ES::Target: EntropySource,
@@ -3723,6 +3729,7 @@ where
37233729
37243730 consignment_endpoint: open_channel_fields.consignment_endpoint,
37253731 ldk_data_dir,
3732+ rgb_kv_store,
37263733 };
37273734
37283735 Ok((funding, channel_context))
@@ -3748,6 +3755,7 @@ where
37483755 _logger: L,
37493756 consignment_endpoint: Option<RgbTransport>,
37503757 ldk_data_dir: PathBuf,
3758+ rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
37513759 ) -> Result<(FundingScope, ChannelContext<SP>), APIError>
37523760 where
37533761 ES::Target: EntropySource,
@@ -3966,6 +3974,7 @@ where
39663974
39673975 consignment_endpoint,
39683976 ldk_data_dir,
3977+ rgb_kv_store,
39693978 };
39703979
39713980 Ok((funding, channel_context))
@@ -4344,11 +4353,15 @@ where
43444353
43454354 /// Get the channel local RGB amount
43464355 pub fn get_local_rgb_amount(&self) -> u64 {
4347- let info_file_path = get_rgb_channel_info_path(
4348- &self.channel_id.0.as_hex().to_string(),
4349- &self.ldk_data_dir,
4350- false,
4351- );
4356+ let channel_id_str = self.channel_id.0.as_hex().to_string();
4357+ // Try KVStore first (using injected store)
4358+ if let Some(ref kv_store) = self.rgb_kv_store {
4359+ if let Ok(rgb_info) = read_rgb_channel_info_kv(kv_store.as_ref(), &channel_id_str, false) {
4360+ return rgb_info.local_rgb_amount;
4361+ }
4362+ }
4363+ // Fallback to filesystem
4364+ let info_file_path = get_rgb_channel_info_path(&channel_id_str, &self.ldk_data_dir, false);
43524365 if info_file_path.exists() {
43534366 let rgb_info = parse_rgb_channel_info(&info_file_path);
43544367 rgb_info.local_rgb_amount
@@ -4359,11 +4372,15 @@ where
43594372
43604373 /// Get the channel remote RGB amount
43614374 pub fn get_remote_rgb_amount(&self) -> u64 {
4362- let info_file_path = get_rgb_channel_info_path(
4363- &self.channel_id.0.as_hex().to_string(),
4364- &self.ldk_data_dir,
4365- false,
4366- );
4375+ let channel_id_str = self.channel_id.0.as_hex().to_string();
4376+ // Try KVStore first (using injected store)
4377+ if let Some(ref kv_store) = self.rgb_kv_store {
4378+ if let Ok(rgb_info) = read_rgb_channel_info_kv(kv_store.as_ref(), &channel_id_str, false) {
4379+ return rgb_info.remote_rgb_amount;
4380+ }
4381+ }
4382+ // Fallback to filesystem
4383+ let info_file_path = get_rgb_channel_info_path(&channel_id_str, &self.ldk_data_dir, false);
43674384 if info_file_path.exists() {
43684385 let rgb_info = parse_rgb_channel_info(&info_file_path);
43694386 rgb_info.remote_rgb_amount
@@ -5080,7 +5097,7 @@ where
50805097 &holder_keys.revocation_key,
50815098 );
50825099 if self.is_colored() {
5083- color_htlc(&mut htlc_tx, htlc, &self.ldk_data_dir)
5100+ color_htlc(&mut htlc_tx, htlc, &self.ldk_data_dir, self.rgb_kv_store.as_ref() )
50845101 .expect("successful htlc coloring");
50855102 }
50865103
@@ -7324,6 +7341,7 @@ where
73247341 &self.context.channel_id,
73257342 &mut closing_transaction,
73267343 &self.context.ldk_data_dir,
7344+ self.context.rgb_kv_store.as_ref(),
73277345 )
73287346 .expect("successful closing TX coloring");
73297347 }
@@ -8915,6 +8933,7 @@ where
89158933 rgb_offered_htlc,
89168934 rgb_received_htlc,
89178935 &self.context.ldk_data_dir,
8936+ self.context.rgb_kv_store.as_ref(),
89188937 );
89198938 }
89208939
@@ -11729,7 +11748,7 @@ where
1172911748 let were_node_one = node_id.as_slice() < counterparty_node_id.as_slice();
1173011749
1173111750 let contract_id = if self.context.is_colored() {
11732- let (rgb_info, _) = get_rgb_channel_info_pending(&self.context.channel_id, &self.context.ldk_data_dir);
11751+ let (rgb_info, _) = get_rgb_channel_info_pending(&self.context.channel_id, &self.context.ldk_data_dir, self.context.rgb_kv_store.as_ref() );
1173311752 Some(rgb_info.contract_id)
1173411753 } else {
1173511754 None
@@ -12883,7 +12902,7 @@ where
1288312902 }
1288412903 }
1288512904 if self.context.is_colored() && rgb_received_htlc > 0 {
12886- update_rgb_channel_amount_pending(&self.context.channel_id, 0, rgb_received_htlc, &self.context.ldk_data_dir);
12905+ update_rgb_channel_amount_pending(&self.context.channel_id, 0, rgb_received_htlc, &self.context.ldk_data_dir, self.context.rgb_kv_store.as_ref() );
1288712906 }
1288812907 if let Some((feerate, update_state)) = self.context.pending_update_fee {
1288912908 if update_state == FeeUpdateState::AwaitingRemoteRevokeToAnnounce {
@@ -13550,6 +13569,7 @@ where
1355013569 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP, counterparty_node_id: PublicKey, their_features: &InitFeatures,
1355113570 channel_value_satoshis: u64, push_msat: u64, user_id: u128, config: &UserConfig, current_chain_height: u32,
1355213571 outbound_scid_alias: u64, temporary_channel_id: Option<ChannelId>, logger: L, consignment_endpoint: Option<RgbTransport>, ldk_data_dir: PathBuf,
13572+ rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
1355313573 ) -> Result<OutboundV1Channel<SP>, APIError>
1355413574 where ES::Target: EntropySource,
1355513575 F::Target: FeeEstimator,
@@ -13589,6 +13609,7 @@ where
1358913609 logger,
1359013610 consignment_endpoint,
1359113611 ldk_data_dir,
13612+ rgb_kv_store,
1359213613 )?;
1359313614 let unfunded_context = UnfundedChannelContext {
1359413615 unfunded_channel_age_ticks: 0,
@@ -13672,7 +13693,7 @@ where
1367213693 let temporary_channel_id = self.context.channel_id;
1367313694 self.context.channel_id = ChannelId::v1_from_funding_outpoint(funding_txo);
1367413695 if self.context.is_colored() {
13675- rename_rgb_files(&self.context.channel_id, &temporary_channel_id, &self.context.ldk_data_dir);
13696+ rename_rgb_files(&self.context.channel_id, &temporary_channel_id, &self.context.ldk_data_dir, self.context.rgb_kv_store.as_ref() );
1367613697 }
1367713698
1367813699 // If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
@@ -13925,7 +13946,8 @@ where
1392513946 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
1392613947 counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
1392713948 their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u128, config: &UserConfig,
13928- current_chain_height: u32, logger: &L, is_0conf: bool, ldk_data_dir: PathBuf
13949+ current_chain_height: u32, logger: &L, is_0conf: bool, ldk_data_dir: PathBuf,
13950+ rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
1392913951 ) -> Result<InboundV1Channel<SP>, ChannelError>
1393013952 where ES::Target: EntropySource,
1393113953 F::Target: FeeEstimator,
@@ -13966,6 +13988,7 @@ where
1396613988 msg.push_msat,
1396713989 msg.common_fields.clone(),
1396813990 ldk_data_dir,
13991+ rgb_kv_store,
1396913992 )?;
1397013993 let unfunded_context = UnfundedChannelContext {
1397113994 unfunded_channel_age_ticks: 0,
@@ -14166,7 +14189,7 @@ where
1416614189 counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
1416714190 funding_inputs: Vec<FundingTxInput>, user_id: u128, config: &UserConfig,
1416814191 current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
14169- logger: L, ldk_data_dir: PathBuf,
14192+ logger: L, ldk_data_dir: PathBuf, rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
1417014193 ) -> Result<Self, APIError>
1417114194 where ES::Target: EntropySource,
1417214195 F::Target: FeeEstimator,
@@ -14209,6 +14232,7 @@ where
1420914232 // ok to pass consignment_endpoint as None since this method is unused
1421014233 None,
1421114234 ldk_data_dir,
14235+ rgb_kv_store,
1421214236 )?;
1421314237 let unfunded_context = UnfundedChannelContext {
1421414238 unfunded_channel_age_ticks: 0,
@@ -14319,7 +14343,7 @@ where
1431914343 holder_node_id: PublicKey, counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
1432014344 their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
1432114345 user_id: u128, config: &UserConfig, current_chain_height: u32, logger: &L,
14322- ldk_data_dir: PathBuf,
14346+ ldk_data_dir: PathBuf, rgb_kv_store: Option<Arc<dyn KVStoreSync + Send + Sync>>,
1432314347 ) -> Result<Self, ChannelError>
1432414348 where ES::Target: EntropySource,
1432514349 F::Target: FeeEstimator,
@@ -14365,6 +14389,7 @@ where
1436514389 0 /* push_msat not used in dual-funding */,
1436614390 msg.common_fields.clone(),
1436714391 ldk_data_dir,
14392+ rgb_kv_store,
1436814393 )?;
1436914394 let channel_id = ChannelId::v2_from_revocation_basepoints(
1437014395 &funding.get_holder_pubkeys().revocation_basepoint,
@@ -15054,16 +15079,16 @@ where
1505415079 }
1505515080}
1505615081
15057- impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c ChannelTypeFeatures, PathBuf)>
15082+ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c ChannelTypeFeatures, PathBuf, Option<Arc<dyn KVStoreSync + Send + Sync>> )>
1505815083 for FundedChannel<SP>
1505915084where
1506015085 ES::Target: EntropySource,
1506115086 SP::Target: SignerProvider,
1506215087{
1506315088 fn read<R: io::Read>(
15064- reader: &mut R, args: (&'a ES, &'b SP, &'c ChannelTypeFeatures, PathBuf),
15089+ reader: &mut R, args: (&'a ES, &'b SP, &'c ChannelTypeFeatures, PathBuf, Option<Arc<dyn KVStoreSync + Send + Sync>> ),
1506515090 ) -> Result<Self, DecodeError> {
15066- let (entropy_source, signer_provider, our_supported_features, ldk_data_dir) = args;
15091+ let (entropy_source, signer_provider, our_supported_features, ldk_data_dir, rgb_kv_store ) = args;
1506715092 let ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
1506815093 if ver <= 2 {
1506915094 return Err(DecodeError::UnknownVersion);
@@ -15859,6 +15884,7 @@ where
1585915884
1586015885 consignment_endpoint,
1586115886 ldk_data_dir,
15887+ rgb_kv_store,
1586215888 },
1586315889 holder_commitment_point,
1586415890 pending_splice,
@@ -16770,7 +16796,9 @@ mod tests {
1677016796 // These aren't set in the test vectors:
1677116797 [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
1677216798 [0; 32],
16799+ std::path::PathBuf::new(),
1677316800 [0; 32],
16801+ None,
1677416802 );
1677516803
1677616804 let holder_pubkeys = signer.pubkeys(&secp_ctx);
0 commit comments