mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 10:39:19 +01:00
Handle unknown fields in network announcements (#1047)
All the data contained in `node_announcement`, `channel_announcement` and `channel_update` is to be included in the signature, including unknown trailing fields. We were ignoring them, causing signature verification to fail when there was unknown fields. In the case of `channel_update` there is a backward compatibility issue to handle, because when persisting channel data in state `NORMAL`, we used to store the `channel_update` followed by other data, and without prefixing it with size information. To work around that we use the same trick as before, based on an additional discriminator codec.
This commit is contained in:
parent
22548733e6
commit
e5c5a4cfbc
@ -121,6 +121,7 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana
|
||||
Transactions.sign(tx, currentKey)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ths method is used to spend revoked transactions, with the corresponding revocation key
|
||||
*
|
||||
@ -137,13 +138,8 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana
|
||||
}
|
||||
|
||||
override def signChannelAnnouncement(channelKeyPath: DeterministicWallet.KeyPath, chainHash: ByteVector32, shortChannelId: ShortChannelId, remoteNodeId: PublicKey, remoteFundingKey: PublicKey, features: ByteVector): (ByteVector64, ByteVector64) = {
|
||||
val witness = if (Announcements.isNode1(nodeId, remoteNodeId)) {
|
||||
Announcements.channelAnnouncementWitnessEncode(chainHash, shortChannelId, nodeId, remoteNodeId, fundingPublicKey(channelKeyPath).publicKey, remoteFundingKey, features)
|
||||
} else {
|
||||
Announcements.channelAnnouncementWitnessEncode(chainHash, shortChannelId, remoteNodeId, nodeId, remoteFundingKey, fundingPublicKey(channelKeyPath).publicKey, features)
|
||||
}
|
||||
val nodeSig = Crypto.sign(witness, nodeKey.privateKey)
|
||||
val bitcoinSig = Crypto.sign(witness, fundingPrivateKey(channelKeyPath).privateKey)
|
||||
(nodeSig, bitcoinSig)
|
||||
val localNodeSecret = nodeKey.privateKey
|
||||
val localFundingPrivKey = fundingPrivateKey(channelKeyPath).privateKey
|
||||
Announcements.signChannelAnnouncement(chainHash, shortChannelId, localNodeSecret, remoteNodeId, localFundingPrivKey, remoteFundingKey, features)
|
||||
}
|
||||
}
|
||||
|
@ -32,20 +32,20 @@ import scala.concurrent.duration._
|
||||
*/
|
||||
object Announcements {
|
||||
|
||||
def channelAnnouncementWitnessEncode(chainHash: ByteVector32, shortChannelId: ShortChannelId, nodeId1: PublicKey, nodeId2: PublicKey, bitcoinKey1: PublicKey, bitcoinKey2: PublicKey, features: ByteVector): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.channelAnnouncementWitnessCodec.encode(features :: chainHash :: shortChannelId :: nodeId1 :: nodeId2 :: bitcoinKey1 :: bitcoinKey2 :: HNil))))
|
||||
def channelAnnouncementWitnessEncode(chainHash: ByteVector32, shortChannelId: ShortChannelId, nodeId1: PublicKey, nodeId2: PublicKey, bitcoinKey1: PublicKey, bitcoinKey2: PublicKey, features: ByteVector, unknownFields: ByteVector): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.channelAnnouncementWitnessCodec.encode(features :: chainHash :: shortChannelId :: nodeId1 :: nodeId2 :: bitcoinKey1 :: bitcoinKey2 :: unknownFields :: HNil))))
|
||||
|
||||
def nodeAnnouncementWitnessEncode(timestamp: Long, nodeId: PublicKey, rgbColor: Color, alias: String, features: ByteVector, addresses: List[NodeAddress]): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.nodeAnnouncementWitnessCodec.encode(features :: timestamp :: nodeId :: rgbColor :: alias :: addresses :: HNil))))
|
||||
def nodeAnnouncementWitnessEncode(timestamp: Long, nodeId: PublicKey, rgbColor: Color, alias: String, features: ByteVector, addresses: List[NodeAddress], unknownFields: ByteVector): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.nodeAnnouncementWitnessCodec.encode(features :: timestamp :: nodeId :: rgbColor :: alias :: addresses :: unknownFields :: HNil))))
|
||||
|
||||
def channelUpdateWitnessEncode(chainHash: ByteVector32, shortChannelId: ShortChannelId, timestamp: Long, messageFlags: Byte, channelFlags: Byte, cltvExpiryDelta: Int, htlcMinimumMsat: Long, feeBaseMsat: Long, feeProportionalMillionths: Long, htlcMaximumMsat: Option[Long]): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.channelUpdateWitnessCodec.encode(chainHash :: shortChannelId :: timestamp :: messageFlags :: channelFlags :: cltvExpiryDelta :: htlcMinimumMsat :: feeBaseMsat :: feeProportionalMillionths :: htlcMaximumMsat :: HNil))))
|
||||
def channelUpdateWitnessEncode(chainHash: ByteVector32, shortChannelId: ShortChannelId, timestamp: Long, messageFlags: Byte, channelFlags: Byte, cltvExpiryDelta: Int, htlcMinimumMsat: Long, feeBaseMsat: Long, feeProportionalMillionths: Long, htlcMaximumMsat: Option[Long], unknownFields: ByteVector): ByteVector =
|
||||
sha256(sha256(serializationResult(LightningMessageCodecs.channelUpdateWitnessCodec.encode(chainHash :: shortChannelId :: timestamp :: messageFlags :: channelFlags :: cltvExpiryDelta :: htlcMinimumMsat :: feeBaseMsat :: feeProportionalMillionths :: htlcMaximumMsat :: unknownFields :: HNil))))
|
||||
|
||||
def signChannelAnnouncement(chainHash: ByteVector32, shortChannelId: ShortChannelId, localNodeSecret: PrivateKey, remoteNodeId: PublicKey, localFundingPrivKey: PrivateKey, remoteFundingKey: PublicKey, features: ByteVector): (ByteVector64, ByteVector64) = {
|
||||
val witness = if (isNode1(localNodeSecret.publicKey, remoteNodeId)) {
|
||||
channelAnnouncementWitnessEncode(chainHash, shortChannelId, localNodeSecret.publicKey, remoteNodeId, localFundingPrivKey.publicKey, remoteFundingKey, features)
|
||||
channelAnnouncementWitnessEncode(chainHash, shortChannelId, localNodeSecret.publicKey, remoteNodeId, localFundingPrivKey.publicKey, remoteFundingKey, features, unknownFields = ByteVector.empty)
|
||||
} else {
|
||||
channelAnnouncementWitnessEncode(chainHash, shortChannelId, remoteNodeId, localNodeSecret.publicKey, remoteFundingKey, localFundingPrivKey.publicKey, features)
|
||||
channelAnnouncementWitnessEncode(chainHash, shortChannelId, remoteNodeId, localNodeSecret.publicKey, remoteFundingKey, localFundingPrivKey.publicKey, features, unknownFields = ByteVector.empty)
|
||||
}
|
||||
val nodeSig = Crypto.sign(witness, localNodeSecret)
|
||||
val bitcoinSig = Crypto.sign(witness, localFundingPrivKey)
|
||||
@ -76,7 +76,7 @@ object Announcements {
|
||||
|
||||
def makeNodeAnnouncement(nodeSecret: PrivateKey, alias: String, color: Color, nodeAddresses: List[NodeAddress], timestamp: Long = Platform.currentTime.milliseconds.toSeconds): NodeAnnouncement = {
|
||||
require(alias.size <= 32)
|
||||
val witness = nodeAnnouncementWitnessEncode(timestamp, nodeSecret.publicKey, color, alias, ByteVector.empty, nodeAddresses)
|
||||
val witness = nodeAnnouncementWitnessEncode(timestamp, nodeSecret.publicKey, color, alias, ByteVector.empty, nodeAddresses, unknownFields = ByteVector.empty)
|
||||
val sig = Crypto.sign(witness, nodeSecret)
|
||||
NodeAnnouncement(
|
||||
signature = sig,
|
||||
@ -135,7 +135,7 @@ object Announcements {
|
||||
val channelFlags = makeChannelFlags(isNode1 = isNode1(nodeSecret.publicKey, remoteNodeId), enable = enable)
|
||||
val htlcMaximumMsatOpt = Some(htlcMaximumMsat)
|
||||
|
||||
val witness = channelUpdateWitnessEncode(chainHash, shortChannelId, timestamp, messageFlags, channelFlags, cltvExpiryDelta, htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, htlcMaximumMsatOpt)
|
||||
val witness = channelUpdateWitnessEncode(chainHash, shortChannelId, timestamp, messageFlags, channelFlags, cltvExpiryDelta, htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, htlcMaximumMsatOpt, unknownFields = ByteVector.empty)
|
||||
val sig = Crypto.sign(witness, nodeSecret)
|
||||
ChannelUpdate(
|
||||
signature = sig,
|
||||
@ -153,7 +153,7 @@ object Announcements {
|
||||
}
|
||||
|
||||
def checkSigs(ann: ChannelAnnouncement): Boolean = {
|
||||
val witness = channelAnnouncementWitnessEncode(ann.chainHash, ann.shortChannelId, ann.nodeId1, ann.nodeId2, ann.bitcoinKey1, ann.bitcoinKey2, ann.features)
|
||||
val witness = channelAnnouncementWitnessEncode(ann.chainHash, ann.shortChannelId, ann.nodeId1, ann.nodeId2, ann.bitcoinKey1, ann.bitcoinKey2, ann.features, ann.unknownFields)
|
||||
verifySignature(witness, ann.nodeSignature1, ann.nodeId1) &&
|
||||
verifySignature(witness, ann.nodeSignature2, ann.nodeId2) &&
|
||||
verifySignature(witness, ann.bitcoinSignature1, ann.bitcoinKey1) &&
|
||||
@ -161,12 +161,12 @@ object Announcements {
|
||||
}
|
||||
|
||||
def checkSig(ann: NodeAnnouncement): Boolean = {
|
||||
val witness = nodeAnnouncementWitnessEncode(ann.timestamp, ann.nodeId, ann.rgbColor, ann.alias, ann.features, ann.addresses)
|
||||
val witness = nodeAnnouncementWitnessEncode(ann.timestamp, ann.nodeId, ann.rgbColor, ann.alias, ann.features, ann.addresses, ann.unknownFields)
|
||||
verifySignature(witness, ann.signature, ann.nodeId)
|
||||
}
|
||||
|
||||
def checkSig(upd: ChannelUpdate, nodeId: PublicKey): Boolean = {
|
||||
val witness = channelUpdateWitnessEncode(upd.chainHash, upd.shortChannelId, upd.timestamp, upd.messageFlags, upd.channelFlags, upd.cltvExpiryDelta, upd.htlcMinimumMsat, upd.feeBaseMsat, upd.feeProportionalMillionths, upd.htlcMaximumMsat)
|
||||
val witness = channelUpdateWitnessEncode(upd.chainHash, upd.shortChannelId, upd.timestamp, upd.messageFlags, upd.channelFlags, upd.cltvExpiryDelta, upd.htlcMinimumMsat, upd.feeBaseMsat, upd.feeProportionalMillionths, upd.htlcMaximumMsat, upd.unknownFields)
|
||||
verifySignature(witness, upd.signature, nodeId)
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +127,8 @@ object ChannelCodecs extends Logging {
|
||||
val sig64OrDERCodec: Codec[ByteVector64] = Codec[ByteVector64](
|
||||
(value: ByteVector64) => bytes(64).encode(value),
|
||||
(wire: BitVector) => bytes.decode(wire).map(_.map {
|
||||
case bin64 if bin64.size == 64 => ByteVector64(bin64)
|
||||
case der => Crypto.der2compact(der)
|
||||
case bin64 if bin64.size == 64 => ByteVector64(bin64)
|
||||
case der => Crypto.der2compact(der)
|
||||
})
|
||||
)
|
||||
|
||||
@ -266,12 +266,37 @@ object ChannelCodecs extends Logging {
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
("lastSent" | fundingLockedCodec)).as[DATA_WAIT_FOR_FUNDING_LOCKED]
|
||||
|
||||
// All channel_announcement's written prior to supporting unknown trailing fields had the same fixed size, because
|
||||
// those are the announcements that *we* created and we always used an empty features field, which was the only
|
||||
// variable-length field.
|
||||
val noUnknownFieldsChannelAnnouncementSizeCodec: Codec[Int] = provide(430)
|
||||
|
||||
// We used to ignore unknown trailing fields, and assume that channel_update size was known. This is not true anymore,
|
||||
// so we need to tell the codec where to stop, otherwise all the remaining part of the data will be decoded as unknown
|
||||
// fields. Fortunately, we can easily tell what size the channel_update will be.
|
||||
val noUnknownFieldsChannelUpdateSizeCodec: Codec[Int] = peek( // we need to take a peek at a specific byte to know what size the message will be, and then rollback to read the full message
|
||||
ignore(8 * (64 + 32 + 8 + 4)) ~> // we skip the first fields: signature + chain_hash + short_channel_id + timestamp
|
||||
byte // this is the messageFlags byte
|
||||
)
|
||||
.map(messageFlags => if ((messageFlags & 1) != 0) 136 else 128) // depending on the value of option_channel_htlc_max, size will be 128B or 136B
|
||||
.decodeOnly // this is for compat, we only need to decode
|
||||
|
||||
// this is a decode-only codec compatible with versions 9afb26e and below
|
||||
val DATA_NORMAL_COMPAT_03_Codec: Codec[DATA_NORMAL] = (
|
||||
("commitments" | commitmentsCodec) ::
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
("buried" | bool) ::
|
||||
("channelAnnouncement" | optional(bool, variableSizeBytes(noUnknownFieldsChannelAnnouncementSizeCodec, channelAnnouncementCodec))) ::
|
||||
("channelUpdate" | variableSizeBytes(noUnknownFieldsChannelUpdateSizeCodec, channelUpdateCodec)) ::
|
||||
("localShutdown" | optional(bool, shutdownCodec)) ::
|
||||
("remoteShutdown" | optional(bool, shutdownCodec))).as[DATA_NORMAL].decodeOnly
|
||||
|
||||
val DATA_NORMAL_Codec: Codec[DATA_NORMAL] = (
|
||||
("commitments" | commitmentsCodec) ::
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
("buried" | bool) ::
|
||||
("channelAnnouncement" | optional(bool, channelAnnouncementCodec)) ::
|
||||
("channelUpdate" | channelUpdateCodec) ::
|
||||
("channelAnnouncement" | optional(bool, variableSizeBytes(uint16, channelAnnouncementCodec))) ::
|
||||
("channelUpdate" | variableSizeBytes(uint16, channelUpdateCodec)) ::
|
||||
("localShutdown" | optional(bool, shutdownCodec)) ::
|
||||
("remoteShutdown" | optional(bool, shutdownCodec))).as[DATA_NORMAL]
|
||||
|
||||
@ -329,11 +354,12 @@ object ChannelCodecs extends Logging {
|
||||
* More info here: https://github.com/scodec/scodec/issues/122
|
||||
*/
|
||||
val stateDataCodec: Codec[HasCommitments] = ("version" | constant(0x00)) ~> discriminated[HasCommitments].by(uint16)
|
||||
.typecase(0x10, DATA_NORMAL_Codec)
|
||||
.typecase(0x09, DATA_CLOSING_Codec)
|
||||
.typecase(0x08, DATA_WAIT_FOR_FUNDING_CONFIRMED_Codec)
|
||||
.typecase(0x01, DATA_WAIT_FOR_FUNDING_CONFIRMED_COMPAT_01_Codec)
|
||||
.typecase(0x02, DATA_WAIT_FOR_FUNDING_LOCKED_Codec)
|
||||
.typecase(0x03, DATA_NORMAL_Codec)
|
||||
.typecase(0x03, DATA_NORMAL_COMPAT_03_Codec)
|
||||
.typecase(0x04, DATA_SHUTDOWN_Codec)
|
||||
.typecase(0x05, DATA_NEGOTIATING_Codec)
|
||||
.typecase(0x06, DATA_CLOSING_COMPAT_06_Codec)
|
||||
|
@ -16,11 +16,19 @@
|
||||
|
||||
package fr.acinq.eclair.wire
|
||||
|
||||
import java.net.{Inet4Address, Inet6Address, InetAddress}
|
||||
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.{ByteVector32, ByteVector64}
|
||||
import fr.acinq.eclair.crypto.Sphinx
|
||||
import fr.acinq.eclair.wire
|
||||
import fr.acinq.eclair.wire.CommonCodecs._
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.codecs._
|
||||
import scodec.{Attempt, Codec, Err}
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
import scodec.Codec
|
||||
|
||||
/**
|
||||
@ -154,13 +162,15 @@ object LightningMessageCodecs {
|
||||
("nodeSignature" | bytes64) ::
|
||||
("bitcoinSignature" | bytes64)).as[AnnouncementSignatures]
|
||||
|
||||
val channelAnnouncementWitnessCodec = ("features" | varsizebinarydata) ::
|
||||
("chainHash" | bytes32) ::
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
("nodeId1" | publicKey) ::
|
||||
("nodeId2" | publicKey) ::
|
||||
("bitcoinKey1" | publicKey) ::
|
||||
("bitcoinKey2" | publicKey)
|
||||
val channelAnnouncementWitnessCodec =
|
||||
("features" | varsizebinarydata) ::
|
||||
("chainHash" | bytes32) ::
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
("nodeId1" | publicKey) ::
|
||||
("nodeId2" | publicKey) ::
|
||||
("bitcoinKey1" | publicKey) ::
|
||||
("bitcoinKey2" | publicKey) ::
|
||||
("unknownFields" | bytes)
|
||||
|
||||
val channelAnnouncementCodec: Codec[ChannelAnnouncement] = (
|
||||
("nodeSignature1" | bytes64) ::
|
||||
@ -169,17 +179,19 @@ object LightningMessageCodecs {
|
||||
("bitcoinSignature2" | bytes64) ::
|
||||
channelAnnouncementWitnessCodec).as[ChannelAnnouncement]
|
||||
|
||||
val nodeAnnouncementWitnessCodec = ("features" | varsizebinarydata) ::
|
||||
("timestamp" | uint32) ::
|
||||
("nodeId" | publicKey) ::
|
||||
("rgbColor" | rgb) ::
|
||||
("alias" | zeropaddedstring(32)) ::
|
||||
("addresses" | listofnodeaddresses)
|
||||
val nodeAnnouncementWitnessCodec =
|
||||
("features" | varsizebinarydata) ::
|
||||
("timestamp" | uint32) ::
|
||||
("nodeId" | publicKey) ::
|
||||
("rgbColor" | rgb) ::
|
||||
("alias" | zeropaddedstring(32)) ::
|
||||
("addresses" | listofnodeaddresses) ::
|
||||
("unknownFields" | bytes)
|
||||
|
||||
val nodeAnnouncementCodec: Codec[NodeAnnouncement] = (
|
||||
("signature" | bytes64) ::
|
||||
nodeAnnouncementWitnessCodec).as[NodeAnnouncement]
|
||||
|
||||
|
||||
val channelUpdateWitnessCodec =
|
||||
("chainHash" | bytes32) ::
|
||||
("shortChannelId" | shortchannelid) ::
|
||||
@ -190,7 +202,8 @@ object LightningMessageCodecs {
|
||||
("htlcMinimumMsat" | uint64overflow) ::
|
||||
("feeBaseMsat" | uint32) ::
|
||||
("feeProportionalMillionths" | uint32) ::
|
||||
("htlcMaximumMsat" | conditional((messageFlags & 1) != 0, uint64overflow))
|
||||
("htlcMaximumMsat" | conditional((messageFlags & 1) != 0, uint64overflow)) ::
|
||||
("unknownFields" | bytes)
|
||||
})
|
||||
|
||||
val channelUpdateCodec: Codec[ChannelUpdate] = (
|
||||
|
@ -164,7 +164,8 @@ case class ChannelAnnouncement(nodeSignature1: ByteVector64,
|
||||
nodeId1: PublicKey,
|
||||
nodeId2: PublicKey,
|
||||
bitcoinKey1: PublicKey,
|
||||
bitcoinKey2: PublicKey) extends RoutingMessage with HasChainHash
|
||||
bitcoinKey2: PublicKey,
|
||||
unknownFields: ByteVector = ByteVector.empty) extends RoutingMessage with HasChainHash
|
||||
|
||||
case class Color(r: Byte, g: Byte, b: Byte) {
|
||||
override def toString: String = f"#$r%02x$g%02x$b%02x" // to hexa s"# ${r}%02x ${r & 0xFF}${g & 0xFF}${b & 0xFF}"
|
||||
@ -206,7 +207,8 @@ case class NodeAnnouncement(signature: ByteVector64,
|
||||
nodeId: PublicKey,
|
||||
rgbColor: Color,
|
||||
alias: String,
|
||||
addresses: List[NodeAddress]) extends RoutingMessage with HasTimestamp
|
||||
addresses: List[NodeAddress],
|
||||
unknownFields: ByteVector = ByteVector.empty) extends RoutingMessage with HasTimestamp
|
||||
|
||||
case class ChannelUpdate(signature: ByteVector64,
|
||||
chainHash: ByteVector32,
|
||||
@ -218,7 +220,8 @@ case class ChannelUpdate(signature: ByteVector64,
|
||||
htlcMinimumMsat: Long,
|
||||
feeBaseMsat: Long,
|
||||
feeProportionalMillionths: Long,
|
||||
htlcMaximumMsat: Option[Long]) extends RoutingMessage with HasTimestamp with HasChainHash {
|
||||
htlcMaximumMsat: Option[Long],
|
||||
unknownFields: ByteVector = ByteVector.empty) extends RoutingMessage with HasTimestamp with HasChainHash {
|
||||
require(((messageFlags & 1) != 0) == htlcMaximumMsat.isDefined, "htlcMaximumMsat is not consistent with messageFlags")
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import akka.actor.{ActorSystem, Props}
|
||||
import akka.testkit.{TestKit, TestProbe}
|
||||
import fr.acinq.eclair.channel.ChannelPersisted
|
||||
import fr.acinq.eclair.db.sqlite.SqliteChannelsDb
|
||||
import fr.acinq.eclair.wire.ChannelCodecsSpec
|
||||
import fr.acinq.eclair.{TestConstants, TestUtils, randomBytes32}
|
||||
import org.scalatest.FunSuiteLike
|
||||
|
||||
@ -35,7 +36,7 @@ class BackupHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike {
|
||||
val dest = new File(TestUtils.BUILD_DIRECTORY, s"backup-${UUID.randomUUID()}")
|
||||
wip.deleteOnExit()
|
||||
dest.deleteOnExit()
|
||||
val channel = ChannelStateSpec.normal
|
||||
val channel = ChannelCodecsSpec.normal
|
||||
db.channels.addOrUpdateChannel(channel)
|
||||
assert(db.channels.listLocalChannels() == Seq(channel))
|
||||
|
||||
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 ACINQ SAS
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package fr.acinq.eclair.db
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey}
|
||||
import fr.acinq.bitcoin.{Block, ByteVector32, Crypto, DeterministicWallet, MilliSatoshi, Satoshi, Transaction}
|
||||
import fr.acinq.eclair.channel.Helpers.Funding
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.{LocalKeyManager, ShaChain, Sphinx}
|
||||
import fr.acinq.eclair.payment.{Local, Relayed}
|
||||
import fr.acinq.eclair.router.Announcements
|
||||
import fr.acinq.eclair.transactions.Transactions.CommitTx
|
||||
import fr.acinq.eclair.transactions._
|
||||
import fr.acinq.eclair.wire.{ChannelCodecs, UpdateAddHtlc}
|
||||
import fr.acinq.eclair.{ShortChannelId, UInt64, randomKey}
|
||||
import org.scalatest.FunSuite
|
||||
import scodec.bits._
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
/**
|
||||
* Created by fabrice on 07/02/17.
|
||||
*/
|
||||
|
||||
class ChannelStateSpec extends FunSuite {
|
||||
|
||||
import ChannelStateSpec._
|
||||
|
||||
test("basic serialization test (NORMAL)") {
|
||||
val data = normal
|
||||
val bin = ChannelCodecs.DATA_NORMAL_Codec.encode(data).require
|
||||
val check = ChannelCodecs.DATA_NORMAL_Codec.decodeValue(bin).require
|
||||
assert(data.commitments.localCommit.spec === check.commitments.localCommit.spec)
|
||||
assert(data === check)
|
||||
}
|
||||
|
||||
test("nonreg") {
|
||||
val bin = ByteVector.fromValidHex(Source.fromInputStream(getClass.getResourceAsStream("/normal_data_htlcs.bin")).mkString)
|
||||
val c = ChannelCodecs.stateDataCodec.decode(bin.toBitVector).require.value
|
||||
|
||||
val ref = Seq(
|
||||
(hex"30440220104aed8d52fe50e2313a9a456607838a0cdac75fdc37afe581c415e7a20da944022034d1ac69c64f34571251be8cc6b50116f26453813267fb9afa3e318a79f4f32401", hex"304502210097fcda40b22916b5d61badedf6126658c2b5927d5002cc2c3e5f88a78ba5f45b02204a74bcf8827d894cab153fc051f39d8e2aeb660162a6a05797f7140587a6133301"),
|
||||
(hex"30450221009e0e57886b81fd4159f672728891d799203b23c351e93134aba445b288443d3502207b77faa4227126b7d087144c75f4e5c8af9db705b37806dbd2d3f4339666d32201", hex"3045022100aa403fa23e82379a16ba16b446dbdee5a4f879ba690ad3f4f10dc445df2832ba022000a51fdbdb69dcbd5518274303fcece60d719cb6d593e882fdb0190253bbaaab01"),
|
||||
(hex"3045022100fb44e66fc294d9ece2c33465398221edcfd857208d32a36dedab9906d00b356d022008c5fcfa7b41f8616d57ed009a8614aca636edae1479b6114e03407ba6fceea701", hex"3045022100a9ad65dada5e5500897173bca610135a13008895ce445fbc90d440d5406bd6150220644d75e5ca774ef6b559ffaf1083a9a5da250c3c87666d96daf35b480ef0c65701"),
|
||||
(hex"3044022009e4f39656dc8712863bffe2acdfa4d2245f65f38a230dd034b226dc2e5fd7ce022049c0108e44c399d1a1b67ab6f60566f491d8682406ac4a03a914f9a21196d6ba01", hex"3044022063a6839c031fd5534d7807a8fff8ca0f9a72d8aa9d78ee104d6ece2b417ac5ce0220193d9b521a44011d31d2bb85be5043119c42a7aee3d9ef68b7388c3c9c3a780501"),
|
||||
(hex"304402207eaf435948b9e04cb6551f97ee5d85ac879e20d3fae3f5c9a0880ef452d32ac902206e9c5c9098c3e3bef010d3142578823c7fb43b43fe0a0036d481f18a0168b20f01", hex"304402205dda44c9d8aaf37a6f5f6c99713d2a001682f2593a960ccaf5c23059cd20016b02200991b09bccdfc87918852650a4bfa7b4ac9028101362631b5ec376427084138e01"),
|
||||
(hex"304402200232dbb9d46dabc6569f3f65f4f2a4b7e5acf7be85687b9897141e9784cb9d370220087b2c1dda444d7351976135b56f2f2ca22d8c03d5aa40acbce8c4241daf541501", hex"3045022100eddaa4f767bc70fd672bee983b1644dbff9479def0efc7cca79f0daa1bad370d02204c810238968ae9e86b99d348464e9ac7a06e40225022ae4203ae36fad928c22401"),
|
||||
(hex"3045022100daa604934db542aa5a9bcbd48eb666fac8acdee92ccd8d42228f52377c51184a022069f855477b27cec39b15fb9e666c09b6c4860c8b80cd1315d2498d97d9cf024601", hex"3044022020e6d43dee03f54574d8245edf2e312d0a492dd2350b7f8df68390b8876de5640220555d46cd545ff0ecc280e6bc82e976ff494bab5f2b128807626753ffb9e5796e01"),
|
||||
(hex"3044022046c3cf88f9e8639c954c584725482dd6e6403deda3824c37ae95db9bf99d341602206432f76c5ca3d61951155c1b223fd35dd4227f83e1ff9a93437b63515567d23f01", hex"3045022100812a360a6ddc44179f80e5b4252bca74bb5dbe1da25230c9e8afcd388a2fd64702202e45a658123f0263ca1157ef9a9995ede1625d1ecba532957185f1d8044aa1d301"),
|
||||
(hex"30440220482df018e51b4f684271682bc3c81c481d288d61000a77df2126afe042c3471d02204772720ff1ea323a271259022a0458ae4d228e5f613ade63fca38eb5d443756a01", hex"3044022076a338d225b8954412198ce5936aaa6433da1f51dd9bcbe69d95a1e0960c169802207db267517fc73e358e09f4c89313ae17ed4d5f6d8432faec9ec1e784a2a7da7c01"),
|
||||
(hex"3045022100916255b5758d66cd46f653f8a5a71b1c857bfae1a7cf85195b5d78476c4138c502200101e3ec9874aa2644691662bf8945a182af1237bb61c459e9dbff495b9097d001", hex"304402201d099a464a7696b22a8e58b65c52e9a519a06a5c49e944155d4e5fbd14d3f5b902203c091c0ec5b840a80be739d29b5fc2c75cb94928e5ea83133f84d226f28cd4b701"),
|
||||
(hex"3045022100d8eaa436faec6b38f155065893f1212ce43615fbec49b4af72f16119774b5472022033aa303992f4a8cfe1c77e6a0d2baa73baad0305a88da16d26122e536867431101", hex"304402203af7b7ea16cc018fdb414f52cd38ed548dc257cbb06c812c9dc1d60500b21485022072cd74b7e49bfd813e09bae778da903b44b7b0ae22b87af4c34cf8bb77dfdef201"),
|
||||
(hex"304402204f5dd042bfb449c522012a2d461e5a94c9ea3be629c0ab091b0e1f5569eb119c022021411ff8affabab12cd39f0eaa64f1b08fa72ada6f37d1d46c6bde4483d869fb01", hex"3044022043573edb37be815d1b97b90803f601dfc91c25279ccda606ad6515fee721fe57022030ac2883408a2075a47337443eb539062a8ac6b5453befb2b9863d697e35dd8201"),
|
||||
(hex"3044022030ff3d4d42ef1c3d742164a30ff7b021215e881d9277a52a1720514a4473289502204b090f6b412e8caacb5bcbf295babb075d9d5490e3f7678c289206780f6f0bc901", hex"304502210093fd7dfa3ef6cdf5b94cfadf83022be98062d53cd7097a73947453b210a481eb0220622e63a21b787ea7bb55f01ab6fe503fcb8ef4cb65adce7a264ae014403646fe01")
|
||||
)
|
||||
|
||||
val sigs = c.commitments
|
||||
.localCommit
|
||||
.publishableTxs
|
||||
.htlcTxsAndSigs
|
||||
.map(data => (Scripts.der(data.localSig), Scripts.der(data.remoteSig)))
|
||||
|
||||
assert(ref === sigs)
|
||||
}
|
||||
}
|
||||
|
||||
object ChannelStateSpec {
|
||||
val keyManager = new LocalKeyManager(ByteVector32(ByteVector.fill(32)(1)), Block.RegtestGenesisBlock.hash)
|
||||
val localParams = LocalParams(
|
||||
keyManager.nodeId,
|
||||
channelKeyPath = DeterministicWallet.KeyPath(Seq(42L)),
|
||||
dustLimitSatoshis = Satoshi(546).toLong,
|
||||
maxHtlcValueInFlightMsat = UInt64(50000000),
|
||||
channelReserveSatoshis = 10000,
|
||||
htlcMinimumMsat = 10000,
|
||||
toSelfDelay = 144,
|
||||
maxAcceptedHtlcs = 50,
|
||||
defaultFinalScriptPubKey = ByteVector.empty,
|
||||
isFunder = true,
|
||||
globalFeatures = hex"dead",
|
||||
localFeatures = hex"beef")
|
||||
|
||||
val remoteParams = RemoteParams(
|
||||
nodeId = randomKey.publicKey,
|
||||
dustLimitSatoshis = Satoshi(546).toLong,
|
||||
maxHtlcValueInFlightMsat = UInt64(5000000),
|
||||
channelReserveSatoshis = 10000,
|
||||
htlcMinimumMsat = 5000,
|
||||
toSelfDelay = 144,
|
||||
maxAcceptedHtlcs = 50,
|
||||
fundingPubKey = PrivateKey(ByteVector32(ByteVector.fill(32)(1)) :+ 1.toByte).publicKey,
|
||||
revocationBasepoint = PrivateKey(ByteVector.fill(32)(2)).publicKey,
|
||||
paymentBasepoint = PrivateKey(ByteVector.fill(32)(3)).publicKey,
|
||||
delayedPaymentBasepoint = PrivateKey(ByteVector.fill(32)(4)).publicKey,
|
||||
htlcBasepoint = PrivateKey(ByteVector.fill(32)(6)).publicKey,
|
||||
globalFeatures = hex"dead",
|
||||
localFeatures = hex"beef")
|
||||
|
||||
val paymentPreimages = Seq(
|
||||
ByteVector32(hex"0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
ByteVector32(hex"0101010101010101010101010101010101010101010101010101010101010101"),
|
||||
ByteVector32(hex"0202020202020202020202020202020202020202020202020202020202020202"),
|
||||
ByteVector32(hex"0303030303030303030303030303030303030303030303030303030303030303"),
|
||||
ByteVector32(hex"0404040404040404040404040404040404040404040404040404040404040404")
|
||||
)
|
||||
|
||||
val htlcs = Seq(
|
||||
DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(1000000).amount, Crypto.sha256(paymentPreimages(0)), 500, ByteVector.fill(Sphinx.PacketLength)(0))),
|
||||
DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(2000000).amount, Crypto.sha256(paymentPreimages(1)), 501, ByteVector.fill(Sphinx.PacketLength)(0))),
|
||||
DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 30, MilliSatoshi(2000000).amount, Crypto.sha256(paymentPreimages(2)), 502, ByteVector.fill(Sphinx.PacketLength)(0))),
|
||||
DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 31, MilliSatoshi(3000000).amount, Crypto.sha256(paymentPreimages(3)), 503, ByteVector.fill(Sphinx.PacketLength)(0))),
|
||||
DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(4000000).amount, Crypto.sha256(paymentPreimages(4)), 504, ByteVector.fill(Sphinx.PacketLength)(0)))
|
||||
)
|
||||
|
||||
val fundingTx = Transaction.read("0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000")
|
||||
val fundingAmount = fundingTx.txOut(0).amount
|
||||
val commitmentInput = Funding.makeFundingInputInfo(fundingTx.hash, 0, fundingAmount, keyManager.fundingPublicKey(localParams.channelKeyPath).publicKey, remoteParams.fundingPubKey)
|
||||
|
||||
val localCommit = LocalCommit(0, CommitmentSpec(htlcs.toSet, 1500, 50000000, 70000000), PublishableTxs(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), Nil))
|
||||
val remoteCommit = RemoteCommit(0, CommitmentSpec(htlcs.map(htlc => htlc.copy(direction = htlc.direction.opposite)).toSet, 1500, 50000, 700000), ByteVector32(hex"0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey)
|
||||
val commitments = Commitments(localParams, remoteParams, channelFlags = 0x01.toByte, localCommit, remoteCommit, LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil),
|
||||
localNextHtlcId = 32L,
|
||||
remoteNextHtlcId = 4L,
|
||||
originChannels = Map(42L -> Local(UUID.randomUUID, None), 15000L -> Relayed(ByteVector32(ByteVector.fill(32)(42)), 43, 11000000L, 10000000L)),
|
||||
remoteNextCommitInfo = Right(randomKey.publicKey),
|
||||
commitInput = commitmentInput, remotePerCommitmentSecrets = ShaChain.init, channelId = ByteVector32.Zeroes)
|
||||
|
||||
val channelUpdate = Announcements.makeChannelUpdate(ByteVector32(ByteVector.fill(32)(1)), randomKey, randomKey.publicKey, ShortChannelId(142553), 42, 15, 575, 53, Channel.MAX_FUNDING_SATOSHIS * 1000L)
|
||||
|
||||
val normal = DATA_NORMAL(commitments, ShortChannelId(42), true, None, channelUpdate, None, None)
|
||||
}
|
@ -24,9 +24,10 @@ import fr.acinq.eclair.channel.{AvailableBalanceChanged, ChannelErrorOccured, Ne
|
||||
import fr.acinq.eclair.db.sqlite.SqliteAuditDb
|
||||
import fr.acinq.eclair.db.sqlite.SqliteUtils.{getVersion, using}
|
||||
import fr.acinq.eclair.payment.{PaymentReceived, PaymentRelayed, PaymentSent}
|
||||
import fr.acinq.eclair.wire.ChannelCodecs
|
||||
import fr.acinq.eclair.wire.{ChannelCodecs, ChannelCodecsSpec}
|
||||
import fr.acinq.eclair._
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
import concurrent.duration._
|
||||
import scala.compat.Platform
|
||||
|
||||
@ -49,7 +50,7 @@ class SqliteAuditDbSpec extends FunSuite {
|
||||
val e4 = NetworkFeePaid(null, randomKey.publicKey, randomBytes32, Transaction(0, Seq.empty, Seq.empty, 0), Satoshi(42), "mutual")
|
||||
val e5 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, MilliSatoshi(42000), MilliSatoshi(1000), randomBytes32, randomBytes32, randomBytes32, timestamp = 0)
|
||||
val e6 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, MilliSatoshi(42000), MilliSatoshi(1000), randomBytes32, randomBytes32, randomBytes32, timestamp = (Platform.currentTime.milliseconds + 10.minutes).toMillis)
|
||||
val e7 = AvailableBalanceChanged(null, randomBytes32, ShortChannelId(500000, 42, 1), 456123000, ChannelStateSpec.commitments)
|
||||
val e7 = AvailableBalanceChanged(null, randomBytes32, ShortChannelId(500000, 42, 1), 456123000, ChannelCodecsSpec.commitments)
|
||||
val e8 = ChannelLifecycleEvent(randomBytes32, randomKey.publicKey, 456123000, true, false, "mutual")
|
||||
val e9 = ChannelErrorOccured(null, randomBytes32, randomKey.publicKey, null, LocalError(new RuntimeException("oops")), true)
|
||||
val e10 = ChannelErrorOccured(null, randomBytes32, randomKey.publicKey, null, RemoteError(wire.Error(randomBytes32, "remote oops")), true)
|
||||
|
@ -21,6 +21,7 @@ import fr.acinq.eclair.TestConstants
|
||||
import fr.acinq.eclair.db.sqlite.SqliteUtils.{getVersion, using}
|
||||
import fr.acinq.eclair.db.sqlite.{SqliteChannelsDb, SqlitePendingRelayDb}
|
||||
import fr.acinq.eclair.wire.ChannelCodecs.stateDataCodec
|
||||
import fr.acinq.eclair.wire.ChannelCodecsSpec
|
||||
import org.scalatest.FunSuite
|
||||
import org.sqlite.SQLiteException
|
||||
import scodec.bits.ByteVector
|
||||
@ -39,7 +40,7 @@ class SqliteChannelsDbSpec extends FunSuite {
|
||||
val db = new SqliteChannelsDb(sqlite)
|
||||
new SqlitePendingRelayDb(sqlite) // needed by db.removeChannel
|
||||
|
||||
val channel = ChannelStateSpec.normal
|
||||
val channel = ChannelCodecsSpec.normal
|
||||
|
||||
val commitNumber = 42
|
||||
val paymentHash1 = ByteVector32.Zeroes
|
||||
@ -78,7 +79,7 @@ class SqliteChannelsDbSpec extends FunSuite {
|
||||
}
|
||||
|
||||
// insert 1 row
|
||||
val channel = ChannelStateSpec.normal
|
||||
val channel = ChannelCodecsSpec.normal
|
||||
val data = stateDataCodec.encode(channel).require.toByteArray
|
||||
using(sqlite.prepareStatement("INSERT INTO local_channels VALUES (?, ?)")) { statement =>
|
||||
statement.setBytes(1, channel.channelId.toArray)
|
||||
|
@ -19,9 +19,8 @@ package fr.acinq.eclair.io
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import akka.testkit.{TestKit, TestProbe}
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.db.ChannelStateSpec
|
||||
import fr.acinq.eclair.randomBytes32
|
||||
import fr.acinq.eclair.wire.{TemporaryNodeFailure, UpdateAddHtlc}
|
||||
import fr.acinq.eclair.wire.{ChannelCodecsSpec, TemporaryNodeFailure, UpdateAddHtlc}
|
||||
import org.scalatest.FunSuiteLike
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
@ -35,7 +34,7 @@ class HtlcReaperSpec extends TestKit(ActorSystem("test")) with FunSuiteLike {
|
||||
|
||||
test("init and cleanup") {
|
||||
|
||||
val data = ChannelStateSpec.normal
|
||||
val data = ChannelCodecsSpec.normal
|
||||
|
||||
// assuming that data has incoming htlcs 0 and 1, we don't care about the amount/payment_hash/onion fields
|
||||
val add0 = UpdateAddHtlc(data.channelId, 0, 20000, randomBytes32, 100, ByteVector.empty)
|
||||
|
@ -16,12 +16,10 @@
|
||||
|
||||
package fr.acinq.eclair.io
|
||||
|
||||
import java.net.{Inet4Address, InetSocketAddress}
|
||||
|
||||
import akka.actor.{ActorRef, PoisonPill, Terminated}
|
||||
import java.net.{Inet4Address, InetAddress, InetSocketAddress, ServerSocket}
|
||||
import akka.actor.{ActorRef, ActorSystem, PoisonPill}
|
||||
|
||||
import akka.actor.FSM.{CurrentState, SubscribeTransitionCallBack, Transition}
|
||||
import akka.actor.{ActorRef, PoisonPill}
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
import fr.acinq.eclair.TestConstants._
|
||||
@ -29,13 +27,13 @@ import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.blockchain.EclairWallet
|
||||
import fr.acinq.eclair.channel.HasCommitments
|
||||
import fr.acinq.eclair.crypto.TransportHandler
|
||||
import fr.acinq.eclair.db.ChannelStateSpec
|
||||
import fr.acinq.eclair.io.Peer._
|
||||
import fr.acinq.eclair.router.RoutingSyncSpec.makeFakeRoutingInfo
|
||||
import fr.acinq.eclair.router.{ChannelRangeQueries, ChannelRangeQueriesSpec, Rebroadcast}
|
||||
import fr.acinq.eclair.wire.{Color, Error, IPv4, NodeAddress, NodeAnnouncement, Ping, Pong}
|
||||
import fr.acinq.eclair.wire.{ChannelCodecsSpec, Color, Error, IPv4, NodeAddress, NodeAnnouncement, Ping, Pong}
|
||||
import org.scalatest.{Outcome, Tag}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class PeerSpec extends TestkitBaseClass {
|
||||
@ -90,7 +88,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
test("restore existing channels") { f =>
|
||||
import f._
|
||||
val probe = TestProbe()
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelStateSpec.normal))
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelCodecsSpec.normal))
|
||||
probe.send(peer, Peer.GetPeerInfo)
|
||||
probe.expectMsg(PeerInfo(remoteNodeId, "CONNECTED", Some(fakeIPAddress.socketAddress), 1))
|
||||
}
|
||||
@ -138,7 +136,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
test("ignore reconnect (no known address)") { f =>
|
||||
import f._
|
||||
val probe = TestProbe()
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelStateSpec.normal)))
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelCodecsSpec.normal)))
|
||||
probe.send(peer, Peer.Reconnect)
|
||||
probe.expectNoMsg()
|
||||
}
|
||||
@ -157,13 +155,13 @@ class PeerSpec extends TestkitBaseClass {
|
||||
|
||||
// we create a dummy tcp server and update bob's announcement to point to it
|
||||
val mockServer = new ServerSocket(0, 1, InetAddress.getLocalHost) // port will be assigned automatically
|
||||
val mockAddress = NodeAddress.fromParts(mockServer.getInetAddress.getHostAddress, mockServer.getLocalPort).get
|
||||
val mockAddress = NodeAddress.fromParts(mockServer.getInetAddress.getHostAddress, mockServer.getLocalPort).get
|
||||
val bobAnnouncement = NodeAnnouncement(randomBytes64, ByteVector.empty, 1, Bob.nodeParams.nodeId, Color(100.toByte, 200.toByte, 300.toByte), "node-alias", mockAddress :: Nil)
|
||||
peer.underlyingActor.nodeParams.db.network.addNode(bobAnnouncement)
|
||||
|
||||
val probe = TestProbe()
|
||||
awaitCond(peer.stateName == INSTANTIATING)
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelStateSpec.normal)))
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelCodecsSpec.normal)))
|
||||
awaitCond(peer.stateName == DISCONNECTED)
|
||||
|
||||
// we have auto-reconnect=false so we need to manually tell the peer to reconnect
|
||||
@ -179,7 +177,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
import f._
|
||||
val probe = TestProbe()
|
||||
val previouslyKnownAddress = new InetSocketAddress("1.2.3.4", 9735)
|
||||
probe.send(peer, Peer.Init(Some(previouslyKnownAddress), Set(ChannelStateSpec.normal)))
|
||||
probe.send(peer, Peer.Init(Some(previouslyKnownAddress), Set(ChannelCodecsSpec.normal)))
|
||||
probe.send(peer, Peer.Reconnect)
|
||||
val interval = (peer.underlyingActor.nodeParams.maxReconnectInterval.toSeconds / 2) to peer.underlyingActor.nodeParams.maxReconnectInterval.toSeconds
|
||||
awaitCond(interval contains peer.stateData.asInstanceOf[DisconnectedData].nextReconnectionDelay.toSeconds)
|
||||
@ -188,7 +186,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
test("reconnect with increasing delays") { f =>
|
||||
import f._
|
||||
val probe = TestProbe()
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelStateSpec.normal))
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelCodecsSpec.normal))
|
||||
probe.send(transport.ref, PoisonPill)
|
||||
awaitCond(peer.stateName === DISCONNECTED)
|
||||
assert(peer.stateData.asInstanceOf[DisconnectedData].nextReconnectionDelay === (10 seconds))
|
||||
@ -216,7 +214,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
import f._
|
||||
|
||||
val probe = TestProbe()
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelStateSpec.normal)))
|
||||
probe.send(peer, Peer.Init(None, Set(ChannelCodecsSpec.normal)))
|
||||
authenticator.send(peer, Authenticator.Authenticated(connection.ref, transport.ref, remoteNodeId, fakeIPAddress.socketAddress, outgoing = true, None))
|
||||
|
||||
probe.send(peer, Peer.GetPeerInfo)
|
||||
@ -230,7 +228,7 @@ class PeerSpec extends TestkitBaseClass {
|
||||
import f._
|
||||
|
||||
val probe = TestProbe()
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelStateSpec.normal))
|
||||
connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer, channels = Set(ChannelCodecsSpec.normal))
|
||||
|
||||
probe.send(peer, Peer.GetPeerInfo)
|
||||
assert(probe.expectMsgType[Peer.PeerInfo].state == "CONNECTED")
|
||||
|
@ -2,14 +2,14 @@ package fr.acinq.eclair.io
|
||||
|
||||
import java.io.File
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import akka.actor.{ActorRef, ActorSystem}
|
||||
import akka.testkit.{TestKit, TestProbe}
|
||||
import fr.acinq.bitcoin.ByteVector64
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
import fr.acinq.eclair.TestConstants._
|
||||
import fr.acinq.eclair.blockchain.TestWallet
|
||||
import fr.acinq.eclair.db._
|
||||
import fr.acinq.eclair.wire.{Color, NodeAddress, NodeAnnouncement}
|
||||
import fr.acinq.eclair.wire.{ChannelCodecsSpec, Color, NodeAddress, NodeAnnouncement}
|
||||
import org.mockito.scalatest.IdiomaticMockito
|
||||
import org.scalatest.FunSuiteLike
|
||||
import scodec.bits._
|
||||
@ -31,7 +31,7 @@ class SwitchboardSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
||||
}
|
||||
)
|
||||
|
||||
val remoteNodeId = ChannelStateSpec.normal.commitments.remoteParams.nodeId
|
||||
val remoteNodeId = ChannelCodecsSpec.normal.commitments.remoteParams.nodeId
|
||||
val authenticator = TestProbe()
|
||||
val watcher = TestProbe()
|
||||
val router = TestProbe()
|
||||
@ -45,7 +45,7 @@ class SwitchboardSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
||||
)
|
||||
|
||||
// add a channel to the db
|
||||
nodeParams.db.channels.addOrUpdateChannel(ChannelStateSpec.normal)
|
||||
nodeParams.db.channels.addOrUpdateChannel(ChannelCodecsSpec.normal)
|
||||
|
||||
val switchboard = system.actorOf(Switchboard.props(nodeParams, authenticator.ref, watcher.ref, router.ref, relayer.ref, wallet))
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user