Skip to content

Commit 1986689

Browse files
committed
Fix Error about CI (e2e)
1 parent e8981f4 commit 1986689

File tree

4 files changed

+176
-35
lines changed

4 files changed

+176
-35
lines changed

crates/fiber-lib/src/ckb/funding/funding_tx.rs

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ struct ExtraCellDepResolver<'a> {
122122
impl CellDepResolver for ExtraCellDepResolver<'_> {
123123
fn resolve(&self, script: &Script) -> Option<packed::CellDep> {
124124
if script == self.funding_source_lock_script {
125-
return self.funding_source_extra_cell_deps.first().cloned();
125+
if let Some(cell_dep) = self.funding_source_extra_cell_deps.first() {
126+
return Some(cell_dep.clone());
127+
}
126128
}
127129
self.default.resolve(script)
128130
}
@@ -604,16 +606,14 @@ impl ExternalFundingTxBuilder {
604606
fn build_funding_cell(&self) -> Result<(packed::CellOutput, packed::Bytes), FundingError> {
605607
match self.request.udt_type_script {
606608
Some(ref udt_type_script) => {
607-
let udt_amount = self
608-
.request
609-
.local_amount
610-
.checked_add(self.request.remote_amount)
611-
.ok_or(FundingError::OverflowError)?;
612-
let ckb_amount = self
613-
.request
614-
.local_reserved_ckb_amount
615-
.checked_add(self.request.remote_reserved_ckb_amount)
616-
.ok_or(FundingError::OverflowError)?;
609+
if self.request.remote_amount > 0 || self.request.remote_reserved_ckb_amount > 0 {
610+
debug!(
611+
"Ignoring remote initial funding in external funding tx builder: remote_amount={}, remote_reserved_ckb_amount={}",
612+
self.request.remote_amount, self.request.remote_reserved_ckb_amount
613+
);
614+
}
615+
let udt_amount = self.request.local_amount;
616+
let ckb_amount = self.request.local_reserved_ckb_amount;
617617

618618
let udt_output = packed::CellOutput::new_builder()
619619
.capacity(Capacity::shannons(ckb_amount).pack())
@@ -627,14 +627,24 @@ impl ExternalFundingTxBuilder {
627627
Ok((udt_output, data.freeze().pack()))
628628
}
629629
None => {
630+
if self.request.remote_amount > 0 || self.request.remote_reserved_ckb_amount > 0 {
631+
debug!(
632+
"Ignoring remote initial funding in external funding tx builder: remote_amount={}, remote_reserved_ckb_amount={}",
633+
self.request.remote_amount, self.request.remote_reserved_ckb_amount
634+
);
635+
}
630636
let local_amount = u64::try_from(self.request.local_amount)
631637
.map_err(|_| FundingError::OverflowError)?;
632638
let remote_amount = u64::try_from(self.request.remote_amount)
633639
.map_err(|_| FundingError::OverflowError)?;
640+
if remote_amount > 0 {
641+
debug!(
642+
"Ignoring remote CKB amount in external funding tx builder after cast: {}",
643+
remote_amount
644+
);
645+
}
634646
let ckb_amount = local_amount
635647
.checked_add(self.request.local_reserved_ckb_amount)
636-
.and_then(|amount| amount.checked_add(remote_amount))
637-
.and_then(|amount| amount.checked_add(self.request.remote_reserved_ckb_amount))
638648
.ok_or(FundingError::OverflowError)?;
639649
let ckb_output = packed::CellOutput::new_builder()
640650
.capacity(Capacity::shannons(ckb_amount).pack())
@@ -949,6 +959,19 @@ impl FundingTx {
949959
#[cfg(test)]
950960
mod tests {
951961
use super::*;
962+
use std::sync::atomic::{AtomicUsize, Ordering};
963+
964+
struct StubCellDepResolver {
965+
resolved: packed::CellDep,
966+
call_count: AtomicUsize,
967+
}
968+
969+
impl CellDepResolver for StubCellDepResolver {
970+
fn resolve(&self, _script: &Script) -> Option<packed::CellDep> {
971+
self.call_count.fetch_add(1, Ordering::Relaxed);
972+
Some(self.resolved.clone())
973+
}
974+
}
952975

953976
/// Build a dummy ExternalFundingContext for unit tests.
954977
fn dummy_external_context() -> ExternalFundingContext {
@@ -961,6 +984,28 @@ mod tests {
961984
}
962985
}
963986

987+
#[test]
988+
fn test_extra_cell_dep_resolver_falls_back_when_no_extra_dep() {
989+
let fallback_cell_dep = packed::CellDep::default();
990+
let default_resolver = StubCellDepResolver {
991+
resolved: fallback_cell_dep.clone(),
992+
call_count: AtomicUsize::new(0),
993+
};
994+
let funding_source_lock_script = Script::default();
995+
let resolver = ExtraCellDepResolver {
996+
default: &default_resolver,
997+
funding_source_lock_script: &funding_source_lock_script,
998+
funding_source_extra_cell_deps: &[],
999+
};
1000+
1001+
let resolved = resolver
1002+
.resolve(&funding_source_lock_script)
1003+
.expect("fallback cell dep should resolve");
1004+
1005+
assert_eq!(resolved, fallback_cell_dep);
1006+
assert_eq!(default_resolver.call_count.load(Ordering::Relaxed), 1);
1007+
}
1008+
9641009
#[test]
9651010
fn test_external_funding_build_ckb_funding_cell() {
9661011
let context = dummy_external_context();
@@ -982,11 +1027,9 @@ mod tests {
9821027

9831028
let (output, data) = builder.build_funding_cell().expect("build funding cell");
9841029

985-
// For CKB channels: capacity = local_amount + remote_amount + local_reserved + remote_reserved
986-
let expected_capacity: u64 = request.local_amount as u64
987-
+ request.remote_amount as u64
988-
+ request.local_reserved_ckb_amount
989-
+ request.remote_reserved_ckb_amount;
1030+
// For external CKB channels: capacity = local_amount + local_reserved.
1031+
let expected_capacity: u64 =
1032+
request.local_amount as u64 + request.local_reserved_ckb_amount;
9901033
let actual_capacity: u64 = output.capacity().unpack();
9911034
assert_eq!(actual_capacity, expected_capacity);
9921035

@@ -1026,9 +1069,8 @@ mod tests {
10261069

10271070
let (output, data) = builder.build_funding_cell().expect("build funding cell");
10281071

1029-
// For UDT channels: capacity = local_reserved + remote_reserved
1030-
let expected_capacity =
1031-
request.local_reserved_ckb_amount + request.remote_reserved_ckb_amount;
1072+
// For external UDT channels: capacity = local_reserved only.
1073+
let expected_capacity = request.local_reserved_ckb_amount;
10321074
let actual_capacity: u64 = output.capacity().unpack();
10331075
assert_eq!(actual_capacity, expected_capacity);
10341076

@@ -1041,8 +1083,8 @@ mod tests {
10411083
udt_type_script
10421084
);
10431085

1044-
// Data should contain the total UDT amount (16 bytes, little-endian)
1045-
let expected_udt_amount: u128 = request.local_amount + request.remote_amount;
1086+
// Data should contain only the local UDT amount (16 bytes, little-endian).
1087+
let expected_udt_amount: u128 = request.local_amount;
10461088
let data_bytes = data.raw_data();
10471089
assert_eq!(data_bytes.len(), 16);
10481090
let mut amount_bytes = [0u8; 16];
@@ -1067,7 +1109,7 @@ mod tests {
10671109

10681110
let builder = ExternalFundingTxBuilder {
10691111
funding_tx: FundingTx::new(),
1070-
request,
1112+
request: request.clone(),
10711113
context,
10721114
};
10731115

@@ -1080,14 +1122,13 @@ mod tests {
10801122
}
10811123

10821124
#[test]
1083-
fn test_external_funding_build_udt_funding_cell_overflow() {
1125+
fn test_external_funding_build_udt_funding_cell_ignores_remote_amount() {
10841126
let context = dummy_external_context();
10851127
let udt_type_script = Script::new_builder()
10861128
.code_hash(packed::Byte32::from_slice(&[1u8; 32]).unwrap())
10871129
.hash_type(packed::Byte::new(0))
10881130
.build();
10891131

1090-
// UDT amounts that overflow u128
10911132
let request = FundingRequest {
10921133
script: Script::default(),
10931134
udt_type_script: Some(udt_type_script),
@@ -1100,16 +1141,20 @@ mod tests {
11001141

11011142
let builder = ExternalFundingTxBuilder {
11021143
funding_tx: FundingTx::new(),
1103-
request,
1144+
request: request.clone(),
11041145
context,
11051146
};
11061147

1107-
let result = builder.build_funding_cell();
1108-
assert!(result.is_err(), "should overflow");
1109-
match result {
1110-
Err(FundingError::OverflowError) => {} // expected
1111-
other => panic!("expected OverflowError, got {:?}", other),
1112-
}
1148+
let (output, data) = builder.build_funding_cell().expect("build funding cell");
1149+
1150+
let actual_capacity: u64 = output.capacity().unpack();
1151+
assert_eq!(actual_capacity, request.local_reserved_ckb_amount);
1152+
1153+
let data_bytes = data.raw_data();
1154+
assert_eq!(data_bytes.len(), 16);
1155+
let mut amount_bytes = [0u8; 16];
1156+
amount_bytes.copy_from_slice(&data_bytes[..16]);
1157+
assert_eq!(u128::from_le_bytes(amount_bytes), request.local_amount);
11131158
}
11141159

11151160
#[test]

crates/fiber-lib/src/fiber/channel.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5470,6 +5470,16 @@ impl ChannelActorState {
54705470
}
54715471
}
54725472

5473+
if self.ephemeral_config.external_funding.enabled {
5474+
if self.to_remote_amount > 0 || self.remote_reserved_ckb_amount > 0 {
5475+
return Err(ProcessingChannelError::InvalidParameter(format!(
5476+
"External funding requires zero remote initial funding, got remote_amount={} remote_reserved_ckb_amount={}",
5477+
self.to_remote_amount, self.remote_reserved_ckb_amount
5478+
)));
5479+
}
5480+
return Ok(());
5481+
}
5482+
54735483
// reserved_ckb_amount
54745484
let occupied_capacity =
54755485
occupied_capacity(&self.get_remote_shutdown_script(), udt_type_script)?.as_u64();
@@ -6825,6 +6835,18 @@ impl ChannelActorState {
68256835

68266836
self.to_remote_amount = accept_channel.funding_amount;
68276837
self.remote_reserved_ckb_amount = accept_channel.reserved_ckb_amount;
6838+
if self.ephemeral_config.external_funding.enabled {
6839+
if accept_channel.funding_amount > 0 || accept_channel.reserved_ckb_amount > 0 {
6840+
warn!(
6841+
"Normalizing acceptor initial funding to zero for external funding channel {:?}: remote_amount={}, remote_reserved_ckb_amount={}",
6842+
self.get_id(),
6843+
accept_channel.funding_amount,
6844+
accept_channel.reserved_ckb_amount
6845+
);
6846+
}
6847+
self.to_remote_amount = 0;
6848+
self.remote_reserved_ckb_amount = 0;
6849+
}
68286850

68296851
self.commit_remote_nonce(accept_channel.next_commitment_nonce.clone());
68306852
self.remote_revocation_nonce_for_send = Some(accept_channel.next_revocation_nonce.clone());
@@ -6927,6 +6949,7 @@ impl ChannelActorState {
69276949
};
69286950
match msg {
69296951
TxCollaborationMsg::TxUpdate(msg) => {
6952+
self.maybe_adapt_acceptor_to_remote_only_funding(&msg.tx)?;
69306953
if self.ephemeral_config.external_funding.enabled
69316954
&& self.ephemeral_config.external_funding.signed_submitted
69326955
{
@@ -7021,6 +7044,68 @@ impl ChannelActorState {
70217044
Ok(())
70227045
}
70237046

7047+
fn maybe_adapt_acceptor_to_remote_only_funding(
7048+
&mut self,
7049+
tx: &Transaction,
7050+
) -> Result<(), ProcessingChannelError> {
7051+
let placeholder_witness = packed::WitnessArgs::new_builder()
7052+
.lock(Some(molecule::bytes::Bytes::from(vec![0u8; 170])).pack())
7053+
.build()
7054+
.as_bytes()
7055+
.to_vec();
7056+
let has_non_placeholder_witness = tx.witnesses().into_iter().any(|witness| {
7057+
let witness: Vec<u8> = witness.unpack();
7058+
witness != placeholder_witness
7059+
});
7060+
if !self.is_acceptor
7061+
|| !has_non_placeholder_witness
7062+
|| self.funding_tx.is_some()
7063+
|| (self.to_local_amount == 0 && self.local_reserved_ckb_amount == 0)
7064+
{
7065+
return Ok(());
7066+
}
7067+
7068+
let tx = tx.clone().into_view();
7069+
let first_output = match tx.outputs().get(0) {
7070+
Some(output) => output,
7071+
None => return Ok(()),
7072+
};
7073+
7074+
if first_output.lock() != self.get_funding_lock_script() {
7075+
return Ok(());
7076+
}
7077+
7078+
let current_capacity: u64 = first_output.capacity().unpack();
7079+
let is_remote_only_funding = if self.funding_udt_type_script.is_some() {
7080+
let Some((_output, data)) = tx.output_with_data(0) else {
7081+
return Ok(());
7082+
};
7083+
if data.as_ref().len() < 16 {
7084+
return Ok(());
7085+
}
7086+
let mut amount_bytes = [0u8; 16];
7087+
amount_bytes.copy_from_slice(&data.as_ref()[0..16]);
7088+
let udt_amount = u128::from_le_bytes(amount_bytes);
7089+
current_capacity == self.remote_reserved_ckb_amount
7090+
&& udt_amount == self.to_remote_amount
7091+
} else {
7092+
current_capacity == self.to_remote_amount as u64 + self.remote_reserved_ckb_amount
7093+
};
7094+
7095+
if is_remote_only_funding {
7096+
warn!(
7097+
"Adapting acceptor channel {:?} to remote-only funding after receiving a fully signed external funding tx: local_amount={}, local_reserved_ckb_amount={}",
7098+
self.get_id(),
7099+
self.to_local_amount,
7100+
self.local_reserved_ckb_amount
7101+
);
7102+
self.to_local_amount = 0;
7103+
self.local_reserved_ckb_amount = 0;
7104+
}
7105+
7106+
Ok(())
7107+
}
7108+
70247109
fn verify_commitment_signed_and_send_ack(
70257110
&mut self,
70267111
commitment_signed: CommitmentSigned,

crates/fiber-lib/src/fiber/network.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,15 +1168,22 @@ where
11681168
});
11691169

11701170
if let Some(reply) = reply {
1171+
if remote_funding_amount > 0 || remote_reserved_ckb_amount > 0 {
1172+
debug!(
1173+
"Ignoring remote initial funding for external funding channel {:?}: remote_amount={}, remote_reserved_ckb_amount={}",
1174+
new_channel_id, remote_funding_amount, remote_reserved_ckb_amount
1175+
);
1176+
}
1177+
11711178
// Build the unsigned funding transaction
11721179
let request = FundingRequest {
11731180
script: funding_source_lock_script.clone(),
11741181
udt_type_script: funding_udt_type_script,
11751182
local_amount: funding_amount,
1176-
remote_amount: remote_funding_amount,
1183+
remote_amount: 0,
11771184
funding_fee_rate,
11781185
local_reserved_ckb_amount,
1179-
remote_reserved_ckb_amount,
1186+
remote_reserved_ckb_amount: 0,
11801187
};
11811188

11821189
let funding_tx = FundingTx::new();

tests/bruno/e2e/external-funding-open/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export REMOVE_OLD_STATE=y
99

1010
This test validates a success-only scenario:
1111

12+
- `open_channel_with_external_funding` is single-sided initial funding:
13+
- the external signer pays only the initiator's channel balance, reserve, and tx fee;
14+
- the peer starts with no initial funded reserve.
15+
1216
- Get node1/node2/node3 CKB balances before open.
1317
- Node1 opens an external-funded channel to node3 via:
1418
- `open_channel_with_external_funding`

0 commit comments

Comments
 (0)