Skip to content

Commit

Permalink
Type ChannelFlags instead of using a raw Byte (#2148)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pm47 authored Jan 25, 2022
1 parent 75ef66e commit 57c2cc5
Show file tree
Hide file tree
Showing 36 changed files with 99 additions and 57 deletions.
1 change: 1 addition & 0 deletions docs/release-notes/eclair-vnext.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]]]]

Expand Down Expand Up @@ -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(
Expand All @@ -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]
}

Expand Down
10 changes: 7 additions & 3 deletions eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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_'")
Expand All @@ -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")

Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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),
Expand Down
Loading

0 comments on commit 57c2cc5

Please sign in to comment.