Merge pull request #2005 from arik-so/2023-01-taproot-message-types

Update messages for Taproot types.
This commit is contained in:
Matt Corallo 2023-04-04 16:38:04 +00:00 committed by GitHub
commit 09f5e50ed2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 192 additions and 9 deletions

View file

@ -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

View file

@ -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

View file

@ -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" }

View file

@ -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)))
}

View file

@ -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() });

View file

@ -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();

View file

@ -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());