mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 10:39:19 +01:00
Enforce a minimum fee rate (#530)
* Enforce a minimum fee rate, with a default at 1 satoshi/byte Same value as bitcoin core's minimum relay fee * add `minFeeratePerByte` to `FallbackFeeProvider` and require that `FeeratesPerByte` and `FeeratesPerKw` be always > 0
This commit is contained in:
parent
1f6d180a0c
commit
bafa4557dc
@ -35,6 +35,7 @@ eclair {
|
||||
72 = 20
|
||||
}
|
||||
}
|
||||
min-feerate = 1 // minimum feerate in satoshis per byte (same default value as bitcoin core's minimum relay fee)
|
||||
|
||||
node-alias = "eclair"
|
||||
node-color = "49daaa"
|
||||
|
@ -126,74 +126,83 @@ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), act
|
||||
}
|
||||
|
||||
def bootstrap: Future[Kit] = {
|
||||
val zmqConnected = Promise[Boolean]()
|
||||
val tcpBound = Promise[Unit]()
|
||||
|
||||
val defaultFeerates = FeeratesPerByte(block_1 = config.getLong("default-feerates.delay-blocks.1"), blocks_2 = config.getLong("default-feerates.delay-blocks.2"), blocks_6 = config.getLong("default-feerates.delay-blocks.6"), blocks_12 = config.getLong("default-feerates.delay-blocks.12"), blocks_36 = config.getLong("default-feerates.delay-blocks.36"), blocks_72 = config.getLong("default-feerates.delay-blocks.72"))
|
||||
Globals.feeratesPerByte.set(defaultFeerates)
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw(defaultFeerates))
|
||||
logger.info(s"initial feeratesPerByte=${Globals.feeratesPerByte.get()}")
|
||||
val feeProvider = (nodeParams.chainHash, bitcoin) match {
|
||||
case (Block.RegtestGenesisBlock.hash, _) => new ConstantFeeProvider(defaultFeerates)
|
||||
case (_, Bitcoind(bitcoinClient)) => new FallbackFeeProvider(new BitgoFeeProvider(nodeParams.chainHash) :: new EarnDotComFeeProvider() :: new BitcoinCoreFeeProvider(bitcoinClient, defaultFeerates) :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
case _ => new FallbackFeeProvider(new BitgoFeeProvider(nodeParams.chainHash) :: new EarnDotComFeeProvider() :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
}
|
||||
system.scheduler.schedule(0 seconds, 10 minutes)(feeProvider.getFeerates.map {
|
||||
case feerates: FeeratesPerByte =>
|
||||
Globals.feeratesPerByte.set(feerates)
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw(feerates))
|
||||
system.eventStream.publish(CurrentFeerates(Globals.feeratesPerKw.get))
|
||||
logger.info(s"current feeratesPerByte=${Globals.feeratesPerByte.get()}")
|
||||
})
|
||||
|
||||
val watcher = bitcoin match {
|
||||
case Bitcoind(bitcoinClient) =>
|
||||
system.actorOf(SimpleSupervisor.props(Props(new ZMQActor(config.getString("bitcoind.zmq"), Some(zmqConnected))), "zmq", SupervisorStrategy.Restart))
|
||||
system.actorOf(SimpleSupervisor.props(ZmqWatcher.props(new ExtendedBitcoinClient(new BatchingBitcoinJsonRPCClient(bitcoinClient))), "watcher", SupervisorStrategy.Resume))
|
||||
case Electrum(electrumClient) =>
|
||||
zmqConnected.success(true)
|
||||
system.actorOf(SimpleSupervisor.props(Props(new ElectrumWatcher(electrumClient)), "watcher", SupervisorStrategy.Resume))
|
||||
}
|
||||
|
||||
val wallet = bitcoin match {
|
||||
case Bitcoind(bitcoinClient) => new BitcoinCoreWallet(bitcoinClient)
|
||||
case Electrum(electrumClient) =>
|
||||
val electrumWallet = system.actorOf(ElectrumWallet.props(seed, electrumClient, ElectrumWallet.WalletParameters(nodeParams.chainHash)), "electrum-wallet")
|
||||
new ElectrumEclairWallet(electrumWallet, nodeParams.chainHash)
|
||||
}
|
||||
wallet.getFinalAddress.map {
|
||||
case address => logger.info(s"initial wallet address=$address")
|
||||
}
|
||||
|
||||
val paymentHandler = system.actorOf(SimpleSupervisor.props(config.getString("payment-handler") match {
|
||||
case "local" => LocalPaymentHandler.props(nodeParams)
|
||||
case "noop" => Props[NoopPaymentHandler]
|
||||
}, "payment-handler", SupervisorStrategy.Resume))
|
||||
val register = system.actorOf(SimpleSupervisor.props(Props(new Register), "register", SupervisorStrategy.Resume))
|
||||
val relayer = system.actorOf(SimpleSupervisor.props(Relayer.props(nodeParams, register, paymentHandler), "relayer", SupervisorStrategy.Resume))
|
||||
val router = system.actorOf(SimpleSupervisor.props(Router.props(nodeParams, watcher), "router", SupervisorStrategy.Resume))
|
||||
val authenticator = system.actorOf(SimpleSupervisor.props(Authenticator.props(nodeParams), "authenticator", SupervisorStrategy.Resume))
|
||||
val switchboard = system.actorOf(SimpleSupervisor.props(Switchboard.props(nodeParams, authenticator, watcher, router, relayer, wallet), "switchboard", SupervisorStrategy.Resume))
|
||||
val server = system.actorOf(SimpleSupervisor.props(Server.props(nodeParams, authenticator, new InetSocketAddress(config.getString("server.binding-ip"), config.getInt("server.port")), Some(tcpBound)), "server", SupervisorStrategy.Restart))
|
||||
val paymentInitiator = system.actorOf(SimpleSupervisor.props(PaymentInitiator.props(nodeParams.nodeId, router, register), "payment-initiator", SupervisorStrategy.Restart))
|
||||
|
||||
val kit = Kit(
|
||||
nodeParams = nodeParams,
|
||||
system = system,
|
||||
watcher = watcher,
|
||||
paymentHandler = paymentHandler,
|
||||
register = register,
|
||||
relayer = relayer,
|
||||
router = router,
|
||||
switchboard = switchboard,
|
||||
paymentInitiator = paymentInitiator,
|
||||
server = server,
|
||||
wallet = wallet)
|
||||
|
||||
val zmqTimeout = after(5 seconds, using = system.scheduler)(Future.failed(BitcoinZMQConnectionTimeoutException))
|
||||
val tcpTimeout = after(5 seconds, using = system.scheduler)(Future.failed(TCPBindException(config.getInt("server.port"))))
|
||||
|
||||
for {
|
||||
_ <- Future.successful(true)
|
||||
feeratesRetrieved = Promise[Boolean]()
|
||||
zmqConnected = Promise[Boolean]()
|
||||
tcpBound = Promise[Unit]()
|
||||
|
||||
defaultFeerates = FeeratesPerByte(
|
||||
block_1 = config.getLong("default-feerates.delay-blocks.1"),
|
||||
blocks_2 = config.getLong("default-feerates.delay-blocks.2"),
|
||||
blocks_6 = config.getLong("default-feerates.delay-blocks.6"),
|
||||
blocks_12 = config.getLong("default-feerates.delay-blocks.12"),
|
||||
blocks_36 = config.getLong("default-feerates.delay-blocks.36"),
|
||||
blocks_72 = config.getLong("default-feerates.delay-blocks.72")
|
||||
)
|
||||
minFeeratePerByte = config.getLong("min-feerate")
|
||||
feeProvider = (nodeParams.chainHash, bitcoin) match {
|
||||
case (Block.RegtestGenesisBlock.hash, _) => new ConstantFeeProvider(defaultFeerates)
|
||||
case (_, Bitcoind(bitcoinClient)) => new FallbackFeeProvider(new BitgoFeeProvider(nodeParams.chainHash) :: new EarnDotComFeeProvider() :: new BitcoinCoreFeeProvider(bitcoinClient, defaultFeerates) :: new ConstantFeeProvider(defaultFeerates) :: Nil, minFeeratePerByte) // order matters!
|
||||
case _ => new FallbackFeeProvider(new BitgoFeeProvider(nodeParams.chainHash) :: new EarnDotComFeeProvider() :: new ConstantFeeProvider(defaultFeerates) :: Nil, minFeeratePerByte) // order matters!
|
||||
}
|
||||
_ = system.scheduler.schedule(0 seconds, 10 minutes)(feeProvider.getFeerates.map {
|
||||
case feerates: FeeratesPerByte =>
|
||||
Globals.feeratesPerByte.set(feerates)
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw(feerates))
|
||||
system.eventStream.publish(CurrentFeerates(Globals.feeratesPerKw.get))
|
||||
logger.info(s"current feeratesPerByte=${Globals.feeratesPerByte.get()}")
|
||||
feeratesRetrieved.trySuccess(true)
|
||||
})
|
||||
_ <- feeratesRetrieved.future
|
||||
|
||||
watcher = bitcoin match {
|
||||
case Bitcoind(bitcoinClient) =>
|
||||
system.actorOf(SimpleSupervisor.props(Props(new ZMQActor(config.getString("bitcoind.zmq"), Some(zmqConnected))), "zmq", SupervisorStrategy.Restart))
|
||||
system.actorOf(SimpleSupervisor.props(ZmqWatcher.props(new ExtendedBitcoinClient(new BatchingBitcoinJsonRPCClient(bitcoinClient))), "watcher", SupervisorStrategy.Resume))
|
||||
case Electrum(electrumClient) =>
|
||||
zmqConnected.success(true)
|
||||
system.actorOf(SimpleSupervisor.props(Props(new ElectrumWatcher(electrumClient)), "watcher", SupervisorStrategy.Resume))
|
||||
}
|
||||
|
||||
wallet = bitcoin match {
|
||||
case Bitcoind(bitcoinClient) => new BitcoinCoreWallet(bitcoinClient)
|
||||
case Electrum(electrumClient) =>
|
||||
val electrumWallet = system.actorOf(ElectrumWallet.props(seed, electrumClient, ElectrumWallet.WalletParameters(nodeParams.chainHash)), "electrum-wallet")
|
||||
new ElectrumEclairWallet(electrumWallet, nodeParams.chainHash)
|
||||
}
|
||||
_ = wallet.getFinalAddress.map {
|
||||
case address => logger.info(s"initial wallet address=$address")
|
||||
}
|
||||
|
||||
paymentHandler = system.actorOf(SimpleSupervisor.props(config.getString("payment-handler") match {
|
||||
case "local" => LocalPaymentHandler.props(nodeParams)
|
||||
case "noop" => Props[NoopPaymentHandler]
|
||||
}, "payment-handler", SupervisorStrategy.Resume))
|
||||
register = system.actorOf(SimpleSupervisor.props(Props(new Register), "register", SupervisorStrategy.Resume))
|
||||
relayer = system.actorOf(SimpleSupervisor.props(Relayer.props(nodeParams, register, paymentHandler), "relayer", SupervisorStrategy.Resume))
|
||||
router = system.actorOf(SimpleSupervisor.props(Router.props(nodeParams, watcher), "router", SupervisorStrategy.Resume))
|
||||
authenticator = system.actorOf(SimpleSupervisor.props(Authenticator.props(nodeParams), "authenticator", SupervisorStrategy.Resume))
|
||||
switchboard = system.actorOf(SimpleSupervisor.props(Switchboard.props(nodeParams, authenticator, watcher, router, relayer, wallet), "switchboard", SupervisorStrategy.Resume))
|
||||
server = system.actorOf(SimpleSupervisor.props(Server.props(nodeParams, authenticator, new InetSocketAddress(config.getString("server.binding-ip"), config.getInt("server.port")), Some(tcpBound)), "server", SupervisorStrategy.Restart))
|
||||
paymentInitiator = system.actorOf(SimpleSupervisor.props(PaymentInitiator.props(nodeParams.nodeId, router, register), "payment-initiator", SupervisorStrategy.Restart))
|
||||
|
||||
kit = Kit(
|
||||
nodeParams = nodeParams,
|
||||
system = system,
|
||||
watcher = watcher,
|
||||
paymentHandler = paymentHandler,
|
||||
register = register,
|
||||
relayer = relayer,
|
||||
router = router,
|
||||
switchboard = switchboard,
|
||||
paymentInitiator = paymentInitiator,
|
||||
server = server,
|
||||
wallet = wallet)
|
||||
|
||||
zmqTimeout = after(5 seconds, using = system.scheduler)(Future.failed(BitcoinZMQConnectionTimeoutException))
|
||||
tcpTimeout = after(5 seconds, using = system.scheduler)(Future.failed(TCPBindException(config.getInt("server.port"))))
|
||||
|
||||
_ <- Future.firstCompletedOf(zmqConnected.future :: zmqTimeout :: Nil)
|
||||
_ <- Future.firstCompletedOf(tcpBound.future :: tcpTimeout :: Nil)
|
||||
_ <- if (config.getBoolean("api.enabled")) {
|
||||
|
@ -23,6 +23,7 @@ import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||
import akka.stream.ActorMaterializer
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
|
||||
import fr.acinq.bitcoin.{BinaryData, Block}
|
||||
import fr.acinq.eclair.feerateKbToByte
|
||||
import org.json4s.JsonAST.{JInt, JValue}
|
||||
import org.json4s.{DefaultFormats, jackson}
|
||||
|
||||
@ -58,7 +59,7 @@ object BitgoFeeProvider {
|
||||
val blockTargets = json \ "feeByBlockTarget"
|
||||
blockTargets.foldField(Seq.empty[BlockTarget]) {
|
||||
// we divide by 1024 because bitgo returns estimates in Satoshi/Kb and we use estimates in Satoshi/Byte
|
||||
case (list, (strBlockTarget, JInt(feePerKb))) => list :+ BlockTarget(strBlockTarget.toInt, feePerKb.longValue() / 1024)
|
||||
case (list, (strBlockTarget, JInt(feePerKb))) => list :+ BlockTarget(strBlockTarget.toInt, feerateKbToByte(feePerKb.longValue()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,8 @@ object EarnDotComFeeProvider {
|
||||
def extractFeerate(feeRanges: Seq[FeeRange], maxBlockDelay: Int): Long = {
|
||||
// first we keep only fee ranges with a max block delay below the limit
|
||||
val belowLimit = feeRanges.filter(_.maxDelay <= maxBlockDelay)
|
||||
// out of all the remaining fee ranges, we select the one with the minimum higher bound
|
||||
belowLimit.minBy(_.maxFee).maxFee
|
||||
// out of all the remaining fee ranges, we select the one with the minimum higher bound and make sure it is > 0
|
||||
Math.max(belowLimit.minBy(_.maxFee).maxFee, 1)
|
||||
}
|
||||
|
||||
def extractFeerates(feeRanges: Seq[FeeRange]): FeeratesPerByte =
|
||||
|
@ -20,10 +20,14 @@ import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
/**
|
||||
* This provider will try all child providers in sequence, until one of them works
|
||||
*
|
||||
* @param providers a sequence of providers; they will be tried one after the others until one of them succeeds
|
||||
* @param minFeeratePerByte a configurable minimum value for feerates
|
||||
*/
|
||||
class FallbackFeeProvider(providers: Seq[FeeProvider])(implicit ec: ExecutionContext) extends FeeProvider {
|
||||
class FallbackFeeProvider(providers: Seq[FeeProvider], minFeeratePerByte: Long)(implicit ec: ExecutionContext) extends FeeProvider {
|
||||
|
||||
require(providers.size >= 1, "need at least one fee provider")
|
||||
require(minFeeratePerByte > 0, "minimum fee rate must be strictly greater than 0")
|
||||
|
||||
def getFeerates(fallbacks: Seq[FeeProvider]): Future[FeeratesPerByte] =
|
||||
fallbacks match {
|
||||
@ -31,6 +35,19 @@ class FallbackFeeProvider(providers: Seq[FeeProvider])(implicit ec: ExecutionCon
|
||||
case head +: remaining => head.getFeerates.recoverWith { case _ => getFeerates(remaining) }
|
||||
}
|
||||
|
||||
override def getFeerates: Future[FeeratesPerByte] = getFeerates(providers)
|
||||
override def getFeerates: Future[FeeratesPerByte] = getFeerates(providers).map(FallbackFeeProvider.enforceMinimumFeerate(_, minFeeratePerByte))
|
||||
|
||||
}
|
||||
|
||||
object FallbackFeeProvider {
|
||||
|
||||
def enforceMinimumFeerate(feeratesPerByte: FeeratesPerByte, minFeeratePerByte: Long) : FeeratesPerByte = feeratesPerByte.copy(
|
||||
block_1 = Math.max(feeratesPerByte.block_1, minFeeratePerByte),
|
||||
blocks_2 = Math.max(feeratesPerByte.blocks_2, minFeeratePerByte),
|
||||
blocks_6 = Math.max(feeratesPerByte.blocks_6, minFeeratePerByte),
|
||||
blocks_12 = Math.max(feeratesPerByte.blocks_12, minFeeratePerByte),
|
||||
blocks_36 = Math.max(feeratesPerByte.blocks_36, minFeeratePerByte),
|
||||
blocks_72 = Math.max(feeratesPerByte.blocks_72, minFeeratePerByte)
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -29,9 +29,13 @@ trait FeeProvider {
|
||||
|
||||
}
|
||||
|
||||
case class FeeratesPerByte(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long)
|
||||
case class FeeratesPerByte(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long) {
|
||||
require(block_1 > 0 && blocks_2 > 0 && blocks_6 > 0 && blocks_12 > 0 && blocks_36 > 0 && blocks_72 > 0, "all feerates must be strictly greater than 0")
|
||||
}
|
||||
|
||||
case class FeeratesPerKw(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long)
|
||||
case class FeeratesPerKw(block_1: Long, blocks_2: Long, blocks_6: Long, blocks_12: Long, blocks_36: Long, blocks_72: Long) {
|
||||
require(block_1 > 0 && blocks_2 > 0 && blocks_6 > 0 && blocks_12 > 0 && blocks_36 > 0 && blocks_72 > 0, "all feerates must be strictly greater than 0")
|
||||
}
|
||||
|
||||
object FeeratesPerKw {
|
||||
def apply(feerates: FeeratesPerByte): FeeratesPerKw = FeeratesPerKw(
|
||||
|
@ -96,8 +96,7 @@ object Helpers {
|
||||
Math.abs((2.0 * (remoteFeeratePerKw - localFeeratePerKw)) / (localFeeratePerKw + remoteFeeratePerKw))
|
||||
|
||||
def shouldUpdateFee(commitmentFeeratePerKw: Long, networkFeeratePerKw: Long, updateFeeMinDiffRatio: Double): Boolean =
|
||||
// negative feerate can happen in regtest mode
|
||||
networkFeeratePerKw > 0 && feeRateMismatch(networkFeeratePerKw, commitmentFeeratePerKw) > updateFeeMinDiffRatio
|
||||
feeRateMismatch(networkFeeratePerKw, commitmentFeeratePerKw) > updateFeeMinDiffRatio
|
||||
|
||||
/**
|
||||
*
|
||||
@ -107,10 +106,8 @@ object Helpers {
|
||||
* @return true if the difference between local and remote fee rates is too high.
|
||||
* the actual check is |remote - local| / avg(local, remote) > mismatch ratio
|
||||
*/
|
||||
def isFeeDiffTooHigh(remoteFeeratePerKw: Long, localFeeratePerKw: Long, maxFeerateMismatchRatio: Double): Boolean = {
|
||||
// negative feerate can happen in regtest mode
|
||||
remoteFeeratePerKw > 0 && feeRateMismatch(remoteFeeratePerKw, localFeeratePerKw) > maxFeerateMismatchRatio
|
||||
}
|
||||
def isFeeDiffTooHigh(remoteFeeratePerKw: Long, localFeeratePerKw: Long, maxFeerateMismatchRatio: Double): Boolean =
|
||||
feeRateMismatch(remoteFeeratePerKw, localFeeratePerKw) > maxFeerateMismatchRatio
|
||||
|
||||
def makeAnnouncementSignatures(nodeParams: NodeParams, commitments: Commitments, shortChannelId: ShortChannelId) = {
|
||||
val features = BinaryData.empty // empty features for now
|
||||
|
@ -51,6 +51,8 @@ package object eclair {
|
||||
case Attempt.Failure(cause) => throw new RuntimeException(s"serialization error: $cause")
|
||||
}
|
||||
|
||||
def feerateKbToByte(feeratePerKb: Long): Long = Math.max(feeratePerKb / 1024, 1)
|
||||
|
||||
/**
|
||||
* Converts feerate in satoshi-per-bytes to feerate in satoshi-per-kw
|
||||
*
|
||||
|
@ -44,7 +44,7 @@ abstract class TestkitBaseClass extends TestKit(ActorSystem("test")) with fixtur
|
||||
|
||||
override def afterAll {
|
||||
TestKit.shutdownActorSystem(system)
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(0))
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(1))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class FallbackFeeProviderSpec extends FunSuite {
|
||||
val provider5 = new FailingFeeProvider(5, dummyFeerates) // fails after 5 tries
|
||||
val provider7 = new FailingFeeProvider(Int.MaxValue, dummyFeerates) // "never" fails
|
||||
|
||||
val fallbackFeeProvider = new FallbackFeeProvider(provider0 :: provider1 :: provider3 :: provider5 :: provider7 :: Nil)
|
||||
val fallbackFeeProvider = new FallbackFeeProvider(provider0 :: provider1 :: provider3 :: provider5 :: provider7 :: Nil, 1)
|
||||
|
||||
assert(await(fallbackFeeProvider.getFeerates) === provider1.feeratesPerByte)
|
||||
|
||||
@ -74,5 +74,11 @@ class FallbackFeeProviderSpec extends FunSuite {
|
||||
|
||||
}
|
||||
|
||||
test("ensure minimum feerate") {
|
||||
val constantFeeProvider = new ConstantFeeProvider(FeeratesPerByte(1, 1, 1, 1, 1, 1))
|
||||
val fallbackFeeProvider = new FallbackFeeProvider(constantFeeProvider :: Nil, 2)
|
||||
assert(await(fallbackFeeProvider.getFeerates) === FeeratesPerByte(2, 2, 2, 2, 2, 2))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1576,16 +1576,6 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CurrentFeerate (ignore negative feerate)") { case (alice, _, alice2bob, _, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
// this happens when in regtest mode
|
||||
val event = CurrentFeerates(FeeratesPerKw.single(-1))
|
||||
sender.send(alice, event)
|
||||
alice2bob.expectNoMsg(500 millis)
|
||||
}
|
||||
}
|
||||
|
||||
test("recv BITCOIN_FUNDING_SPENT (their commit w/ htlc)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
|
@ -616,16 +616,6 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CurrentFeerate (ignore negative feerate)") { case (alice, _, alice2bob, _, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
// this happens when in regtest mode
|
||||
val event = CurrentFeerates(FeeratesPerKw.single(-1))
|
||||
sender.send(alice, event)
|
||||
alice2bob.expectNoMsg(500 millis)
|
||||
}
|
||||
}
|
||||
|
||||
test("recv BITCOIN_FUNDING_SPENT (their commit)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, _, _) =>
|
||||
within(30 seconds) {
|
||||
// bob publishes his current commit tx, which contains two pending htlcs alice->bob
|
||||
|
@ -83,7 +83,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix
|
||||
}
|
||||
|
||||
override def afterAll {
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(0))
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(1))
|
||||
TestKit.shutdownActorSystem(system)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user