Skip to content
Draft
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
1 change: 1 addition & 0 deletions smite-ir/src/mutators/operation_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ fn mutate_operation(op: &mut Operation, rng: &mut impl Rng) -> bool {
| Operation::RecvAcceptChannel
| Operation::RecvFundingSigned
| Operation::RecvChannelReady
| Operation::RecvShutdown
| Operation::BroadcastTransaction
| Operation::LookupShortChannelId => {
unreachable!("is_param_mutable returned true for {op:?}")
Expand Down
133 changes: 89 additions & 44 deletions smite-ir/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::fmt::Write;
use bitcoin::{opcodes::all as opcodes, script::Builder, script::PushBytes};
use rand::{Rng, RngExt};
use serde::{Deserialize, Serialize};
use smite::bolt::ShortChannelId;
use smite::bolt::{FeatureBit, Features, ShortChannelId};

use super::VariableType;

Expand Down Expand Up @@ -228,6 +228,8 @@ pub enum Operation {
/// point unknown) and its funding transaction has enough confirmations for
/// the target to have sent `channel_ready`.
RecvChannelReady,
/// Receive and parse a `shutdown` message.
RecvShutdown,
/// Mines the given number of blocks on the Bitcoin network.
MineBlocks(u8),
/// Sign wallet inputs of the transaction and broadcast it via `bitcoin-cli`.
Expand Down Expand Up @@ -520,56 +522,93 @@ impl ChannelTypeVariant {

/// The feature bits (even/required) contained in this channel type.
#[must_use]
pub fn bits(self) -> &'static [usize] {
// BOLT 9 feature bits:
// 12 = option_static_remotekey
// 22 = option_anchors
// 40 = zero_fee_commitments
// 46 = option_scid_alias
// 50 = option_zeroconf
// 80 = option_simple_taproot
// 180 = option_simple_taproot_staging
// 2022 = option_script_enforced_lease
pub fn bits(self) -> &'static [FeatureBit] {
use Features as F;
match self {
Self::StaticRemoteKey => &[12],
Self::StaticRemoteKeyScidAlias => &[12, 46],
Self::StaticRemoteKeyZeroConf => &[12, 50],
Self::StaticRemoteKeyScidAliasZeroConf => &[12, 46, 50],
Self::Anchors => &[12, 22],
Self::AnchorsScidAlias => &[12, 22, 46],
Self::AnchorsZeroConf => &[12, 22, 50],
Self::AnchorsScidAliasZeroConf => &[12, 22, 46, 50],
Self::ZeroFeeCommitments => &[40],
Self::ZeroFeeCommitmentsScidAlias => &[40, 46],
Self::ZeroFeeCommitmentsZeroConf => &[40, 50],
Self::ZeroFeeCommitmentsScidAliasZeroConf => &[40, 46, 50],
Self::SimpleTaproot => &[80],
Self::SimpleTaprootScidAlias => &[80, 46],
Self::SimpleTaprootZeroConf => &[80, 50],
Self::SimpleTaprootScidAliasZeroConf => &[80, 46, 50],
Self::SimpleTaprootStaging => &[180],
Self::SimpleTaprootStagingScidAlias => &[180, 46],
Self::SimpleTaprootStagingZeroConf => &[180, 50],
Self::SimpleTaprootStagingScidAliasZeroConf => &[180, 46, 50],
Self::ScriptEnforcedLease => &[12, 22, 2022],
Self::ScriptEnforcedLeaseScidAlias => &[12, 22, 2022, 46],
Self::ScriptEnforcedLeaseZeroConf => &[12, 22, 2022, 50],
Self::ScriptEnforcedLeaseScidAliasZeroConf => &[12, 22, 2022, 46, 50],
Self::StaticRemoteKey => &[F::OPTION_STATIC_REMOTEKEY],
Self::StaticRemoteKeyScidAlias => &[F::OPTION_STATIC_REMOTEKEY, F::OPTION_SCID_ALIAS],
Self::StaticRemoteKeyZeroConf => &[F::OPTION_STATIC_REMOTEKEY, F::OPTION_ZEROCONF],
Self::StaticRemoteKeyScidAliasZeroConf => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
Self::Anchors => &[F::OPTION_STATIC_REMOTEKEY, F::OPTION_ANCHORS],
Self::AnchorsScidAlias => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCID_ALIAS,
],
Self::AnchorsZeroConf => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_ZEROCONF,
],
Self::AnchorsScidAliasZeroConf => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
Self::ZeroFeeCommitments => &[F::ZERO_FEE_COMMITMENTS],
Self::ZeroFeeCommitmentsScidAlias => &[F::ZERO_FEE_COMMITMENTS, F::OPTION_SCID_ALIAS],
Self::ZeroFeeCommitmentsZeroConf => &[F::ZERO_FEE_COMMITMENTS, F::OPTION_ZEROCONF],
Self::ZeroFeeCommitmentsScidAliasZeroConf => &[
F::ZERO_FEE_COMMITMENTS,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
Self::SimpleTaproot => &[F::OPTION_SIMPLE_TAPROOT],
Self::SimpleTaprootScidAlias => &[F::OPTION_SIMPLE_TAPROOT, F::OPTION_SCID_ALIAS],
Self::SimpleTaprootZeroConf => &[F::OPTION_SIMPLE_TAPROOT, F::OPTION_ZEROCONF],
Self::SimpleTaprootScidAliasZeroConf => &[
F::OPTION_SIMPLE_TAPROOT,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
Self::SimpleTaprootStaging => &[F::OPTION_SIMPLE_TAPROOT_STAGING],
Self::SimpleTaprootStagingScidAlias => {
&[F::OPTION_SIMPLE_TAPROOT_STAGING, F::OPTION_SCID_ALIAS]
}
Self::SimpleTaprootStagingZeroConf => {
&[F::OPTION_SIMPLE_TAPROOT_STAGING, F::OPTION_ZEROCONF]
}
Self::SimpleTaprootStagingScidAliasZeroConf => &[
F::OPTION_SIMPLE_TAPROOT_STAGING,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
Self::ScriptEnforcedLease => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCRIPT_ENFORCED_LEASE,
],
Self::ScriptEnforcedLeaseScidAlias => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCRIPT_ENFORCED_LEASE,
F::OPTION_SCID_ALIAS,
],
Self::ScriptEnforcedLeaseZeroConf => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCRIPT_ENFORCED_LEASE,
F::OPTION_ZEROCONF,
],
Self::ScriptEnforcedLeaseScidAliasZeroConf => &[
F::OPTION_STATIC_REMOTEKEY,
F::OPTION_ANCHORS,
F::OPTION_SCRIPT_ENFORCED_LEASE,
F::OPTION_SCID_ALIAS,
F::OPTION_ZEROCONF,
],
}
}

/// Encodes the channel type as a BOLT feature bitmap (big-endian bytes).
#[must_use]
#[allow(clippy::missing_panics_doc)] // bits() is always non-empty
pub fn encode(self) -> Vec<u8> {
let bits = self.bits();
let max_bit = *bits.iter().max().expect("non-empty bits");
let num_bytes = max_bit / 8 + 1;
let mut out = vec![0u8; num_bytes];
for &bit in bits {
out[num_bytes - 1 - bit / 8] |= 1 << (bit % 8);
}
out
Features::from_bits(self.bits()).into_bytes()
}
}

Expand Down Expand Up @@ -713,6 +752,7 @@ impl fmt::Display for Operation {
Self::RecvAcceptChannel => write!(f, "RecvAcceptChannel"),
Self::RecvFundingSigned => write!(f, "RecvFundingSigned"),
Self::RecvChannelReady => write!(f, "RecvChannelReady()"),
Self::RecvShutdown => write!(f, "RecvShutdown"),
Self::BroadcastTransaction => write!(f, "BroadcastTransaction"),
Self::LookupShortChannelId => write!(f, "LookupShortChannelId"),
}
Expand Down Expand Up @@ -751,6 +791,7 @@ impl Operation {
Self::SendMessage
| Self::SendChannelReady { .. }
| Self::RecvChannelReady
| Self::RecvShutdown

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should output the spk so it can be used in subsequent channel closing messages, otherwise, we will always be rejected in those cases later

| Self::MineBlocks(_)
| Self::BroadcastTransaction => None,
Self::SendOpenChannel => Some(VariableType::SentOpenChannel),
Expand Down Expand Up @@ -810,6 +851,7 @@ impl Operation {
],
Self::RecvAcceptChannel => vec![VariableType::SentOpenChannel],
Self::RecvFundingSigned => vec![VariableType::SentFundingCreated],
Self::RecvShutdown => vec![VariableType::SentShutdown],
Self::BroadcastTransaction | Self::LookupShortChannelId => {
vec![VariableType::FundingTransaction]
}
Expand Down Expand Up @@ -920,6 +962,7 @@ impl Operation {
| Self::SendShutdown
| Self::RecvFundingSigned
| Self::RecvChannelReady
| Self::RecvShutdown
| Self::MineBlocks(_)
| Self::BroadcastTransaction
| Self::LookupShortChannelId => vec![],
Expand All @@ -944,6 +987,7 @@ impl Operation {
| Self::RecvAcceptChannel
| Self::RecvFundingSigned
| Self::RecvChannelReady
| Self::RecvShutdown
| Self::MineBlocks(_)
| Self::CreateFundingTransaction
| Self::BroadcastTransaction
Expand Down Expand Up @@ -1013,6 +1057,7 @@ impl Operation {
| Self::RecvAcceptChannel
| Self::RecvFundingSigned
| Self::RecvChannelReady
| Self::RecvShutdown
| Self::BroadcastTransaction
| Self::LookupShortChannelId => false,
}
Expand Down
7 changes: 6 additions & 1 deletion smite-ir/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ fn display_send_and_recv_channel_ready_program() {
}

#[test]
fn display_send_shutdown_program() {
fn display_send_and_recv_shutdown_program() {
let instructions = vec![
Instruction {
operation: Operation::LoadChannelId([0xcd; 32]),
Expand All @@ -567,6 +567,10 @@ fn display_send_shutdown_program() {
operation: Operation::SendShutdown,
inputs: vec![0, 1],
},
Instruction {
operation: Operation::RecvShutdown,
inputs: vec![2],
},
];

let program = Program { instructions };
Expand All @@ -579,6 +583,7 @@ fn display_send_shutdown_program() {
format!("v0 = LoadChannelId(0x{cid_hex})"),
format!("v1 = LoadShutdownScript(P2wpkh(0x{spk_hex}))"),
"v2 = SendShutdown(v0, v1)".into(),
"RecvShutdown(v2)".into(),
];
assert_eq!(lines.len(), expected.len(), "line count mismatch");
for (i, (got, want)) in lines.iter().zip(expected.iter()).enumerate() {
Expand Down
Loading