Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for zero-conf and scid-alias #2224

Merged
merged 55 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
bbd0b34
rename funding_locked -> channel_ready
pm47 Mar 29, 2022
244d6dd
add new options, reassign trampoline bit
pm47 Mar 30, 2022
838559e
add variations to channel type with alias/zeroconf
pm47 Mar 30, 2022
1e88cb6
set min_depth to 0 in zeroconf
pm47 Mar 29, 2022
54b91ea
add an alias tlv to channel_ready
pm47 Mar 29, 2022
7ae4b1a
store local/remote aliases in channel data
pm47 May 3, 2022
2be5699
fix race condition
pm47 May 17, 2022
dd23c14
bypass blockchain validation for local channels
pm47 May 17, 2022
93bbb8c
address review comments
pm47 Jun 1, 2022
c965f97
fix codec bug and add non-reg test
pm47 Jun 1, 2022
a8940d3
add test proving bug in scid selection for channel_update
pm47 Jun 2, 2022
cac1d22
simplify scid selection for channel_update
pm47 Jun 2, 2022
aab4f76
add test proving bug in rebroadcast
pm47 Jun 2, 2022
32a0d5a
fix rebroadcast bug
pm47 Jun 2, 2022
3aa0560
handle local node announcement synchronously
pm47 Jun 2, 2022
774432e
always re-send channel_update at reconnection for unannounced channels
pm47 Jun 2, 2022
93a3d7e
add channel relay tests
pm47 Jun 3, 2022
2cf1338
remove remaining triple equals
pm47 Jun 3, 2022
7a5a3df
fix rebase
pm47 Jun 3, 2022
a9e572f
fix bug with graph update when channel graduates from private to public
pm47 Jun 3, 2022
ecbcb58
factor channel-router integration test
pm47 Jun 3, 2022
c1fabe7
add integration tests for zero-conf
pm47 Jun 3, 2022
4d25535
fix bug created by de2dee374: need to populate meta for graduating ch…
pm47 Jun 5, 2022
58de78c
fix bug created by de2dee374: need to do watcher/db calls for local p…
pm47 Jun 5, 2022
ca67ffc
nit: comment formatting
pm47 Jun 5, 2022
19d2943
fix race condition in PaymentIntegrationTest
pm47 Jun 6, 2022
9743113
update scala plugins
pm47 Jun 6, 2022
391c8a2
factor ZeroConfAliasIntegrationSpec
pm47 Jun 6, 2022
e26420b
add unit test on scid_alias activation
pm47 Jun 6, 2022
a4c3ab4
added channel_type encoding tests with zeroconf/alias
pm47 Jun 6, 2022
14837e3
added roundtrip serialization test on channel_ready with alias
pm47 Jun 6, 2022
18a3e28
streamline channel_type handling in open api
pm47 Jun 6, 2022
7e41af2
(hopefully) fix race condition in ZeroConfAliasIntegrationSpec
pm47 Jun 6, 2022
1523c41
fix comment
pm47 Jun 6, 2022
0a5a239
force-close zero-conf channels if no remote_alias
pm47 Jun 8, 2022
9be02bf
support early channel_ready as funder
pm47 Jun 8, 2022
572136d
tentative race condition fix in MessageIntegrationSpec
pm47 Jun 8, 2022
a426e1b
emit TransactionConfirmed when funding txis deeply confirmed for zero…
pm47 Jun 8, 2022
34cc748
clean up the router scid map
pm47 Jun 8, 2022
896c4e5
increase timeout to encrypt bitcoin wallet in tests
pm47 Jun 9, 2022
31799b7
group all short ids in a class
pm47 Jun 9, 2022
0db76d4
fix scaladoc warnings
pm47 Jun 9, 2022
957f014
fix error: knownDirectSubclasses of RealShortChannelId observed befor…
pm47 Jun 9, 2022
db232e1
convert scid traits to case classes
pm47 Jun 10, 2022
c20f672
leverage 31799b7ae to simplify generation of routing hints
pm47 Jun 10, 2022
305124f
simplify scid.equals()
pm47 Jun 13, 2022
79ef2c3
Remove watch-confirmed with depth 0 in zero-conf (#2310)
t-bast Jun 13, 2022
189d101
Improve tests in #2224 (#2314)
t-bast Jun 14, 2022
b5f137f
implement waitFor with Thread.sleep
pm47 Jun 14, 2022
dcc5236
first draft of release notes
pm47 Jun 14, 2022
02bfd0f
test activation of zeroconf feature
pm47 Jun 14, 2022
a1ebd76
also remove real scid from the map on channel down
pm47 Jun 15, 2022
ac60f87
address review comments
pm47 Jun 15, 2022
4f6385b
fixup! test activation of zeroconf feature
pm47 Jun 15, 2022
04fc0e6
simplify and fix tests
pm47 Jun 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ eclair {
option_dual_fund = disabled
option_onion_messages = optional
option_channel_type = optional
option_scid_alias = optional
option_payment_metadata = optional
trampoline_payment_prototype = disabled
// By enabling option_zeroconf, you will be trusting your peers as fundee. You will lose funds if they double spend
// their funding tx.
option_zeroconf = disabled
t-bast marked this conversation as resolved.
Show resolved Hide resolved
keysend = disabled
trampoline_payment_prototype = disabled
}
override-init-features = [ // optional per-node features
# {
Expand Down
2 changes: 2 additions & 0 deletions eclair-core/src/main/scala/fr/acinq/eclair/BlockHeight.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ case class BlockHeight(private val underlying: Long) extends Ordered[BlockHeight
def toInt: Int = underlying.toInt
def toLong: Long = underlying
def toDouble: Double = underlying.toDouble

override def toString() = underlying.toString
// @formatter:on
}

Expand Down
20 changes: 12 additions & 8 deletions eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,18 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
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(
remoteNodeId = nodeId,
fundingSatoshis = fundingAmount,
pushMsat = pushAmount_opt.getOrElse(0 msat),
channelType_opt = channelType_opt,
fundingTxFeeratePerKw_opt = fundingFeeratePerByte_opt.map(FeeratePerKw(_)),
channelFlags = announceChannel_opt.map(announceChannel => ChannelFlags(announceChannel = announceChannel)),
timeout_opt = Some(openTimeout))).mapTo[ChannelOpenResponse]
for {
_ <- Future.successful(0)
open = Peer.OpenChannel(
remoteNodeId = nodeId,
fundingSatoshis = fundingAmount,
pushMsat = pushAmount_opt.getOrElse(0 msat),
channelType_opt = channelType_opt,
fundingTxFeeratePerKw_opt = fundingFeeratePerByte_opt.map(FeeratePerKw(_)),
channelFlags = announceChannel_opt.map(announceChannel => ChannelFlags(announceChannel = announceChannel)),
timeout_opt = Some(openTimeout))
res <- (appKit.switchboard ? open).mapTo[ChannelOpenResponse]
} yield res
t-bast marked this conversation as resolved.
Show resolved Hide resolved
}

override 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
16 changes: 14 additions & 2 deletions eclair-core/src/main/scala/fr/acinq/eclair/Features.scala
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,21 @@ object Features {
val mandatory = 44
}

case object ScidAlias extends Feature with InitFeature with NodeFeature with ChannelTypeFeature {
val rfcName = "option_scid_alias"
val mandatory = 46
}

case object PaymentMetadata extends Feature with InvoiceFeature {
val rfcName = "option_payment_metadata"
val mandatory = 48
}

case object ZeroConf extends Feature with InitFeature with NodeFeature with ChannelTypeFeature {
val rfcName = "option_zeroconf"
val mandatory = 50
}

case object KeySend extends Feature with NodeFeature {
val rfcName = "keysend"
val mandatory = 54
Expand Down Expand Up @@ -278,9 +288,11 @@ object Features {
DualFunding,
OnionMessages,
ChannelType,
ScidAlias,
PaymentMetadata,
TrampolinePaymentPrototype,
KeySend
ZeroConf,
KeySend,
TrampolinePaymentPrototype
)

// Features may depend on other features, as specified in Bolt 9.
Expand Down
13 changes: 12 additions & 1 deletion eclair-core/src/main/scala/fr/acinq/eclair/ShortChannelId.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package fr.acinq.eclair

trait RealShortChannelId extends ShortChannelId
trait LocalAlias extends ShortChannelId

/**
* A short channel id uniquely identifies a channel by the coordinates of its funding tx output in the blockchain.
* See BOLT 7: https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#requirements
Expand All @@ -24,6 +27,12 @@ case class ShortChannelId(private val id: Long) extends Ordered[ShortChannelId]

def toLong: Long = id

/** Careful: only call this if you are sure that this scid is actually a real scid */
def toReal: RealShortChannelId = new ShortChannelId(id) with RealShortChannelId

/** Careful: only call this if you are sure that this scid is actually a local alias */
def toAlias: LocalAlias = new ShortChannelId(id) with LocalAlias

def blockHeight = ShortChannelId.blockHeight(this)

override def toString: String = {
Expand All @@ -42,7 +51,7 @@ object ShortChannelId {
case _ => throw new IllegalArgumentException(s"Invalid short channel id: $s")
}

def apply(blockHeight: BlockHeight, txIndex: Int, outputIndex: Int): ShortChannelId = ShortChannelId(toShortId(blockHeight.toInt, txIndex, outputIndex))
def apply(blockHeight: BlockHeight, txIndex: Int, outputIndex: Int): RealShortChannelId = ShortChannelId(toShortId(blockHeight.toInt, txIndex, outputIndex)).toReal

def toShortId(blockHeight: Int, txIndex: Int, outputIndex: Int): Long = ((blockHeight & 0xFFFFFFL) << 40) | ((txIndex & 0xFFFFFFL) << 16) | (outputIndex & 0xFFFFL)

Expand All @@ -56,6 +65,8 @@ object ShortChannelId {
def outputIndex(shortChannelId: ShortChannelId): Int = (shortChannelId.id & 0xFFFF).toInt

def coordinates(shortChannelId: ShortChannelId): TxCoordinates = TxCoordinates(blockHeight(shortChannelId), txIndex(shortChannelId), outputIndex(shortChannelId))

def generateLocalAlias(): LocalAlias = new ShortChannelId(System.nanoTime()) with LocalAlias // TODO: fixme (duplicate, etc.)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ needs fixing, this is a dummy impl that leaks information on the creation date of the channel.

Since generating an alias only happens at channel creation, we can afford doing something "costly". For example this could be an AtomicLong that we initialize at startup by checking all currently assigned localAlias, and then we do an addAndGet with a random increment when we need to generate a new alias.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we really need a counter, wouldn't a randomLong() in the range that cannot be used by normal channels be enough?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot afford a duplicate here though and the space isn't that big. We should expect a collision for 5 billion attempts on 64 bits and only 80k attempts for 32 bits right? https://en.wikipedia.org/wiki/Birthday_attack

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true, the space isn't that big, but I'm afraid there may be privacy issues with generating those incrementally...I'll check what other implementations do

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some maths to confirm this, let me know if my calculations look correct:

  • scids are 64 bits long
  • we want to reserve the range [0; 2^22] for real scids
  • that leaves us with 2^42 available values for aliases
  • we'll consider that we want to have 250k channels using aliases (~2^18)
  • the probability of a collision is then p(n) ~= 2^36 / 2^43 ~= 0.8%

This is indeed not great! But using a counter that we increment leaks information about the approximate creation time of the channel, which could let an attacker find the channel outpoint on-chain...so I believe that what we should do instead is:

  • generate an alias randomly in the [2^22:2^64] range
  • check our alias map to see if it's already assigned and re-roll if it is

It means we'll probably need to send a message to the router to obtain a new alias, the router is where we can guarantee uniqueness.

}

case class TxCoordinates(blockHeight: BlockHeight, txIndex: Int, outputIndex: Int)
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ private class BalanceActor(context: ActorContext[Command],
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.OnchainConfirmed).update(result.onChain.confirmed.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.OnchainUnconfirmed).update(result.onChain.unconfirmed.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.waitForFundingConfirmed).update(result.offChain.waitForFundingConfirmed.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.waitForFundingLocked).update(result.offChain.waitForFundingLocked.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.waitForChannelReady).update(result.offChain.waitForChannelReady.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.normal).update(result.offChain.normal.total.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.shutdown).update(result.offChain.shutdown.total.toMilliBtc.toDouble)
Metrics.GlobalBalanceDetailed.withTag(Tags.BalanceType, Tags.BalanceTypes.Offchain).withTag(Tags.OffchainState, Tags.OffchainStates.closingLocal).update(result.offChain.closing.localCloseBalance.total.toMilliBtc.toDouble)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ object CheckBalance {
* The overall balance among all channels in all states.
*/
case class OffChainBalance(waitForFundingConfirmed: Btc = 0.sat,
waitForFundingLocked: Btc = 0.sat,
waitForChannelReady: Btc = 0.sat,
normal: MainAndHtlcBalance = MainAndHtlcBalance(),
shutdown: MainAndHtlcBalance = MainAndHtlcBalance(),
negotiating: Btc = 0.sat,
closing: ClosingBalance = ClosingBalance(),
waitForPublishFutureCommitment: Btc = 0.sat) {
val total: Btc = waitForFundingConfirmed + waitForFundingLocked + normal.total + shutdown.total + negotiating + closing.total + waitForPublishFutureCommitment
val total: Btc = waitForFundingConfirmed + waitForChannelReady + normal.total + shutdown.total + negotiating + closing.total + waitForPublishFutureCommitment
}

def updateMainBalance(localCommit: LocalCommit): Btc => Btc = { v: Btc =>
Expand Down Expand Up @@ -201,7 +201,7 @@ object CheckBalance {
channels
.foldLeft(OffChainBalance()) {
case (r, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => r.modify(_.waitForFundingConfirmed).using(updateMainBalance(d.commitments.localCommit))
case (r, d: DATA_WAIT_FOR_FUNDING_LOCKED) => r.modify(_.waitForFundingLocked).using(updateMainBalance(d.commitments.localCommit))
case (r, d: DATA_WAIT_FOR_CHANNEL_READY) => r.modify(_.waitForChannelReady).using(updateMainBalance(d.commitments.localCommit))
case (r, d: DATA_NORMAL) => r.modify(_.normal).using(updateMainAndHtlcBalance(d.commitments, knownPreimages))
case (r, d: DATA_SHUTDOWN) => r.modify(_.shutdown).using(updateMainAndHtlcBalance(d.commitments, knownPreimages))
case (r, d: DATA_NEGOTIATING) => r.modify(_.negotiating).using(updateMainBalance(d.commitments.localCommit))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object Monitoring {

object OffchainStates {
val waitForFundingConfirmed = "waitForFundingConfirmed"
val waitForFundingLocked = "waitForFundingLocked"
val waitForChannelReady = "waitForChannelReady"
val normal = "normal"
val shutdown = "shutdown"
val negotiating = "negotiating"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import akka.actor.typed.eventstream.EventStream
import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler}
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
import fr.acinq.bitcoin.scalacompat._
import fr.acinq.eclair.RealShortChannelId
import fr.acinq.eclair.blockchain.Monitoring.Metrics
import fr.acinq.eclair.blockchain._
import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient
Expand All @@ -30,7 +31,7 @@ import fr.acinq.eclair.{BlockHeight, KamonExt, NodeParams, ShortChannelId, Times
import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}
import scala.util.{Failure, Random, Success}

/**
* Created by PM on 21/02/2016.
Expand Down Expand Up @@ -136,8 +137,8 @@ object ZmqWatcher {
/** This event is sent when a [[WatchSpentBasic]] condition is met. */
sealed trait WatchSpentBasicTriggered extends WatchTriggered

case class WatchExternalChannelSpent(replyTo: ActorRef[WatchExternalChannelSpentTriggered], txId: ByteVector32, outputIndex: Int, shortChannelId: ShortChannelId) extends WatchSpentBasic[WatchExternalChannelSpentTriggered]
case class WatchExternalChannelSpentTriggered(shortChannelId: ShortChannelId) extends WatchSpentBasicTriggered
case class WatchExternalChannelSpent(replyTo: ActorRef[WatchExternalChannelSpentTriggered], txId: ByteVector32, outputIndex: Int, shortChannelId: RealShortChannelId) extends WatchSpentBasic[WatchExternalChannelSpentTriggered]
case class WatchExternalChannelSpentTriggered(shortChannelId: RealShortChannelId) extends WatchSpentBasicTriggered

case class WatchFundingSpent(replyTo: ActorRef[WatchFundingSpentTriggered], txId: ByteVector32, outputIndex: Int, hints: Set[ByteVector32]) extends WatchSpent[WatchFundingSpentTriggered]
case class WatchFundingSpentTriggered(spendingTx: Transaction) extends WatchSpentTriggered
Expand Down Expand Up @@ -236,6 +237,11 @@ private class ZmqWatcher(nodeParams: NodeParams, blockHeight: AtomicLong, client
case _: WatchConfirmed[_] => // nothing to do
case _: WatchFundingLost => // nothing to do
}
watches
.collect {
case w: WatchFundingConfirmed if w.minDepth == 0 && w.txId == tx.txid =>
checkConfirmed(w)
}
t-bast marked this conversation as resolved.
Show resolved Hide resolved
Behaviors.same

case ProcessNewBlock(blockHash) =>
Expand Down Expand Up @@ -406,13 +412,21 @@ private class ZmqWatcher(nodeParams: NodeParams, blockHeight: AtomicLong, client
client.getTxConfirmations(w.txId).flatMap {
case Some(confirmations) if confirmations >= w.minDepth =>
client.getTransaction(w.txId).flatMap { tx =>
client.getTransactionShortId(w.txId).map {
case (height, index) => w match {
case w: WatchFundingConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchFundingConfirmedTriggered(height, index, tx))
case w: WatchFundingDeeplyBuried => context.self ! TriggerEvent(w.replyTo, w, WatchFundingDeeplyBuriedTriggered(height, index, tx))
case w: WatchTxConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchTxConfirmedTriggered(height, index, tx))
case w: WatchParentTxConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchParentTxConfirmedTriggered(height, index, tx))
}
w match {
case w: WatchFundingConfirmed if confirmations == 0 =>
// if the tx doesn't have confirmations but we don't require any, we reply with a fake block index
// otherwise, we get the real short id
context.self ! TriggerEvent(w.replyTo, w, WatchFundingConfirmedTriggered(BlockHeight(0), 0, tx))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a blockheight 0 for unconfirmed transactions is a bit hacky.

Future.successful((): Unit)
case _ =>
client.getTransactionShortId(w.txId).map {
case (height, index) => w match {
case w: WatchFundingConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchFundingConfirmedTriggered(height, index, tx))
case w: WatchFundingDeeplyBuried => context.self ! TriggerEvent(w.replyTo, w, WatchFundingDeeplyBuriedTriggered(height, index, tx))
case w: WatchTxConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchTxConfirmedTriggered(height, index, tx))
case w: WatchParentTxConfirmed => context.self ! TriggerEvent(w.replyTo, w, WatchParentTxConfirmedTriggered(height, index, tx))
}
}
}
}
case _ => Future.successful((): Unit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ case class FeerateTolerance(ratioLow: Double, ratioHigh: Double, anchorOutputMax
channelType match {
case ChannelTypes.Standard | ChannelTypes.StaticRemoteKey =>
proposedFeerate < networkFeerate * ratioLow || networkFeerate * ratioHigh < proposedFeerate
case ChannelTypes.AnchorOutputs | ChannelTypes.AnchorOutputsZeroFeeHtlcTx =>
case ChannelTypes.AnchorOutputs | _: ChannelTypes.AnchorOutputsZeroFeeHtlcTx =>
// when using anchor outputs, we allow any feerate: fees will be set with CPFP and RBF at broadcast time
false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ object BlockchainWatchdog {
case CheckLatestHeaders(blockHeight) =>
val id = UUID.randomUUID()
if (headersOverDnsEnabled) {
context.spawn(HeadersOverDns(nodeParams.chainHash, blockHeight), s"${HeadersOverDns.Source}-${blockHeight.toLong}-$id") ! HeadersOverDns.CheckLatestHeaders(context.self)
context.spawn(HeadersOverDns(nodeParams.chainHash, blockHeight), s"${HeadersOverDns.Source}-${blockHeight}-$id") ! HeadersOverDns.CheckLatestHeaders(context.self)
}
explorers.foreach { explorer =>
context.spawn(ExplorerApi(nodeParams.chainHash, blockHeight, explorer), s"${explorer.name}-${blockHeight.toLong}-$id") ! ExplorerApi.CheckLatestHeaders(context.self)
context.spawn(ExplorerApi(nodeParams.chainHash, blockHeight, explorer), s"${explorer.name}-${blockHeight}-$id") ! ExplorerApi.CheckLatestHeaders(context.self)
}
Behaviors.same
case headers@LatestHeaders(blockHeight, blockHeaders, source) =>
Expand Down
Loading