Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions lightning/src/ln/accountable_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry};
use crate::ln::functional_test_utils::*;
use crate::ln::msgs::{accountable_from_bool, ChannelMessageHandler, ExperimentalAccountable};
use crate::routing::router::{PaymentParameters, RouteParameters};

fn test_accountable_forwarding_with_override(
override_accountable: ExperimentalAccountable, expected_forwarded: ExperimentalAccountable,
) {
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);

let _chan_ab = create_announced_chan_between_nodes(&nodes, 0, 1);
let _chan_bc = create_announced_chan_between_nodes(&nodes, 1, 2);

let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[2]);
let route_params = RouteParameters::from_payment_params_and_value(
PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV),
100_000,
);
let onion_fields = RecipientOnionFields::secret_only(payment_secret);
let payment_id = PaymentId(payment_hash.0);
nodes[0]
.node
.send_payment(payment_hash, onion_fields, payment_id, route_params, Retry::Attempts(0))
.unwrap();
check_added_monitors(&nodes[0], 1);

let updates_ab = get_htlc_update_msgs(&nodes[0], &nodes[1].node.get_our_node_id());
assert_eq!(updates_ab.update_add_htlcs.len(), 1);
let mut htlc_ab = updates_ab.update_add_htlcs[0].clone();
assert_eq!(htlc_ab.accountable, accountable_from_bool(false));

// Override accountable value if requested
if let Some(override_value) = override_accountable {
htlc_ab.accountable = Some(override_value);
}

nodes[1].node.handle_update_add_htlc(nodes[0].node.get_our_node_id(), &htlc_ab);
do_commitment_signed_dance(&nodes[1], &nodes[0], &updates_ab.commitment_signed, false, false);
expect_and_process_pending_htlcs(&nodes[1], false);
check_added_monitors(&nodes[1], 1);

let updates_bc = get_htlc_update_msgs(&nodes[1], &nodes[2].node.get_our_node_id());
assert_eq!(updates_bc.update_add_htlcs.len(), 1);
let htlc_bc = &updates_bc.update_add_htlcs[0];
assert_eq!(
htlc_bc.accountable, expected_forwarded,
"B -> C should have accountable = {:?}",
expected_forwarded
);

nodes[2].node.handle_update_add_htlc(nodes[1].node.get_our_node_id(), htlc_bc);
do_commitment_signed_dance(&nodes[2], &nodes[1], &updates_bc.commitment_signed, false, false);
expect_and_process_pending_htlcs(&nodes[2], false);
check_added_monitors(&nodes[2], 0);
expect_payment_claimable!(nodes[2], payment_hash, payment_secret, 100_000);
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
}

#[test]
fn test_accountable_signal() {
// Tests forwarding of accountable signal for various incoming signal values.
test_accountable_forwarding_with_override(None, accountable_from_bool(false));
test_accountable_forwarding_with_override(Some(7), accountable_from_bool(true));
test_accountable_forwarding_with_override(Some(3), accountable_from_bool(false));
}
1 change: 1 addition & 0 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,7 @@ fn update_add_msg(
skimmed_fee_msat: None,
blinding_point,
hold_htlc: None,
accountable: None,
}
}

Expand Down
67 changes: 62 additions & 5 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use crate::ln::interactivetxs::{
InteractiveTxSigningSession, NegotiationError, SharedOwnedInput, SharedOwnedOutput,
TX_COMMON_FIELDS_WEIGHT,
};
use crate::ln::msgs;
use crate::ln::msgs::{self, accountable_from_bool};
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
use crate::ln::onion_utils::{
AttributionData, HTLCFailReason, LocalHTLCFailureReason, HOLD_TIME_UNIT_MILLIS,
Expand Down Expand Up @@ -433,6 +433,7 @@ struct OutboundHTLCOutput {
skimmed_fee_msat: Option<u64>,
send_timestamp: Option<Duration>,
hold_htlc: Option<()>,
accountable: Option<bool>,
}

/// See AwaitingRemoteRevoke ChannelState for more info
Expand All @@ -451,6 +452,7 @@ enum HTLCUpdateAwaitingACK {
skimmed_fee_msat: Option<u64>,
blinding_point: Option<PublicKey>,
hold_htlc: Option<()>,
accountable: Option<bool>,
},
ClaimHTLC {
payment_preimage: PaymentPreimage,
Expand Down Expand Up @@ -8358,7 +8360,7 @@ where
skimmed_fee_msat,
blinding_point,
hold_htlc,
..
accountable,
} => {
match self.send_htlc(
amount_msat,
Expand All @@ -8370,6 +8372,7 @@ where
skimmed_fee_msat,
blinding_point,
hold_htlc.is_some(),
accountable.unwrap_or(false),
fee_estimator,
logger,
) {
Expand Down Expand Up @@ -9688,6 +9691,7 @@ where
skimmed_fee_msat: htlc.skimmed_fee_msat,
blinding_point: htlc.blinding_point,
hold_htlc: htlc.hold_htlc,
accountable: accountable_from_bool(htlc.accountable.unwrap_or(false)),
});
}
}
Expand Down Expand Up @@ -12517,7 +12521,8 @@ where
pub fn queue_add_htlc<F: Deref, L: Deref>(
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32,
source: HTLCSource, onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>,
blinding_point: Option<PublicKey>, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
blinding_point: Option<PublicKey>, accountable: bool,
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
) -> Result<(), (LocalHTLCFailureReason, String)>
where
F::Target: FeeEstimator,
Expand All @@ -12534,6 +12539,7 @@ where
blinding_point,
// This method is only called for forwarded HTLCs, which are never held at the next hop
false,
accountable,
fee_estimator,
logger,
)
Expand Down Expand Up @@ -12565,7 +12571,7 @@ where
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32,
source: HTLCSource, onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool,
skimmed_fee_msat: Option<u64>, blinding_point: Option<PublicKey>, hold_htlc: bool,
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
accountable: bool, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
) -> Result<bool, (LocalHTLCFailureReason, String)>
where
F::Target: FeeEstimator,
Expand Down Expand Up @@ -12647,6 +12653,7 @@ where
skimmed_fee_msat,
blinding_point,
hold_htlc: hold_htlc.then(|| ()),
accountable: Some(accountable),
});
return Ok(false);
}
Expand All @@ -12669,6 +12676,7 @@ where
skimmed_fee_msat,
send_timestamp,
hold_htlc: hold_htlc.then(|| ()),
accountable: Some(accountable),
});
self.context.next_holder_htlc_id += 1;

Expand Down Expand Up @@ -12895,7 +12903,8 @@ where
pub fn send_htlc_and_commit<F: Deref, L: Deref>(
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32,
source: HTLCSource, onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>,
hold_htlc: bool, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
hold_htlc: bool, accountable: bool, fee_estimator: &LowerBoundedFeeEstimator<F>,
logger: &L,
) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
where
F::Target: FeeEstimator,
Expand All @@ -12911,6 +12920,7 @@ where
skimmed_fee_msat,
None,
hold_htlc,
accountable,
fee_estimator,
logger,
);
Expand Down Expand Up @@ -14521,6 +14531,7 @@ where
let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
let mut pending_outbound_blinding_points: Vec<Option<PublicKey>> = Vec::new();
let mut pending_outbound_held_htlc_flags: Vec<Option<()>> = Vec::new();
let mut pending_outbound_accountable: Vec<Option<bool>> = Vec::new();

(self.context.pending_outbound_htlcs.len() as u64).write(writer)?;
for htlc in self.context.pending_outbound_htlcs.iter() {
Expand Down Expand Up @@ -14564,6 +14575,7 @@ where
pending_outbound_skimmed_fees.push(htlc.skimmed_fee_msat);
pending_outbound_blinding_points.push(htlc.blinding_point);
pending_outbound_held_htlc_flags.push(htlc.hold_htlc);
pending_outbound_accountable.push(htlc.accountable);
}

let holding_cell_htlc_update_count = self.context.holding_cell_htlc_updates.len();
Expand All @@ -14575,6 +14587,8 @@ where
Vec::with_capacity(holding_cell_htlc_update_count);
let mut holding_cell_held_htlc_flags: Vec<Option<()>> =
Vec::with_capacity(holding_cell_htlc_update_count);
let mut holding_cell_accountable_flags: Vec<Option<bool>> =
Vec::with_capacity(holding_cell_htlc_update_count);
// Vec of (htlc_id, failure_code, sha256_of_onion)
let mut malformed_htlcs: Vec<(u64, u16, [u8; 32])> = Vec::new();
(holding_cell_htlc_update_count as u64).write(writer)?;
Expand All @@ -14589,6 +14603,7 @@ where
blinding_point,
skimmed_fee_msat,
hold_htlc,
accountable,
} => {
0u8.write(writer)?;
amount_msat.write(writer)?;
Expand All @@ -14600,6 +14615,7 @@ where
holding_cell_skimmed_fees.push(skimmed_fee_msat);
holding_cell_blinding_points.push(blinding_point);
holding_cell_held_htlc_flags.push(hold_htlc);
holding_cell_accountable_flags.push(accountable);
},
&HTLCUpdateAwaitingACK::ClaimHTLC {
ref payment_preimage,
Expand Down Expand Up @@ -14860,6 +14876,8 @@ where
(69, holding_cell_held_htlc_flags, optional_vec), // Added in 0.2
(71, holder_commitment_point_previous_revoked, option), // Added in 0.3
(73, holder_commitment_point_last_revoked, option), // Added in 0.3
(75, holding_cell_accountable_flags, optional_vec), // Added in 0.3
(77, pending_outbound_accountable, optional_vec), // Added in 0.3
});

Ok(())
Expand Down Expand Up @@ -15009,6 +15027,7 @@ where
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});
}

Expand All @@ -15028,6 +15047,7 @@ where
skimmed_fee_msat: None,
blinding_point: None,
hold_htlc: None,
accountable: None,
},
1 => HTLCUpdateAwaitingACK::ClaimHTLC {
payment_preimage: Readable::read(reader)?,
Expand Down Expand Up @@ -15229,6 +15249,8 @@ where

let mut pending_outbound_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
let mut holding_cell_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
let mut pending_outbound_accountable_opt: Option<Vec<Option<bool>>> = None;
let mut holding_cell_accountable_opt: Option<Vec<Option<bool>>> = None;

read_tlv_fields!(reader, {
(0, announcement_sigs, option),
Expand Down Expand Up @@ -15278,6 +15300,8 @@ where
(69, holding_cell_held_htlc_flags_opt, optional_vec), // Added in 0.2
(71, holder_commitment_point_previous_revoked_opt, option), // Added in 0.3
(73, holder_commitment_point_last_revoked_opt, option), // Added in 0.3
(75, holding_cell_accountable_opt, optional_vec), // Added in 0.3
(77, pending_outbound_accountable_opt, optional_vec), // Added in 0.3
});

let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
Expand Down Expand Up @@ -15402,6 +15426,28 @@ where
}
}

if let Some(accountable_htlcs) = holding_cell_accountable_opt {
let mut iter = accountable_htlcs.into_iter();
for htlc in holding_cell_htlc_updates.iter_mut() {
if let HTLCUpdateAwaitingACK::AddHTLC { ref mut accountable, .. } = htlc {
*accountable = iter.next().ok_or(DecodeError::InvalidValue)?;
}
}
// We expect all accountable HTLC signals to be consumed above
if iter.next().is_some() {
return Err(DecodeError::InvalidValue);
}
}
if let Some(held_htlcs) = pending_outbound_accountable_opt {
let mut iter = held_htlcs.into_iter();
for htlc in pending_outbound_htlcs.iter_mut() {
htlc.accountable = iter.next().ok_or(DecodeError::InvalidValue)?;
}
// We expect all accountable HTLC signals to be consumed above
if iter.next().is_some() {
return Err(DecodeError::InvalidValue);
}
}
if let Some(attribution_data_list) = removed_htlc_attribution_data {
let mut removed_htlcs = pending_inbound_htlcs.iter_mut().filter_map(|status| {
if let InboundHTLCState::LocalRemoved(reason) = &mut status.state {
Expand Down Expand Up @@ -16005,6 +16051,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});

// Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
Expand Down Expand Up @@ -16460,6 +16507,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
};
let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
Expand All @@ -16486,6 +16534,7 @@ mod tests {
skimmed_fee_msat: None,
blinding_point: None,
hold_htlc: None,
accountable: None,
};
let dummy_holding_cell_claim_htlc = |attribution_data| HTLCUpdateAwaitingACK::ClaimHTLC {
payment_preimage: PaymentPreimage([42; 32]),
Expand Down Expand Up @@ -16857,6 +16906,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});

let payment_preimage_3 =
Expand All @@ -16872,6 +16922,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});

let payment_preimage_4 =
Expand Down Expand Up @@ -17287,6 +17338,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});

chan.context.pending_outbound_htlcs.push(OutboundHTLCOutput {
Expand All @@ -17300,6 +17352,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
});

test_commitment!("304402207d0870964530f97b62497b11153c551dca0a1e226815ef0a336651158da0f82402200f5378beee0e77759147b8a0a284decd11bfd2bc55c8fafa41c134fe996d43c8",
Expand Down Expand Up @@ -17541,6 +17594,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
}),
);

Expand Down Expand Up @@ -17631,6 +17685,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
}
}),
);
Expand Down Expand Up @@ -17687,6 +17742,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
}),
);

Expand Down Expand Up @@ -17746,6 +17802,7 @@ mod tests {
blinding_point: None,
send_timestamp: None,
hold_htlc: None,
accountable: None,
}),
);

Expand Down
Loading