mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 15:02:20 +01:00
Merge pull request #2005 from arik-so/2023-01-taproot-message-types
Update messages for Taproot types.
This commit is contained in:
commit
09f5e50ed2
7 changed files with 192 additions and 9 deletions
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
|
@ -180,6 +180,15 @@ jobs:
|
|||
cargo check --no-default-features --features=futures --release
|
||||
cargo doc --release
|
||||
RUSTDOCFLAGS="--cfg=anchors" cargo doc --release
|
||||
- name: Run cargo check for Taproot build.
|
||||
run: |
|
||||
cargo check --release
|
||||
cargo check --no-default-features --features=no-std --release
|
||||
cargo check --no-default-features --features=futures --release
|
||||
cargo doc --release
|
||||
env:
|
||||
RUSTFLAGS: '--cfg=anchors --cfg=taproot'
|
||||
RUSTDOCFLAGS: '--cfg=anchors --cfg=taproot'
|
||||
|
||||
fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -94,4 +94,6 @@ fi
|
|||
echo -e "\n\nTest anchors builds"
|
||||
pushd lightning
|
||||
RUSTFLAGS="$RUSTFLAGS --cfg=anchors" cargo test --verbose --color always -p lightning
|
||||
echo -e "\n\nTest Taproot builds"
|
||||
RUSTFLAGS="$RUSTFLAGS --cfg=anchors --cfg=taproot" cargo test --verbose --color always -p lightning
|
||||
popd
|
||||
|
|
|
@ -56,3 +56,6 @@ regex = "1.5.6"
|
|||
version = "0.29.0"
|
||||
default-features = false
|
||||
features = ["bitcoinconsensus", "secp-recovery"]
|
||||
|
||||
[target.'cfg(taproot)'.dependencies]
|
||||
musig2 = { git = "https://github.com/arik-so/rust-musig2", rev = "27797d7" }
|
||||
|
|
|
@ -2362,7 +2362,9 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
|
||||
Ok((msgs::FundingSigned {
|
||||
channel_id: self.channel_id,
|
||||
signature
|
||||
signature,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
}, channel_monitor))
|
||||
}
|
||||
|
||||
|
@ -3918,6 +3920,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
channel_id: self.channel_id,
|
||||
per_commitment_secret,
|
||||
next_per_commitment_point,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5364,6 +5368,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
None => Builder::new().into_script(),
|
||||
}),
|
||||
channel_type: Some(self.channel_type.clone()),
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5428,7 +5434,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
temporary_channel_id,
|
||||
funding_txid: funding_txo.txid,
|
||||
funding_output_index: funding_txo.index,
|
||||
signature
|
||||
signature,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5947,6 +5957,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
channel_id: self.channel_id,
|
||||
signature,
|
||||
htlc_signatures,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
}, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
|
||||
}
|
||||
|
||||
|
|
|
@ -738,7 +738,9 @@ fn test_update_fee_that_funder_cannot_afford() {
|
|||
let commit_signed_msg = msgs::CommitmentSigned {
|
||||
channel_id: chan.2,
|
||||
signature: res.0,
|
||||
htlc_signatures: res.1
|
||||
htlc_signatures: res.1,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
};
|
||||
|
||||
let update_fee = msgs::UpdateFee {
|
||||
|
@ -1458,7 +1460,9 @@ fn test_fee_spike_violation_fails_htlc() {
|
|||
let commit_signed_msg = msgs::CommitmentSigned {
|
||||
channel_id: chan.2,
|
||||
signature: res.0,
|
||||
htlc_signatures: res.1
|
||||
htlc_signatures: res.1,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
};
|
||||
|
||||
// Send the commitment_signed message to the nodes[1].
|
||||
|
@ -1469,7 +1473,9 @@ fn test_fee_spike_violation_fails_htlc() {
|
|||
let raa_msg = msgs::RevokeAndACK {
|
||||
channel_id: chan.2,
|
||||
per_commitment_secret: local_secret,
|
||||
next_per_commitment_point: next_local_point
|
||||
next_per_commitment_point: next_local_point,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
};
|
||||
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &raa_msg);
|
||||
|
||||
|
@ -7497,7 +7503,13 @@ fn test_counterparty_raa_skip_no_crash() {
|
|||
}
|
||||
|
||||
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(),
|
||||
&msgs::RevokeAndACK { channel_id, per_commitment_secret, next_per_commitment_point });
|
||||
&msgs::RevokeAndACK {
|
||||
channel_id,
|
||||
per_commitment_secret,
|
||||
next_per_commitment_point,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
});
|
||||
assert_eq!(check_closed_broadcast!(nodes[1], true).unwrap().data, "Received an unexpected revoke_and_ack");
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: "Received an unexpected revoke_and_ack".to_string() });
|
||||
|
|
|
@ -51,6 +51,11 @@ use crate::routing::gossip::NodeId;
|
|||
/// 21 million * 10^8 * 1000
|
||||
pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
|
||||
|
||||
#[cfg(taproot)]
|
||||
/// A partial signature that also contains the Musig2 nonce its signer used
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PartialSignatureWithNonce(pub musig2::types::PartialSignature, pub musig2::types::PublicNonce);
|
||||
|
||||
/// An error in decoding a message or struct.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DecodeError {
|
||||
|
@ -244,6 +249,9 @@ pub struct AcceptChannel {
|
|||
/// our feature bits with our counterparty's feature bits from the [`Init`] message.
|
||||
/// This is required to match the equivalent field in [`OpenChannel::channel_type`].
|
||||
pub channel_type: Option<ChannelTypeFeatures>,
|
||||
#[cfg(taproot)]
|
||||
/// Next nonce the channel initiator should use to create a funding output signature against
|
||||
pub next_local_nonce: Option<musig2::types::PublicNonce>,
|
||||
}
|
||||
|
||||
/// A [`funding_created`] message to be sent to or received from a peer.
|
||||
|
@ -259,6 +267,12 @@ pub struct FundingCreated {
|
|||
pub funding_output_index: u16,
|
||||
/// The signature of the channel initiator (funder) on the initial commitment transaction
|
||||
pub signature: Signature,
|
||||
#[cfg(taproot)]
|
||||
/// The partial signature of the channel initiator (funder)
|
||||
pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
|
||||
#[cfg(taproot)]
|
||||
/// Next nonce the channel acceptor should use to finalize the funding output signature
|
||||
pub next_local_nonce: Option<musig2::types::PublicNonce>
|
||||
}
|
||||
|
||||
/// A [`funding_signed`] message to be sent to or received from a peer.
|
||||
|
@ -270,6 +284,9 @@ pub struct FundingSigned {
|
|||
pub channel_id: [u8; 32],
|
||||
/// The signature of the channel acceptor (fundee) on the initial commitment transaction
|
||||
pub signature: Signature,
|
||||
#[cfg(taproot)]
|
||||
/// The partial signature of the channel acceptor (fundee)
|
||||
pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
|
||||
}
|
||||
|
||||
/// A [`channel_ready`] message to be sent to or received from a peer.
|
||||
|
@ -409,6 +426,9 @@ pub struct CommitmentSigned {
|
|||
pub signature: Signature,
|
||||
/// Signatures on the HTLC transactions
|
||||
pub htlc_signatures: Vec<Signature>,
|
||||
#[cfg(taproot)]
|
||||
/// The partial Taproot signature on the commitment transaction
|
||||
pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
|
||||
}
|
||||
|
||||
/// A [`revoke_and_ack`] message to be sent to or received from a peer.
|
||||
|
@ -422,6 +442,9 @@ pub struct RevokeAndACK {
|
|||
pub per_commitment_secret: [u8; 32],
|
||||
/// The next sender-broadcast commitment transaction's per-commitment point
|
||||
pub next_per_commitment_point: PublicKey,
|
||||
#[cfg(taproot)]
|
||||
/// Musig nonce the recipient should use in their next commitment signature message
|
||||
pub next_local_nonce: Option<musig2::types::PublicNonce>
|
||||
}
|
||||
|
||||
/// An [`update_fee`] message to be sent to or received from a peer
|
||||
|
@ -1288,7 +1311,7 @@ impl Readable for OptionalField<u64> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(taproot))]
|
||||
impl_writeable_msg!(AcceptChannel, {
|
||||
temporary_channel_id,
|
||||
dust_limit_satoshis,
|
||||
|
@ -1309,6 +1332,28 @@ impl_writeable_msg!(AcceptChannel, {
|
|||
(1, channel_type, option),
|
||||
});
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl_writeable_msg!(AcceptChannel, {
|
||||
temporary_channel_id,
|
||||
dust_limit_satoshis,
|
||||
max_htlc_value_in_flight_msat,
|
||||
channel_reserve_satoshis,
|
||||
htlc_minimum_msat,
|
||||
minimum_depth,
|
||||
to_self_delay,
|
||||
max_accepted_htlcs,
|
||||
funding_pubkey,
|
||||
revocation_basepoint,
|
||||
payment_point,
|
||||
delayed_payment_basepoint,
|
||||
htlc_basepoint,
|
||||
first_per_commitment_point,
|
||||
shutdown_scriptpubkey
|
||||
}, {
|
||||
(1, channel_type, option),
|
||||
(4, next_local_nonce, option),
|
||||
});
|
||||
|
||||
impl_writeable_msg!(AnnouncementSignatures, {
|
||||
channel_id,
|
||||
short_channel_id,
|
||||
|
@ -1363,30 +1408,60 @@ impl_writeable!(ClosingSignedFeeRange, {
|
|||
max_fee_satoshis
|
||||
});
|
||||
|
||||
#[cfg(not(taproot))]
|
||||
impl_writeable_msg!(CommitmentSigned, {
|
||||
channel_id,
|
||||
signature,
|
||||
htlc_signatures
|
||||
}, {});
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl_writeable_msg!(CommitmentSigned, {
|
||||
channel_id,
|
||||
signature,
|
||||
htlc_signatures
|
||||
}, {
|
||||
(2, partial_signature_with_nonce, option)
|
||||
});
|
||||
|
||||
impl_writeable!(DecodedOnionErrorPacket, {
|
||||
hmac,
|
||||
failuremsg,
|
||||
pad
|
||||
});
|
||||
|
||||
#[cfg(not(taproot))]
|
||||
impl_writeable_msg!(FundingCreated, {
|
||||
temporary_channel_id,
|
||||
funding_txid,
|
||||
funding_output_index,
|
||||
signature
|
||||
}, {});
|
||||
#[cfg(taproot)]
|
||||
impl_writeable_msg!(FundingCreated, {
|
||||
temporary_channel_id,
|
||||
funding_txid,
|
||||
funding_output_index,
|
||||
signature
|
||||
}, {
|
||||
(2, partial_signature_with_nonce, option),
|
||||
(4, next_local_nonce, option)
|
||||
});
|
||||
|
||||
#[cfg(not(taproot))]
|
||||
impl_writeable_msg!(FundingSigned, {
|
||||
channel_id,
|
||||
signature
|
||||
}, {});
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl_writeable_msg!(FundingSigned, {
|
||||
channel_id,
|
||||
signature
|
||||
}, {
|
||||
(2, partial_signature_with_nonce, option)
|
||||
});
|
||||
|
||||
impl_writeable_msg!(ChannelReady, {
|
||||
channel_id,
|
||||
next_per_commitment_point,
|
||||
|
@ -1446,12 +1521,22 @@ impl_writeable_msg!(OpenChannel, {
|
|||
(1, channel_type, option),
|
||||
});
|
||||
|
||||
#[cfg(not(taproot))]
|
||||
impl_writeable_msg!(RevokeAndACK, {
|
||||
channel_id,
|
||||
per_commitment_secret,
|
||||
next_per_commitment_point
|
||||
}, {});
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl_writeable_msg!(RevokeAndACK, {
|
||||
channel_id,
|
||||
per_commitment_secret,
|
||||
next_per_commitment_point
|
||||
}, {
|
||||
(4, next_local_nonce, option)
|
||||
});
|
||||
|
||||
impl_writeable_msg!(Shutdown, {
|
||||
channel_id,
|
||||
scriptpubkey
|
||||
|
@ -2444,6 +2529,8 @@ mod tests {
|
|||
first_per_commitment_point: pubkey_6,
|
||||
shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
|
||||
channel_type: None,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
};
|
||||
let encoded_value = accept_channel.encode();
|
||||
let mut target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020212345678901234562334032891223698321446687011447600083a840000034d000c89d4c0bcc0bc031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076602531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe33703462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f703f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap();
|
||||
|
@ -2469,6 +2556,10 @@ mod tests {
|
|||
funding_txid: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
|
||||
funding_output_index: 255,
|
||||
signature: sig_1,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
};
|
||||
let encoded_value = funding_created.encode();
|
||||
let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202026e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c200ffd977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
|
||||
|
@ -2483,6 +2574,8 @@ mod tests {
|
|||
let funding_signed = msgs::FundingSigned {
|
||||
channel_id: [2; 32],
|
||||
signature: sig_1,
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
};
|
||||
let encoded_value = funding_signed.encode();
|
||||
let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
|
||||
|
@ -2646,6 +2739,8 @@ mod tests {
|
|||
channel_id: [2; 32],
|
||||
signature: sig_1,
|
||||
htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
|
||||
#[cfg(taproot)]
|
||||
partial_signature_with_nonce: None,
|
||||
};
|
||||
let encoded_value = commitment_signed.encode();
|
||||
let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
|
||||
|
@ -2671,6 +2766,8 @@ mod tests {
|
|||
channel_id: [2; 32],
|
||||
per_commitment_secret: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
next_per_commitment_point: pubkey_1,
|
||||
#[cfg(taproot)]
|
||||
next_local_nonce: None,
|
||||
};
|
||||
let encoded_value = raa.encode();
|
||||
let target_value = hex::decode("02020202020202020202020202020202020202020202020202020202020202020101010101010101010101010101010101010101010101010101010101010101031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap();
|
||||
|
|
|
@ -38,6 +38,8 @@ use bitcoin::hash_types::{Txid, BlockHash};
|
|||
use core::marker::Sized;
|
||||
use core::time::Duration;
|
||||
use crate::ln::msgs::DecodeError;
|
||||
#[cfg(taproot)]
|
||||
use crate::ln::msgs::PartialSignatureWithNonce;
|
||||
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
|
||||
|
||||
use crate::util::byte_utils::{be48_to_array, slice_to_be48};
|
||||
|
@ -574,6 +576,7 @@ impl_array!(16); // for IPv6
|
|||
impl_array!(32); // for channel id & hmac
|
||||
impl_array!(PUBLIC_KEY_SIZE); // for PublicKey
|
||||
impl_array!(64); // for ecdsa::Signature and schnorr::Signature
|
||||
impl_array!(66); // for MuSig2 nonces
|
||||
impl_array!(1300); // for OnionPacket.hop_data
|
||||
|
||||
impl Writeable for [u16; 8] {
|
||||
|
@ -861,6 +864,39 @@ impl Readable for SecretKey {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl Writeable for musig2::types::PublicNonce {
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
||||
self.serialize().write(w)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl Readable for musig2::types::PublicNonce {
|
||||
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
|
||||
let buf: [u8; PUBLIC_KEY_SIZE * 2] = Readable::read(r)?;
|
||||
musig2::types::PublicNonce::from_slice(&buf).map_err(|_| DecodeError::InvalidValue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl Writeable for PartialSignatureWithNonce {
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
||||
self.0.serialize().write(w)?;
|
||||
self.1.write(w)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(taproot)]
|
||||
impl Readable for PartialSignatureWithNonce {
|
||||
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
|
||||
let partial_signature_buf: [u8; SECRET_KEY_SIZE] = Readable::read(r)?;
|
||||
let partial_signature = musig2::types::PartialSignature::from_slice(&partial_signature_buf).map_err(|_| DecodeError::InvalidValue)?;
|
||||
let public_nonce: musig2::types::PublicNonce = Readable::read(r)?;
|
||||
Ok(PartialSignatureWithNonce(partial_signature, public_nonce))
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for Sha256dHash {
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
|
||||
w.write_all(&self[..])
|
||||
|
@ -1251,6 +1287,7 @@ impl Readable for Duration {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::convert::TryFrom;
|
||||
use bitcoin::secp256k1::ecdsa;
|
||||
use crate::util::ser::{Readable, Hostname, Writeable};
|
||||
|
||||
#[test]
|
||||
|
@ -1273,11 +1310,22 @@ mod tests {
|
|||
assert_eq!(Hostname::read(&mut buf.as_slice()).unwrap().as_str(), "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Taproot will likely fill legacy signature fields with all 0s.
|
||||
/// This test ensures that doing so won't break serialization.
|
||||
fn null_signature_codec() {
|
||||
let buffer = vec![0u8; 64];
|
||||
let mut cursor = crate::io::Cursor::new(buffer.clone());
|
||||
let signature = ecdsa::Signature::read(&mut cursor).unwrap();
|
||||
let serialization = signature.serialize_compact();
|
||||
assert_eq!(buffer, serialization.to_vec())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bigsize_encoding_decoding() {
|
||||
let values = vec![0, 252, 253, 65535, 65536, 4294967295, 4294967296, 18446744073709551615];
|
||||
let bytes = vec![
|
||||
"00",
|
||||
"00",
|
||||
"fc",
|
||||
"fd00fd",
|
||||
"fdffff",
|
||||
|
@ -1286,7 +1334,7 @@ mod tests {
|
|||
"ff0000000100000000",
|
||||
"ffffffffffffffffff"
|
||||
];
|
||||
for i in 0..=7 {
|
||||
for i in 0..=7 {
|
||||
let mut stream = crate::io::Cursor::new(::hex::decode(bytes[i]).unwrap());
|
||||
assert_eq!(super::BigSize::read(&mut stream).unwrap().0, values[i]);
|
||||
let mut stream = super::VecWriter(Vec::new());
|
||||
|
|
Loading…
Add table
Reference in a new issue