Skip to content

fix: replace secp placeholders when merging funding witnesses - #1715

Merged
quake merged 1 commit into
nervosnetwork:developfrom
LusoCryptoLabs:placeholder-witness
Oct 29, 2026
Merged

quake merged 1 commit into
nervosnetwork:developfrom
LusoCryptoLabs:placeholder-witness

Conversation

@LusoCryptoLabs

Copy link
Copy Markdown
Contributor

merge_external_funding_witnesses is meant to fill our empty or placeholder witnesses from the peer's TxSignatures. is_empty_or_placeholder_witness passes witness.as_slice() to is_secp_sighash_placeholder_witness, which expects the raw witness. as_slice() of a packed::Bytes carries molecule's 4-byte length header, so the zero-signature WitnessArgs the funding builder writes for the peer's secp256k1 inputs is never taken for a placeholder. The initiator keeps the zeros instead of the peer's signature, and its copy of the funding tx fails with -302 TransactionFailedToVerify (secp256k1 lock, error -11). The acceptor's copy is complete and gets the channel open.

  • is_empty_or_placeholder_witness checks witness.raw_data().

This is also what #1713 needs to help in practice: with secp256k1 inputs on the acceptor's side, the merged set it replies with still holds the placeholder until this is fixed.

Seen on our testnet LSP (a fork with #1623; this code is the same on develop): openings sent a copy of the funding tx that failed with -302 at the LSP's input, the same size as the copy that was committed. Reproduced on a dev chain through a proxy that keeps every send_transaction: before the change, the initiator's copy of each opening had a zero signature at the acceptor's input, in both signing orders; after it, every copy was fully signed. With the change on our testnet LSP, the next four openings (two from secp256k1 keys, two from passkey wallets, one of them in a UDT, in both signing orders) sent no copy that failed; with the binary before it, each of the five openings that day did.

Checked on this branch:

  • test_external_funding_witness_merge_replaces_secp_placeholders: a local placeholder takes the peer's signature, and a peer's placeholder does not replace ours. It fails on develop.
  • the other external funding tests
  • cargo fmt, typos, cargo shear, make clippy
  • cargo test -p fnn --features rocksdb: all pass except fiber::tests::mpp::test_mpp_waiting_ack_settlement_hands_off_to_durable_retry_queue, which fails on develop too

@quake
quake merged commit 11846d6 into nervosnetwork:develop Oct 29, 2026
47 checks passed
LusoCryptoLabs added a commit to LusoCryptoLabs/ckb-script-pitfalls that referenced this pull request Oct 29, 2026
as_slice() of a Bytes field carries the four length bytes, so it never equals the content. Seen in nervosnetwork/fiber#1715. Host test with a control.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants