From 6680b27417c51d53cb0e4ba0d710d18da5e6e070 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 16 Sep 2026 13:39:06 +0530 Subject: [PATCH 1/4] smite: move REGTEST_CHAIN_HASH to bolt::types Signed-off-by: Nishant Bansal --- smite-scenarios/src/executor/tests/harness.rs | 6 +++--- smite-scenarios/src/scenarios.rs | 2 +- smite-scenarios/src/scenarios/setup.rs | 8 +------- smite/src/bolt.rs | 8 ++++---- smite/src/bolt/types.rs | 6 ++++++ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/smite-scenarios/src/executor/tests/harness.rs b/smite-scenarios/src/executor/tests/harness.rs index 64ca233a..668e6f1a 100644 --- a/smite-scenarios/src/executor/tests/harness.rs +++ b/smite-scenarios/src/executor/tests/harness.rs @@ -2,7 +2,7 @@ use crate::executor::*; use bitcoin::{Amount, Transaction}; -use smite::bolt::{AcceptChannelTlvs, ChannelTypeVariant, FromMessage}; +use smite::bolt::{AcceptChannelTlvs, ChannelTypeVariant, FromMessage, REGTEST_CHAIN_HASH}; use std::collections::VecDeque; use std::str::FromStr; @@ -254,7 +254,7 @@ pub fn sample_pubkey(byte: u8) -> PublicKey { pub fn sample_context() -> ProgramContext { ProgramContext { target_pubkey: sample_pubkey(1), - chain_hash: [0xcc; 32], + chain_hash: REGTEST_CHAIN_HASH, block_height: 800_000, negotiated_features: Features::from_bits(&[ Features::OPTION_STATIC_REMOTEKEY, @@ -467,7 +467,7 @@ pub fn sample_funding_negotiation() -> PendingChannel { PendingChannel { open_channel: OpenChannel { - chain_hash: [0xcc; 32], + chain_hash: REGTEST_CHAIN_HASH, temporary_channel_id: TemporaryChannelId::new([0xbb; 32]), funding_satoshis: 10_000_000, push_msat: 3_000_000_000, diff --git a/smite-scenarios/src/scenarios.rs b/smite-scenarios/src/scenarios.rs index 48a43b3f..7ba62b3c 100644 --- a/smite-scenarios/src/scenarios.rs +++ b/smite-scenarios/src/scenarios.rs @@ -10,7 +10,7 @@ pub use encrypted_bytes::EncryptedBytesScenario; pub use init::InitScenario; pub use ir::IrScenario; pub use noise::NoiseScenario; -pub use setup::{PostInitSetup, REGTEST_CHAIN_HASH, SnapshotSetup}; +pub use setup::{PostInitSetup, SnapshotSetup}; use smite::scenarios::ScenarioError; use std::time::Duration; diff --git a/smite-scenarios/src/scenarios/setup.rs b/smite-scenarios/src/scenarios/setup.rs index c626279d..2cfe5773 100644 --- a/smite-scenarios/src/scenarios/setup.rs +++ b/smite-scenarios/src/scenarios/setup.rs @@ -2,7 +2,7 @@ use std::time::Duration; -use smite::bolt::{FeatureBit, Features, Init, InitTlvs, Message}; +use smite::bolt::{FeatureBit, Features, Init, InitTlvs, Message, REGTEST_CHAIN_HASH}; use smite::noise::NoiseConnection; use smite::scenarios::ScenarioError; @@ -10,12 +10,6 @@ use super::{handshake_with_target, ping_pong}; use crate::executor::ProgramContext; use crate::targets::{INITIAL_BLOCKS, Target}; -/// Bitcoin regtest genesis hash (in BOLT 2 network byte order). -pub const REGTEST_CHAIN_HASH: [u8; 32] = [ - 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, - 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, -]; - const TIMEOUT: Duration = Duration::from_secs(5); /// Pre-snapshot setup that establishes a ready-to-use connection and produces diff --git a/smite/src/bolt.rs b/smite/src/bolt.rs index 978fa434..95d025eb 100644 --- a/smite/src/bolt.rs +++ b/smite/src/bolt.rs @@ -74,10 +74,10 @@ pub use tx_init_rbf::{TxInitRbf, TxInitRbfTlvs}; pub use tx_remove_input::TxRemoveInput; pub use tx_remove_output::TxRemoveOutput; pub use types::{ - BigSize, CHANNEL_ID_SIZE, COMPACT_SIGNATURE_SIZE, ChannelId, ChannelTypeVariant, - MAX_MESSAGE_SIZE, PAYMENT_ONION_PACKET_SIZE, PER_COMMITMENT_SECRET_SIZE, PUBLIC_KEY_SIZE, - SHA256_HASH_SIZE, SHORT_CHANNEL_ID_SIZE, ShortChannelId, TXID_SIZE, TemporaryChannelId, Tu32, - Tu64, + BigSize, CHAIN_HASH_SIZE, CHANNEL_ID_SIZE, COMPACT_SIGNATURE_SIZE, ChannelId, + ChannelTypeVariant, MAX_MESSAGE_SIZE, PAYMENT_ONION_PACKET_SIZE, PER_COMMITMENT_SECRET_SIZE, + PUBLIC_KEY_SIZE, REGTEST_CHAIN_HASH, SHA256_HASH_SIZE, SHORT_CHANNEL_ID_SIZE, ShortChannelId, + TXID_SIZE, TemporaryChannelId, Tu32, Tu64, }; pub use update_add_htlc::{UpdateAddHtlc, UpdateAddHtlcTlvs}; pub use update_fail_htlc::{UpdateFailHtlc, UpdateFailHtlcTlvs}; diff --git a/smite/src/bolt/types.rs b/smite/src/bolt/types.rs index 5bdbb694..45e0ea6c 100644 --- a/smite/src/bolt/types.rs +++ b/smite/src/bolt/types.rs @@ -37,6 +37,12 @@ pub const PAYMENT_ONION_PACKET_SIZE: usize = 1366; /// Size of a per-commitment secret in bytes. pub const PER_COMMITMENT_SECRET_SIZE: usize = 32; +/// Bitcoin regtest genesis hash (in BOLT 2 network byte order). +pub const REGTEST_CHAIN_HASH: [u8; CHAIN_HASH_SIZE] = [ + 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, + 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, +]; + /// A 32-byte channel identifier. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] pub struct ChannelId(pub [u8; CHANNEL_ID_SIZE]); From 070fcbd79e7fa3811c3fd0727bff2f815067e7bf Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 16 Sep 2026 13:58:38 +0530 Subject: [PATCH 2/4] smite: add open_channel sanity checks to accept_channel oracle Signed-off-by: Nishant Bansal --- smite/src/oracles/accept_channel.rs | 134 +++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 11 deletions(-) diff --git a/smite/src/oracles/accept_channel.rs b/smite/src/oracles/accept_channel.rs index 54af06a1..1ea87dc7 100644 --- a/smite/src/oracles/accept_channel.rs +++ b/smite/src/oracles/accept_channel.rs @@ -2,14 +2,15 @@ use super::Oracle; use crate::bolt::{ - AcceptChannel, ChannelTypeVariant, Features, OpenChannel, is_acceptable_shutdown_script, - is_standard_shutdown_script, + AcceptChannel, ChannelTypeVariant, Features, OpenChannel, REGTEST_CHAIN_HASH, + is_acceptable_shutdown_script, is_standard_shutdown_script, }; use crate::channel_tx::CommitmentCost; use crate::pending_channel::PendingChannel; use crate::violation::Violation; use bitcoin::Amount; +use bitcoin::hex::DisplayHex; // Constants from the BOLT 2 `open_channel` and `accept_channel` requirements: // https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#requirements-8 @@ -22,6 +23,14 @@ const MIN_DUST_LIMIT_SATOSHIS: u64 = 354; // whether the initiator wishes to announce the channel publicly. const ANNOUNCE_CHANNEL_FLAG: u8 = 1; +// A high dust limit leaves too much of the channel unenforceable on-chain, +// so values above this are considered unreasonably large. +const MAX_DUST_LIMIT_SATOSHIS: u64 = 10_000; + +// A long delay locks the receiver's funds for too long after a unilateral +// close, so values above this (~2 weeks) are considered unreasonably large. +const MAX_TO_SELF_DELAY: u16 = 2016; + /// Context for `AcceptChannelOracle` pub struct AcceptChannelContext<'a> { /// The `accept_channel` received from the peer. @@ -99,6 +108,7 @@ impl Oracle> for AcceptChannelOracle { /// be less than or equal to the channel reserve. However, implementations /// such as LDK accept zero channel reserves on the receiving side, so we do /// not enforce this check on the target's receiving side. +#[allow(clippy::too_many_lines)] fn verify_accepted_open_channel( open_channel: &OpenChannel, negotiated_features: &Features, @@ -108,6 +118,18 @@ fn verify_accepted_open_channel( return Err("option_dual_fund has been negotiated".to_string()); } + // Check that the channel is opened on regtest. + // + // TODO: Take the chain hash in use from the scenario context once Smite + // fuzzes targets on other chains. + if open_channel.chain_hash != REGTEST_CHAIN_HASH { + return Err(format!( + "chain_hash {} is not the chain hash {} in use", + open_channel.chain_hash.as_hex(), + REGTEST_CHAIN_HASH.as_hex(), + )); + } + // Check that the funding amounts are valid. let max_funding = max_funding_satoshis(negotiated_features); if open_channel.funding_satoshis > max_funding { @@ -125,6 +147,14 @@ fn verify_accepted_open_channel( )); } + // Check that the channel reserve leaves a spendable balance. + if open_channel.channel_reserve_satoshis >= open_channel.funding_satoshis { + return Err(format!( + "channel_reserve_satoshis {} is not below funding_satoshis {}", + open_channel.channel_reserve_satoshis, open_channel.funding_satoshis, + )); + } + // Check that the upfront shutdown script is present and valid when negotiated. if negotiated_features.supports_feature(Features::OPTION_UPFRONT_SHUTDOWN_SCRIPT) { let Some(script) = &open_channel.tlvs.upfront_shutdown_script else { @@ -158,13 +188,24 @@ fn verify_accepted_open_channel( return Err("channel_type is not a known variant".to_string()); } - // Check that feerate_per_kw is 0 when `zero_fee_commitments` is negotiated. - if channel_type.supports_feature(Features::ZERO_FEE_COMMITMENTS) - && open_channel.feerate_per_kw != 0 - { + // Check that feerate_per_kw is 0 when `zero_fee_commitments` is negotiated, + // and that it is non-zero otherwise. + if channel_type.supports_feature(Features::ZERO_FEE_COMMITMENTS) { + if open_channel.feerate_per_kw != 0 { + return Err(format!( + "zero_fee_commitments requires feerate_per_kw to be 0, but got {}", + open_channel.feerate_per_kw, + )); + } + } else if open_channel.feerate_per_kw == 0 { + return Err("feerate_per_kw must be non-zero without zero_fee_commitments".to_string()); + } + + // Check that to_self_delay is not unreasonably large. + if open_channel.to_self_delay > MAX_TO_SELF_DELAY { return Err(format!( - "zero_fee_commitments requires feerate_per_kw to be 0, but got {}", - open_channel.feerate_per_kw, + "to_self_delay {} exceeds the maximum of {MAX_TO_SELF_DELAY} blocks", + open_channel.to_self_delay, )); } @@ -183,7 +224,13 @@ fn verify_accepted_open_channel( )); } - // Check the dust limit is not below the minimum. + // Check the dust limit is within the acceptable range. + if open_channel.dust_limit_satoshis > MAX_DUST_LIMIT_SATOSHIS { + return Err(format!( + "dust_limit_satoshis {} exceeds the maximum of {MAX_DUST_LIMIT_SATOSHIS} sat", + open_channel.dust_limit_satoshis, + )); + } if open_channel.dust_limit_satoshis < MIN_DUST_LIMIT_SATOSHIS { return Err(format!( "dust_limit_satoshis {} is below the minimum of {MIN_DUST_LIMIT_SATOSHIS} sat", @@ -368,7 +415,7 @@ fn max_accepted_htlcs_limit(channel_type: &Features) -> u16 { #[cfg(test)] mod tests { use super::*; - use crate::bolt::{AcceptChannelTlvs, OpenChannelTlvs, TemporaryChannelId}; + use crate::bolt::{AcceptChannelTlvs, CHAIN_HASH_SIZE, OpenChannelTlvs, TemporaryChannelId}; use bitcoin::hashes::Hash; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use bitcoin::{PubkeyHash, ScriptBuf, WPubkeyHash}; @@ -382,7 +429,7 @@ mod tests { fn open_channel() -> OpenChannel { let key = pubkey(1); OpenChannel { - chain_hash: [0u8; 32], + chain_hash: REGTEST_CHAIN_HASH, temporary_channel_id: TemporaryChannelId::new([1u8; 32]), funding_satoshis: 10_000_000, push_msat: 3_000_000_000, @@ -571,6 +618,19 @@ mod tests { ); } + #[test] + fn open_channel_for_another_chain() { + let mut oc = open_channel(); + oc.chain_hash = [0xaa; CHAIN_HASH_SIZE]; + + assert_fail( + &accept_channel(), + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid open_channel: chain_hash aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not the chain hash", + ); + } + #[test] fn funding_satoshis_above_non_wumbo_limit_without_option_support_large_channel() { let mut oc = open_channel(); @@ -613,6 +673,19 @@ mod tests { ); } + #[test] + fn open_channel_channel_reserve_not_below_the_funding_amount() { + let mut oc = open_channel(); + oc.channel_reserve_satoshis = oc.funding_satoshis; + + assert_fail( + &accept_channel(), + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid open_channel: channel_reserve_satoshis 10000000 is not below funding_satoshis 10000000", + ); + } + #[test] fn open_channel_invalid_upfront_shutdown_script() { let mut oc = open_channel(); @@ -704,6 +777,32 @@ mod tests { ); } + #[test] + fn open_channel_zero_feerate_without_zero_fee_commitments() { + let mut oc = open_channel(); + oc.feerate_per_kw = 0; + + assert_fail( + &accept_channel(), + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid open_channel: feerate_per_kw must be non-zero without zero_fee_commitments", + ); + } + + #[test] + fn open_channel_to_self_delay_above_the_maximum() { + let mut oc = open_channel(); + oc.to_self_delay = MAX_TO_SELF_DELAY + 1; + + assert_fail( + &accept_channel(), + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid open_channel: to_self_delay 2017 exceeds the maximum of 2016 blocks", + ); + } + #[test] fn open_channel_option_scid_alias_for_public_channel() { let mut oc = open_channel(); @@ -746,6 +845,19 @@ mod tests { ); } + #[test] + fn open_channel_dust_limit_above_the_maximum() { + let mut oc = open_channel(); + oc.dust_limit_satoshis = MAX_DUST_LIMIT_SATOSHIS + 1; + + assert_fail( + &accept_channel(), + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid open_channel: dust_limit_satoshis 10001 exceeds the maximum of 10000 sat", + ); + } + #[test] fn open_channel_dust_limit_below_the_minimum() { let mut oc = open_channel(); From 86c84278d74edd3cf56e4544b10e0b7521250f9d Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 16 Sep 2026 14:07:57 +0530 Subject: [PATCH 3/4] smite: add accept_channel sanity checks to accept_channel oracle Signed-off-by: Nishant Bansal --- smite/src/oracles/accept_channel.rs | 101 +++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/smite/src/oracles/accept_channel.rs b/smite/src/oracles/accept_channel.rs index 1ea87dc7..1a603c09 100644 --- a/smite/src/oracles/accept_channel.rs +++ b/smite/src/oracles/accept_channel.rs @@ -317,7 +317,7 @@ fn verify_accept_channel( )); } - // Check the HTLC limit is within the maximum. + // Check the HTLC limit is within the acceptable range. let htlc_limit = max_accepted_htlcs_limit(&channel_type); if accept_channel.max_accepted_htlcs > htlc_limit { return Err(format!( @@ -325,8 +325,17 @@ fn verify_accept_channel( accept_channel.max_accepted_htlcs, )); } + if accept_channel.max_accepted_htlcs == 0 { + return Err("max_accepted_htlcs 0 leaves the channel unable to carry HTLCs".to_string()); + } - // Check the dust limit is not below the minimum. + // Check the dust limit is within the acceptable range. + if accept_channel.dust_limit_satoshis > MAX_DUST_LIMIT_SATOSHIS { + return Err(format!( + "dust_limit_satoshis {} exceeds the maximum of {MAX_DUST_LIMIT_SATOSHIS} sat", + accept_channel.dust_limit_satoshis, + )); + } if accept_channel.dust_limit_satoshis < MIN_DUST_LIMIT_SATOSHIS { return Err(format!( "dust_limit_satoshis {} is below the minimum of {MIN_DUST_LIMIT_SATOSHIS} sat", @@ -334,6 +343,26 @@ fn verify_accept_channel( )); } + // Check the minimum HTLC is within the in-flight limit and the channel capacity. + if accept_channel.htlc_minimum_msat > accept_channel.max_htlc_value_in_flight_msat { + return Err(format!( + "htlc_minimum_msat {} exceeds max_htlc_value_in_flight_msat {}", + accept_channel.htlc_minimum_msat, accept_channel.max_htlc_value_in_flight_msat, + )); + } + let funding_msat = open_channel.funding_satoshis * 1000; + if accept_channel.htlc_minimum_msat > funding_msat { + return Err(format!( + "htlc_minimum_msat {} exceeds the open_channel funding amount {funding_msat} msat", + accept_channel.htlc_minimum_msat, + )); + } + + // Check the acceptor gives itself time to punish a revoked commitment. + if accept_channel.to_self_delay == 0 { + return Err("to_self_delay must be non-zero".to_string()); + } + // Check the initial commitment satisfies the channel reserve. verify_initial_commitment( open_channel, @@ -1061,6 +1090,33 @@ mod tests { ); } + #[test] + fn accept_channel_max_accepted_htlcs_of_zero() { + let mut ac = accept_channel(); + ac.max_accepted_htlcs = 0; + + assert_fail( + &ac, + Some(&pending_negotiation(open_channel())), + &sample_negotiated_features(), + "invalid accept_channel: max_accepted_htlcs 0 leaves the channel unable to carry HTLCs", + ); + } + + #[test] + fn accept_channel_dust_limit_above_the_maximum() { + let mut ac = accept_channel(); + ac.dust_limit_satoshis = MAX_DUST_LIMIT_SATOSHIS + 1; + ac.channel_reserve_satoshis = ac.dust_limit_satoshis; + + assert_fail( + &ac, + Some(&pending_negotiation(open_channel())), + &sample_negotiated_features(), + "invalid accept_channel: dust_limit_satoshis 10001 exceeds the maximum of 10000 sat", + ); + } + #[test] fn accept_channel_dust_limit_below_the_minimum() { let mut ac = accept_channel(); @@ -1074,6 +1130,47 @@ mod tests { ); } + #[test] + fn accept_channel_htlc_minimum_above_the_in_flight_limit() { + let mut ac = accept_channel(); + ac.htlc_minimum_msat = ac.max_htlc_value_in_flight_msat + 1; + + assert_fail( + &ac, + Some(&pending_negotiation(open_channel())), + &sample_negotiated_features(), + "invalid accept_channel: htlc_minimum_msat 100000001 exceeds max_htlc_value_in_flight_msat 100000000", + ); + } + + #[test] + fn accept_channel_htlc_minimum_above_the_funding_amount() { + let oc = open_channel(); + let mut ac = accept_channel(); + ac.htlc_minimum_msat = oc.funding_satoshis * 1000 + 1; + ac.max_htlc_value_in_flight_msat = ac.htlc_minimum_msat; + + assert_fail( + &ac, + Some(&pending_negotiation(oc)), + &sample_negotiated_features(), + "invalid accept_channel: htlc_minimum_msat 10000000001 exceeds the open_channel funding amount 10000000000 msat", + ); + } + + #[test] + fn accept_channel_zero_to_self_delay() { + let mut ac = accept_channel(); + ac.to_self_delay = 0; + + assert_fail( + &ac, + Some(&pending_negotiation(open_channel())), + &sample_negotiated_features(), + "invalid accept_channel: to_self_delay must be non-zero", + ); + } + #[test] fn accept_channel_initial_commitment_below_reserves() { let mut ac = accept_channel(); From 3c5b9648bb62d03f53600fa165bd10631b29f706 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sat, 19 Sep 2026 14:39:26 +0530 Subject: [PATCH 4/4] smite-scenarios: suppress known oracle violations Signed-off-by: Nishant Bansal --- smite-scenarios/src/targets/cln.rs | 18 ++++++++++++++++++ smite-scenarios/src/targets/eclair.rs | 8 ++++++++ smite-scenarios/src/targets/lnd.rs | 13 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/smite-scenarios/src/targets/cln.rs b/smite-scenarios/src/targets/cln.rs index d706b8c4..8c3a514e 100644 --- a/smite-scenarios/src/targets/cln.rs +++ b/smite-scenarios/src/targets/cln.rs @@ -389,6 +389,17 @@ impl Target for ClnTarget { /// (hardcoded 546) exceeds its own `channel_reserve_satoshis`, which /// BOLT 2 forbids. /// See: + /// + /// - CLN accepts `open_channel` with `option_scid_alias` in `channel_type` + /// on a channel that is to be announced, which BOLT 2 forbids the opener + /// from sending. + /// See: + /// + /// - CLN currently allows an unreasonably large `dust_limit_satoshis` + /// during `open_channel` negotiation, leaving too much of the channel + /// balance unenforceable on-chain. BOLT 2 allows the receiver fail the + /// channel if it considers `dust_limit_satoshis` too large. A fix is in + /// progress upstream. fn known_violations() -> &'static [&'static [&'static str]] { &[ &[ @@ -410,6 +421,13 @@ impl Target for ClnTarget { "sat cannot cover anchor cost of", ], &["invalid accept_channel: dust_limit_satoshis 546 exceeds channel_reserve_satoshis"], + &[ + "accepted invalid open_channel: option_scid_alias requires the channel to be private", + ], + &[ + "accepted invalid open_channel: dust_limit_satoshis", + "exceeds the maximum of 10000 sat", + ], ] } } diff --git a/smite-scenarios/src/targets/eclair.rs b/smite-scenarios/src/targets/eclair.rs index a5525606..c38cec77 100644 --- a/smite-scenarios/src/targets/eclair.rs +++ b/smite-scenarios/src/targets/eclair.rs @@ -259,6 +259,11 @@ impl Target for EclairTarget { /// fee or fund the anchor outputs. This situation should be rejected /// early, as required by BOLT 2. /// See: + /// + /// - Eclair accepts `open_channel` with `option_scid_alias` in + /// `channel_type` on a channel that is to be announced, which BOLT 2 + /// forbids the opener from sending. + /// See: fn known_violations() -> &'static [&'static [&'static str]] { &[ &[ @@ -269,6 +274,9 @@ impl Target for EclairTarget { "accepted invalid open_channel: opener balance", "sat cannot cover anchor cost of", ], + &[ + "accepted invalid open_channel: option_scid_alias requires the channel to be private", + ], ] } } diff --git a/smite-scenarios/src/targets/lnd.rs b/smite-scenarios/src/targets/lnd.rs index d6613562..4c32e169 100644 --- a/smite-scenarios/src/targets/lnd.rs +++ b/smite-scenarios/src/targets/lnd.rs @@ -347,6 +347,15 @@ impl Target for LndTarget { /// a wrapping `uint64` and then tested as an `int64`, so any push above /// roughly 2^63 wraps back into the non-negative range. /// See: + /// + /// - LND accepts `open_channel` with an empty `channel_type`, which matches + /// none of the channel types defined in BOLT 2, and falls back to opening + /// a legacy channel. + /// See: + /// + /// - LND accepts `open_channel` with `feerate_per_kw` of 0 without + /// `zero_fee_commitments`, as it enforces no lower bound on the feerate. + /// See: fn known_violations() -> &'static [&'static [&'static str]] { &[ &["accepted invalid open_channel: open_channel does not include a channel_type"], @@ -356,6 +365,10 @@ impl Target for LndTarget { "accepted invalid open_channel: push_msat", "exceeds funding amount", ], + &["accepted invalid open_channel: channel_type is not a known variant"], + &[ + "accepted invalid open_channel: feerate_per_kw must be non-zero without zero_fee_commitments", + ], ] } }