mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 02:27:32 +01:00
Correctly set new channel balance (#1431)
When we announce a new public channel, make sure we don't override the balance information with None. Clean up IntegrationSpec warnings. Fix PaymentLifecycle test: this test was broken by the recent changes in BaseRouterSpec.
This commit is contained in:
parent
e0320da383
commit
2e79ccaf3f
@ -125,7 +125,9 @@ object Validation {
|
||||
val nodeAnn = Announcements.makeNodeAnnouncement(nodeParams.privateKey, nodeParams.alias, nodeParams.color, nodeParams.publicAddresses, nodeParams.features)
|
||||
ctx.self ! nodeAnn
|
||||
}
|
||||
Some(PublicChannel(c, tx.txid, capacity, None, None, None))
|
||||
// public channels that haven't yet been announced are considered as private channels
|
||||
val channelMeta_opt = d0.privateChannels.get(c.shortChannelId).map(_.meta)
|
||||
Some(PublicChannel(c, tx.txid, capacity, None, None, channelMeta_opt))
|
||||
}
|
||||
case ValidateResult(c, Right((tx, fundingTxStatus: UtxoStatus.Spent))) =>
|
||||
if (fundingTxStatus.spendingTxConfirmed) {
|
||||
|
@ -50,7 +50,7 @@ import fr.acinq.eclair.payment.send.PaymentLifecycle.{State => _}
|
||||
import fr.acinq.eclair.router.Graph.WeightRatios
|
||||
import fr.acinq.eclair.router.RouteCalculation.ROUTE_MAX_LENGTH
|
||||
import fr.acinq.eclair.router.Router.{GossipDecision, PublicChannel, RouteParams, NORMAL => _, State => _}
|
||||
import fr.acinq.eclair.router.{Announcements, AnnouncementsBatchValidationSpec}
|
||||
import fr.acinq.eclair.router.{Announcements, AnnouncementsBatchValidationSpec, Router}
|
||||
import fr.acinq.eclair.transactions.Transactions
|
||||
import fr.acinq.eclair.transactions.Transactions.{HtlcSuccessTx, HtlcTimeoutTx}
|
||||
import fr.acinq.eclair.wire._
|
||||
@ -62,7 +62,6 @@ import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.funsuite.AnyFunSuiteLike
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.compat.Platform
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
@ -122,11 +121,11 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
override def beforeAll: Unit = {
|
||||
startBitcoind()
|
||||
}
|
||||
|
||||
override def afterAll(): Unit = {
|
||||
override def afterAll: Unit = {
|
||||
// gracefully stopping bitcoin will make it store its state cleanly to disk, which is good for later debugging
|
||||
logger.info(s"stopping bitcoind")
|
||||
stopBitcoind()
|
||||
@ -157,7 +156,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
nodes = nodes + (name -> kit)
|
||||
}
|
||||
|
||||
def javaProps(props: Seq[(String, String)]) = {
|
||||
def javaProps(props: Seq[(String, String)]): Properties = {
|
||||
val properties = new Properties()
|
||||
props.foreach(p => properties.setProperty(p._1, p._2))
|
||||
properties
|
||||
@ -231,7 +230,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
awaitCond({
|
||||
val watches = nodes.values.foldLeft(Set.empty[Watch]) {
|
||||
case (watches, setup) =>
|
||||
sender.send(setup.watcher, 'watches)
|
||||
sender.send(setup.watcher, Symbol("watches"))
|
||||
watches ++ sender.expectMsgType[Set[Watch]]
|
||||
}
|
||||
watches.count(_.isInstanceOf[WatchConfirmed]) == channelEndpointsCount
|
||||
@ -253,15 +252,15 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
subset.foreach {
|
||||
case (_, setup) =>
|
||||
awaitCond({
|
||||
sender.send(setup.router, 'nodes)
|
||||
sender.send(setup.router, Symbol("nodes"))
|
||||
sender.expectMsgType[Iterable[NodeAnnouncement]](20 seconds).size == nodes
|
||||
}, max = 60 seconds, interval = 1 second)
|
||||
awaitCond({
|
||||
sender.send(setup.router, 'channels)
|
||||
sender.send(setup.router, Symbol("channels"))
|
||||
sender.expectMsgType[Iterable[ChannelAnnouncement]](20 seconds).size == channels
|
||||
}, max = 60 seconds, interval = 1 second)
|
||||
awaitCond({
|
||||
sender.send(setup.router, 'updates)
|
||||
sender.send(setup.router, Symbol("updates"))
|
||||
sender.expectMsgType[Iterable[ChannelUpdate]](20 seconds).size == updates
|
||||
}, max = 60 seconds, interval = 1 second)
|
||||
}
|
||||
@ -277,6 +276,17 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
awaitAnnouncements(nodes.filterKeys(key => !List("A", "B").contains(key)).toMap, 10, 12, 24)
|
||||
}
|
||||
|
||||
test("wait for channels balance") {
|
||||
// Channels balance should now be available in the router
|
||||
val sender = TestProbe()
|
||||
val nodeId = nodes("C").nodeParams.nodeId
|
||||
sender.send(nodes("C").router, Router.GetRoutingState)
|
||||
val routingState = sender.expectMsgType[Router.RoutingState]
|
||||
val publicChannels = routingState.channels.filter(pc => Set(pc.ann.nodeId1, pc.ann.nodeId2).contains(nodeId))
|
||||
assert(publicChannels.nonEmpty)
|
||||
publicChannels.foreach(pc => assert(pc.meta_opt.map(m => m.balance1 > 0.msat || m.balance2 > 0.msat) === Some(true), pc))
|
||||
}
|
||||
|
||||
test("open a wumbo channel and wait for longer than the default min_depth") {
|
||||
// we open a 5BTC channel and check that we scale `min_depth` up to 13 confirmations
|
||||
val funder = nodes("C")
|
||||
@ -295,7 +305,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
generateBlocks(bitcoincli, 2)
|
||||
|
||||
// get the channelId
|
||||
sender.send(fundee.register, 'channels)
|
||||
sender.send(fundee.register, Symbol("channels"))
|
||||
val Some((_, fundeeChannel)) = sender.expectMsgType[Map[ByteVector32, ActorRef]].find(_._1 == tempChannelId)
|
||||
sender.send(fundeeChannel, CMD_GETSTATEDATA)
|
||||
val channelId = sender.expectMsgType[HasCommitments].channelId
|
||||
@ -374,7 +384,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
val sender = TestProbe()
|
||||
// to simulate this, we will update B's relay params
|
||||
// first we find out the short channel id for channel B-C
|
||||
sender.send(nodes("B").router, 'channels)
|
||||
sender.send(nodes("B").router, Symbol("channels"))
|
||||
val shortIdBC = sender.expectMsgType[Iterable[ChannelAnnouncement]].find(c => Set(c.nodeId1, c.nodeId2) == Set(nodes("B").nodeParams.nodeId, nodes("C").nodeParams.nodeId)).get.shortChannelId
|
||||
// we also need the full commitment
|
||||
sender.send(nodes("B").register, ForwardShortId(shortIdBC, CMD_GETINFO))
|
||||
@ -399,7 +409,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
|
||||
awaitCond({
|
||||
// in the meantime, the router will have updated its state
|
||||
sender.send(nodes("A").router, 'channelsMap)
|
||||
sender.send(nodes("A").router, Symbol("channelsMap"))
|
||||
// we then put everything back like before by asking B to refresh its channel update (this will override the one we created)
|
||||
val u_opt = updateFor(nodes("B").nodeParams.nodeId, sender.expectMsgType[Map[ShortChannelId, PublicChannel]](10 seconds).apply(channelUpdateBC.shortChannelId))
|
||||
u_opt.contains(channelUpdateBC)
|
||||
@ -415,7 +425,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
assert(channelUpdateBC_new.timestamp > channelUpdateBC.timestamp)
|
||||
assert(channelUpdateBC_new.cltvExpiryDelta == nodes("B").nodeParams.expiryDeltaBlocks)
|
||||
awaitCond({
|
||||
sender.send(nodes("A").router, 'channelsMap)
|
||||
sender.send(nodes("A").router, Symbol("channelsMap"))
|
||||
val u = updateFor(nodes("B").nodeParams.nodeId, sender.expectMsgType[Map[ShortChannelId, PublicChannel]](10 seconds).apply(channelUpdateBC.shortChannelId)).get
|
||||
u.cltvExpiryDelta == nodes("B").nodeParams.expiryDeltaBlocks
|
||||
}, max = 30 seconds, interval = 1 second)
|
||||
@ -881,7 +891,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
val res = sender.expectMsgType[JValue](10 seconds)
|
||||
val previouslyReceivedByC = res.filter(_ \ "address" == JString(finalAddressC)).flatMap(_ \ "txids" \\ classOf[JString])
|
||||
// we then kill the connection between C and F
|
||||
sender.send(nodes("F1").switchboard, 'peers)
|
||||
sender.send(nodes("F1").switchboard, Symbol("peers"))
|
||||
val peers = sender.expectMsgType[Iterable[ActorRef]]
|
||||
// F's only node is C
|
||||
peers.head ! Peer.Disconnect(nodes("C").nodeParams.nodeId)
|
||||
@ -962,7 +972,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
val res = sender.expectMsgType[JValue](10 seconds)
|
||||
val previouslyReceivedByC = res.filter(_ \ "address" == JString(finalAddressC)).flatMap(_ \ "txids" \\ classOf[JString])
|
||||
// we then kill the connection between C and F
|
||||
sender.send(nodes("F2").switchboard, 'peers)
|
||||
sender.send(nodes("F2").switchboard, Symbol("peers"))
|
||||
val peers = sender.expectMsgType[Iterable[ActorRef]]
|
||||
// F's only node is C
|
||||
peers.head ! Disconnect(nodes("C").nodeParams.nodeId)
|
||||
@ -1274,7 +1284,7 @@ class IntegrationSpec extends TestKitBaseClass with BitcoindService with AnyFunS
|
||||
sender.expectMsg(GossipDecision.Accepted(ann))
|
||||
}
|
||||
awaitCond({
|
||||
sender.send(nodes("D").router, 'channels)
|
||||
sender.send(nodes("D").router, Symbol("channels"))
|
||||
sender.expectMsgType[Iterable[ChannelAnnouncement]](5 seconds).size == channels.size + 8 // 8 remaining channels because D->F{1-5} have disappeared
|
||||
}, max = 120 seconds, interval = 1 second)
|
||||
}
|
||||
|
@ -38,13 +38,12 @@ import fr.acinq.eclair.payment.relay.{Origin, Relayer}
|
||||
import fr.acinq.eclair.payment.send.PaymentInitiator.{SendPaymentConfig, SendPaymentRequest}
|
||||
import fr.acinq.eclair.payment.send.PaymentLifecycle
|
||||
import fr.acinq.eclair.payment.send.PaymentLifecycle._
|
||||
import fr.acinq.eclair.router.Announcements.{makeChannelUpdate, makeNodeAnnouncement}
|
||||
import fr.acinq.eclair.router.Announcements.makeChannelUpdate
|
||||
import fr.acinq.eclair.router.Router._
|
||||
import fr.acinq.eclair.router._
|
||||
import fr.acinq.eclair.transactions.Scripts
|
||||
import fr.acinq.eclair.wire.Onion.FinalLegacyPayload
|
||||
import fr.acinq.eclair.wire._
|
||||
import scodec.bits.HexStringSyntax
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
@ -487,38 +486,36 @@ class PaymentLifecycleSpec extends BaseRouterSpec {
|
||||
}
|
||||
|
||||
test("payment succeeded to a channel with fees=0") { routerFixture =>
|
||||
import fr.acinq.eclair.randomKey
|
||||
import routerFixture._
|
||||
|
||||
// the network will be a --(1)--> b ---(2)--> c --(3)--> d and e --(4)--> f (we are a) and b -> g has fees=0
|
||||
// \
|
||||
// \--(5)--> g
|
||||
val (priv_g, priv_funding_g) = (randomKey, randomKey)
|
||||
val (g, funding_g) = (priv_g.publicKey, priv_funding_g.publicKey)
|
||||
val ann_g = makeNodeAnnouncement(priv_g, "node-G", Color(-30, 10, -50), Nil, TestConstants.Bob.nodeParams.features)
|
||||
val channelId_bg = ShortChannelId(420000, 5, 0)
|
||||
val chan_bg = channelAnnouncement(channelId_bg, priv_b, priv_g, priv_funding_b, priv_funding_g)
|
||||
val channelUpdate_bg = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, g, channelId_bg, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 0 msat, feeProportionalMillionths = 0, htlcMaximumMsat = 500000000 msat)
|
||||
val channelUpdate_gb = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_g, b, channelId_bg, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 8, htlcMaximumMsat = 500000000 msat)
|
||||
assert(Router.getDesc(channelUpdate_bg, chan_bg) === ChannelDesc(chan_bg.shortChannelId, priv_b.publicKey, priv_g.publicKey))
|
||||
// the network will be a --(1)--> b ---(2)--> c --(3)--> d
|
||||
// | |
|
||||
// | +---(100)---+
|
||||
// | | and b -> h has fees = 0
|
||||
// +---(5)--> g ---(6)--> h
|
||||
// and e --(4)--> f (we are a)
|
||||
val channelId_bh = ShortChannelId(420000, 100, 0)
|
||||
val chan_bh = channelAnnouncement(channelId_bh, priv_b, priv_h, priv_funding_b, priv_funding_h)
|
||||
val channelUpdate_bh = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, h, channelId_bh, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 0 msat, feeProportionalMillionths = 0, htlcMaximumMsat = 500000000 msat)
|
||||
val channelUpdate_hb = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_h, b, channelId_bh, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 8, htlcMaximumMsat = 500000000 msat)
|
||||
assert(Router.getDesc(channelUpdate_bh, chan_bh) === ChannelDesc(channelId_bh, priv_b.publicKey, priv_h.publicKey))
|
||||
val peerConnection = TestProbe()
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, chan_bg)
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, ann_g)
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, channelUpdate_bg)
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, channelUpdate_gb)
|
||||
watcher.expectMsg(ValidateRequest(chan_bg))
|
||||
watcher.send(router, ValidateResult(chan_bg, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_g)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))))
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, chan_bh)
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, channelUpdate_bh)
|
||||
router ! PeerRoutingMessage(peerConnection.ref, remoteNodeId, channelUpdate_hb)
|
||||
watcher.expectMsg(ValidateRequest(chan_bh))
|
||||
watcher.send(router, ValidateResult(chan_bh, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_h)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))))
|
||||
watcher.expectMsgType[WatchSpentBasic]
|
||||
|
||||
val payFixture = createPaymentLifecycle()
|
||||
import payFixture._
|
||||
|
||||
// we send a payment to G
|
||||
val request = SendPayment(g, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), 5)
|
||||
// we send a payment to H
|
||||
val request = SendPayment(h, FinalLegacyPayload(defaultAmountMsat, defaultExpiry), 5)
|
||||
sender.send(paymentFSM, request)
|
||||
routerForwarder.expectMsgType[RouteRequest]
|
||||
|
||||
// the route will be A -> B -> G where B -> G has a channel_update with fees=0
|
||||
// the route will be A -> B -> H where B -> H has a channel_update with fees=0
|
||||
val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]])
|
||||
routerForwarder.forward(router)
|
||||
val Transition(_, WAITING_FOR_ROUTE, WAITING_FOR_PAYMENT_COMPLETE) = monitor.expectMsgClass(classOf[Transition[_]])
|
||||
@ -528,9 +525,8 @@ class PaymentLifecycleSpec extends BaseRouterSpec {
|
||||
val PaymentSent(_, _, paymentOK.paymentPreimage, finalAmount, _, PartialPayment(_, request.finalPayload.amount, fee, ByteVector32.Zeroes, _, _) :: Nil) = eventListener.expectMsgType[PaymentSent]
|
||||
assert(finalAmount === defaultAmountMsat)
|
||||
|
||||
// during the route computation the fees were treated as if they were 1msat but when sending the onion we actually put zero
|
||||
// NB: A -> B doesn't pay fees because it's our direct neighbor
|
||||
// NB: B -> G doesn't asks for fees at all
|
||||
// NB: B -> H doesn't asks for fees at all
|
||||
assert(fee === 0.msat)
|
||||
assert(paymentOK.recipientAmount === request.finalPayload.amount)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user