1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-19 09:54:02 +01:00

Type ChannelFlags instead of using a raw Byte (#2148)

This has the same kind of impact as the typing of `Features`. In particular we can now explicitly set the values in `eclair.conf`:
`eclair.channel.channel-flags.announce-channel=true`. I took the opportunity to move this channel-related config key in its own config section, with the goal that we move the other fields in a follow-up PR.

It also has the nice side effect of providing a pretty json formatting out of the box:
```json
"channelFlags": {
  "announceChannel": true
}
```

The `open` method of the API has been updated: `channelFlags` has been replaced by a new `announceChannel` parameter.
This commit is contained in:
Pierre-Marie Padiou 2022-01-25 18:35:32 +01:00 committed by GitHub
parent 75ef66e54c
commit 57c2cc5df9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 99 additions and 57 deletions

View File

@ -176,6 +176,7 @@ This release contains many other API updates:
- `findroute`, `findroutetonode` and `findroutebetweennodes` now accept `--maxFeeMsat` to specify an upper bound of fees (#1969)
- `getsentinfo` output includes `failedNode` field for all failed routes
- for `payinvoice` and `sendtonode`, `--feeThresholdSat` has been renamed to `--maxFeeFlatSat`
- for `open`, `--channelFlags` has been replaced by `--announceChannel`
- the `networkstats` API has been removed
Have a look at our [API documentation](https://acinq.github.io/eclair) for more details.

View File

@ -69,7 +69,12 @@ eclair {
# }
]
sync-whitelist = [] // a list of public keys; if non-empty, we will only do the initial sync with those peers
channel-flags = 1 // announce channels
channel {
channel-flags {
announce-channel = true
}
}
dust-limit-satoshis = 546
max-remote-dust-limit-satoshis = 600

View File

@ -88,7 +88,7 @@ trait Eclair {
def disconnect(nodeId: PublicKey)(implicit timeout: Timeout): Future[String]
def open(nodeId: PublicKey, fundingAmount: Satoshi, pushAmount_opt: Option[MilliSatoshi], channelType_opt: Option[SupportedChannelType], fundingFeeratePerByte_opt: Option[FeeratePerByte], flags_opt: Option[Int], openTimeout_opt: Option[Timeout])(implicit timeout: Timeout): Future[ChannelOpenResponse]
def open(nodeId: PublicKey, fundingAmount: Satoshi, pushAmount_opt: Option[MilliSatoshi], channelType_opt: Option[SupportedChannelType], fundingFeeratePerByte_opt: Option[FeeratePerByte], announceChannel_opt: Option[Boolean], openTimeout_opt: Option[Timeout])(implicit timeout: Timeout): Future[ChannelOpenResponse]
def close(channels: List[ApiTypes.ChannelIdentifier], scriptPubKey_opt: Option[ByteVector], closingFeerates_opt: Option[ClosingFeerates])(implicit timeout: Timeout): Future[Map[ApiTypes.ChannelIdentifier, Either[Throwable, CommandResponse[CMD_CLOSE]]]]
@ -177,7 +177,7 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
(appKit.switchboard ? Peer.Disconnect(nodeId)).mapTo[String]
}
override def open(nodeId: PublicKey, fundingAmount: Satoshi, pushAmount_opt: Option[MilliSatoshi], channelType_opt: Option[SupportedChannelType], fundingFeeratePerByte_opt: Option[FeeratePerByte], flags_opt: Option[Int], openTimeout_opt: Option[Timeout])(implicit timeout: Timeout): Future[ChannelOpenResponse] = {
override def open(nodeId: PublicKey, fundingAmount: Satoshi, pushAmount_opt: Option[MilliSatoshi], channelType_opt: Option[SupportedChannelType], fundingFeeratePerByte_opt: Option[FeeratePerByte], announceChannel_opt: Option[Boolean], openTimeout_opt: Option[Timeout])(implicit timeout: Timeout): Future[ChannelOpenResponse] = {
// we want the open timeout to expire *before* the default ask timeout, otherwise user will get a generic response
val openTimeout = openTimeout_opt.getOrElse(Timeout(20 seconds))
(appKit.switchboard ? Peer.OpenChannel(
@ -186,7 +186,7 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
pushMsat = pushAmount_opt.getOrElse(0 msat),
channelType_opt = channelType_opt,
fundingTxFeeratePerKw_opt = fundingFeeratePerByte_opt.map(FeeratePerKw(_)),
channelFlags = flags_opt.map(_.toByte),
channelFlags = announceChannel_opt.map(announceChannel => ChannelFlags(announceChannel = announceChannel)),
timeout_opt = Some(openTimeout))).mapTo[ChannelOpenResponse]
}

View File

@ -21,7 +21,7 @@ import fr.acinq.bitcoin.Crypto.PublicKey
import fr.acinq.bitcoin.{Block, ByteVector32, Crypto, Satoshi}
import fr.acinq.eclair.Setup.Seeds
import fr.acinq.eclair.blockchain.fee._
import fr.acinq.eclair.channel.Channel
import fr.acinq.eclair.channel.{Channel, ChannelFlags}
import fr.acinq.eclair.channel.Channel.UnhandledExceptionStrategy
import fr.acinq.eclair.crypto.Noise.KeyPair
import fr.acinq.eclair.crypto.keymanager.{ChannelKeyManager, NodeKeyManager}
@ -86,7 +86,7 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
initialRandomReconnectDelay: FiniteDuration,
maxReconnectInterval: FiniteDuration,
chainHash: ByteVector32,
channelFlags: Byte,
channelFlags: ChannelFlags,
watchSpentWindow: FiniteDuration,
paymentRequestExpiry: FiniteDuration,
multiPartPaymentExpiry: FiniteDuration,
@ -220,6 +220,8 @@ object NodeParams extends Logging {
"router.path-finding.ratio-channel-capacity" -> "router.path-finding.default.ratios.channel-capacity",
"router.path-finding.hop-cost-base-msat" -> "router.path-finding.default.hop-cost.fee-base-msat",
"router.path-finding.hop-cost-millionths" -> "router.path-finding.default.hop-cost.fee-proportional-millionths",
// v0.6.3
"channel-flags" -> "channel.channel-flags",
)
deprecatedKeyPaths.foreach {
case (old, new_) => require(!config.hasPath(old), s"configuration key '$old' has been replaced by '$new_'")
@ -232,6 +234,8 @@ object NodeParams extends Logging {
val chain = config.getString("chain")
val chainHash = hashFromChain(chain)
val channelFlags = ChannelFlags(announceChannel = config.getBoolean("channel.channel-flags.announce-channel"))
val color = ByteVector.fromValidHex(config.getString("node-color"))
require(color.size == 3, "color should be a 3-bytes hex buffer")
@ -449,7 +453,7 @@ object NodeParams extends Logging {
initialRandomReconnectDelay = FiniteDuration(config.getDuration("initial-random-reconnect-delay").getSeconds, TimeUnit.SECONDS),
maxReconnectInterval = FiniteDuration(config.getDuration("max-reconnect-interval").getSeconds, TimeUnit.SECONDS),
chainHash = chainHash,
channelFlags = config.getInt("channel-flags").toByte,
channelFlags = channelFlags,
watchSpentWindow = watchSpentWindow,
paymentRequestExpiry = FiniteDuration(config.getDuration("payment-request-expiry").getSeconds, TimeUnit.SECONDS),
multiPartPaymentExpiry = FiniteDuration(config.getDuration("multi-part-payment-expiry").getSeconds, TimeUnit.SECONDS),

View File

@ -84,7 +84,7 @@ case class INPUT_INIT_FUNDER(temporaryChannelId: ByteVector32,
localParams: LocalParams,
remote: ActorRef,
remoteInit: Init,
channelFlags: Byte,
channelFlags: ChannelFlags,
channelConfig: ChannelConfig,
channelType: SupportedChannelType)
case class INPUT_INIT_FUNDEE(temporaryChannelId: ByteVector32,
@ -400,7 +400,7 @@ final case class DATA_WAIT_FOR_FUNDING_CREATED(temporaryChannelId: ByteVector32,
pushAmount: MilliSatoshi,
initialFeeratePerKw: FeeratePerKw,
remoteFirstPerCommitmentPoint: PublicKey,
channelFlags: Byte,
channelFlags: ChannelFlags,
channelConfig: ChannelConfig,
channelFeatures: ChannelFeatures,
lastSent: AcceptChannel) extends ChannelData {
@ -414,7 +414,7 @@ final case class DATA_WAIT_FOR_FUNDING_SIGNED(channelId: ByteVector32,
localSpec: CommitmentSpec,
localCommitTx: CommitTx,
remoteCommit: RemoteCommit,
channelFlags: Byte,
channelFlags: ChannelFlags,
channelConfig: ChannelConfig,
channelFeatures: ChannelFeatures,
lastSent: FundingCreated) extends ChannelData
@ -492,8 +492,11 @@ case class RemoteParams(nodeId: PublicKey,
initFeatures: Features,
shutdownScript: Option[ByteVector])
case class ChannelFlags(announceChannel: Boolean) {
override def toString: String = s"ChannelFlags(announceChannel=$announceChannel)"
}
object ChannelFlags {
val AnnounceChannel = 0x01.toByte
val Empty = 0x00.toByte
val Private: ChannelFlags = ChannelFlags(announceChannel = false)
val Public: ChannelFlags = ChannelFlags(announceChannel = true)
}
// @formatter:on

View File

@ -74,7 +74,7 @@ case class Commitments(channelId: ByteVector32,
channelConfig: ChannelConfig,
channelFeatures: ChannelFeatures,
localParams: LocalParams, remoteParams: RemoteParams,
channelFlags: Byte,
channelFlags: ChannelFlags,
localCommit: LocalCommit, remoteCommit: RemoteCommit,
localChanges: LocalChanges, remoteChanges: RemoteChanges,
localNextHtlcId: Long, remoteNextHtlcId: Long,
@ -204,7 +204,7 @@ case class Commitments(channelId: ByteVector32,
val remoteNodeId: PublicKey = remoteParams.nodeId
val announceChannel: Boolean = (channelFlags & 0x01) != 0
val announceChannel: Boolean = channelFlags.announceChannel
val capacity: Satoshi = commitInput.txOut.amount

View File

@ -465,7 +465,7 @@ object Peer {
}
case class Disconnect(nodeId: PublicKey) extends PossiblyHarmful
case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, channelType_opt: Option[SupportedChannelType], fundingTxFeeratePerKw_opt: Option[FeeratePerKw], channelFlags: Option[Byte], timeout_opt: Option[Timeout]) extends PossiblyHarmful {
case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, channelType_opt: Option[SupportedChannelType], fundingTxFeeratePerKw_opt: Option[FeeratePerKw], channelFlags: Option[ChannelFlags], timeout_opt: Option[Timeout]) extends PossiblyHarmful {
require(pushMsat <= fundingSatoshis, s"pushMsat must be less or equal to fundingSatoshis")
require(fundingSatoshis >= 0.sat, s"fundingSatoshis must be positive")
require(pushMsat >= 0.msat, s"pushMsat must be positive")

View File

@ -272,7 +272,7 @@ private[channel] object ChannelCodecs0 {
("channelVersion" | channelVersionCodec) >>:~ { channelVersion =>
("localParams" | localParamsCodec(channelVersion)) ::
("remoteParams" | remoteParamsCodec) ::
("channelFlags" | byte) ::
("channelFlags" | channelflags) ::
("localCommit" | localCommitCodec) ::
("remoteCommit" | remoteCommitCodec) ::
("localChanges" | localChangesCodec) ::

View File

@ -181,7 +181,7 @@ private[channel] object ChannelTypes0 {
case class Commitments(channelVersion: ChannelVersion,
localParams: LocalParams, remoteParams: RemoteParams,
channelFlags: Byte,
channelFlags: ChannelFlags,
localCommit: LocalCommit, remoteCommit: RemoteCommit,
localChanges: LocalChanges, remoteChanges: RemoteChanges,
localNextHtlcId: Long, remoteNextHtlcId: Long,

View File

@ -188,7 +188,7 @@ private[channel] object ChannelCodecs1 {
("channelVersion" | channelVersionCodec) >>:~ { channelVersion =>
("localParams" | localParamsCodec(channelVersion)) ::
("remoteParams" | remoteParamsCodec) ::
("channelFlags" | byte) ::
("channelFlags" | channelflags) ::
("localCommit" | localCommitCodec) ::
("remoteCommit" | remoteCommitCodec) ::
("localChanges" | localChangesCodec) ::

View File

@ -223,7 +223,7 @@ private[channel] object ChannelCodecs2 {
("channelVersion" | channelVersionCodec) >>:~ { channelVersion =>
("localParams" | localParamsCodec(channelVersion)) ::
("remoteParams" | remoteParamsCodec) ::
("channelFlags" | byte) ::
("channelFlags" | channelflags) ::
("localCommit" | localCommitCodec) ::
("remoteCommit" | remoteCommitCodec) ::
("localChanges" | localChangesCodec) ::

View File

@ -266,7 +266,7 @@ private[channel] object ChannelCodecs3 {
(("channelFeatures" | channelFeaturesCodec) >>:~ { channelFeatures =>
("localParams" | localParamsCodec(channelFeatures)) ::
("remoteParams" | remoteParamsCodec) ::
("channelFlags" | byte) ::
("channelFlags" | channelflags) ::
("localCommit" | localCommitCodec) ::
("remoteCommit" | remoteCommitCodec) ::
("localChanges" | localChangesCodec) ::

View File

@ -19,6 +19,7 @@ package fr.acinq.eclair.wire.protocol
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Satoshi}
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
import fr.acinq.eclair.channel.ChannelFlags
import fr.acinq.eclair.crypto.Mac32
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, MilliSatoshi, ShortChannelId, TimestampSecond, UInt64}
import org.apache.commons.codec.binary.Base32
@ -109,6 +110,8 @@ object CommonCodecs {
val listofsignatures: Codec[List[ByteVector64]] = listOfN(uint16, bytes64)
val channelflags: Codec[ChannelFlags] = (ignore(7) dropLeft bool).as[ChannelFlags]
val ipv4address: Codec[Inet4Address] = bytes(4).xmap(b => InetAddress.getByAddress(b.toArray).asInstanceOf[Inet4Address], a => ByteVector(a.getAddress))
val ipv6address: Codec[Inet6Address] = bytes(16).exmap(b => Attempt.fromTry(Try(Inet6Address.getByAddress(null, b.toArray, null))), a => Attempt.fromTry(Try(ByteVector(a.getAddress))))

View File

@ -91,7 +91,7 @@ object LightningMessageCodecs {
("delayedPaymentBasepoint" | publicKey) ::
("htlcBasepoint" | publicKey) ::
("firstPerCommitmentPoint" | publicKey) ::
("channelFlags" | byte) ::
("channelFlags" | channelflags) ::
("tlvStream" | OpenChannelTlv.openTlvCodec)).as[OpenChannel]
val acceptChannelCodec: Codec[AcceptChannel] = (

View File

@ -20,7 +20,7 @@ import com.google.common.base.Charsets
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Satoshi}
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
import fr.acinq.eclair.channel.ChannelType
import fr.acinq.eclair.channel.{ChannelFlags, ChannelType}
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, Features, MilliSatoshi, ShortChannelId, TimestampSecond, UInt64}
import scodec.bits.ByteVector
@ -102,7 +102,7 @@ case class OpenChannel(chainHash: ByteVector32,
delayedPaymentBasepoint: PublicKey,
htlcBasepoint: PublicKey,
firstPerCommitmentPoint: PublicKey,
channelFlags: Byte,
channelFlags: ChannelFlags,
tlvStream: TlvStream[OpenChannelTlv] = TlvStream.empty) extends ChannelMessage with HasTemporaryChannelId with HasChainHash {
val upfrontShutdownScript_opt: Option[ByteVector] = tlvStream.get[ChannelTlv.UpfrontShutdownScriptTlv].map(_.script)
val channelType_opt: Option[ChannelType] = tlvStream.get[ChannelTlv.ChannelTypeTlv].map(_.channelType)

View File

@ -95,12 +95,12 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I
val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87")
// standard conversion
eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, channelType_opt = None, fundingFeeratePerByte_opt = Some(FeeratePerByte(5 sat)), flags_opt = None, openTimeout_opt = None)
eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, channelType_opt = None, fundingFeeratePerByte_opt = Some(FeeratePerByte(5 sat)), announceChannel_opt = None, openTimeout_opt = None)
val open = switchboard.expectMsgType[OpenChannel]
assert(open.fundingTxFeeratePerKw_opt === Some(FeeratePerKw(1250 sat)))
// check that minimum fee rate of 253 sat/bw is used
eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, channelType_opt = Some(ChannelTypes.StaticRemoteKey), fundingFeeratePerByte_opt = Some(FeeratePerByte(1 sat)), flags_opt = None, openTimeout_opt = None)
eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, channelType_opt = Some(ChannelTypes.StaticRemoteKey), fundingFeeratePerByte_opt = Some(FeeratePerByte(1 sat)), announceChannel_opt = None, openTimeout_opt = None)
val open1 = switchboard.expectMsgType[OpenChannel]
assert(open1.fundingTxFeeratePerKw_opt === Some(FeeratePerKw.MinimumFeeratePerKw))
assert(open1.channelType_opt === Some(ChannelTypes.StaticRemoteKey))

View File

@ -21,7 +21,7 @@ import fr.acinq.eclair.FeatureSupport.{Mandatory, Optional}
import fr.acinq.eclair.Features._
import fr.acinq.eclair.blockchain.fee._
import fr.acinq.eclair.channel.Channel.UnhandledExceptionStrategy
import fr.acinq.eclair.channel.LocalParams
import fr.acinq.eclair.channel.{ChannelFlags, LocalParams}
import fr.acinq.eclair.crypto.keymanager.{LocalChannelKeyManager, LocalNodeKeyManager}
import fr.acinq.eclair.io.MessageRelay.RelayAll
import fr.acinq.eclair.io.{Peer, PeerConnection}
@ -139,7 +139,7 @@ object TestConstants {
initialRandomReconnectDelay = 5 seconds,
maxReconnectInterval = 1 hour,
chainHash = Block.RegtestGenesisBlock.hash,
channelFlags = 1,
channelFlags = ChannelFlags.Public,
watchSpentWindow = 1 second,
paymentRequestExpiry = 1 hour,
multiPartPaymentExpiry = 30 seconds,
@ -272,7 +272,7 @@ object TestConstants {
initialRandomReconnectDelay = 5 seconds,
maxReconnectInterval = 1 hour,
chainHash = Block.RegtestGenesisBlock.hash,
channelFlags = 1,
channelFlags = ChannelFlags.Public,
watchSpentWindow = 1 second,
paymentRequestExpiry = 1 hour,
multiPartPaymentExpiry = 30 seconds,

View File

@ -483,7 +483,7 @@ object CommitmentsSpec {
ChannelFeatures(),
localParams,
remoteParams,
channelFlags = if (announceChannel) ChannelFlags.AnnounceChannel else ChannelFlags.Empty,
channelFlags = ChannelFlags(announceChannel = announceChannel),
LocalCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil),
RemoteCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toRemote, toLocal), randomBytes32(), randomKey().publicKey),
LocalChanges(Nil, Nil, Nil),
@ -506,7 +506,7 @@ object CommitmentsSpec {
ChannelFeatures(),
localParams,
remoteParams,
channelFlags = if (announceChannel) ChannelFlags.AnnounceChannel else ChannelFlags.Empty,
channelFlags = ChannelFlags(announceChannel = announceChannel),
LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil),
RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toRemote, toLocal), randomBytes32(), randomKey().publicKey),
LocalChanges(Nil, Nil, Nil),

View File

@ -79,7 +79,7 @@ class FuzzySpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Channe
registerA ! alice
registerB ! bob
// no announcements
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, Alice.channelParams, pipe, bobInit, channelFlags = 0x00.toByte, ChannelConfig.standard, ChannelTypes.Standard)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, Alice.channelParams, pipe, bobInit, channelFlags = ChannelFlags.Private, ChannelConfig.standard, ChannelTypes.Standard)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, pipe, aliceInit, ChannelConfig.standard, ChannelTypes.Standard)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -181,7 +181,7 @@ trait ChannelStateTestsHelperMethods extends TestKitBase {
val channelConfig = ChannelConfig.standard
val (aliceParams, bobParams, channelType) = computeFeatures(setup, tags)
val channelFlags = if (tags.contains(ChannelStateTestsTags.ChannelsPublic)) ChannelFlags.AnnounceChannel else ChannelFlags.Empty
val channelFlags = ChannelFlags(announceChannel = tags.contains(ChannelStateTestsTags.ChannelsPublic))
val initialFeeratePerKw = if (tags.contains(ChannelStateTestsTags.AnchorOutputs) || tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
val (fundingSatoshis, pushMsat) = if (tags.contains(ChannelStateTestsTags.NoPushMsat)) {
(TestConstants.fundingSatoshis, 0.msat)

View File

@ -62,7 +62,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
val fundingAmount = if (test.tags.contains(ChannelStateTestsTags.Wumbo)) Btc(5).toSatoshi else TestConstants.fundingSatoshis
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingAmount, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingAmount, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
alice2bob.expectMsgType[OpenChannel]
alice2bob.forward(bob)
@ -155,7 +155,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS
// Bob advertises support for anchor outputs, but Alice doesn't.
val aliceParams = Alice.channelParams
val bobParams = Bob.channelParams.copy(initFeatures = Features(Features.StaticRemoteKey -> FeatureSupport.Optional, Features.AnchorOutputs -> FeatureSupport.Optional))
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, Init(bobParams.initFeatures), ChannelFlags.Empty, channelConfig, ChannelTypes.AnchorOutputs)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, Init(bobParams.initFeatures), ChannelFlags.Private, channelConfig, ChannelTypes.AnchorOutputs)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, Init(bobParams.initFeatures), channelConfig, ChannelTypes.AnchorOutputs)
val open = alice2bob.expectMsgType[OpenChannel]
assert(open.channelType_opt === Some(ChannelTypes.AnchorOutputs))

View File

@ -55,7 +55,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui
val aliceInit = Init(aliceParams.initFeatures)
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
awaitCond(bob.stateName == WAIT_FOR_OPEN_CHANNEL)
withFixture(test.toNoArgTest(FixtureParam(alice, bob, alice2bob, bob2alice, bob2blockchain)))

View File

@ -63,7 +63,7 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun
val aliceInit = Init(aliceParams.initFeatures)
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -46,7 +46,7 @@ class WaitForFundingInternalStateSpec extends TestKitBaseClass with FixtureAnyFu
val aliceInit = Init(aliceParams.initFeatures)
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
alice2bob.expectMsgType[OpenChannel]
alice2bob.forward(bob)

View File

@ -62,7 +62,7 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
val aliceInit = Init(aliceParams.initFeatures)
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -52,7 +52,7 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF
within(30 seconds) {
val listener = TestProbe()
system.eventStream.subscribe(listener.ref, classOf[TransactionPublished])
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -49,7 +49,7 @@ class WaitForFundingLockedStateSpec extends TestKitBaseClass with FixtureAnyFunS
val bobInit = Init(bobParams.initFeatures)
within(30 seconds) {
alice.underlyingActor.nodeParams.db.peers.addOrUpdateRelayFees(bobParams.nodeId, relayFees)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -67,7 +67,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags)
val aliceInit = Init(aliceParams.initFeatures)
val bobInit = Init(bobParams.initFeatures)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[SetChannelId]

View File

@ -58,7 +58,7 @@ import scala.jdk.CollectionConverters._
class PaymentIntegrationSpec extends IntegrationSpec {
test("start eclair nodes") {
instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.expiry-delta-blocks" -> 130, "eclair.server.port" -> 29730, "eclair.api.port" -> 28080, "eclair.channel-flags" -> 0).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig)) // A's channels are private
instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.expiry-delta-blocks" -> 130, "eclair.server.port" -> 29730, "eclair.api.port" -> 28080, "eclair.channel.channel-flags.announce-channel" -> false).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig)) // A's channels are private
instantiateEclairNode("B", ConfigFactory.parseMap(Map("eclair.node-alias" -> "B", "eclair.expiry-delta-blocks" -> 131, "eclair.server.port" -> 29731, "eclair.api.port" -> 28081, "eclair.trampoline-payments-enable" -> true).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("C", ConfigFactory.parseMap(Map("eclair.node-alias" -> "C", "eclair.expiry-delta-blocks" -> 132, "eclair.server.port" -> 29732, "eclair.api.port" -> 28082, "eclair.trampoline-payments-enable" -> true).asJava).withFallback(withAnchorOutputsZeroFeeHtlcTxs).withFallback(commonConfig))
instantiateEclairNode("D", ConfigFactory.parseMap(Map("eclair.node-alias" -> "D", "eclair.expiry-delta-blocks" -> 133, "eclair.server.port" -> 29733, "eclair.api.port" -> 28083, "eclair.trampoline-payments-enable" -> true).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))

View File

@ -74,7 +74,7 @@ class RustyTestsSpec extends TestKitBaseClass with Matchers with FixtureAnyFunSu
val bobInit = Init(Bob.channelParams.initFeatures)
// alice and bob will both have 1 000 000 sat
feeEstimator.setFeerate(FeeratesPerKw.single(FeeratePerKw(10000 sat)))
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, 2000000 sat, 1000000000 msat, feeEstimator.getFeeratePerKw(target = 2), feeEstimator.getFeeratePerKw(target = 6), Alice.channelParams, pipe, bobInit, ChannelFlags.Empty, channelConfig, channelType)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, 2000000 sat, 1000000000 msat, feeEstimator.getFeeratePerKw(target = 2), feeEstimator.getFeeratePerKw(target = 6), Alice.channelParams, pipe, bobInit, ChannelFlags.Private, channelConfig, channelType)
alice2blockchain.expectMsgType[TxPublisher.SetChannelId]
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, pipe, aliceInit, channelConfig, channelType)
bob2blockchain.expectMsgType[TxPublisher.SetChannelId]

View File

@ -534,7 +534,7 @@ object PeerSpec {
}
def createOpenChannelMessage(openTlv: TlvStream[OpenChannelTlv] = TlvStream.empty): protocol.OpenChannel = {
protocol.OpenChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), 25000 sat, 0 msat, 483 sat, UInt64(100), 1000 sat, 1 msat, TestConstants.feeratePerKw, CltvExpiryDelta(144), 10, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, 0, openTlv)
protocol.OpenChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), 25000 sat, 0 msat, 483 sat, UInt64(100), 1000 sat, 1 msat, TestConstants.feeratePerKw, CltvExpiryDelta(144), 10, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, ChannelFlags.Private, openTlv)
}
}

View File

@ -371,7 +371,8 @@ object PaymentPacketSpec {
val params = LocalParams(null, null, null, null, null, null, null, 0, isFunder = true, null, None, null)
val remoteParams = RemoteParams(randomKey().publicKey, null, null, null, null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, null, None)
val commitInput = InputInfo(OutPoint(randomBytes32(), 1), TxOut(testCapacity, Nil), Nil)
new Commitments(channelId, ChannelConfig.standard, ChannelFeatures(), params, remoteParams, 0.toByte, null, null, null, null, 0, 0, Map.empty, null, commitInput, null) {
val channelFlags = ChannelFlags.Private
new Commitments(channelId, ChannelConfig.standard, ChannelFeatures(), params, remoteParams, channelFlags, null, null, null, null, 0, 0, Map.empty, null, commitInput, null) {
override lazy val availableBalanceForSend: MilliSatoshi = testAvailableBalanceForSend.max(0 msat)
override lazy val availableBalanceForReceive: MilliSatoshi = testAvailableBalanceForReceive.max(0 msat)
}

File diff suppressed because one or more lines are too long

View File

@ -20,12 +20,13 @@ import com.google.common.net.InetAddresses
import fr.acinq.bitcoin.Crypto.PrivateKey
import fr.acinq.bitcoin._
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
import fr.acinq.eclair.channel.ChannelFlags
import fr.acinq.eclair.crypto.Hmac256
import fr.acinq.eclair.wire.protocol.CommonCodecs._
import fr.acinq.eclair.{UInt64, randomBytes32}
import org.scalatest.funsuite.AnyFunSuite
import scodec.DecodeResult
import scodec.bits.{BitVector, HexStringSyntax}
import scodec.bits.{BinStringSyntax, BitVector, HexStringSyntax}
import scodec.codecs.uint32
import java.net.{Inet4Address, Inet6Address, InetAddress}
@ -137,6 +138,21 @@ class CommonCodecsSpec extends AnyFunSuite {
}
}
test("encode/decode channel flags") {
val testCases = Map(
bin"00000000" -> ChannelFlags(announceChannel = false),
bin"00000001" -> ChannelFlags(announceChannel = true),
)
testCases.foreach { case (bin, obj) =>
assert(channelflags.decode(bin).require === DecodeResult(obj, BitVector.empty))
assert(channelflags.encode(obj).require === bin)
}
// BOLT 2: The receiving node MUST [...] ignore undefined bits in channel_flags.
assert(channelflags.decode(bin"11111111").require === DecodeResult(ChannelFlags(announceChannel = true), BitVector.empty))
assert(channelflags.decode(bin"11111110").require === DecodeResult(ChannelFlags(announceChannel = false), BitVector.empty))
}
test("encode/decode with rgb codec") {
val color = Color(47.toByte, 255.toByte, 142.toByte)
val bin = rgb.encode(color).require

View File

@ -20,7 +20,7 @@ import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64, SatoshiLong}
import fr.acinq.eclair._
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
import fr.acinq.eclair.channel.ChannelTypes
import fr.acinq.eclair.channel.{ChannelFlags, ChannelTypes}
import fr.acinq.eclair.json.JsonSerializers
import fr.acinq.eclair.router.Announcements
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._
@ -152,7 +152,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite {
}
test("encode/decode open_channel") {
val defaultOpen = OpenChannel(ByteVector32.Zeroes, ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), 0.toByte)
val defaultOpen = OpenChannel(ByteVector32.Zeroes, ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private)
// Legacy encoding that omits the upfront_shutdown_script and trailing tlv stream.
// To allow extending all messages with TLV streams, the upfront_shutdown_script was moved to a TLV stream extension
// in https://github.com/lightningnetwork/lightning-rfc/pull/714 and made mandatory when including a TLV stream.
@ -254,7 +254,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite {
}
test("encode/decode all channel messages") {
val open = OpenChannel(randomBytes32(), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), 0.toByte)
val open = OpenChannel(randomBytes32(), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private)
val accept = AcceptChannel(randomBytes32(), 3 sat, UInt64(4), 5 sat, 6 msat, 7, CltvExpiryDelta(8), 9, publicKey(1), point(2), point(3), point(4), point(5), point(6))
val funding_created = FundingCreated(randomBytes32(), bin32(0), 3, randomBytes64())
val funding_signed = FundingSigned(randomBytes32(), randomBytes64())

View File

@ -33,8 +33,8 @@ trait Channel {
import fr.acinq.eclair.api.serde.JsonSupport.{formats, marshaller, serialization}
val open: Route = postRequest("open") { implicit t =>
formFields(nodeIdFormParam, "fundingSatoshis".as[Satoshi], "pushMsat".as[MilliSatoshi].?, "channelType".?, "fundingFeerateSatByte".as[FeeratePerByte].?, "channelFlags".as[Int].?, "openTimeoutSeconds".as[Timeout].?) {
(nodeId, fundingSatoshis, pushMsat, channelType, fundingFeerateSatByte, channelFlags, openTimeout_opt) =>
formFields(nodeIdFormParam, "fundingSatoshis".as[Satoshi], "pushMsat".as[MilliSatoshi].?, "channelType".?, "fundingFeerateSatByte".as[FeeratePerByte].?, "announceChannel".as[Boolean].?, "openTimeoutSeconds".as[Timeout].?) {
(nodeId, fundingSatoshis, pushMsat, channelType, fundingFeerateSatByte, announceChannel_opt, openTimeout_opt) =>
val (channelTypeOk, channelType_opt) = channelType match {
case Some(str) if str == ChannelTypes.Standard.toString => (true, Some(ChannelTypes.Standard))
case Some(str) if str == ChannelTypes.StaticRemoteKey.toString => (true, Some(ChannelTypes.StaticRemoteKey))
@ -47,7 +47,7 @@ trait Channel {
reject(MalformedFormFieldRejection("channelType", s"Channel type not supported: must be ${ChannelTypes.Standard.toString}, ${ChannelTypes.StaticRemoteKey.toString}, ${ChannelTypes.AnchorOutputs.toString} or ${ChannelTypes.AnchorOutputsZeroFeeHtlcTx.toString}"))
} else {
complete {
eclairApi.open(nodeId, fundingSatoshis, pushMsat, channelType_opt, fundingFeerateSatByte, channelFlags, openTimeout_opt)
eclairApi.open(nodeId, fundingSatoshis, pushMsat, channelType_opt, fundingFeerateSatByte, announceChannel_opt, openTimeout_opt)
}
}
}