Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send channel tlc info directly to counterparty and update network graph with owned channel information #446

Merged
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7a7e2b5
Add {local,remote}_tlc_info to ChannelActorState
contrun Jan 6, 2025
afc5307
Add UpdateTlcInfo peer message
contrun Jan 6, 2025
2812f57
Send UpdateTlcInfo on channel ready
contrun Jan 6, 2025
c54fda0
Fix disabled channel flags
contrun Jan 6, 2025
c6116f6
Fix using disabled channnel
contrun Jan 6, 2025
a36adab
Remove unused UpdateTlcInfo
contrun Jan 6, 2025
0e69c37
Add test for tlc info in private channel
contrun Jan 6, 2025
7fadd70
Read direct channel info while building payment route
contrun Jan 6, 2025
402149d
Use liquid capacity while building route
contrun Jan 6, 2025
ce3247d
Set exact balance to graph edge for owned channels
contrun Jan 6, 2025
f2346fb
Prefetch all graph edges for owned channels
contrun Jan 6, 2025
56f1bef
Add unit test for payment over private channel
contrun Jan 7, 2025
a7c6017
Revert "Read direct channel info while building payment route"
contrun Jan 7, 2025
1724fa9
Convert owned channels to graph ChannelInfo
contrun Jan 7, 2025
4686404
Move fields to ChannelTlcInfo
contrun Jan 7, 2025
f50a273
Keep UpdateTlcInfo up with ChannelUpdate
contrun Jan 7, 2025
1e96242
Use bitflags for ChannelUpdate {message,channel}_flags
contrun Jan 7, 2025
5479342
Add balance field to ChannelUpdateInfo in graph
contrun Jan 7, 2025
12a8555
Fix setting incorrect amount for owned channels in graph
contrun Jan 7, 2025
34f175d
chore: remove some noise
contrun Jan 7, 2025
48ac972
Merge remote-tracking branch 'nervosnetwork/develop' into update-chan…
contrun Jan 7, 2025
2facf08
Add test for sending payment over private channel with insufficient b…
contrun Jan 7, 2025
fb4691e
Sort channels by explicit balance in finding path
contrun Jan 8, 2025
221e965
Add dedicated test to check path finding prefers newer channel
contrun Jan 8, 2025
383b341
Test path finding prefers channel with larger balance
contrun Jan 8, 2025
cf3d47c
Update comments while sorting channels in path-finding
contrun Jan 8, 2025
510d491
Add OwnedChannelUpdateEvent for owned channel updates
contrun Jan 10, 2025
305bdee
Update graph on channel ready
contrun Jan 10, 2025
4b155c4
Update networkgraph ChannelUpdateInfo for owned channels
contrun Jan 10, 2025
0d996cd
Update owned channel balance in graph
contrun Jan 10, 2025
b282f9b
Fix balance not set while converting ChannelActorState
contrun Jan 10, 2025
b2a7509
Separate public/private channel network graph balance test
contrun Jan 10, 2025
447cfc2
Ignore our own channel gossip messages
contrun Jan 10, 2025
c604628
Fix test_channel_update_version, test_node1_node2_channel_update
contrun Jan 10, 2025
35361f6
Fix unit tests in graph.rs because gossip message not processed
contrun Jan 10, 2025
dce8858
Remove channel from graph on channel actor exited
contrun Jan 10, 2025
dfb2683
Notify world about channel updates
contrun Jan 10, 2025
75ed475
Merge remote-tracking branch 'nervosnetwork/develop' into update-chan…
contrun Jan 10, 2025
9c9aece
Remove old loading channel from store code
contrun Jan 10, 2025
ab91390
Remove duplicated Up event on channel ready
contrun Jan 10, 2025
fdf4a12
Fix tests
contrun Jan 10, 2025
67e3e5a
Rename receivable_balance to inbound_liquidity
contrun Jan 14, 2025
036c47a
Use struct for UpdateTlcInfo
contrun Jan 14, 2025
f25f54e
Send only OwnedChannelUpdateEvent::Update on channel parameter changed
contrun Jan 14, 2025
636cc87
Merge remote-tracking branch 'nervosnetwork/develop' into update-chan…
contrun Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
334 changes: 185 additions & 149 deletions src/fiber/channel.rs

Large diffs are not rendered by default.

513 changes: 475 additions & 38 deletions src/fiber/gen/fiber.rs

Large diffs are not rendered by default.

156 changes: 132 additions & 24 deletions src/fiber/graph.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::channel::ChannelActorStateStore;
use super::channel::{ChannelActorState, ChannelActorStateStore, ChannelTlcInfo};
use super::config::AnnouncedNodeName;
use super::gossip::GossipMessageStore;
use super::history::{Direction, InternalResult, PaymentHistory, TimedResult};
Expand Down Expand Up @@ -156,6 +156,67 @@ impl ChannelInfo {
}
}

impl TryFrom<&ChannelActorState> for ChannelInfo {
type Error = String;

fn try_from(state: &ChannelActorState) -> Result<Self, Self::Error> {
if !state.is_ready() {
return Err("Channel is not ready".to_string());
}

let timestamp = 0;
let channel_outpoint = state.must_get_funding_transaction_outpoint();
let capacity = state.get_liquid_capacity();
let udt_type_script = state.funding_udt_type_script.clone();

let (
node1,
node2,
mut update_of_node1,
mut update_of_node2,
node1_receivable_balance,
node2_receivable_balance,
) = if state.local_is_node1() {
(
state.local_pubkey,
state.remote_pubkey,
Some(state.local_tlc_info.clone().into()),
state.remote_tlc_info.clone().map(ChannelUpdateInfo::from),
state.to_remote_amount,
state.to_local_amount,
)
} else {
(
state.remote_pubkey,
state.local_pubkey,
state.remote_tlc_info.clone().map(ChannelUpdateInfo::from),
Some(state.local_tlc_info.clone().into()),
state.to_local_amount,
state.to_remote_amount,
)
};

if let Some(update_of_node1) = update_of_node1.as_mut() {
update_of_node1.receivable_balance = Some(node1_receivable_balance);
}
if let Some(update_of_node2) = update_of_node2.as_mut() {
update_of_node2.receivable_balance = Some(node2_receivable_balance);
}

Ok(Self {
channel_outpoint,
timestamp,
features: 0,
node1,
node2,
capacity,
udt_type_script,
update_of_node1,
update_of_node2,
})
}
}

impl From<(u64, ChannelAnnouncement)> for ChannelInfo {
fn from((timestamp, channel_announcement): (u64, ChannelAnnouncement)) -> Self {
Self {
Expand All @@ -178,13 +239,37 @@ pub struct ChannelUpdateInfo {
pub timestamp: u64,
/// Whether the channel can be currently used for payments (in this one direction).
pub enabled: bool,
/// The exact amount of balance that we can receive from the other party via the channel.
/// Note that this is not our balance, but the balance of the other party.
/// This node is forwarding the balance for the other party, so we need to use the receivable balance
/// instead of our balance.
pub receivable_balance: Option<u128>,
/// The difference in htlc expiry values that you must have when routing through this channel (in milliseconds).
contrun marked this conversation as resolved.
Show resolved Hide resolved
pub tlc_expiry_delta: u64,
/// The minimum value, which must be relayed to the next hop via the channel
pub tlc_minimum_value: u128,
pub fee_rate: u64,
}

impl From<&ChannelTlcInfo> for ChannelUpdateInfo {
fn from(info: &ChannelTlcInfo) -> Self {
Self {
timestamp: info.timestamp,
enabled: info.enabled,
receivable_balance: None,
tlc_expiry_delta: info.tlc_expiry_delta,
tlc_minimum_value: info.tlc_minimum_value,
fee_rate: info.tlc_fee_proportional_millionths as u64,
}
}
}

impl From<ChannelTlcInfo> for ChannelUpdateInfo {
fn from(info: ChannelTlcInfo) -> Self {
Self::from(&info)
}
}

impl From<ChannelUpdate> for ChannelUpdateInfo {
fn from(update: ChannelUpdate) -> Self {
Self::from(&update)
Expand All @@ -196,6 +281,7 @@ impl From<&ChannelUpdate> for ChannelUpdateInfo {
Self {
timestamp: update.timestamp,
enabled: !update.is_disabled(),
receivable_balance: None,
tlc_expiry_delta: update.tlc_expiry_delta,
tlc_minimum_value: update.tlc_minimum_value,
fee_rate: update.tlc_fee_proportional_millionths as u64,
Expand Down Expand Up @@ -595,15 +681,28 @@ where

// Iterating over HashMap's values is not guaranteed to be in order,
// which may introduce randomness in the path finding.
// the weight algorithm in find_path does not considering capacity,
// so the channel with larger capacity maybe have the same weight with the channel with smaller capacity
// so we sort by capacity reverse order to make sure we try channel with larger capacity firstly
channels.sort_by(|(_, _, a, _), (_, _, b, _)| {
b.capacity().cmp(&a.capacity()).then(
b.channel_last_update_time()
.cmp(&a.channel_last_update_time()),
)
});
// We will first sort the channels by receivable_balance, then capacity, and at last update time.
// This is because the weight algorithm in find_path does not considering receivable_balance and capacity,
// so the channel with larger receivable_balance/capacity maybe have the same weight with the channel
// with smaller receivable_balance/capacity, even though the former have better chance to success.
channels.sort_by(
|(_, _, a_channel_info, a_channel_update_info),
(_, _, b_channel_info, b_channel_update_info)| {
b_channel_update_info
.receivable_balance
.cmp(&a_channel_update_info.receivable_balance)
.then(
b_channel_info
.capacity()
.cmp(&a_channel_info.capacity())
.then(
b_channel_info
.channel_last_update_time()
.cmp(&a_channel_info.channel_last_update_time()),
),
)
},
);
channels.into_iter()
}

Expand Down Expand Up @@ -670,6 +769,25 @@ where
self.source = source;
}

pub fn load_owned_channel_info(&mut self) {
for (_peer_id, channel_id, _state) in self.store.get_active_channel_states(None) {
match self.store.get_channel_actor_state(&channel_id) {
Some(channel_actor_state) => {
assert_eq!(channel_actor_state.local_pubkey, self.source);
match ChannelInfo::try_from(&channel_actor_state) {
Ok(channel_info) => {
self.channels
.insert(channel_info.channel_outpoint.clone(), channel_info);
}
Err(_) => {}
};
}
// It is possible that after we obtained the list of channels, the channel is deleted.
None => {}
}
}
}

/// Returns a list of `PaymentHopData` for all nodes in the route,
/// including the origin and the target node.
pub fn build_route(
Expand Down Expand Up @@ -935,20 +1053,10 @@ where
continue;
}

// if this is a direct channel, try to load the channel actor state for balance
if from == self.source || to == self.source {
if let Some(state) = self
.store
.get_channel_state_by_outpoint(&channel_info.out_point())
{
let balance = if from == self.source {
state.to_local_amount
} else {
state.to_remote_amount
};
if amount_to_send > balance {
continue;
}
// If we already know the balance of the channel, check if we can send the amount.
if let Some(balance) = channel_update.receivable_balance {
if amount_to_send > balance {
continue;
}
}

Expand Down
24 changes: 13 additions & 11 deletions src/fiber/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use tracing::{debug, error, info, trace, warn};
use super::channel::{
get_funding_and_reserved_amount, occupied_capacity, AcceptChannelParameter, ChannelActor,
ChannelActorMessage, ChannelActorStateStore, ChannelCommand, ChannelCommandWithId,
ChannelEvent, ChannelInitializationParameter, ChannelState, ChannelSubscribers,
ChannelEvent, ChannelInitializationParameter, ChannelState, ChannelSubscribers, ChannelTlcInfo,
OpenChannelParameter, ProcessingChannelError, ProcessingChannelResult, PublicChannelInfo,
RevocationData, SettlementData, ShuttingDownFlags, DEFAULT_COMMITMENT_FEE_RATE,
DEFAULT_FEE_RATE, DEFAULT_MAX_TLC_VALUE_IN_FLIGHT, MAX_COMMITMENT_DELAY_EPOCHS,
Expand Down Expand Up @@ -1572,12 +1572,12 @@ where
payment_session: &mut PaymentSession,
payment_data: &SendPaymentData,
) -> Result<Vec<PaymentHopData>, Error> {
match self
.network_graph
.read()
.await
.build_route(payment_data.clone())
{
// Load owned channel info before building route, so that we use private channels and also the
// exact balance of the channels.
let mut rwgraph = self.network_graph.write().await;
rwgraph.load_owned_channel_info();
let graph = tokio::sync::RwLockWriteGuard::downgrade(rwgraph);
match graph.build_route(payment_data.clone()) {
Err(e) => {
let error = format!("Failed to build route, {}", e);
self.set_payment_fail_with_error(payment_session, &error);
Expand Down Expand Up @@ -2085,11 +2085,12 @@ where
ChannelInitializationParameter::OpenChannel(OpenChannelParameter {
funding_amount,
seed,
public_channel_info: public.then_some(PublicChannelInfo::new(
tlc_info: ChannelTlcInfo::new(
tlc_min_value.unwrap_or(self.tlc_min_value),
tlc_expiry_delta.unwrap_or(self.tlc_expiry_delta),
tlc_fee_proportional_millionths.unwrap_or(self.tlc_fee_proportional_millionths),
)),
),
public_channel_info: public.then_some(PublicChannelInfo::new()),
funding_udt_type_script,
shutdown_script,
channel_id_sender: tx,
Expand Down Expand Up @@ -2171,11 +2172,12 @@ where
ChannelInitializationParameter::AcceptChannel(AcceptChannelParameter {
funding_amount,
reserved_ckb_amount,
public_channel_info: open_channel.is_public().then_some(PublicChannelInfo::new(
tlc_info: ChannelTlcInfo::new(
min_tlc_value.unwrap_or(self.tlc_min_value),
tlc_expiry_delta.unwrap_or(self.tlc_expiry_delta),
tlc_fee_proportional_millionths.unwrap_or(self.tlc_fee_proportional_millionths),
)),
),
public_channel_info: open_channel.is_public().then_some(PublicChannelInfo::new()),
seed,
open_channel,
shutdown_script,
Expand Down
11 changes: 11 additions & 0 deletions src/fiber/schema/fiber.mol
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ struct ClosingSigned {
partial_signature: Byte32,
}

table UpdateTlcInfo {
contrun marked this conversation as resolved.
Show resolved Hide resolved
channel_id: Byte32,
timestamp: Uint64,
channel_flags: Uint32,
tlc_expiry_delta: Uint64,
tlc_minimum_value: Uint128,
tlc_maximum_value: Uint128,
tlc_fee_proportional_millionths: Uint128,
}

table AddTlc {
channel_id: Byte32,
tlc_id: Uint64,
Expand Down Expand Up @@ -180,6 +190,7 @@ union FiberMessage {
TxAckRBF,
CommitmentSigned,
ChannelReady,
UpdateTlcInfo,
AddTlc,
RemoveTlc,
RevokeAndAck,
Expand Down
30 changes: 30 additions & 0 deletions src/fiber/tests/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,36 @@ async fn test_create_private_channel() {
.await;
}

#[tokio::test]
async fn test_create_channel_with_remote_tlc_info() {
async fn test(public: bool) {
let node_a_funding_amount = 100000000000;
let node_b_funding_amount = 6200000000;

let (node_a, node_b, channel_id, _) = NetworkNode::new_2_nodes_with_established_channel(
node_a_funding_amount,
node_b_funding_amount,
public,
)
.await;

let node_a_channel_state = node_a.store.get_channel_actor_state(&channel_id).unwrap();
let node_b_channel_state = node_b.store.get_channel_actor_state(&channel_id).unwrap();

assert_eq!(
Some(node_a_channel_state.local_tlc_info),
node_b_channel_state.remote_tlc_info
);
assert_eq!(
Some(node_b_channel_state.local_tlc_info),
node_a_channel_state.remote_tlc_info
);
}

test(true).await;
test(false).await;
}

#[tokio::test]
async fn test_create_public_channel() {
init_tracing();
Expand Down
Loading
Loading