mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
parent
6d43d443ba
commit
d71208cf0f
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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],
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user