mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-13 19:37:35 +01:00
Merge commit '3b7afd92d47bad552de7f93ce34e244939ed1fdc' into android
This commit is contained in:
commit
48a5ac2e16
12 changed files with 54 additions and 51 deletions
|
@ -8,9 +8,9 @@ scala:
|
|||
env:
|
||||
- export LD_LIBRARY_PATH=/usr/local/lib
|
||||
before_install:
|
||||
- wget http://mirror.ibcp.fr/pub/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.zip
|
||||
- unzip -qq apache-maven-3.5.4-bin.zip
|
||||
- export M2_HOME=$PWD/apache-maven-3.5.4
|
||||
- wget http://apache.crihan.fr/dist/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.zip
|
||||
- unzip -qq apache-maven-3.6.0-bin.zip
|
||||
- export M2_HOME=$PWD/apache-maven-3.6.0
|
||||
- export PATH=$M2_HOME/bin:$PATH
|
||||
script:
|
||||
- mvn install
|
||||
|
|
2
BUILD.md
2
BUILD.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Requirements
|
||||
- [OpenJDK 11](https://jdk.java.net/11/).
|
||||
- [Maven](https://maven.apache.org/download.cgi) 3.5.4 or newer
|
||||
- [Maven](https://maven.apache.org/download.cgi) 3.6.0 or newer
|
||||
- [Docker](https://www.docker.com/) 18.03 or newer (optional) if you want to run all tests
|
||||
|
||||
:warning: You can also use [Oracle JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) to build and run eclair, but we recommend you use Open JDK11.
|
||||
|
|
|
@ -6,7 +6,7 @@ FROM openjdk:8u171-jdk-alpine as BUILD
|
|||
|
||||
RUN apk add --no-cache curl tar bash
|
||||
|
||||
ARG MAVEN_VERSION=3.5.4
|
||||
ARG MAVEN_VERSION=3.6.0
|
||||
ARG USER_HOME_DIR="/root"
|
||||
ARG SHA=ce50b1c91364cb77efe3776f756a6d92b76d9038b0a0782f7d53acf1e997a14d
|
||||
ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
|
||||
|
|
|
@ -339,7 +339,7 @@ class Peer(nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: Actor
|
|||
case (count, (_, origins)) if origins.contains(self) =>
|
||||
// the announcement came from this peer, we don't send it back
|
||||
count
|
||||
case (count, (msg: HasTimestamp, _)) if !timestampInRange(msg, d.gossipTimestampFilter) =>
|
||||
case (count, (msg, _)) if !timestampInRange(msg, d.gossipTimestampFilter) =>
|
||||
// the peer has set up a filter on timestamp and this message is out of range
|
||||
count
|
||||
case (count, (msg, _)) =>
|
||||
|
@ -606,14 +606,15 @@ object Peer {
|
|||
*
|
||||
* @param gossipTimestampFilter_opt optional gossip timestamp range
|
||||
* @return
|
||||
* - true if the msg's timestamp is in the requested range, or if there is no filtering
|
||||
* - true if there is a filter and msg has no timestamp, or has one that matches the filter
|
||||
* - false otherwise
|
||||
*/
|
||||
def timestampInRange(msg: HasTimestamp, gossipTimestampFilter_opt: Option[GossipTimestampFilter]): Boolean = {
|
||||
def timestampInRange(msg: RoutingMessage, gossipTimestampFilter_opt: Option[GossipTimestampFilter]): Boolean = {
|
||||
// check if this message has a timestamp that matches our timestamp filter
|
||||
gossipTimestampFilter_opt match {
|
||||
case None => true // no filtering
|
||||
case Some(GossipTimestampFilter(_, firstTimestamp, timestampRange)) => msg.timestamp >= firstTimestamp && msg.timestamp <= firstTimestamp + timestampRange
|
||||
(msg, gossipTimestampFilter_opt) match {
|
||||
case (_, None) => false // BOLT 7: A node which wants any gossip messages would have to send this, otherwise [...] no gossip messages would be received.
|
||||
case (hasTs: HasTimestamp, Some(GossipTimestampFilter(_, firstTimestamp, timestampRange))) => hasTs.timestamp >= firstTimestamp && hasTs.timestamp <= firstTimestamp + timestampRange
|
||||
case _ => true // if there is a filter and message doesn't have a timestamp (e.g. channel_announcement), then we send it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ trait StateTestsHelperMethods extends TestKitBase {
|
|||
relayerB: TestProbe,
|
||||
channelUpdateListener: TestProbe)
|
||||
|
||||
def init(nodeParamsA: NodeParams = TestConstants.Alice.nodeParams, nodeParamsB: NodeParams = TestConstants.Bob.nodeParams): SetupFixture = {
|
||||
def init(nodeParamsA: NodeParams = TestConstants.Alice.nodeParams, nodeParamsB: NodeParams = TestConstants.Bob.nodeParams, wallet: EclairWallet = new TestWallet): SetupFixture = {
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(TestConstants.feeratePerKw))
|
||||
val alice2bob = TestProbe()
|
||||
val bob2alice = TestProbe()
|
||||
|
@ -59,7 +59,6 @@ trait StateTestsHelperMethods extends TestKitBase {
|
|||
system.eventStream.subscribe(channelUpdateListener.ref, classOf[LocalChannelUpdate])
|
||||
system.eventStream.subscribe(channelUpdateListener.ref, classOf[LocalChannelDown])
|
||||
val router = TestProbe()
|
||||
val wallet = new TestWallet
|
||||
val alice: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(nodeParamsA, wallet, Bob.nodeParams.nodeId, alice2blockchain.ref, router.ref, relayerA.ref))
|
||||
val bob: TestFSMRef[State, Data, Channel] = TestFSMRef(new Channel(nodeParamsB, wallet, Alice.nodeParams.nodeId, bob2blockchain.ref, router.ref, relayerB.ref))
|
||||
SetupFixture(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, router, relayerA, relayerB, channelUpdateListener)
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
package fr.acinq.eclair.channel.states.a
|
||||
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.{Block, ByteVector32}
|
||||
import fr.acinq.bitcoin.{Block, ByteVector32, Satoshi}
|
||||
import fr.acinq.eclair.TestConstants.{Alice, Bob}
|
||||
import fr.acinq.eclair.blockchain.{MakeFundingTxResponse, TestWallet}
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.channel.{WAIT_FOR_FUNDING_INTERNAL, _}
|
||||
import fr.acinq.eclair.wire.{AcceptChannel, Error, Init, OpenChannel}
|
||||
import fr.acinq.eclair.{TestConstants, TestkitBaseClass}
|
||||
import org.scalatest.{Outcome, Tag}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.concurrent.{Future, Promise}
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
|
@ -36,10 +39,13 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp
|
|||
case class FixtureParam(alice: TestFSMRef[State, Data, Channel], alice2bob: TestProbe, bob2alice: TestProbe, alice2blockchain: TestProbe)
|
||||
|
||||
override def withFixture(test: OneArgTest): Outcome = {
|
||||
val noopWallet = new TestWallet {
|
||||
override def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRatePerKw: Long): Future[MakeFundingTxResponse] = Promise[MakeFundingTxResponse].future // will never be completed
|
||||
}
|
||||
val setup = if (test.tags.contains("mainnet")) {
|
||||
init(TestConstants.Alice.nodeParams.copy(chainHash = Block.LivenetGenesisBlock.hash), TestConstants.Bob.nodeParams.copy(chainHash = Block.LivenetGenesisBlock.hash))
|
||||
init(TestConstants.Alice.nodeParams.copy(chainHash = Block.LivenetGenesisBlock.hash), TestConstants.Bob.nodeParams.copy(chainHash = Block.LivenetGenesisBlock.hash), wallet = noopWallet)
|
||||
} else {
|
||||
init()
|
||||
init(wallet = noopWallet)
|
||||
}
|
||||
import setup._
|
||||
val aliceInit = Init(Alice.channelParams.globalFeatures, Alice.channelParams.localFeatures)
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
package fr.acinq.eclair.channel.states.b
|
||||
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.ByteVector32
|
||||
import fr.acinq.bitcoin.{ByteVector32, Satoshi}
|
||||
import fr.acinq.eclair.TestConstants.{Alice, Bob}
|
||||
import fr.acinq.eclair.blockchain.{MakeFundingTxResponse, TestWallet}
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.wire._
|
||||
import fr.acinq.eclair.{TestConstants, TestkitBaseClass}
|
||||
import org.scalatest.Outcome
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.concurrent.{Future, Promise}
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
|
@ -36,7 +39,10 @@ class WaitForFundingCreatedInternalStateSpec extends TestkitBaseClass with State
|
|||
case class FixtureParam(alice: TestFSMRef[State, Data, Channel], alice2bob: TestProbe, bob2alice: TestProbe, alice2blockchain: TestProbe)
|
||||
|
||||
override def withFixture(test: OneArgTest): Outcome = {
|
||||
val setup = init()
|
||||
val noopWallet = new TestWallet {
|
||||
override def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRatePerKw: Long): Future[MakeFundingTxResponse] = Promise[MakeFundingTxResponse].future // will never be completed
|
||||
}
|
||||
val setup = init(wallet = noopWallet)
|
||||
import setup._
|
||||
val aliceInit = Init(Alice.channelParams.globalFeatures, Alice.channelParams.localFeatures)
|
||||
val bobInit = Init(Bob.channelParams.globalFeatures, Bob.channelParams.localFeatures)
|
||||
|
|
|
@ -67,7 +67,7 @@ class SqliteNetworkDbSpec extends FunSuite {
|
|||
val sqlite = inmem
|
||||
val db = new SqliteNetworkDb(sqlite)
|
||||
|
||||
def sig = Crypto.encodeSignature(Crypto.sign(randomKey.toBin, randomKey)) :+ 1.toByte
|
||||
def sig = Crypto.encodeSignature(Crypto.sign(randomBytes32, randomKey)) :+ 1.toByte
|
||||
|
||||
val channel_1 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, ShortChannelId(42), randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, sig, sig, sig, sig)
|
||||
val channel_2 = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, ShortChannelId(43), randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, sig, sig, sig, sig)
|
||||
|
@ -107,7 +107,7 @@ class SqliteNetworkDbSpec extends FunSuite {
|
|||
test("remove many channels") {
|
||||
val sqlite = inmem
|
||||
val db = new SqliteNetworkDb(sqlite)
|
||||
val sig = Crypto.encodeSignature(Crypto.sign(randomKey.toBin, randomKey)) :+ 1.toByte
|
||||
val sig = Crypto.encodeSignature(Crypto.sign(randomBytes32, randomKey)) :+ 1.toByte
|
||||
val priv = randomKey
|
||||
val pub = priv.publicKey
|
||||
val capacity = Satoshi(10000)
|
||||
|
|
|
@ -149,6 +149,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
instantiateEclairNode("F3", ConfigFactory.parseMap(Map("eclair.node-alias" -> "F3", "eclair.expiry-delta-blocks" -> 137, "eclair.server.port" -> 29737, "eclair.api.port" -> 28087, "eclair.payment-handler" -> "noop")).withFallback(commonConfig))
|
||||
instantiateEclairNode("F4", ConfigFactory.parseMap(Map("eclair.node-alias" -> "F4", "eclair.expiry-delta-blocks" -> 138, "eclair.server.port" -> 29738, "eclair.api.port" -> 28088, "eclair.payment-handler" -> "noop")).withFallback(commonConfig))
|
||||
instantiateEclairNode("F5", ConfigFactory.parseMap(Map("eclair.node-alias" -> "F5", "eclair.expiry-delta-blocks" -> 139, "eclair.server.port" -> 29739, "eclair.api.port" -> 28089, "eclair.payment-handler" -> "noop")).withFallback(commonConfig))
|
||||
instantiateEclairNode("G", ConfigFactory.parseMap(Map("eclair.node-alias" -> "G", "eclair.expiry-delta-blocks" -> 140, "eclair.server.port" -> 29740, "eclair.api.port" -> 28090, "eclair.fee-base-msat" -> 1010, "eclair.fee-proportional-millionths" -> 102)).withFallback(commonConfig))
|
||||
|
||||
// by default C has a normal payment handler, but this can be overriden in tests
|
||||
val paymentHandlerC = nodes("C").system.actorOf(LocalPaymentHandler.props(nodes("C").nodeParams))
|
||||
|
@ -172,7 +173,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
}
|
||||
|
||||
test("connect nodes") {
|
||||
// ,--G--, // G is being added later in a test
|
||||
// ,--G--,
|
||||
// / \
|
||||
// A---B ------- C ==== D
|
||||
// \ / \
|
||||
|
@ -182,7 +183,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
val eventListener = TestProbe()
|
||||
nodes.values.foreach(_.system.eventStream.subscribe(eventListener.ref, classOf[ChannelStateChanged]))
|
||||
|
||||
connect(nodes("A"), nodes("B"), 10000000, 0)
|
||||
connect(nodes("A"), nodes("B"), 11000000, 0)
|
||||
connect(nodes("B"), nodes("C"), 2000000, 0)
|
||||
connect(nodes("C"), nodes("D"), 5000000, 0)
|
||||
connect(nodes("C"), nodes("D"), 5000000, 0)
|
||||
|
@ -193,8 +194,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
connect(nodes("C"), nodes("F3"), 5000000, 0)
|
||||
connect(nodes("C"), nodes("F4"), 5000000, 0)
|
||||
connect(nodes("C"), nodes("F5"), 5000000, 0)
|
||||
connect(nodes("B"), nodes("G"), 16000000, 0)
|
||||
connect(nodes("G"), nodes("C"), 16000000, 0)
|
||||
|
||||
val numberOfChannels = 11
|
||||
val numberOfChannels = 13
|
||||
val channelEndpointsCount = 2 * numberOfChannels
|
||||
|
||||
// we make sure all channels have set up their WatchConfirmed for the funding tx
|
||||
|
@ -246,8 +249,8 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
// A requires private channels, as a consequence:
|
||||
// - only A and B know about channel A-B
|
||||
// - A is not announced
|
||||
awaitAnnouncements(nodes.filterKeys(key => List("A", "B").contains(key)), 9, 10, 22)
|
||||
awaitAnnouncements(nodes.filterKeys(key => !List("A", "B").contains(key)), 9, 10, 20)
|
||||
awaitAnnouncements(nodes.filterKeys(key => List("A", "B").contains(key)), 10, 12, 26)
|
||||
awaitAnnouncements(nodes.filterKeys(key => !List("A", "B").contains(key)), 10, 12, 24)
|
||||
}
|
||||
|
||||
test("send an HTLC A->D") {
|
||||
|
@ -399,33 +402,21 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService
|
|||
|
||||
test("send an HTLC A->B->G->C using heuristics to select the route") {
|
||||
val sender = TestProbe()
|
||||
|
||||
// G has very large channels but slightly more expensive than the others
|
||||
instantiateEclairNode("G", ConfigFactory.parseMap(Map("eclair.node-alias" -> "G", "eclair.expiry-delta-blocks" -> 140, "eclair.server.port" -> 29740, "eclair.api.port" -> 28090, "eclair.fee-base-msat" -> 1010, "eclair.fee-proportional-millionths" -> 102)).withFallback(commonConfig))
|
||||
connect(nodes("B"), nodes("G"), 16000000, 0)
|
||||
connect(nodes("G"), nodes("C"), 16000000, 0)
|
||||
|
||||
sender.send(bitcoincli, BitcoinReq("generate", 10))
|
||||
sender.expectMsgType[JValue](10 seconds)
|
||||
|
||||
awaitCond({
|
||||
sender.send(nodes("A").router, 'channels)
|
||||
sender.expectMsgType[Iterable[ChannelAnnouncement]](5 seconds).exists(chanAnn => chanAnn.nodeId1 == nodes("G").nodeParams.nodeId || chanAnn.nodeId2 == nodes("G").nodeParams.nodeId)
|
||||
}, max = 60 seconds, interval = 3 seconds)
|
||||
|
||||
val amountMsat = MilliSatoshi(2000)
|
||||
// first we retrieve a payment hash from C
|
||||
val amountMsat = MilliSatoshi(2000)
|
||||
sender.send(nodes("C").paymentHandler, ReceivePayment(Some(amountMsat), "Change from coffee"))
|
||||
val pr = sender.expectMsgType[PaymentRequest](30 seconds)
|
||||
|
||||
// the payment is requesting to use a capacity-optimized route which will select node G even though it's a bit more expensive
|
||||
sender.send(nodes("A").paymentInitiator,
|
||||
SendPayment(amountMsat.amount, pr.paymentHash, nodes("C").nodeParams.nodeId, routeParams = integrationTestRouteParams.map(_.copy(ratios = Some(WeightRatios(0, 0, 1))))))
|
||||
SendPayment(amountMsat.amount, pr.paymentHash, nodes("C").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams.map(_.copy(ratios = Some(WeightRatios(0, 0, 1))))))
|
||||
|
||||
awaitCond({
|
||||
val route = sender.expectMsgType[PaymentSucceeded].route
|
||||
route.exists(_.nodeId == nodes("G").nodeParams.nodeId) // assert the used route is actually going through G
|
||||
}, max = 30 seconds, interval = 3 seconds)
|
||||
sender.expectMsgType[PaymentResult](10 seconds) match {
|
||||
case PaymentFailed(_, failures) => failures == Seq.empty // if something went wrong fail with a hint
|
||||
case PaymentSucceeded(_, _, _, route) => route.exists(_.nodeId == nodes("G").nodeParams.nodeId)
|
||||
}
|
||||
}, max = 30 seconds, interval = 10 seconds)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -109,9 +109,7 @@ class PeerSpec extends TestkitBaseClass {
|
|||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer)
|
||||
val rebroadcast = Rebroadcast(channels.map(_ -> Set.empty[ActorRef]).toMap, updates.map(_ -> Set.empty[ActorRef]).toMap, nodes.map(_ -> Set.empty[ActorRef]).toMap)
|
||||
probe.send(peer, rebroadcast)
|
||||
channels.foreach(transport.expectMsg(_))
|
||||
updates.foreach(transport.expectMsg(_))
|
||||
nodes.foreach(transport.expectMsg(_))
|
||||
transport.expectNoMsg(2 seconds)
|
||||
}
|
||||
|
||||
test("filter gossip message (filtered by origin)") { f =>
|
||||
|
@ -122,6 +120,8 @@ class PeerSpec extends TestkitBaseClass {
|
|||
channels.map(_ -> Set.empty[ActorRef]).toMap + (channels(5) -> Set(peer)),
|
||||
updates.map(_ -> Set.empty[ActorRef]).toMap + (updates(6) -> Set(peer)) + (updates(10) -> Set(peer)),
|
||||
nodes.map(_ -> Set.empty[ActorRef]).toMap + (nodes(4) -> Set(peer)))
|
||||
val filter = wire.GossipTimestampFilter(Alice.nodeParams.chainHash, 0, Long.MaxValue) // no filtering on timestamps
|
||||
probe.send(peer, filter)
|
||||
probe.send(peer, rebroadcast)
|
||||
// peer won't send out announcements that came from itself
|
||||
(channels.toSet - channels(5)).foreach(transport.expectMsg(_))
|
||||
|
|
|
@ -134,8 +134,8 @@ object RoutingSyncSpec {
|
|||
val TxCoordinates(blockHeight, _, _) = ShortChannelId.coordinates(shortChannelId)
|
||||
val channelUpdate_ab = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_b.publicKey, shortChannelId, cltvExpiryDelta = 7, 0, feeBaseMsat = 766000, feeProportionalMillionths = 10, 500000000L, timestamp = blockHeight)
|
||||
val channelUpdate_ba = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, priv_a.publicKey, shortChannelId, cltvExpiryDelta = 7, 0, feeBaseMsat = 766000, feeProportionalMillionths = 10, 500000000L, timestamp = blockHeight)
|
||||
val nodeAnnouncement_a = makeNodeAnnouncement(priv_a, "a", Alice.nodeParams.color, List())
|
||||
val nodeAnnouncement_b = makeNodeAnnouncement(priv_b, "b", Bob.nodeParams.color, List())
|
||||
val nodeAnnouncement_a = makeNodeAnnouncement(priv_a, "a", Color(0, 0, 0), List())
|
||||
val nodeAnnouncement_b = makeNodeAnnouncement(priv_b, "b", Color(0, 0, 0), List())
|
||||
(channelAnn_ab, channelUpdate_ab, channelUpdate_ba, nodeAnnouncement_a, nodeAnnouncement_b)
|
||||
}
|
||||
}
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -66,7 +66,7 @@
|
|||
<scala.version.short>2.11</scala.version.short>
|
||||
<akka.version>2.3.14</akka.version>
|
||||
<sttp.version>1.3.9</sttp.version>
|
||||
<bitcoinlib.version>0.10</bitcoinlib.version>
|
||||
<bitcoinlib.version>0.11</bitcoinlib.version>
|
||||
<guava.version>24.0-android</guava.version>
|
||||
</properties>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue