Support Eclair v0.6.2 (#3765)

* Support Eclair v0.6.2

* cleanup
This commit is contained in:
rorp 2021-10-19 09:46:54 -07:00 committed by GitHub
parent 6d43d443ba
commit d71208cf0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 81 additions and 78 deletions

View File

@ -27,6 +27,7 @@ case class GetInfoResult(
version: String,
nodeId: NodeId,
alias: String,
color: String,
features: Features,
chainHash: DoubleSha256Digest,
network: BitcoinNetwork,
@ -137,8 +138,7 @@ case class NodeInfo(
nodeId: NodeId,
rgbColor: String,
alias: String,
addresses: Vector[InetSocketAddress],
unknownFields: String)
addresses: Vector[InetSocketAddress])
case class ChannelDesc(shortChannelId: ShortChannelId, a: NodeId, b: NodeId)
@ -235,13 +235,14 @@ object SentPayment {
)
}
case class ChannelFlags(isEnabled: Boolean, isNode1: Boolean)
case class ChannelUpdate(
signature: ECDigitalSignature,
chainHash: DoubleSha256Digest,
shortChannelId: ShortChannelId,
timestamp: Instant, //seconds
messageFlags: Int,
channelFlags: Int,
channelFlags: ChannelFlags,
cltvExpiryDelta: Int,
htlcMinimumMsat: MilliSatoshis,
feeProportionalMillionths: FeeProportionalMillionths,

View File

@ -817,16 +817,21 @@ object JsonReaders {
SerializerUtil.processJsString(s => UnknownFeature(s.toInt))(jsValue)
}
implicit val activatedFeatureReads: Reads[ActivatedFeature] =
implicit val featuresReads: Reads[Features] = {
Reads { jsValue =>
for {
feature <- (jsValue \ "name").validate[Feature]
support <- (jsValue \ "support").validate[FeatureSupport]
} yield ActivatedFeature(feature, support)
activatedObj <- (jsValue \ "activated")
.validate[Map[String, FeatureSupport]]
unknown <- (jsValue \ "unknown").validate[Set[UnknownFeature]]
} yield {
val activated = activatedObj.toSeq.map(x =>
ActivatedFeature(featuresByName(x._1), x._2))
Features(
activated = activated.toSet,
unknown = unknown
)
}
}
implicit val featuresReads: Reads[Features] = {
Json.reads[Features]
}
implicit val getInfoResultReads: Reads[GetInfoResult] = {
@ -855,15 +860,13 @@ object JsonReaders {
rgbColor <- (jsValue \ "rgbColor").validate[String]
alias <- (jsValue \ "alias").validate[String]
addresses <- (jsValue \ "addresses").validate[Vector[InetSocketAddress]]
unknownFields <- (jsValue \ "unknownFields").validate[String]
} yield NodeInfo(signature,
features,
timestamp,
nodeId,
rgbColor,
alias,
addresses,
unknownFields)
addresses)
}
}
@ -1009,6 +1012,9 @@ object JsonReaders {
SerializerUtil.buildJsErrorMsg("jsobject", err)
}
implicit val channelFlagsReads: Reads[ChannelFlags] =
Json.reads[ChannelFlags]
implicit val channelUpdateReads: Reads[ChannelUpdate] = {
Reads { jsValue =>
for {
@ -1017,8 +1023,7 @@ object JsonReaders {
shortChannelId <- (jsValue \ "shortChannelId").validate[ShortChannelId]
timestamp <- (jsValue \ "timestamp")
.validate[Instant](instantReadsSeconds)
messageFlags <- (jsValue \ "messageFlags").validate[Int]
channelFlags <- (jsValue \ "channelFlags").validate[Int]
channelFlags <- (jsValue \ "channelFlags").validate[ChannelFlags]
cltvExpiryDelta <- (jsValue \ "cltvExpiryDelta").validate[Int]
htlcMinimumMsat <- (jsValue \ "htlcMinimumMsat").validate[MilliSatoshis]
feeProportionalMillionths <- (jsValue \ "feeProportionalMillionths")
@ -1031,7 +1036,6 @@ object JsonReaders {
chainHash,
shortChannelId,
timestamp,
messageFlags,
channelFlags,
cltvExpiryDelta,
htlcMinimumMsat,

View File

@ -40,6 +40,11 @@ object Feature {
val mandatory = 2
}
case object OptionUpfrontShutdownScript extends Feature {
val rfcName = "option_upfront_shutdown_script"
val mandatory = 4
}
case object ChannelRangeQueries extends Feature {
val rfcName = "gossip_queries"
val mandatory = 6
@ -75,14 +80,38 @@ object Feature {
val mandatory = 18
}
case object AnchorOutputs extends Feature {
val rfcName = "option_anchor_outputs"
val mandatory = 20
}
case object AnchorOutputsZeroFeeHtlcTx extends Feature {
val rfcName = "option_anchors_zero_fee_htlc_tx"
val mandatory = 22
}
case object ShutdownAnySegwit extends Feature {
val rfcName = "option_shutdown_anysegwit"
val mandatory = 26
}
// TODO: @t-bast: update feature bits once spec-ed (currently reserved here: https://github.com/lightningnetwork/lightning-rfc/issues/605)
// We're not advertising these bits yet in our announcements, clients have to assume support.
// This is why we haven't added them yet to `areSupported`.
case object TrampolinePayment extends Feature {
val rfcName = "trampoline_payment"
val mandatory = 50
}
case object KeySend extends Feature {
val rfcName = "keysend"
val mandatory = 54
}
val knownFeatures: Set[Feature] = Set(
OptionDataLossProtect,
InitialRoutingSync,
OptionUpfrontShutdownScript,
ChannelRangeQueries,
VariableLengthOnion,
ChannelRangeQueriesExtended,
@ -90,6 +119,10 @@ object Feature {
BasicMultiPartPayment,
Wumbo,
TrampolinePayment,
StaticRemoteKey
StaticRemoteKey,
AnchorOutputs,
AnchorOutputsZeroFeeHtlcTx,
ShutdownAnySegwit,
KeySend
)
}

View File

@ -604,7 +604,7 @@ class EclairRpcClientTest extends BitcoinSAsyncTest {
}
it should "be able to pay to a hash" in {
it should "be able to make a spontaneous payment (keysend)" in {
val amt = 50.msats
val getPayment = {
(client: EclairRpcClient, otherClient: EclairRpcClient) =>
@ -625,16 +625,14 @@ class EclairRpcClientTest extends BitcoinSAsyncTest {
wsEventP.success(event)
}
}
invoice <- otherClient.createInvoice("foo", amt, preimage)
paymentId <- client.sendToNode(otherClientNodeId,
amt,
invoice.lnTags.paymentHash.hash,
None,
None,
None,
Some("ext_id"))
wsEvent <- wsEventP.future
succeeded <- client.getSentInfo(invoice.lnTags.paymentHash.hash)
succeeded <- client.getSentInfo(paymentId)
_ <- client.close(channelId)
bitcoind <- bitcoindRpcClientF
address <- bitcoind.getNewAddress
@ -651,12 +649,9 @@ class EclairRpcClientTest extends BitcoinSAsyncTest {
val succeededPayment = succeeded.head
assert(succeededPayment.amount == amt)
assert(succeededPayment.externalId.contains("ext_id"))
succeededPayment.status match {
case sent: OutgoingPaymentStatus.Succeeded =>
assert(sent.paymentPreimage == preimage)
case s: OutgoingPaymentStatus =>
fail(s"Unexpected payment status ${s}")
}
assert(
succeededPayment.status
.isInstanceOf[OutgoingPaymentStatus.Succeeded])
}
}
}
@ -1031,7 +1026,9 @@ class EclairRpcClientTest extends BitcoinSAsyncTest {
for {
(channelId, oldFee) <- channelAndFeeF
client <- clientF
_ <- client.updateRelayFee(channelId, oldFee * 2, 1)
otherClient <- otherClientF
info <- otherClient.getInfo
_ <- client.updateRelayFee(info.nodeId, oldFee * 2, 1)
channel <- client.channel(channelId)
newFeeOpt = channel.feeBaseMsat
} yield {
@ -1040,31 +1037,6 @@ class EclairRpcClientTest extends BitcoinSAsyncTest {
}
}
it should "update the relay fee of a channel with short channel id" in {
val channelAndFeeF = for {
channelId <-
EclairRpcTestUtil.openAndConfirmChannel(clientF, otherClientF)
client <- clientF
channel <- client.channel(channelId)
} yield {
assert(channel.feeBaseMsat.isDefined)
assert(channel.feeBaseMsat.get > MilliSatoshis.zero)
assert(channel.shortChannelId.isDefined)
(channel.channelId, channel.shortChannelId.get, channel.feeBaseMsat.get)
}
for {
client <- clientF
(channelId, shortChannelId, oldFee) <- channelAndFeeF
_ <- client.updateRelayFee(shortChannelId, oldFee * 4, 1)
channel <- client.channel(channelId)
newFeeOpt = channel.feeBaseMsat
} yield {
assert(newFeeOpt.isDefined)
assert(newFeeOpt.get == oldFee * 4)
}
}
it should "get all nodes" in {
clientF.flatMap(_.allNodes().flatMap(nodes => assert(nodes.nonEmpty)))
}

View File

@ -19,8 +19,8 @@ TaskKeys.downloadEclair := {
Files.createDirectories(binaryDir)
}
val version = "0.5.0"
val commit = "ac08560"
val version = "0.6.2"
val commit = "6817d6f"
logger.debug(s"(Maybe) downloading Eclair binaries for version: $version")

View File

@ -93,12 +93,12 @@ trait EclairApi {
def isConnected(nodeId: NodeId): Future[Boolean]
def updateRelayFee(
channelId: ChannelId,
nodeId: NodeId,
feeBaseMsat: MilliSatoshis,
feeProportionalMillionths: Long): Future[UpdateRelayFeeResult]
def updateRelayFee(
shortChannelId: ShortChannelId,
nodeIds: Vector[NodeId],
feeBaseMsat: MilliSatoshis,
feePropertionalMillionths: Long
): Future[UpdateRelayFeeResult]
@ -244,7 +244,6 @@ trait EclairApi {
def sendToNode(
nodeId: NodeId,
amountMsat: MilliSatoshis,
paymentHash: Sha256Digest,
maxAttempts: Option[Int],
feeThresholdSat: Option[Satoshis],
maxFeePct: Option[Int],

View File

@ -488,14 +488,12 @@ class EclairRpcClient(
override def sendToNode(
nodeId: NodeId,
amountMsat: MilliSatoshis,
paymentHash: Sha256Digest,
maxAttempts: Option[Int],
feeThresholdSat: Option[Satoshis],
maxFeePct: Option[Int],
externalId: Option[String]): Future[PaymentId] = {
val params = Seq("nodeId" -> nodeId.toString,
"amountMsat" -> amountMsat.toBigDecimal.toString,
"paymentHash" -> paymentHash.hex) ++ Seq(
"amountMsat" -> amountMsat.toBigDecimal.toString) ++ Seq(
maxAttempts.map(x => "maxAttempts" -> x.toString),
feeThresholdSat.map(x => "feeThresholdSat" -> x.toBigDecimal.toString),
maxFeePct.map(x => "maxFeePct" -> x.toString),
@ -531,24 +529,19 @@ class EclairRpcClient(
}
override def updateRelayFee(
channelId: ChannelId,
nodeId: NodeId,
feeBaseMsat: MilliSatoshis,
feeProportionalMillionths: Long): Future[UpdateRelayFeeResult] = {
eclairCall[UpdateRelayFeeResult](
"updaterelayfee",
"channelId" -> channelId.hex,
"feeBaseMsat" -> feeBaseMsat.toLong.toString,
"feeProportionalMillionths" -> feeProportionalMillionths.toString
)
updateRelayFee(Vector(nodeId), feeBaseMsat, feeProportionalMillionths)
}
override def updateRelayFee(
shortChannelId: ShortChannelId,
nodeIds: Vector[NodeId],
feeBaseMsat: MilliSatoshis,
feeProportionalMillionths: Long): Future[UpdateRelayFeeResult] = {
eclairCall[UpdateRelayFeeResult](
"updaterelayfee",
"shortChannelId" -> shortChannelId.toHumanReadableString,
"nodeIds" -> nodeIds.map(_.hex).mkString(","),
"feeBaseMsat" -> feeBaseMsat.toLong.toString,
"feeProportionalMillionths" -> feeProportionalMillionths.toString
)
@ -961,13 +954,13 @@ object EclairRpcClient {
implicit system: ActorSystem) = new EclairRpcClient(instance, binary)
/** The current commit we support of Eclair */
private[bitcoins] val commit = "ac08560"
private[bitcoins] val commit = "6817d6f"
/** The current version we support of Eclair */
private[bitcoins] val version = "0.5.0"
private[bitcoins] val version = "0.6.2"
/** The bitcoind version that eclair is officially tested & supported with by ACINQ
* @see https://github.com/ACINQ/eclair/releases/tag/v0.4
* @see https://github.com/ACINQ/eclair/releases/tag/v0.6.2
*/
val bitcoindV: BitcoindVersion = BitcoindVersion.V19
val bitcoindV: BitcoindVersion = BitcoindVersion.V21
}

View File

@ -88,7 +88,7 @@ trait EclairRpcTestUtil extends Logging {
port: Int = RpcUtil.randomPort,
apiPort: Int = RpcUtil.randomPort): Config = {
val configMap = {
val rawBlock = bitcoindInstance.zmqConfig.rawBlock.get
val hashBlock = bitcoindInstance.zmqConfig.hashBlock.get
val rawTx = bitcoindInstance.zmqConfig.rawTx.get
Map[String, Any](
"eclair.chain" -> "regtest",
@ -104,7 +104,7 @@ trait EclairRpcTestUtil extends Logging {
.asInstanceOf[BitcoindAuthCredentials.PasswordBased]
.password,
"eclair.bitcoind.rpcport" -> bitcoindInstance.rpcUri.getPort,
"eclair.bitcoind.zmqblock" -> s"tcp://${rawBlock.getHostName}:${rawBlock.getPort}",
"eclair.bitcoind.zmqblock" -> s"tcp://${hashBlock.getHostName}:${hashBlock.getPort}",
"eclair.bitcoind.zmqtx" -> s"tcp://${rawTx.getHostName}:${rawTx.getPort}",
"eclair.api.enabled" -> true,
"eclair.api.binding-ip" -> "127.0.0.1",
@ -119,7 +119,8 @@ trait EclairRpcTestUtil extends Logging {
"eclair.max-payment-fee" -> 10, // avoid complaints about too high fees
"eclair.alias" -> "suredbits",
"eclair.fulfill-safety-before-timeout-blocks" -> 1,
"eclair.min-final-expiry-delta-blocks" -> 2
"eclair.min-final-expiry-delta-blocks" -> 2,
"eclair.features.keysend" -> "optional"
)
}
val c = ConfigFactory.parseMap(configMap.asJava)