From f2866f2fa366e544da72f333f9f5d54f5a778fb6 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 21 Aug 2019 11:52:34 +0200 Subject: [PATCH 01/18] package: small visual/comments clean-up --- .../main/scala/fr/acinq/eclair/package.scala | 119 +++++++++--------- .../scala/fr/acinq/eclair/router/Graph.scala | 2 +- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 2d7709c974..71a83969dd 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -29,9 +29,9 @@ import scala.util.{Failure, Success, Try} package object eclair { /** - * We are using 'new SecureRandom()' instead of 'SecureRandom.getInstanceStrong()' because the latter can hang on Linux - * See http://bugs.java.com/view_bug.do?bug_id=6521844 and https://tersesystems.com/2015/12/17/the-right-way-to-use-securerandom/ - */ + * We are using 'new SecureRandom()' instead of 'SecureRandom.getInstanceStrong()' because the latter can hang on Linux + * See http://bugs.java.com/view_bug.do?bug_id=6521844 and https://tersesystems.com/2015/12/17/the-right-way-to-use-securerandom/ + */ val secureRandom = new SecureRandom() def randomBytes(length: Int): ByteVector = { @@ -59,82 +59,80 @@ package object eclair { } /** - * Converts feerate in satoshi-per-bytes to feerate in satoshi-per-kw - * - * @param feeratePerByte fee rate in satoshi-per-bytes - * @return feerate in satoshi-per-kw - */ + * Converts fee rate in satoshi-per-bytes to fee rate in satoshi-per-kw + * + * @param feeratePerByte fee rate in satoshi-per-bytes + * @return fee rate in satoshi-per-kw + */ def feerateByte2Kw(feeratePerByte: Long): Long = feerateKB2Kw(feeratePerByte * 1000) /** - * - * @param feeratesPerKw fee rate in satoshi-per-kw - * @return fee rate in satoshi-per-byte - */ - def feerateKw2Byte(feeratesPerKw: Long): Long = feeratesPerKw / 250 + * Converts fee rate in satoshi-per-kw to fee rate in satoshi-per-byte + * + * @param feeratePerKw fee rate in satoshi-per-kw + * @return fee rate in satoshi-per-byte + */ + def feerateKw2Byte(feeratePerKw: Long): Long = feeratePerKw / 250 /** - why 253 and not 250 since feerate-per-kw is feerate-per-kb / 250 and the minimum relay fee rate is 1000 satoshi/Kb ? - - because bitcoin core uses neither the actual tx size in bytes or the tx weight to check fees, but a "virtual size" - which is (3 * weight) / 4 ... - so we want : - fee > 1000 * virtual size - feerate-per-kw * weight > 1000 * (3 * weight / 4) - feerate_per-kw > 250 + 3000 / (4 * weight) - with a conservative minimum weight of 400, we get a minimum feerate_per-kw of 253 - - see https://github.com/ElementsProject/lightning/pull/1251 + * why 253 and not 250 since feerate-per-kw is feerate-per-kb / 250 and the minimum relay fee rate is 1000 satoshi/Kb ? + * + * because bitcoin core uses neither the actual tx size in bytes or the tx weight to check fees, but a "virtual size" + * which is (3 * weight) / 4 ... + * so we want : + * fee > 1000 * virtual size + * feerate-per-kw * weight > 1000 * (3 * weight / 4) + * feerate_per-kw > 250 + 3000 / (4 * weight) + * with a conservative minimum weight of 400, we get a minimum feerate_per-kw of 253 + * + * see https://github.com/ElementsProject/lightning/pull/1251 **/ val MinimumFeeratePerKw = 253 /** - minimum relay fee rate, in satoshi per kilo - bitcoin core uses virtual size and not the actual size in bytes, see above + * minimum relay fee rate, in satoshi per kilo + * bitcoin core uses virtual size and not the actual size in bytes, see above **/ val MinimumRelayFeeRate = 1000 /** - * Converts feerate in satoshi-per-kilobytes to feerate in satoshi-per-kw - * - * @param feeratePerKB fee rate in satoshi-per-kilobytes - * @return feerate in satoshi-per-kw - */ + * Converts fee rate in satoshi-per-kilobytes to fee rate in satoshi-per-kw + * + * @param feeratePerKB fee rate in satoshi-per-kilobytes + * @return fee rate in satoshi-per-kw + */ def feerateKB2Kw(feeratePerKB: Long): Long = Math.max(feeratePerKB / 4, MinimumFeeratePerKw) /** - * - * @param feeratesPerKw fee rate in satoshi-per-kw - * @return fee rate in satoshi-per-kilobyte - */ - def feerateKw2KB(feeratesPerKw: Long): Long = feeratesPerKw * 4 - + * Converts fee rate in satoshi-per-kw to fee rate in satoshi-per-kilobyte + * + * @param feeratePerKw fee rate in satoshi-per-kw + * @return fee rate in satoshi-per-kilobyte + */ + def feerateKw2KB(feeratePerKw: Long): Long = feeratePerKw * 4 def isPay2PubkeyHash(address: String): Boolean = address.startsWith("1") || address.startsWith("m") || address.startsWith("n") /** - * Tests whether the binary data is composed solely of printable ASCII characters (see BOLT 1) - * - * @param data to check - */ + * Tests whether the binary data is composed solely of printable ASCII characters (see BOLT 1) + * + * @param data to check + */ def isAsciiPrintable(data: ByteVector): Boolean = data.toArray.forall(ch => ch >= 32 && ch < 127) /** - * - * @param baseMsat fixed fee - * @param proportional proportional fee - * @param msat amount in millisatoshi - * @return the fee (in msat) that a node should be paid to forward an HTLC of 'amount' millisatoshis - */ - def nodeFee(baseMsat: MilliSatoshi, proportional: Long, msat: MilliSatoshi): MilliSatoshi = baseMsat + (msat * proportional) / 1000000 + * @param baseFee fixed fee + * @param proportionalFee proportional fee (millionths) + * @param paymentAmount payment amount in millisatoshi + * @return the fee that a node should be paid to forward an HTLC of 'paymentAmount' millisatoshis + */ + def nodeFee(baseFee: MilliSatoshi, proportionalFee: Long, paymentAmount: MilliSatoshi): MilliSatoshi = baseFee + (paymentAmount * proportionalFee) / 1000000 /** - * - * @param address base58 of bech32 address - * @param chainHash hash of the chain we're on, which will be checked against the input address - * @return the public key script that matches the input address. - */ - + * @param address base58 of bech32 address + * @param chainHash hash of the chain we're on, which will be checked against the input address + * @return the public key script that matches the input address. + */ def addressToPublicKeyScript(address: String, chainHash: ByteVector32): Seq[ScriptElt] = { Try(Base58Check.decode(address)) match { case Success((Base58.Prefix.PubkeyAddressTestnet, pubKeyHash)) if chainHash == Block.TestnetGenesisBlock.hash || chainHash == Block.RegtestGenesisBlock.hash => Script.pay2pkh(pubKeyHash) @@ -156,14 +154,13 @@ package object eclair { } /** - * We use this in the context of timestamp filtering, when we don't need an upper bound. - */ + * We use this in the context of timestamp filtering, when we don't need an upper bound. + */ val MaxEpochSeconds = Duration.fromNanos(Long.MaxValue).toSeconds /** - * One MilliSatoshi is a thousand of a Satoshi, the smallest unit usable in bitcoin - * @param amount - */ + * One MilliSatoshi is a thousand of a Satoshi, the smallest unit usable in bitcoin + */ case class MilliSatoshi(amount: Long) { // @formatter:off def toLong = amount @@ -191,6 +188,7 @@ package object eclair { } implicit object NumericMilliSatoshi extends Numeric[MilliSatoshi] { + // @formatter:off override def plus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount + y.amount) override def minus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount - y.amount) override def times(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount * y.amount) @@ -201,13 +199,16 @@ package object eclair { override def toFloat(x: MilliSatoshi): Float = x.toLong override def toDouble(x: MilliSatoshi): Double = x.toLong override def compare(x: MilliSatoshi, y: MilliSatoshi): Int = x.compare(y) + // @formatter:on } private def satoshi2millisatoshi(input: Satoshi): MilliSatoshi = MilliSatoshi(input.amount * 1000L) + // @formatter:off def maxOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.max(x.amount, y.amount)) def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.amount, y.amount)) def maxOf(x: Satoshi, y: Satoshi) = Satoshi(Math.max(x.amount, y.amount)) def minOf(x: Satoshi, y: Satoshi) = Satoshi(Math.min(x.amount, y.amount)) + // @formatter:on } \ No newline at end of file diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala index 27e92a3238..6eab194d9e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala @@ -318,7 +318,7 @@ object Graph { * @return the new amount updated with the necessary fees for this edge */ private def edgeFeeCost(edge: GraphEdge, amountWithFees: MilliSatoshi):MilliSatoshi = { - if(edgeHasZeroFee(edge)) amountWithFees + nodeFee(baseMsat = MilliSatoshi(1), proportional = 0, amountWithFees) + if(edgeHasZeroFee(edge)) amountWithFees + nodeFee(baseFee = MilliSatoshi(1), proportionalFee = 0, amountWithFees) else amountWithFees + nodeFee(edge.update.feeBaseMsat, edge.update.feeProportionalMillionths, amountWithFees) } From a835b06ac4f4b52f42738db7642ff7b91f2c79bf Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 21 Aug 2019 13:50:01 +0200 Subject: [PATCH 02/18] Add more numeric utilities to MilliSatoshi --- .../main/scala/fr/acinq/eclair/package.scala | 9 ++++ .../scala/fr/acinq/eclair/PackageSpec.scala | 50 +++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 71a83969dd..02b226550b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -165,15 +165,24 @@ package object eclair { // @formatter:off def toLong = amount def +(other: MilliSatoshi) = MilliSatoshi(amount + other.amount) + def +(other: Satoshi) = MilliSatoshi(amount + other.toMilliSatoshi.amount) + def +(other: Long) = MilliSatoshi(amount + other) def -(other: MilliSatoshi) = MilliSatoshi(amount - other.amount) + def -(other: Satoshi) = MilliSatoshi(amount - other.toMilliSatoshi.amount) + def -(other: Long) = MilliSatoshi(amount - other) def *(m: Long) = MilliSatoshi(amount * m) def *(m: Double) = MilliSatoshi((amount * m).toLong) def /(d: Long) = MilliSatoshi(amount / d) def compare(other: MilliSatoshi): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 + def compare(other: Satoshi): Int = compare(other.toMilliSatoshi) def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 + def <= (that: Satoshi): Boolean = compare(that) <= 0 def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 + def >= (that: Satoshi): Boolean = compare(that) >= 0 def < (that: MilliSatoshi): Boolean = compare(that) < 0 + def < (that: Satoshi): Boolean = compare(that) < 0 def > (that: MilliSatoshi): Boolean = compare(that) > 0 + def > (that: Satoshi): Boolean = compare(that) > 0 def unary_-() = MilliSatoshi(-amount) def truncateToSatoshi: Satoshi = Satoshi(amount / 1000) // @formatter:on diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala index 3dd302c3c9..4261a18620 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala @@ -17,15 +17,15 @@ package fr.acinq.eclair import fr.acinq.bitcoin.Crypto.PrivateKey -import fr.acinq.bitcoin.{Base58, Base58Check, Bech32, Block, ByteVector32, Crypto, Script} +import fr.acinq.bitcoin.{Base58, Base58Check, Bech32, Block, ByteVector32, Crypto, Satoshi, Script} import org.scalatest.FunSuite import scodec.bits._ import scala.util.Try /** - * Created by PM on 27/01/2017. - */ + * Created by PM on 27/01/2017. + */ class PackageSpec extends FunSuite { @@ -34,7 +34,7 @@ class PackageSpec extends FunSuite { (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 1, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE") :: (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000", 2, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0002") :: (hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00F0", 0x0F00, hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0") :: Nil) - .map(x => (ByteVector32(x._1), x._2, ByteVector32(x._3))) + .map(x => (ByteVector32(x._1), x._2, ByteVector32(x._3))) data.foreach(x => assert(toLongId(ByteVector32(x._1), x._2) === x._3)) } @@ -113,4 +113,46 @@ class PackageSpec extends FunSuite { assert(ShortChannelId(Long.MaxValue - 1) < ShortChannelId(Long.MaxValue)) assert(ShortChannelId(Long.MaxValue) < ShortChannelId(Long.MaxValue + 1)) } + + test("millisatoshi numeric operations") { + // add + assert(MilliSatoshi(561) + MilliSatoshi(0) === MilliSatoshi(561)) + assert(MilliSatoshi(561) + 0 === MilliSatoshi(561)) + assert(MilliSatoshi(561) + MilliSatoshi(1105) === MilliSatoshi(1666)) + assert(MilliSatoshi(561) + 1105 === MilliSatoshi(1666)) + assert(MilliSatoshi(2000) + Satoshi(3) === MilliSatoshi(5000)) + + // subtract + assert(MilliSatoshi(561) - MilliSatoshi(0) === MilliSatoshi(561)) + assert(MilliSatoshi(561) - 0 === MilliSatoshi(561)) + assert(MilliSatoshi(1105) - MilliSatoshi(561) === MilliSatoshi(544)) + assert(MilliSatoshi(1105) - 561 === MilliSatoshi(544)) + assert(MilliSatoshi(561) - MilliSatoshi(1105) === -MilliSatoshi(544)) + assert(MilliSatoshi(561) - 1105 === -MilliSatoshi(544)) + assert(MilliSatoshi(1105) - Satoshi(1) === MilliSatoshi(105)) + + // multiply + assert(MilliSatoshi(561) * 1 === MilliSatoshi(561)) + assert(MilliSatoshi(561) * 2 === MilliSatoshi(1122)) + assert(MilliSatoshi(561) * 2.5 === MilliSatoshi(1402)) + + // divide + assert(MilliSatoshi(561) / 1 === MilliSatoshi(561)) + assert(MilliSatoshi(561) / 2 === MilliSatoshi(280)) + + // compare + assert(MilliSatoshi(561) <= MilliSatoshi(561)) + assert(MilliSatoshi(561) <= MilliSatoshi(1105)) + assert(MilliSatoshi(561) < MilliSatoshi(1105)) + assert(MilliSatoshi(561) >= MilliSatoshi(561)) + assert(MilliSatoshi(1105) >= MilliSatoshi(561)) + assert(MilliSatoshi(1105) > MilliSatoshi(561)) + assert(MilliSatoshi(1000) <= Satoshi(1)) + assert(MilliSatoshi(1000) <= Satoshi(2)) + assert(MilliSatoshi(1000) < Satoshi(2)) + assert(MilliSatoshi(1000) >= Satoshi(1)) + assert(MilliSatoshi(2000) >= Satoshi(1)) + assert(MilliSatoshi(2000) > Satoshi(1)) + } + } From 4306fdc1ce4ffc809aed124b6920c463881b8576 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 21 Aug 2019 14:59:28 +0200 Subject: [PATCH 03/18] Add msat/sat/mbtc/btc postfix to long --- .../main/scala/fr/acinq/eclair/package.scala | 9 ++++-- .../scala/fr/acinq/eclair/PackageSpec.scala | 31 +++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 02b226550b..58a7fde72f 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -166,10 +166,8 @@ package object eclair { def toLong = amount def +(other: MilliSatoshi) = MilliSatoshi(amount + other.amount) def +(other: Satoshi) = MilliSatoshi(amount + other.toMilliSatoshi.amount) - def +(other: Long) = MilliSatoshi(amount + other) def -(other: MilliSatoshi) = MilliSatoshi(amount - other.amount) def -(other: Satoshi) = MilliSatoshi(amount - other.toMilliSatoshi.amount) - def -(other: Long) = MilliSatoshi(amount - other) def *(m: Long) = MilliSatoshi(amount * m) def *(m: Double) = MilliSatoshi((amount * m).toLong) def /(d: Long) = MilliSatoshi(amount / d) @@ -188,6 +186,13 @@ package object eclair { // @formatter:on } + implicit class LongToBtcAmounts(l: Long) { + def msat: MilliSatoshi = MilliSatoshi(l) + def sat: Satoshi = Satoshi(l) + def mbtc: MilliBtc = MilliBtc(l) + def btc: Btc = Btc(l) + } + implicit class ToMilliSatoshiConversion(amount: BtcAmount) { def toMilliSatoshi: MilliSatoshi = amount match { case sat: Satoshi => satoshi2millisatoshi(sat) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala index 4261a18620..60920efef7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala @@ -116,25 +116,22 @@ class PackageSpec extends FunSuite { test("millisatoshi numeric operations") { // add - assert(MilliSatoshi(561) + MilliSatoshi(0) === MilliSatoshi(561)) - assert(MilliSatoshi(561) + 0 === MilliSatoshi(561)) - assert(MilliSatoshi(561) + MilliSatoshi(1105) === MilliSatoshi(1666)) - assert(MilliSatoshi(561) + 1105 === MilliSatoshi(1666)) - assert(MilliSatoshi(2000) + Satoshi(3) === MilliSatoshi(5000)) + assert(MilliSatoshi(561) + 0.msat === MilliSatoshi(561)) + assert(MilliSatoshi(561) + 0.sat === MilliSatoshi(561)) + assert(MilliSatoshi(561) + 1105.msat === MilliSatoshi(1666)) + assert(MilliSatoshi(2000) + 3.sat === MilliSatoshi(5000)) // subtract - assert(MilliSatoshi(561) - MilliSatoshi(0) === MilliSatoshi(561)) - assert(MilliSatoshi(561) - 0 === MilliSatoshi(561)) - assert(MilliSatoshi(1105) - MilliSatoshi(561) === MilliSatoshi(544)) - assert(MilliSatoshi(1105) - 561 === MilliSatoshi(544)) - assert(MilliSatoshi(561) - MilliSatoshi(1105) === -MilliSatoshi(544)) - assert(MilliSatoshi(561) - 1105 === -MilliSatoshi(544)) - assert(MilliSatoshi(1105) - Satoshi(1) === MilliSatoshi(105)) + assert(MilliSatoshi(561) - 0.msat === MilliSatoshi(561)) + assert(MilliSatoshi(1105) - 561.msat === MilliSatoshi(544)) + assert(561.msat - 1105.msat === -MilliSatoshi(544)) + assert(MilliSatoshi(561) - 1105.msat === -MilliSatoshi(544)) + assert(MilliSatoshi(1105) - 1.sat === MilliSatoshi(105)) // multiply - assert(MilliSatoshi(561) * 1 === MilliSatoshi(561)) - assert(MilliSatoshi(561) * 2 === MilliSatoshi(1122)) - assert(MilliSatoshi(561) * 2.5 === MilliSatoshi(1402)) + assert(MilliSatoshi(561) * 1 === 561.msat) + assert(MilliSatoshi(561) * 2 === 1122.msat) + assert(MilliSatoshi(561) * 2.5 === 1402.msat) // divide assert(MilliSatoshi(561) / 1 === MilliSatoshi(561)) @@ -142,13 +139,13 @@ class PackageSpec extends FunSuite { // compare assert(MilliSatoshi(561) <= MilliSatoshi(561)) - assert(MilliSatoshi(561) <= MilliSatoshi(1105)) + assert(MilliSatoshi(561) <= 1105.msat) assert(MilliSatoshi(561) < MilliSatoshi(1105)) assert(MilliSatoshi(561) >= MilliSatoshi(561)) assert(MilliSatoshi(1105) >= MilliSatoshi(561)) assert(MilliSatoshi(1105) > MilliSatoshi(561)) assert(MilliSatoshi(1000) <= Satoshi(1)) - assert(MilliSatoshi(1000) <= Satoshi(2)) + assert(MilliSatoshi(1000) <= 2.sat) assert(MilliSatoshi(1000) < Satoshi(2)) assert(MilliSatoshi(1000) >= Satoshi(1)) assert(MilliSatoshi(2000) >= Satoshi(1)) From 5cd4b2607bcde958c11e7e637d18780e98e80bed Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 21 Aug 2019 15:06:21 +0200 Subject: [PATCH 04/18] Add more overloads to maxOf / minOf --- .../src/main/scala/fr/acinq/eclair/package.scala | 6 +++++- .../src/test/scala/fr/acinq/eclair/PackageSpec.scala | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 58a7fde72f..c4b10795bb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -220,8 +220,12 @@ package object eclair { // @formatter:off def maxOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.max(x.amount, y.amount)) - def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.amount, y.amount)) + def maxOf(x: MilliSatoshi, y: Satoshi) = MilliSatoshi(Math.max(x.amount, y.toMilliSatoshi.amount)) + def maxOf(x: Satoshi, y: MilliSatoshi): MilliSatoshi = maxOf(y, x) def maxOf(x: Satoshi, y: Satoshi) = Satoshi(Math.max(x.amount, y.amount)) + def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.amount, y.amount)) + def minOf(x: MilliSatoshi, y: Satoshi) = MilliSatoshi(Math.min(x.amount, y.toMilliSatoshi.amount)) + def minOf(x: Satoshi, y: MilliSatoshi): MilliSatoshi = minOf(y, x) def minOf(x: Satoshi, y: Satoshi) = Satoshi(Math.min(x.amount, y.amount)) // @formatter:on diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala index 60920efef7..7975cd97e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala @@ -150,6 +150,18 @@ class PackageSpec extends FunSuite { assert(MilliSatoshi(1000) >= Satoshi(1)) assert(MilliSatoshi(2000) >= Satoshi(1)) assert(MilliSatoshi(2000) > Satoshi(1)) + + // maxOf + assert(maxOf(561 msat, 1105 msat) === MilliSatoshi(1105)) + assert(maxOf(1 sat, 1105 msat) === MilliSatoshi(1105)) + assert(maxOf(1105 msat, 2 sat) === MilliSatoshi(2000)) + assert(maxOf(1 sat, 2 sat) === Satoshi(2)) + + // minOf + assert(minOf(561 msat, 1105 msat) === MilliSatoshi(561)) + assert(minOf(1 sat, 1105 msat) === MilliSatoshi(1000)) + assert(minOf(1105 msat, 2 sat) === MilliSatoshi(1105)) + assert(minOf(1 sat, 2 sat) === Satoshi(1)) } } From b12616735eb65cfa9836e21d2910997e099e0635 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Thu, 22 Aug 2019 16:43:23 +0200 Subject: [PATCH 05/18] Move MilliSatoshi out of package object. Provide utilities in MilliSatoshi object for Java. Add Java tests. --- .../scala/fr/acinq/eclair/CoinUtils.scala | 100 +++++++++--------- .../scala/fr/acinq/eclair/MilliSatoshi.scala | 76 +++++++++++++ .../fr/acinq/eclair/api/JsonSerializers.scala | 2 +- .../fr/acinq/eclair/channel/Commitments.scala | 8 +- .../fr/acinq/eclair/channel/Helpers.scala | 7 +- .../main/scala/fr/acinq/eclair/io/Peer.scala | 8 +- .../main/scala/fr/acinq/eclair/package.scala | 65 +++--------- .../acinq/eclair/payment/PaymentRequest.scala | 18 ++-- .../scala/fr/acinq/eclair/router/Router.scala | 2 +- .../fr/acinq/eclair/wire/CommonCodecs.scala | 2 +- .../eclair/wire/LightningMessageCodecs.scala | 6 +- .../fr/acinq/eclair/MilliSatoshiTest.java | 40 +++++++ .../fr/acinq/eclair/MilliSatoshiSpec.scala | 79 ++++++++++++++ .../scala/fr/acinq/eclair/PackageSpec.scala | 50 --------- .../states/StateTestsHelperMethods.scala | 6 +- .../eclair/payment/HtlcGenerationSpec.scala | 5 +- .../fr/acinq/eclair/gui/GUIUpdater.scala | 6 +- .../scala/fr/acinq/eclair/gui/Handlers.scala | 2 +- .../controllers/ChannelPaneController.scala | 2 +- .../gui/controllers/MainController.scala | 2 +- .../ReceivePaymentController.scala | 2 +- .../controllers/SendPaymentController.scala | 11 +- 22 files changed, 297 insertions(+), 202 deletions(-) create mode 100644 eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala create mode 100644 eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java create mode 100644 eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala b/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala index 2e58bef4dd..210974a147 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala @@ -17,14 +17,16 @@ package fr.acinq.eclair import java.text.{DecimalFormat, NumberFormat} + import fr.acinq.bitcoin.{Btc, BtcAmount, MilliBtc, Satoshi} import grizzled.slf4j.Logging + import scala.util.{Failure, Success, Try} /** - * Internal UI utility class, useful for lossless conversion between BtcAmount. - * The issue being that Satoshi contains a Long amount and it can not be converted to MilliSatoshi without losing the decimal part. - */ + * Internal UI utility class, useful for lossless conversion between BtcAmount. + * The issue being that Satoshi contains a Long amount and it can not be converted to MilliSatoshi without losing the decimal part. + */ private sealed trait BtcAmountGUILossless { def amount_msat: Long def unit: CoinUnit @@ -124,15 +126,15 @@ object CoinUtils extends Logging { } /** - * Converts a string amount denominated in a bitcoin unit to a Millisatoshi amount. The amount might be truncated if - * it has too many decimals because MilliSatoshi only accepts Long amount. - * - * @param amount numeric String, can be decimal. - * @param unit bitcoin unit, can be milliSatoshi, Satoshi, Bits, milliBTC, BTC. - * @return amount as a MilliSatoshi object. - * @throws NumberFormatException if the amount parameter is not numeric. - * @throws IllegalArgumentException if the unit is not equals to milliSatoshi, Satoshi or milliBTC. - */ + * Converts a string amount denominated in a bitcoin unit to a Millisatoshi amount. The amount might be truncated if + * it has too many decimals because MilliSatoshi only accepts Long amount. + * + * @param amount numeric String, can be decimal. + * @param unit bitcoin unit, can be milliSatoshi, Satoshi, Bits, milliBTC, BTC. + * @return amount as a MilliSatoshi object. + * @throws NumberFormatException if the amount parameter is not numeric. + * @throws IllegalArgumentException if the unit is not equals to milliSatoshi, Satoshi or milliBTC. + */ @throws(classOf[NumberFormatException]) @throws(classOf[IllegalArgumentException]) def convertStringAmountToMsat(amount: String, unit: String): MilliSatoshi = { @@ -152,13 +154,11 @@ object CoinUtils extends Logging { } def convertStringAmountToSat(amount: String, unit: String): Satoshi = - CoinUtils.convertStringAmountToMsat(amount, unit).truncateToSatoshi + CoinUtils.convertStringAmountToMsat(amount, unit).truncateToSatoshi /** - * Only BtcUnit, MBtcUnit, BitUnit, SatUnit and MSatUnit codes or label are supported. - * @param unit - * @return - */ + * Only BtcUnit, MBtcUnit, BitUnit, SatUnit and MSatUnit codes or label are supported. + */ def getUnitFromString(unit: String): CoinUnit = unit.toLowerCase() match { case u if u == MSatUnit.code || u == MSatUnit.label.toLowerCase() => MSatUnit case u if u == SatUnit.code || u == SatUnit.label.toLowerCase() => SatUnit @@ -169,26 +169,26 @@ object CoinUtils extends Logging { } /** - * Converts BtcAmount to a GUI Unit (wrapper containing amount as a millisatoshi long) - * - * @param amount BtcAmount - * @param unit unit to convert to - * @return a GUICoinAmount - */ + * Converts BtcAmount to a GUI Unit (wrapper containing amount as a millisatoshi long) + * + * @param amount BtcAmount + * @param unit unit to convert to + * @return a GUICoinAmount + */ private def convertAmountToGUIUnit(amount: BtcAmount, unit: CoinUnit): BtcAmountGUILossless = (amount, unit) match { // amount is msat, so no conversion required - case (a: MilliSatoshi, MSatUnit) => GUIMSat(a.amount * MSatUnit.factorToMsat) - case (a: MilliSatoshi, SatUnit) => GUISat(a.amount * MSatUnit.factorToMsat) - case (a: MilliSatoshi, BitUnit) => GUIBits(a.amount * MSatUnit.factorToMsat) - case (a: MilliSatoshi, MBtcUnit) => GUIMBtc(a.amount * MSatUnit.factorToMsat) - case (a: MilliSatoshi, BtcUnit) => GUIBtc(a.amount * MSatUnit.factorToMsat) + case (a: MilliSatoshi, MSatUnit) => GUIMSat(a.toLong * MSatUnit.factorToMsat) + case (a: MilliSatoshi, SatUnit) => GUISat(a.toLong * MSatUnit.factorToMsat) + case (a: MilliSatoshi, BitUnit) => GUIBits(a.toLong * MSatUnit.factorToMsat) + case (a: MilliSatoshi, MBtcUnit) => GUIMBtc(a.toLong * MSatUnit.factorToMsat) + case (a: MilliSatoshi, BtcUnit) => GUIBtc(a.toLong * MSatUnit.factorToMsat) // amount is satoshi, convert sat -> msat - case (a: Satoshi, MSatUnit) => GUIMSat(a.amount * SatUnit.factorToMsat) - case (a: Satoshi, SatUnit) => GUISat(a.amount * SatUnit.factorToMsat) - case (a: Satoshi, BitUnit) => GUIBits(a.amount * SatUnit.factorToMsat) - case (a: Satoshi, MBtcUnit) => GUIMBtc(a.amount * SatUnit.factorToMsat) - case (a: Satoshi, BtcUnit) => GUIBtc(a.amount * SatUnit.factorToMsat) + case (a: Satoshi, MSatUnit) => GUIMSat(a.toLong * SatUnit.factorToMsat) + case (a: Satoshi, SatUnit) => GUISat(a.toLong * SatUnit.factorToMsat) + case (a: Satoshi, BitUnit) => GUIBits(a.toLong * SatUnit.factorToMsat) + case (a: Satoshi, MBtcUnit) => GUIMBtc(a.toLong * SatUnit.factorToMsat) + case (a: Satoshi, BtcUnit) => GUIBtc(a.toLong * SatUnit.factorToMsat) // amount is mbtc case (a: MilliBtc, MSatUnit) => GUIMSat((a.amount * MBtcUnit.factorToMsat).toLong) @@ -204,18 +204,18 @@ object CoinUtils extends Logging { case (a: Btc, MBtcUnit) => GUIMBtc((a.amount * BtcUnit.factorToMsat).toLong) case (a: Btc, BtcUnit) => GUIBtc((a.amount * BtcUnit.factorToMsat).toLong) - case (a, _) => + case (_, _) => throw new IllegalArgumentException(s"unhandled conversion from $amount to $unit") } /** - * Converts the amount to the user preferred unit and returns a localized formatted String. - * This method is useful for read only displays. - * - * @param amount BtcAmount - * @param withUnit if true, append the user unit shortLabel (mBTC, BTC, mSat...) - * @return formatted amount - */ + * Converts the amount to the user preferred unit and returns a localized formatted String. + * This method is useful for read only displays. + * + * @param amount BtcAmount + * @param withUnit if true, append the user unit shortLabel (mBTC, BTC, mSat...) + * @return formatted amount + */ def formatAmountInUnit(amount: BtcAmount, unit: CoinUnit, withUnit: Boolean = false): String = { val formatted = COIN_FORMAT.format(rawAmountInUnit(amount, unit)) if (withUnit) s"$formatted ${unit.shortLabel}" else formatted @@ -227,14 +227,14 @@ object CoinUtils extends Logging { } /** - * Converts the amount to the user preferred unit and returns the BigDecimal value. - * This method is useful to feed numeric text input without formatting. - * - * Returns -1 if the given amount can not be converted. - * - * @param amount BtcAmount - * @return BigDecimal value of the BtcAmount - */ + * Converts the amount to the user preferred unit and returns the BigDecimal value. + * This method is useful to feed numeric text input without formatting. + * + * Returns -1 if the given amount can not be converted. + * + * @param amount BtcAmount + * @return BigDecimal value of the BtcAmount + */ def rawAmountInUnit(amount: BtcAmount, unit: CoinUnit): BigDecimal = Try(convertAmountToGUIUnit(amount, unit) match { case a: BtcAmountGUILossless => BigDecimal(a.amount_msat) / a.unit.factorToMsat case a => throw new IllegalArgumentException(s"unhandled unit $a") @@ -245,5 +245,5 @@ object CoinUtils extends Logging { -1 } - def rawAmountInUnit(msat: MilliSatoshi, unit: CoinUnit): BigDecimal = BigDecimal(msat.amount) / unit.factorToMsat + def rawAmountInUnit(msat: MilliSatoshi, unit: CoinUnit): BigDecimal = BigDecimal(msat.toLong) / unit.factorToMsat } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala new file mode 100644 index 0000000000..351fdce029 --- /dev/null +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -0,0 +1,76 @@ +/* + * 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 + +import fr.acinq.bitcoin.{Btc, BtcAmount, MilliBtc, Satoshi, btc2satoshi, millibtc2satoshi} + +/** + * Created by t-bast on 22/08/2019. + */ + +/** + * One MilliSatoshi is a thousand of a Satoshi, the smallest unit usable in bitcoin + */ +case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatoshi] { + + // @formatter:off + def +(other: MilliSatoshi) = MilliSatoshi(underlying + other.underlying) + def +(other: BtcAmount) = MilliSatoshi(underlying + other.toMilliSatoshi.underlying) + def -(other: MilliSatoshi) = MilliSatoshi(underlying - other.underlying) + def -(other: BtcAmount) = MilliSatoshi(underlying - other.toMilliSatoshi.underlying) + def *(m: Long) = MilliSatoshi(underlying * m) + def *(m: Double) = MilliSatoshi((underlying * m).toLong) + def /(d: Long) = MilliSatoshi(underlying / d) + def unary_-() = MilliSatoshi(-underlying) + override def compare(other: MilliSatoshi): Int = if (underlying == other.underlying) 0 else if (underlying < other.underlying) -1 else 1 + // Since BtcAmount is a sealed trait that MilliSatoshi cannot extend, we need to redefine comparison operators. + def compare(other: BtcAmount): Int = { + val otherMsat = other.toMilliSatoshi.underlying + if (underlying == otherMsat) 0 else if (underlying < otherMsat) -1 else 1 + } + def <=(that: BtcAmount): Boolean = compare(that) <= 0 + def >=(that: BtcAmount): Boolean = compare(that) >= 0 + def <(that: BtcAmount): Boolean = compare(that) < 0 + def >(that: BtcAmount): Boolean = compare(that) > 0 + def truncateToSatoshi: Satoshi = Satoshi(underlying / 1000) + def toLong: Long = underlying + // @formatter:on + +} + +object MilliSatoshi { + + private def satoshi2millisatoshi(input: Satoshi): MilliSatoshi = MilliSatoshi(input.amount * 1000L) + + def toMilliSatoshi(amount: BtcAmount): MilliSatoshi = amount match { + case sat: Satoshi => satoshi2millisatoshi(sat) + case millis: MilliBtc => satoshi2millisatoshi(millibtc2satoshi(millis)) + case bitcoin: Btc => satoshi2millisatoshi(btc2satoshi(bitcoin)) + } + + // @formatter:off + def maxOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.max(x.toLong, y.toLong)) + def maxOf(x: MilliSatoshi, y: BtcAmount) = MilliSatoshi(Math.max(x.toLong, y.toMilliSatoshi.toLong)) + def maxOf(x: BtcAmount, y: MilliSatoshi): MilliSatoshi = maxOf(y, x) + def maxOf(x: Satoshi, y: Satoshi) = Satoshi(Math.max(x.toLong, y.toLong)) + def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.toLong, y.toLong)) + def minOf(x: MilliSatoshi, y: BtcAmount) = MilliSatoshi(Math.min(x.toLong, y.toMilliSatoshi.toLong)) + def minOf(x: BtcAmount, y: MilliSatoshi): MilliSatoshi = minOf(y, x) + def minOf(x: Satoshi, y: Satoshi) = Satoshi(Math.min(x.toLong, y.toLong)) + // @formatter:on + +} diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala index 203c6c7f35..0aa2a777ca 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala @@ -62,7 +62,7 @@ class SatoshiSerializer extends CustomSerializer[Satoshi](format => ({ null }, { })) class MilliSatoshiSerializer extends CustomSerializer[MilliSatoshi](format => ({ null }, { - case x: MilliSatoshi => JInt(x.amount) + case x: MilliSatoshi => JInt(x.toLong) })) class ShortChannelIdSerializer extends CustomSerializer[ShortChannelId](format => ({ null }, { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 21533f0dba..3afa2ca295 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -19,15 +19,13 @@ package fr.acinq.eclair.channel import akka.event.LoggingAdapter import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, sha256} import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, Satoshi} -import fr.acinq.eclair -import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets} import fr.acinq.eclair.crypto.{Generators, KeyManager, ShaChain, Sphinx} import fr.acinq.eclair.payment._ import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.transactions._ import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, MilliSatoshi, UInt64} +import fr.acinq.eclair.{Globals, MilliSatoshi, UInt64, _} // @formatter:off case class LocalChanges(proposed: List[UpdateMessage], signed: List[UpdateMessage], acked: List[UpdateMessage]) { @@ -89,13 +87,13 @@ case class Commitments(channelVersion: ChannelVersion, lazy val availableBalanceForSend: MilliSatoshi = { val reduced = CommitmentSpec.reduce(remoteCommit.spec, remoteChanges.acked, localChanges.proposed) val feesMsat = if (localParams.isFunder) commitTxFee(remoteParams.dustLimit, reduced).toMilliSatoshi else MilliSatoshi(0) - maxOf(reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) + MilliSatoshi.maxOf(reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) } lazy val availableBalanceForReceive: MilliSatoshi = { val reduced = CommitmentSpec.reduce(localCommit.spec, localChanges.acked, remoteChanges.proposed) val feesMsat = if (localParams.isFunder) MilliSatoshi(0) else commitTxFee(localParams.dustLimit, reduced).toMilliSatoshi - maxOf(reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) + MilliSatoshi.maxOf(reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index 1f49e73429..3241dc36ef 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -20,19 +20,16 @@ import akka.event.LoggingAdapter import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, ripemd160, sha256} import fr.acinq.bitcoin.Script._ import fr.acinq.bitcoin.{OutPoint, _} -import fr.acinq.eclair -import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.EclairWallet import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets} import fr.acinq.eclair.channel.Channel.REFRESH_CHANNEL_UPDATE_INTERVAL import fr.acinq.eclair.crypto.{Generators, KeyManager} import fr.acinq.eclair.db.ChannelsDb -import fr.acinq.eclair.payment.{Local, Origin} import fr.acinq.eclair.transactions.Scripts._ import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.transactions._ import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, NodeParams, ShortChannelId, addressToPublicKeyScript} +import fr.acinq.eclair.{NodeParams, ShortChannelId, addressToPublicKeyScript, _} import scodec.bits.ByteVector import scala.compat.Platform @@ -455,7 +452,7 @@ object Helpers { require(isValidFinalScriptPubkey(remoteScriptPubkey), "invalid remoteScriptPubkey") log.debug(s"making closing tx with closingFee={} and commitments:\n{}", closingFee, Commitments.specs2String(commitments)) // TODO: check that - val dustLimitSatoshis = maxOf(localParams.dustLimit, remoteParams.dustLimit) + val dustLimitSatoshis = MilliSatoshi.maxOf(localParams.dustLimit, remoteParams.dustLimit) val closingTx = Transactions.makeClosingTx(commitInput, localScriptPubkey, remoteScriptPubkey, localParams.isFunder, dustLimitSatoshis, closingFee, localCommit.spec) val localClosingSig = keyManager.sign(closingTx, keyManager.fundingPublicKey(commitments.localParams.channelKeyPath)) val closingSigned = ClosingSigned(channelId, closingFee, localClosingSig) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index 3f672d2e71..a19195ea38 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -607,9 +607,9 @@ object Peer { case object ResumeAnnouncements case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, fundingTxFeeratePerKw_opt: Option[Long], channelFlags: Option[Byte], timeout_opt: Option[Timeout]) { require(fundingSatoshis < Channel.MAX_FUNDING, s"fundingSatoshis must be less than ${Channel.MAX_FUNDING}") - require(pushMsat.amount <= 1000 * fundingSatoshis.amount, s"pushMsat must be less or equal to fundingSatoshis") + require(pushMsat.toLong <= 1000 * fundingSatoshis.amount, s"pushMsat must be less or equal to fundingSatoshis") require(fundingSatoshis.amount >= 0, s"fundingSatoshis must be positive") - require(pushMsat.amount >= 0, s"pushMsat must be positive") + require(pushMsat.toLong >= 0, s"pushMsat must be positive") fundingTxFeeratePerKw_opt.foreach(feeratePerKw => require(feeratePerKw >= MinimumFeeratePerKw, s"fee rate $feeratePerKw is below minimum $MinimumFeeratePerKw rate/kw")) } case object GetPeerInfo @@ -643,7 +643,7 @@ object Peer { channelKeyPath, dustLimit = nodeParams.dustLimit, maxHtlcValueInFlightMsat = nodeParams.maxHtlcValueInFlightMsat, - channelReserve = maxOf(Satoshi((nodeParams.reserveToFundingRatio * fundingAmount.toLong).toLong), nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit + channelReserve = MilliSatoshi.maxOf(Satoshi((nodeParams.reserveToFundingRatio * fundingAmount.toLong).toLong), nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit htlcMinimum = nodeParams.htlcMinimum, toSelfDelay = nodeParams.toRemoteDelayBlocks, // we choose their delay maxAcceptedHtlcs = nodeParams.maxAcceptedHtlcs, @@ -658,7 +658,7 @@ object Peer { * * @param gossipTimestampFilter_opt optional gossip timestamp range * @return - * - true if there is a filter and msg has no timestamp, or has one that matches the filter + * - true if there is a filter and msg has no timestamp, or has one that matches the filter * - false otherwise */ def timestampInRange(msg: RoutingMessage, gossipTimestampFilter_opt: Option[GossipTimestampFilter]): Boolean = { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index c4b10795bb..1fce09231f 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -158,55 +158,21 @@ package object eclair { */ val MaxEpochSeconds = Duration.fromNanos(Long.MaxValue).toSeconds - /** - * One MilliSatoshi is a thousand of a Satoshi, the smallest unit usable in bitcoin - */ - case class MilliSatoshi(amount: Long) { - // @formatter:off - def toLong = amount - def +(other: MilliSatoshi) = MilliSatoshi(amount + other.amount) - def +(other: Satoshi) = MilliSatoshi(amount + other.toMilliSatoshi.amount) - def -(other: MilliSatoshi) = MilliSatoshi(amount - other.amount) - def -(other: Satoshi) = MilliSatoshi(amount - other.toMilliSatoshi.amount) - def *(m: Long) = MilliSatoshi(amount * m) - def *(m: Double) = MilliSatoshi((amount * m).toLong) - def /(d: Long) = MilliSatoshi(amount / d) - def compare(other: MilliSatoshi): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 - def compare(other: Satoshi): Int = compare(other.toMilliSatoshi) - def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 - def <= (that: Satoshi): Boolean = compare(that) <= 0 - def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 - def >= (that: Satoshi): Boolean = compare(that) >= 0 - def < (that: MilliSatoshi): Boolean = compare(that) < 0 - def < (that: Satoshi): Boolean = compare(that) < 0 - def > (that: MilliSatoshi): Boolean = compare(that) > 0 - def > (that: Satoshi): Boolean = compare(that) > 0 - def unary_-() = MilliSatoshi(-amount) - def truncateToSatoshi: Satoshi = Satoshi(amount / 1000) - // @formatter:on - } - implicit class LongToBtcAmounts(l: Long) { + // @formatter:off def msat: MilliSatoshi = MilliSatoshi(l) def sat: Satoshi = Satoshi(l) def mbtc: MilliBtc = MilliBtc(l) def btc: Btc = Btc(l) - } - - implicit class ToMilliSatoshiConversion(amount: BtcAmount) { - def toMilliSatoshi: MilliSatoshi = amount match { - case sat: Satoshi => satoshi2millisatoshi(sat) - case millis: MilliBtc => satoshi2millisatoshi(millibtc2satoshi(millis)) - case bitcoin: Btc => satoshi2millisatoshi(btc2satoshi(bitcoin)) - } + // @formatter:on } implicit object NumericMilliSatoshi extends Numeric[MilliSatoshi] { // @formatter:off - override def plus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount + y.amount) - override def minus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount - y.amount) - override def times(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.amount * y.amount) - override def negate(x: MilliSatoshi): MilliSatoshi = MilliSatoshi(-x.amount) + override def plus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = x + y + override def minus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = x - y + override def times(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = MilliSatoshi(x.toLong * y.toLong) + override def negate(x: MilliSatoshi): MilliSatoshi = -x override def fromInt(x: Int): MilliSatoshi = MilliSatoshi(x) override def toInt(x: MilliSatoshi): Int = x.toLong.toInt override def toLong(x: MilliSatoshi): Long = x.toLong @@ -216,17 +182,12 @@ package object eclair { // @formatter:on } - private def satoshi2millisatoshi(input: Satoshi): MilliSatoshi = MilliSatoshi(input.amount * 1000L) - - // @formatter:off - def maxOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.max(x.amount, y.amount)) - def maxOf(x: MilliSatoshi, y: Satoshi) = MilliSatoshi(Math.max(x.amount, y.toMilliSatoshi.amount)) - def maxOf(x: Satoshi, y: MilliSatoshi): MilliSatoshi = maxOf(y, x) - def maxOf(x: Satoshi, y: Satoshi) = Satoshi(Math.max(x.amount, y.amount)) - def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.amount, y.amount)) - def minOf(x: MilliSatoshi, y: Satoshi) = MilliSatoshi(Math.min(x.amount, y.toMilliSatoshi.amount)) - def minOf(x: Satoshi, y: MilliSatoshi): MilliSatoshi = minOf(y, x) - def minOf(x: Satoshi, y: Satoshi) = Satoshi(Math.min(x.amount, y.amount)) - // @formatter:on + implicit class ToMilliSatoshiConversion(amount: BtcAmount) { + // @formatter:off + def toMilliSatoshi: MilliSatoshi = MilliSatoshi.toMilliSatoshi(amount) + def +(other: MilliSatoshi): MilliSatoshi = amount.toMilliSatoshi + other + def -(other: MilliSatoshi): MilliSatoshi = amount.toMilliSatoshi - other + // @formatter:on + } } \ No newline at end of file diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala index fc6ea0ca3e..6f6768845e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala @@ -16,16 +16,16 @@ package fr.acinq.eclair.payment -import fr.acinq.bitcoin.{Base58, Base58Check, Bech32, Block, ByteVector32, ByteVector64, Crypto} import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} -import fr.acinq.eclair.{MilliSatoshi, ShortChannelId} +import fr.acinq.bitcoin.{Base58, Base58Check, Bech32, Block, ByteVector32, ByteVector64, Crypto} import fr.acinq.eclair.payment.PaymentRequest._ +import fr.acinq.eclair.{MilliSatoshi, ShortChannelId} import scodec.Codec import scodec.bits.{BitVector, ByteOrdering, ByteVector} import scodec.codecs.{list, ubyte} -import scala.concurrent.duration._ import scala.compat.Platform +import scala.concurrent.duration._ import scala.util.Try /** @@ -41,7 +41,7 @@ import scala.util.Try */ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestamp: Long, nodeId: PublicKey, tags: List[PaymentRequest.TaggedField], signature: ByteVector) { - amount.map(a => require(a.amount > 0, s"amount is not valid")) + amount.map(a => require(a.toLong > 0, s"amount is not valid")) require(tags.collect { case _: PaymentRequest.PaymentHash => {} }.size == 1, "there must be exactly one payment hash tag") require(tags.collect { case PaymentRequest.Description(_) | PaymentRequest.DescriptionHash(_) => {} }.size == 1, "there must be exactly one description tag or one description hash tag") @@ -392,7 +392,7 @@ object PaymentRequest { * @param amount * @return the unit allowing for the shortest representation possible */ - def unit(amount: MilliSatoshi): Char = amount.amount * 10 match { // 1 milli-satoshis == 10 pico-bitcoin + def unit(amount: MilliSatoshi): Char = amount.toLong * 10 match { // 1 milli-satoshis == 10 pico-bitcoin case pico if pico % 1000 > 0 => 'p' case pico if pico % 1000000 > 0 => 'n' case pico if pico % 1000000000 > 0 => 'u' @@ -412,10 +412,10 @@ object PaymentRequest { def encode(amount: Option[MilliSatoshi]): String = { amount match { case None => "" - case Some(amt) if unit(amt) == 'p' => s"${amt.amount * 10L}p" // 1 pico-bitcoin == 10 milli-satoshis - case Some(amt) if unit(amt) == 'n' => s"${amt.amount / 100L}n" - case Some(amt) if unit(amt) == 'u' => s"${amt.amount / 100000L}u" - case Some(amt) if unit(amt) == 'm' => s"${amt.amount / 100000000L}m" + case Some(amt) if unit(amt) == 'p' => s"${amt.toLong * 10L}p" // 1 pico-bitcoin == 10 milli-satoshis + case Some(amt) if unit(amt) == 'n' => s"${amt.toLong / 100L}n" + case Some(amt) if unit(amt) == 'u' => s"${amt.toLong / 100000L}u" + case Some(amt) if unit(amt) == 'm' => s"${amt.toLong / 100000000L}m" } } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala index 59d241fa72..d06b58fdf9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala @@ -398,7 +398,7 @@ class Router(nodeParams: NodeParams, watcher: ActorRef, initialized: Option[Prom case Event(FinalizeRoute(partialHops), d) => // split into sublists [(a,b),(b,c), ...] then get the edges between each of those pairs, then select the largest edge between them - val edges = partialHops.sliding(2).map { case List(v1, v2) => d.graph.getEdgesBetween(v1, v2).maxBy(_.update.htlcMaximumMsat) } + val edges = partialHops.sliding(2).map { case List(v1, v2) => d.graph.getEdgesBetween(v1, v2).maxBy(_.update.htlcMaximumMsat.getOrElse(0 msat)) } val hops = edges.map(d => Hop(d.desc.a, d.desc.b, d.update)).toSeq sender ! RouteResponse(hops, Set.empty, Set.empty) stay diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/CommonCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/CommonCodecs.scala index fc749c8fe8..947f8a1d3b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/CommonCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/CommonCodecs.scala @@ -55,7 +55,7 @@ object CommonCodecs { val uint64: Codec[UInt64] = bytes(8).xmap(b => UInt64(b), a => a.toByteVector.padLeft(8)) val satoshi: Codec[Satoshi] = uint64overflow.xmapc(l => Satoshi(l))(_.toLong) - val millisatoshi: Codec[MilliSatoshi] = uint64overflow.xmapc(l => MilliSatoshi(l))(_.amount) + val millisatoshi: Codec[MilliSatoshi] = uint64overflow.xmapc(l => MilliSatoshi(l))(_.toLong) /** * We impose a minimal encoding on some values (such as varint and truncated int) to ensure that signed hashes can be diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageCodecs.scala index 055d9ffa16..01ed54bb88 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/LightningMessageCodecs.scala @@ -16,11 +16,9 @@ package fr.acinq.eclair.wire -import fr.acinq.eclair.crypto.Sphinx -import fr.acinq.eclair.{MilliSatoshi, wire} import fr.acinq.eclair.wire.CommonCodecs._ +import fr.acinq.eclair.{MilliSatoshi, wire} import scodec.Codec -import scodec.bits.ByteVector import scodec.codecs._ /** @@ -192,7 +190,7 @@ object LightningMessageCodecs { ("channelFlags" | byte) :: ("cltvExpiryDelta" | uint16) :: ("htlcMinimumMsat" | millisatoshi) :: - ("feeBaseMsat" | uint32.xmapc(l => MilliSatoshi(l))(_.amount)) :: + ("feeBaseMsat" | uint32.xmapc(l => MilliSatoshi(l))(_.toLong)) :: ("feeProportionalMillionths" | uint32) :: ("htlcMaximumMsat" | conditional((messageFlags & 1) != 0, millisatoshi)) :: ("unknownFields" | bytes) diff --git a/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java b/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java new file mode 100644 index 0000000000..24195b6e94 --- /dev/null +++ b/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java @@ -0,0 +1,40 @@ +/* + * 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; + +import fr.acinq.bitcoin.Satoshi; + +/** + * This class is a compile-time check that we are able to compile Java code that uses MilliSatoshi utilities. + */ +public final class MilliSatoshiTest { + + public static void Test() { + MilliSatoshi msat = new MilliSatoshi(561); + Satoshi sat = new Satoshi(1); + msat.truncateToSatoshi(); + MilliSatoshi.maxOf(msat, sat); + MilliSatoshi.minOf(sat, msat); + MilliSatoshi.toMilliSatoshi(sat); + msat = MilliSatoshi.toMilliSatoshi(sat).$plus(msat); + msat = msat.$plus(msat); + msat = msat.$times(2.0); + Boolean check1 = msat.$less$eq(new MilliSatoshi(1105)); + Boolean check2 = msat.$greater(sat); + } + +} diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala new file mode 100644 index 0000000000..db5c10051b --- /dev/null +++ b/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala @@ -0,0 +1,79 @@ +/* + * 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 + +import fr.acinq.bitcoin.Satoshi +import fr.acinq.eclair.MilliSatoshi.{maxOf, minOf} +import org.scalatest.FunSuite + +/** + * Created by t-bast on 22/08/2019. + */ + +class MilliSatoshiSpec extends FunSuite { + + test("millisatoshi numeric operations") { + // add + assert(MilliSatoshi(561) + 0.msat === MilliSatoshi(561)) + assert(MilliSatoshi(561) + 0.sat === MilliSatoshi(561)) + assert(MilliSatoshi(561) + 1105.msat === MilliSatoshi(1666)) + assert(MilliSatoshi(2000) + 3.sat === MilliSatoshi(5000)) + + // subtract + assert(MilliSatoshi(561) - 0.msat === MilliSatoshi(561)) + assert(MilliSatoshi(1105) - 561.msat === MilliSatoshi(544)) + assert(561.msat - 1105.msat === -MilliSatoshi(544)) + assert(MilliSatoshi(561) - 1105.msat === -MilliSatoshi(544)) + assert(MilliSatoshi(1105) - 1.sat === MilliSatoshi(105)) + + // multiply + assert(MilliSatoshi(561) * 1 === 561.msat) + assert(MilliSatoshi(561) * 2 === 1122.msat) + assert(MilliSatoshi(561) * 2.5 === 1402.msat) + + // divide + assert(MilliSatoshi(561) / 1 === MilliSatoshi(561)) + assert(MilliSatoshi(561) / 2 === MilliSatoshi(280)) + + // compare + assert(MilliSatoshi(561) <= MilliSatoshi(561)) + assert(MilliSatoshi(561) <= 1105.msat) + assert(MilliSatoshi(561) < MilliSatoshi(1105)) + assert(MilliSatoshi(561) >= MilliSatoshi(561)) + assert(MilliSatoshi(1105) >= MilliSatoshi(561)) + assert(MilliSatoshi(1105) > MilliSatoshi(561)) + assert(MilliSatoshi(1000) <= Satoshi(1)) + assert(MilliSatoshi(1000) <= 2.sat) + assert(MilliSatoshi(1000) < Satoshi(2)) + assert(MilliSatoshi(1000) >= Satoshi(1)) + assert(MilliSatoshi(2000) >= Satoshi(1)) + assert(MilliSatoshi(2000) > Satoshi(1)) + + // maxOf + assert(maxOf(561 msat, 1105 msat) === MilliSatoshi(1105)) + assert(maxOf(1 sat, 1105 msat) === MilliSatoshi(1105)) + assert(maxOf(1105 msat, 2 sat) === MilliSatoshi(2000)) + assert(maxOf(1 sat, 2 sat) === Satoshi(2)) + + // minOf + assert(minOf(561 msat, 1105 msat) === MilliSatoshi(561)) + assert(minOf(1 sat, 1105 msat) === MilliSatoshi(1000)) + assert(minOf(1105 msat, 2 sat) === MilliSatoshi(1105)) + assert(minOf(1 sat, 2 sat) === Satoshi(1)) + } + +} diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala index 7975cd97e0..8e13db4ffb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala @@ -114,54 +114,4 @@ class PackageSpec extends FunSuite { assert(ShortChannelId(Long.MaxValue) < ShortChannelId(Long.MaxValue + 1)) } - test("millisatoshi numeric operations") { - // add - assert(MilliSatoshi(561) + 0.msat === MilliSatoshi(561)) - assert(MilliSatoshi(561) + 0.sat === MilliSatoshi(561)) - assert(MilliSatoshi(561) + 1105.msat === MilliSatoshi(1666)) - assert(MilliSatoshi(2000) + 3.sat === MilliSatoshi(5000)) - - // subtract - assert(MilliSatoshi(561) - 0.msat === MilliSatoshi(561)) - assert(MilliSatoshi(1105) - 561.msat === MilliSatoshi(544)) - assert(561.msat - 1105.msat === -MilliSatoshi(544)) - assert(MilliSatoshi(561) - 1105.msat === -MilliSatoshi(544)) - assert(MilliSatoshi(1105) - 1.sat === MilliSatoshi(105)) - - // multiply - assert(MilliSatoshi(561) * 1 === 561.msat) - assert(MilliSatoshi(561) * 2 === 1122.msat) - assert(MilliSatoshi(561) * 2.5 === 1402.msat) - - // divide - assert(MilliSatoshi(561) / 1 === MilliSatoshi(561)) - assert(MilliSatoshi(561) / 2 === MilliSatoshi(280)) - - // compare - assert(MilliSatoshi(561) <= MilliSatoshi(561)) - assert(MilliSatoshi(561) <= 1105.msat) - assert(MilliSatoshi(561) < MilliSatoshi(1105)) - assert(MilliSatoshi(561) >= MilliSatoshi(561)) - assert(MilliSatoshi(1105) >= MilliSatoshi(561)) - assert(MilliSatoshi(1105) > MilliSatoshi(561)) - assert(MilliSatoshi(1000) <= Satoshi(1)) - assert(MilliSatoshi(1000) <= 2.sat) - assert(MilliSatoshi(1000) < Satoshi(2)) - assert(MilliSatoshi(1000) >= Satoshi(1)) - assert(MilliSatoshi(2000) >= Satoshi(1)) - assert(MilliSatoshi(2000) > Satoshi(1)) - - // maxOf - assert(maxOf(561 msat, 1105 msat) === MilliSatoshi(1105)) - assert(maxOf(1 sat, 1105 msat) === MilliSatoshi(1105)) - assert(maxOf(1105 msat, 2 sat) === MilliSatoshi(2000)) - assert(maxOf(1 sat, 2 sat) === Satoshi(2)) - - // minOf - assert(minOf(561 msat, 1105 msat) === MilliSatoshi(561)) - assert(minOf(1 sat, 1105 msat) === MilliSatoshi(1000)) - assert(minOf(1105 msat, 2 sat) === MilliSatoshi(1105)) - assert(minOf(1 sat, 2 sat) === Satoshi(1)) - } - } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala index e614c054d7..c1e2969163 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala @@ -20,7 +20,6 @@ import java.util.UUID import akka.testkit.{TestFSMRef, TestKitBase, TestProbe} import fr.acinq.bitcoin.{ByteVector32, Crypto} -import fr.acinq.eclair import fr.acinq.eclair.TestConstants.{Alice, Bob, TestFeeEstimator} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.fee.FeeTargets @@ -29,8 +28,7 @@ import fr.acinq.eclair.io.Peer import fr.acinq.eclair.payment.PaymentLifecycle import fr.acinq.eclair.router.Hop import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, NodeParams, TestConstants, randomBytes32} -import fr.acinq.eclair._ +import fr.acinq.eclair.{NodeParams, TestConstants, randomBytes32, _} /** * Created by PM on 23/08/2016. @@ -100,7 +98,7 @@ trait StateTestsHelperMethods extends TestKitBase { bob2blockchain.expectMsgType[WatchConfirmed] // deeply buried awaitCond(alice.stateName == NORMAL) awaitCond(bob.stateName == NORMAL) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == maxOf(pushMsat - TestConstants.Alice.channelParams.channelReserve.toMilliSatoshi, MilliSatoshi(0))) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == MilliSatoshi.maxOf(pushMsat - TestConstants.Alice.channelParams.channelReserve.toMilliSatoshi, MilliSatoshi(0))) // x2 because alice and bob share the same relayer channelUpdateListener.expectMsgType[LocalChannelUpdate] channelUpdateListener.expectMsgType[LocalChannelUpdate] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala index 02252bc923..9724026345 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala @@ -20,7 +20,6 @@ import java.util.UUID import fr.acinq.bitcoin.DeterministicWallet.ExtendedPrivateKey import fr.acinq.bitcoin.{Block, ByteVector32, Crypto, DeterministicWallet} -import fr.acinq.eclair.maxOf import fr.acinq.eclair.channel.{Channel, ChannelVersion, Commitments} import fr.acinq.eclair.crypto.Sphinx import fr.acinq.eclair.crypto.Sphinx.{DecryptedPacket, PacketAndSecrets} @@ -152,8 +151,8 @@ object HtlcGenerationSpec { def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = MilliSatoshi(50000000L), testAvailableBalanceForReceive: MilliSatoshi = MilliSatoshi(50000000L)) = new Commitments(ChannelVersion.STANDARD, null, null, 0.toByte, null, null, null, null, 0, 0, Map.empty, null, null, null, channelId) { - override lazy val availableBalanceForSend: MilliSatoshi = maxOf(testAvailableBalanceForSend, MilliSatoshi(0)) - override lazy val availableBalanceForReceive: MilliSatoshi = maxOf(testAvailableBalanceForReceive, MilliSatoshi(0)) + override lazy val availableBalanceForSend: MilliSatoshi = MilliSatoshi.maxOf(testAvailableBalanceForSend, MilliSatoshi(0)) + override lazy val availableBalanceForReceive: MilliSatoshi = MilliSatoshi.maxOf(testAvailableBalanceForReceive, MilliSatoshi(0)) } def randomExtendedPrivateKey: ExtendedPrivateKey = DeterministicWallet.generate(randomBytes32) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala index 1f955e9d4b..d63fb219f9 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala @@ -86,7 +86,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging val (channelPaneController, root) = createChannelPanel(channel, peer, remoteNodeId, isFunder, channelId) channelPaneController.updateBalance(currentData.commitments) val m1 = m + (channel -> channelPaneController) - val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.amount).sum) + val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.toLong).sum) runInGuiThread(() => { channelPaneController.refreshBalance() mainController.refreshTotalBalance(totalBalance) @@ -118,7 +118,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging case ChannelSignatureReceived(channel, commitments) if m.contains(channel) => val channelPaneController = m(channel) channelPaneController.updateBalance(commitments) - val totalBalance = MilliSatoshi(m.values.map(_.getBalance.amount).sum) + val totalBalance = MilliSatoshi(m.values.map(_.getBalance.toLong).sum) runInGuiThread(() => { channelPaneController.refreshBalance() mainController.refreshTotalBalance(totalBalance) @@ -129,7 +129,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging log.debug(s"channel=${channelPaneController.channelId.getText} to be removed from gui") runInGuiThread(() => mainController.channelBox.getChildren.remove(channelPaneController.root)) val m1 = m - actor - val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.amount).sum) + val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.toLong).sum) runInGuiThread(() => { mainController.refreshTotalBalance(totalBalance) }) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala index 54765f834a..8b2f3e4975 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/Handlers.scala @@ -82,7 +82,7 @@ class Handlers(fKit: Future[Kit])(implicit ec: ExecutionContext = ExecutionConte def send(overrideAmountMsat_opt: Option[Long], req: PaymentRequest) = { val amountMsat = overrideAmountMsat_opt - .orElse(req.amount.map(_.amount)) + .orElse(req.amount.map(_.toLong)) .getOrElse(throw new RuntimeException("you need to manually specify an amount for this payment request")) logger.info(s"sending $amountMsat to ${req.paymentHash} @ ${req.nodeId}") (for { diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ChannelPaneController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ChannelPaneController.scala index c4691f0148..25cd6ac350 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ChannelPaneController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ChannelPaneController.scala @@ -135,7 +135,7 @@ class ChannelPaneController(val channelRef: ActorRef, val peerNodeId: String) ex def refreshBalance(): Unit = { amountUs.setText(s"${CoinUtils.formatAmountInUnit(balance, FxApp.getUnit, false)} / ${CoinUtils.formatAmountInUnit(capacity, FxApp.getUnit, withUnit = true)}") - balanceBar.setProgress(balance.amount.toDouble / capacity.amount) + balanceBar.setProgress(balance.toLong.toDouble / capacity.toLong) } def getBalance: MilliSatoshi = balance diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/MainController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/MainController.scala index 60626148c8..0a2badc42b 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/MainController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/MainController.scala @@ -344,7 +344,7 @@ class MainController(val handlers: Handlers, val hostServices: HostServices) ext }) paymentRelayedFeesColumn.setCellValueFactory(new Callback[CellDataFeatures[PaymentRelayedRecord, String], ObservableValue[String]]() { def call(p: CellDataFeatures[PaymentRelayedRecord, String]) = new SimpleStringProperty(CoinUtils.formatAmountInUnit( - MilliSatoshi(p.getValue.event.amountIn.amount - p.getValue.event.amountOut.amount), FxApp.getUnit, withUnit = true)) + p.getValue.event.amountIn - p.getValue.event.amountOut, FxApp.getUnit, withUnit = true)) }) paymentRelayedHashColumn.setCellValueFactory(paymentHashCellValueFactory) paymentRelayedDateColumn.setCellValueFactory(paymentDateCellValueFactory) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala index 2abe281afb..e9f360392f 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala @@ -71,7 +71,7 @@ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends case "" => createPaymentRequest(None) case GUIValidators.amountDecRegex(_*) => Try(CoinUtils.convertStringAmountToMsat(amount.getText, unit.getValue)) match { - case Success(amountMsat) if amountMsat.amount < 0 => + case Success(amountMsat) if amountMsat.toLong < 0 => handleError("Amount must be greater than 0") case Failure(_) => handleError("Amount is incorrect") diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/SendPaymentController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/SendPaymentController.scala index 5cce7374c9..a484446e74 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/SendPaymentController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/SendPaymentController.scala @@ -16,6 +16,10 @@ package fr.acinq.eclair.gui.controllers +import fr.acinq.eclair.CoinUtils +import fr.acinq.eclair.gui.{FxApp, Handlers} +import fr.acinq.eclair.payment.PaymentRequest +import grizzled.slf4j.Logging import javafx.beans.value.{ChangeListener, ObservableValue} import javafx.event.{ActionEvent, EventHandler} import javafx.fxml.FXML @@ -24,11 +28,6 @@ import javafx.scene.input.KeyCode.{ENTER, TAB} import javafx.scene.input.KeyEvent import javafx.stage.Stage -import fr.acinq.eclair.CoinUtils -import fr.acinq.eclair.gui.{FxApp, Handlers} -import fr.acinq.eclair.payment.PaymentRequest -import grizzled.slf4j.Logging - import scala.util.{Failure, Success, Try} /** @@ -111,7 +110,7 @@ class SendPaymentController(val handlers: Handlers, val stage: Stage) extends Lo (Try(CoinUtils.convertStringAmountToMsat(amountField.getText(), FxApp.getUnit.code)), readPaymentRequest()) match { case (Success(amountMsat), Success(pr)) => // we always override the payment request amount with the one from the UI - Try(handlers.send(Some(amountMsat.amount), pr)) match { + Try(handlers.send(Some(amountMsat.toLong), pr)) match { case Success(_) => stage.close() case Failure(f) => paymentRequestError.setText(s"Invalid Payment Request: ${f.getMessage}") } From 4f1e119a7fa8593c14bb95ae9007cfecf7b2cf03 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Thu, 22 Aug 2019 17:33:37 +0200 Subject: [PATCH 06/18] fixup! Move MilliSatoshi out of package object. Provide utilities in MilliSatoshi object for Java. Add Java tests. --- .../src/main/scala/fr/acinq/eclair/MilliSatoshi.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index 351fdce029..73b22f09d5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -38,10 +38,7 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos def unary_-() = MilliSatoshi(-underlying) override def compare(other: MilliSatoshi): Int = if (underlying == other.underlying) 0 else if (underlying < other.underlying) -1 else 1 // Since BtcAmount is a sealed trait that MilliSatoshi cannot extend, we need to redefine comparison operators. - def compare(other: BtcAmount): Int = { - val otherMsat = other.toMilliSatoshi.underlying - if (underlying == otherMsat) 0 else if (underlying < otherMsat) -1 else 1 - } + def compare(other: BtcAmount): Int = compare(other.toMilliSatoshi) def <=(that: BtcAmount): Boolean = compare(that) <= 0 def >=(that: BtcAmount): Boolean = compare(that) >= 0 def <(that: BtcAmount): Boolean = compare(that) < 0 From a64ddc84468b7f77acc09bd51d383ecbeedc6efc Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Thu, 22 Aug 2019 17:56:20 +0200 Subject: [PATCH 07/18] fixup! fixup! Move MilliSatoshi out of package object. Provide utilities in MilliSatoshi object for Java. Add Java tests. --- eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index 73b22f09d5..9c06dbb7b7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -36,7 +36,7 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos def *(m: Double) = MilliSatoshi((underlying * m).toLong) def /(d: Long) = MilliSatoshi(underlying / d) def unary_-() = MilliSatoshi(-underlying) - override def compare(other: MilliSatoshi): Int = if (underlying == other.underlying) 0 else if (underlying < other.underlying) -1 else 1 + override def compare(other: MilliSatoshi): Int = underlying.compareTo(other.underlying) // Since BtcAmount is a sealed trait that MilliSatoshi cannot extend, we need to redefine comparison operators. def compare(other: BtcAmount): Int = compare(other.toMilliSatoshi) def <=(that: BtcAmount): Boolean = compare(that) <= 0 From 88a9a9c570610d3c1f2efbb14242ed6d1ec94a92 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Fri, 23 Aug 2019 10:14:42 +0200 Subject: [PATCH 08/18] Replace maxOf/minOf by max/min directly on MilliSatoshi --- .../scala/fr/acinq/eclair/MilliSatoshi.scala | 26 +++++------ .../fr/acinq/eclair/channel/Commitments.scala | 4 +- .../fr/acinq/eclair/channel/Helpers.scala | 2 +- .../main/scala/fr/acinq/eclair/io/Peer.scala | 43 +++++++++---------- .../main/scala/fr/acinq/eclair/package.scala | 6 +++ .../fr/acinq/eclair/MilliSatoshiTest.java | 4 +- .../fr/acinq/eclair/MilliSatoshiSpec.scala | 17 ++++---- .../states/StateTestsHelperMethods.scala | 2 +- .../eclair/payment/HtlcGenerationSpec.scala | 4 +- 9 files changed, 54 insertions(+), 54 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index 9c06dbb7b7..369fad66b7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -36,13 +36,20 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos def *(m: Double) = MilliSatoshi((underlying * m).toLong) def /(d: Long) = MilliSatoshi(underlying / d) def unary_-() = MilliSatoshi(-underlying) + override def compare(other: MilliSatoshi): Int = underlying.compareTo(other.underlying) // Since BtcAmount is a sealed trait that MilliSatoshi cannot extend, we need to redefine comparison operators. def compare(other: BtcAmount): Int = compare(other.toMilliSatoshi) - def <=(that: BtcAmount): Boolean = compare(that) <= 0 - def >=(that: BtcAmount): Boolean = compare(that) >= 0 - def <(that: BtcAmount): Boolean = compare(that) < 0 - def >(that: BtcAmount): Boolean = compare(that) > 0 + def <=(other: BtcAmount): Boolean = compare(other) <= 0 + def >=(other: BtcAmount): Boolean = compare(other) >= 0 + def <(other: BtcAmount): Boolean = compare(other) < 0 + def >(other: BtcAmount): Boolean = compare(other) > 0 + + def max(other: MilliSatoshi): MilliSatoshi = if (this > other) this else other + def max(other: BtcAmount): MilliSatoshi = if (this > other) this else other.toMilliSatoshi + def min(other: MilliSatoshi): MilliSatoshi = if (this < other) this else other + def min(other: BtcAmount): MilliSatoshi = if (this < other) this else other.toMilliSatoshi + def truncateToSatoshi: Satoshi = Satoshi(underlying / 1000) def toLong: Long = underlying // @formatter:on @@ -59,15 +66,4 @@ object MilliSatoshi { case bitcoin: Btc => satoshi2millisatoshi(btc2satoshi(bitcoin)) } - // @formatter:off - def maxOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.max(x.toLong, y.toLong)) - def maxOf(x: MilliSatoshi, y: BtcAmount) = MilliSatoshi(Math.max(x.toLong, y.toMilliSatoshi.toLong)) - def maxOf(x: BtcAmount, y: MilliSatoshi): MilliSatoshi = maxOf(y, x) - def maxOf(x: Satoshi, y: Satoshi) = Satoshi(Math.max(x.toLong, y.toLong)) - def minOf(x: MilliSatoshi, y: MilliSatoshi) = MilliSatoshi(Math.min(x.toLong, y.toLong)) - def minOf(x: MilliSatoshi, y: BtcAmount) = MilliSatoshi(Math.min(x.toLong, y.toMilliSatoshi.toLong)) - def minOf(x: BtcAmount, y: MilliSatoshi): MilliSatoshi = minOf(y, x) - def minOf(x: Satoshi, y: Satoshi) = Satoshi(Math.min(x.toLong, y.toLong)) - // @formatter:on - } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 3afa2ca295..0d3ab28612 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -87,13 +87,13 @@ case class Commitments(channelVersion: ChannelVersion, lazy val availableBalanceForSend: MilliSatoshi = { val reduced = CommitmentSpec.reduce(remoteCommit.spec, remoteChanges.acked, localChanges.proposed) val feesMsat = if (localParams.isFunder) commitTxFee(remoteParams.dustLimit, reduced).toMilliSatoshi else MilliSatoshi(0) - MilliSatoshi.maxOf(reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) + (reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat).max(MilliSatoshi(0)) } lazy val availableBalanceForReceive: MilliSatoshi = { val reduced = CommitmentSpec.reduce(localCommit.spec, localChanges.acked, remoteChanges.proposed) val feesMsat = if (localParams.isFunder) MilliSatoshi(0) else commitTxFee(localParams.dustLimit, reduced).toMilliSatoshi - MilliSatoshi.maxOf(reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat, MilliSatoshi(0)) + (reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat).max(MilliSatoshi(0)) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index 3241dc36ef..d83af9fd8f 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -452,7 +452,7 @@ object Helpers { require(isValidFinalScriptPubkey(remoteScriptPubkey), "invalid remoteScriptPubkey") log.debug(s"making closing tx with closingFee={} and commitments:\n{}", closingFee, Commitments.specs2String(commitments)) // TODO: check that - val dustLimitSatoshis = MilliSatoshi.maxOf(localParams.dustLimit, remoteParams.dustLimit) + val dustLimitSatoshis = localParams.dustLimit.max(remoteParams.dustLimit) val closingTx = Transactions.makeClosingTx(commitInput, localScriptPubkey, remoteScriptPubkey, localParams.isFunder, dustLimitSatoshis, closingFee, localCommit.spec) val localClosingSig = keyManager.sign(closingTx, keyManager.fundingPublicKey(commitments.localParams.channelKeyPath)) val closingSigned = ClosingSigned(channelId, closingFee, localClosingSig) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index a19195ea38..ad8022af71 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -26,7 +26,6 @@ import akka.util.Timeout import com.google.common.net.HostAndPort import fr.acinq.bitcoin.Crypto.PublicKey import fr.acinq.bitcoin.{ByteVector32, DeterministicWallet, Protocol, Satoshi} -import fr.acinq.eclair import fr.acinq.eclair.blockchain.EclairWallet import fr.acinq.eclair.channel._ import fr.acinq.eclair.crypto.TransportHandler @@ -41,8 +40,8 @@ import scala.concurrent.duration._ import scala.util.Random /** - * Created by PM on 26/08/2016. - */ + * Created by PM on 26/08/2016. + */ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: ActorRef, watcher: ActorRef, router: ActorRef, relayer: ActorRef, wallet: EclairWallet) extends FSMDiagnosticActorLogging[Peer.State, Peer.Data] { import Peer._ @@ -349,8 +348,8 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: A case Event(DelayedRebroadcast(rebroadcast), d: ConnectedData) => /** - * Send and count in a single iteration - */ + * Send and count in a single iteration + */ def sendAndCount(msgs: Map[_ <: RoutingMessage, Set[ActorRef]]): Int = msgs.foldLeft(0) { case (count, (_, origins)) if origins.contains(self) => // the announcement came from this peer, we don't send it back @@ -511,13 +510,13 @@ class Peer(val nodeParams: NodeParams, remoteNodeId: PublicKey, authenticator: A } /** - * The transition INSTANTIATING -> DISCONNECTED happens in 2 scenarios - * - Manual connection to a new peer: then when(DISCONNECTED) we expect a Peer.Connect from the switchboard - * - Eclair restart: The switchboard creates the peers and sends Init and then Peer.Reconnect to trigger reconnection attempts - * - * So when we see this transition we NO-OP because we don't want to start a Reconnect timer but the peer will receive the trigger - * (Connect/Reconnect) messages from the switchboard. - */ + * The transition INSTANTIATING -> DISCONNECTED happens in 2 scenarios + * - Manual connection to a new peer: then when(DISCONNECTED) we expect a Peer.Connect from the switchboard + * - Eclair restart: The switchboard creates the peers and sends Init and then Peer.Reconnect to trigger reconnection attempts + * + * So when we see this transition we NO-OP because we don't want to start a Reconnect timer but the peer will receive the trigger + * (Connect/Reconnect) messages from the switchboard. + */ onTransition { case INSTANTIATING -> DISCONNECTED => () case _ -> DISCONNECTED if nodeParams.autoReconnect => setTimer(RECONNECT_TIMER, Reconnect, Random.nextInt(nodeParams.initialRandomReconnectDelay.toMillis.toInt).millis, repeat = false) // we add some randomization to not have peers reconnect to each other exactly at the same time @@ -643,7 +642,7 @@ object Peer { channelKeyPath, dustLimit = nodeParams.dustLimit, maxHtlcValueInFlightMsat = nodeParams.maxHtlcValueInFlightMsat, - channelReserve = MilliSatoshi.maxOf(Satoshi((nodeParams.reserveToFundingRatio * fundingAmount.toLong).toLong), nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit + channelReserve = Satoshi((nodeParams.reserveToFundingRatio * fundingAmount.toLong).toLong).max(nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit htlcMinimum = nodeParams.htlcMinimum, toSelfDelay = nodeParams.toRemoteDelayBlocks, // we choose their delay maxAcceptedHtlcs = nodeParams.maxAcceptedHtlcs, @@ -654,13 +653,13 @@ object Peer { } /** - * Peer may want to filter announcements based on timestamp - * - * @param gossipTimestampFilter_opt optional gossip timestamp range - * @return - * - true if there is a filter and msg has no timestamp, or has one that matches the filter - * - false otherwise - */ + * Peer may want to filter announcements based on timestamp + * + * @param gossipTimestampFilter_opt optional gossip timestamp range + * @return + * - true if there is a filter and msg has no timestamp, or has one that matches the filter + * - false otherwise + */ def timestampInRange(msg: RoutingMessage, gossipTimestampFilter_opt: Option[GossipTimestampFilter]): Boolean = { // check if this message has a timestamp that matches our timestamp filter (msg, gossipTimestampFilter_opt) match { @@ -673,7 +672,7 @@ object Peer { def hostAndPort2InetSocketAddress(hostAndPort: HostAndPort): InetSocketAddress = new InetSocketAddress(hostAndPort.getHost, hostAndPort.getPort) /** - * Exponential backoff retry with a finite max - */ + * Exponential backoff retry with a finite max + */ def nextReconnectionDelay(currentDelay: FiniteDuration, maxReconnectInterval: FiniteDuration): FiniteDuration = (2 * currentDelay).min(maxReconnectInterval) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 1fce09231f..56cc3d8443 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -190,4 +190,10 @@ package object eclair { // @formatter:on } + // TODO: we can remove that once bitcoin-lib offers it + implicit class MaxMinSatoshi(amount: Satoshi) { + def max(other: Satoshi): Satoshi = if (amount > other) amount else other + def min(other: Satoshi): Satoshi = if (amount < other) amount else other + } + } \ No newline at end of file diff --git a/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java b/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java index 24195b6e94..e48c72cf9e 100644 --- a/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java +++ b/eclair-core/src/test/java/fr/acinq/eclair/MilliSatoshiTest.java @@ -27,8 +27,8 @@ public static void Test() { MilliSatoshi msat = new MilliSatoshi(561); Satoshi sat = new Satoshi(1); msat.truncateToSatoshi(); - MilliSatoshi.maxOf(msat, sat); - MilliSatoshi.minOf(sat, msat); + msat = msat.max(sat); + msat = msat.min(sat); MilliSatoshi.toMilliSatoshi(sat); msat = MilliSatoshi.toMilliSatoshi(sat).$plus(msat); msat = msat.$plus(msat); diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala index db5c10051b..ae0cb5236c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/MilliSatoshiSpec.scala @@ -17,7 +17,6 @@ package fr.acinq.eclair import fr.acinq.bitcoin.Satoshi -import fr.acinq.eclair.MilliSatoshi.{maxOf, minOf} import org.scalatest.FunSuite /** @@ -64,16 +63,16 @@ class MilliSatoshiSpec extends FunSuite { assert(MilliSatoshi(2000) > Satoshi(1)) // maxOf - assert(maxOf(561 msat, 1105 msat) === MilliSatoshi(1105)) - assert(maxOf(1 sat, 1105 msat) === MilliSatoshi(1105)) - assert(maxOf(1105 msat, 2 sat) === MilliSatoshi(2000)) - assert(maxOf(1 sat, 2 sat) === Satoshi(2)) + assert((561 msat).max(1105 msat) === MilliSatoshi(1105)) + assert((1105 msat).max(1 sat) === MilliSatoshi(1105)) + assert((1105 msat).max(2 sat) === MilliSatoshi(2000)) + assert((1 sat).max(2 sat) === Satoshi(2)) // minOf - assert(minOf(561 msat, 1105 msat) === MilliSatoshi(561)) - assert(minOf(1 sat, 1105 msat) === MilliSatoshi(1000)) - assert(minOf(1105 msat, 2 sat) === MilliSatoshi(1105)) - assert(minOf(1 sat, 2 sat) === Satoshi(1)) + assert((561 msat).min(1105 msat) === MilliSatoshi(561)) + assert((1105 msat).min(1 sat) === MilliSatoshi(1000)) + assert((1105 msat).min(2 sat) === MilliSatoshi(1105)) + assert((1 sat).min(2 sat) === Satoshi(1)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala index c1e2969163..cf347e0131 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala @@ -98,7 +98,7 @@ trait StateTestsHelperMethods extends TestKitBase { bob2blockchain.expectMsgType[WatchConfirmed] // deeply buried awaitCond(alice.stateName == NORMAL) awaitCond(bob.stateName == NORMAL) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == MilliSatoshi.maxOf(pushMsat - TestConstants.Alice.channelParams.channelReserve.toMilliSatoshi, MilliSatoshi(0))) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == (pushMsat - TestConstants.Alice.channelParams.channelReserve).max(MilliSatoshi(0))) // x2 because alice and bob share the same relayer channelUpdateListener.expectMsgType[LocalChannelUpdate] channelUpdateListener.expectMsgType[LocalChannelUpdate] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala index 9724026345..22557eba7f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala @@ -151,8 +151,8 @@ object HtlcGenerationSpec { def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = MilliSatoshi(50000000L), testAvailableBalanceForReceive: MilliSatoshi = MilliSatoshi(50000000L)) = new Commitments(ChannelVersion.STANDARD, null, null, 0.toByte, null, null, null, null, 0, 0, Map.empty, null, null, null, channelId) { - override lazy val availableBalanceForSend: MilliSatoshi = MilliSatoshi.maxOf(testAvailableBalanceForSend, MilliSatoshi(0)) - override lazy val availableBalanceForReceive: MilliSatoshi = MilliSatoshi.maxOf(testAvailableBalanceForReceive, MilliSatoshi(0)) + override lazy val availableBalanceForSend: MilliSatoshi = testAvailableBalanceForSend.max(MilliSatoshi(0)) + override lazy val availableBalanceForReceive: MilliSatoshi = testAvailableBalanceForReceive.max(MilliSatoshi(0)) } def randomExtendedPrivateKey: ExtendedPrivateKey = DeterministicWallet.generate(randomBytes32) From e3c096bb09a29ab4b567a0fc255fe85b2158fdfa Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Fri, 23 Aug 2019 15:22:44 +0200 Subject: [PATCH 09/18] Update bitcoin-lib to 0.15-SNAPSHOT --- .../scala/fr/acinq/eclair/CoinUtils.scala | 20 +- .../scala/fr/acinq/eclair/MilliSatoshi.scala | 2 +- .../fr/acinq/eclair/api/JsonSerializers.scala | 4 +- .../fee/BitcoinCoreFeeProvider.scala | 6 +- .../fr/acinq/eclair/channel/Channel.scala | 2 +- .../fr/acinq/eclair/channel/Helpers.scala | 542 +++++++++--------- .../eclair/db/sqlite/SqliteNetworkDb.scala | 2 +- .../main/scala/fr/acinq/eclair/io/Peer.scala | 4 +- .../main/scala/fr/acinq/eclair/package.scala | 8 +- .../eclair/transactions/Transactions.scala | 120 ++-- .../electrum/ElectrumWalletBasicSpec.scala | 15 +- .../fee/BitcoinCoreFeeProviderSpec.scala | 2 +- .../transactions/ClaimReceivedHtlcSpec.scala | 8 +- .../transactions/ClaimSentHtlcSpec.scala | 10 +- pom.xml | 2 +- 15 files changed, 370 insertions(+), 377 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala b/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala index 210974a147..c12bd3ba8d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/CoinUtils.scala @@ -191,18 +191,18 @@ object CoinUtils extends Logging { case (a: Satoshi, BtcUnit) => GUIBtc(a.toLong * SatUnit.factorToMsat) // amount is mbtc - case (a: MilliBtc, MSatUnit) => GUIMSat((a.amount * MBtcUnit.factorToMsat).toLong) - case (a: MilliBtc, SatUnit) => GUISat((a.amount * MBtcUnit.factorToMsat).toLong) - case (a: MilliBtc, BitUnit) => GUIBits((a.amount * MBtcUnit.factorToMsat).toLong) - case (a: MilliBtc, MBtcUnit) => GUIMBtc((a.amount * MBtcUnit.factorToMsat).toLong) - case (a: MilliBtc, BtcUnit) => GUIBtc((a.amount * MBtcUnit.factorToMsat).toLong) + case (a: MilliBtc, MSatUnit) => GUIMSat((a.toBigDecimal * MBtcUnit.factorToMsat).toLong) + case (a: MilliBtc, SatUnit) => GUISat((a.toBigDecimal * MBtcUnit.factorToMsat).toLong) + case (a: MilliBtc, BitUnit) => GUIBits((a.toBigDecimal * MBtcUnit.factorToMsat).toLong) + case (a: MilliBtc, MBtcUnit) => GUIMBtc((a.toBigDecimal * MBtcUnit.factorToMsat).toLong) + case (a: MilliBtc, BtcUnit) => GUIBtc((a.toBigDecimal * MBtcUnit.factorToMsat).toLong) // amount is mbtc - case (a: Btc, MSatUnit) => GUIMSat((a.amount * BtcUnit.factorToMsat).toLong) - case (a: Btc, SatUnit) => GUISat((a.amount * BtcUnit.factorToMsat).toLong) - case (a: Btc, BitUnit) => GUIBits((a.amount * BtcUnit.factorToMsat).toLong) - case (a: Btc, MBtcUnit) => GUIMBtc((a.amount * BtcUnit.factorToMsat).toLong) - case (a: Btc, BtcUnit) => GUIBtc((a.amount * BtcUnit.factorToMsat).toLong) + case (a: Btc, MSatUnit) => GUIMSat((a.toBigDecimal * BtcUnit.factorToMsat).toLong) + case (a: Btc, SatUnit) => GUISat((a.toBigDecimal * BtcUnit.factorToMsat).toLong) + case (a: Btc, BitUnit) => GUIBits((a.toBigDecimal * BtcUnit.factorToMsat).toLong) + case (a: Btc, MBtcUnit) => GUIMBtc((a.toBigDecimal * BtcUnit.factorToMsat).toLong) + case (a: Btc, BtcUnit) => GUIBtc((a.toBigDecimal * BtcUnit.factorToMsat).toLong) case (_, _) => throw new IllegalArgumentException(s"unhandled conversion from $amount to $unit") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index 369fad66b7..f4b92e0072 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -58,7 +58,7 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos object MilliSatoshi { - private def satoshi2millisatoshi(input: Satoshi): MilliSatoshi = MilliSatoshi(input.amount * 1000L) + private def satoshi2millisatoshi(input: Satoshi): MilliSatoshi = MilliSatoshi(input.toLong * 1000L) def toMilliSatoshi(amount: BtcAmount): MilliSatoshi = amount match { case sat: Satoshi => satoshi2millisatoshi(sat) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala index 0aa2a777ca..9fcfde61ea 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/api/JsonSerializers.scala @@ -58,7 +58,7 @@ class UInt64Serializer extends CustomSerializer[UInt64](format => ({ null }, { })) class SatoshiSerializer extends CustomSerializer[Satoshi](format => ({ null }, { - case x: Satoshi => JInt(x.amount) + case x: Satoshi => JInt(x.toLong) })) class MilliSatoshiSerializer extends CustomSerializer[MilliSatoshi](format => ({ null }, { @@ -116,7 +116,7 @@ class OutPointKeySerializer extends CustomKeySerializer[OutPoint](format => ({ n })) class InputInfoSerializer extends CustomSerializer[InputInfo](format => ({ null }, { - case x: InputInfo => JObject(("outPoint", JString(s"${x.outPoint.txid}:${x.outPoint.index}")), ("amountSatoshis", JInt(x.txOut.amount.amount))) + case x: InputInfo => JObject(("outPoint", JString(s"${x.outPoint.txid}:${x.outPoint.index}")), ("amountSatoshis", JInt(x.txOut.amount.toLong))) })) class ColorSerializer extends CustomSerializer[Color](format => ({ null }, { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala index b25bf1d900..947b7aa99d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala @@ -64,16 +64,16 @@ object BitcoinCoreFeeProvider { json \ "feerate" match { case JDecimal(feerate) => // estimatesmartfee returns a fee rate in Btc/KB - btc2satoshi(Btc(feerate)).amount + btc2satoshi(Btc(feerate)).toLong case JInt(feerate) if feerate.toLong < 0 => // negative value means failure feerate.toLong case JInt(feerate) => // should (hopefully) never happen - btc2satoshi(Btc(feerate.toLong)).amount + btc2satoshi(Btc(feerate.toLong)).toLong } case JArray(errors) => - val error = errors collect { case JString(error) => error } mkString (", ") + val error = errors collect { case JString(error) => error } mkString ", " throw new RuntimeException(s"estimatesmartfee failed: $error") case _ => throw new RuntimeException("estimatesmartfee failed") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala index d095f595fb..848403f0a5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -2211,7 +2211,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId } def feePaid(fee: Satoshi, tx: Transaction, desc: String, channelId: ByteVector32): Unit = { - log.info(s"paid feeSatoshi=${fee.amount} for txid=${tx.txid} desc=$desc") + log.info(s"paid feeSatoshi=${fee.toLong} for txid=${tx.txid} desc=$desc") context.system.eventStream.publish(NetworkFeePaid(self, remoteNodeId, channelId, tx, fee, desc)) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index d83af9fd8f..da46c04b1c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -38,17 +38,17 @@ import scala.concurrent.duration._ import scala.util.{Failure, Success, Try} /** - * Created by PM on 20/05/2016. - */ + * Created by PM on 20/05/2016. + */ object Helpers { /** - * Depending on the state, returns the current temporaryChannelId or channelId - * - * @param stateData - * @return the long identifier of the channel - */ + * Depending on the state, returns the current temporaryChannelId or channelId + * + * @param stateData + * @return the long identifier of the channel + */ def getChannelId(stateData: Data): ByteVector32 = stateData match { case Nothing => ByteVector32.Zeroes case d: DATA_WAIT_FOR_OPEN_CHANNEL => d.initFundee.temporaryChannelId @@ -60,11 +60,11 @@ object Helpers { } /** - * We update local/global features at reconnection - * - * @param data - * @return - */ + * We update local/global features at reconnection + * + * @param data + * @return + */ def updateFeatures(data: HasCommitments, localInit: Init, remoteInit: Init): HasCommitments = { val commitments1 = data.commitments.copy( localParams = data.commitments.localParams.copy(globalFeatures = localInit.globalFeatures, localFeatures = localInit.localFeatures), @@ -81,8 +81,8 @@ object Helpers { } /** - * Called by the fundee - */ + * Called by the fundee + */ def validateParamsFundee(nodeParams: NodeParams, open: OpenChannel): Unit = { // BOLT #2: if the chain_hash value, within the open_channel, message is set to a hash of a chain that is unknown to the receiver: // MUST reject the channel. @@ -126,8 +126,8 @@ object Helpers { } /** - * Called by the funder - */ + * Called by the funder + */ def validateParamsFunder(nodeParams: NodeParams, open: OpenChannel, accept: AcceptChannel): Unit = { if (accept.maxAcceptedHtlcs > Channel.MAX_ACCEPTED_HTLCS) throw InvalidMaxAcceptedHtlcs(accept.temporaryChannelId, accept.maxAcceptedHtlcs, Channel.MAX_ACCEPTED_HTLCS) // only enforce dust limit check on mainnet @@ -155,14 +155,14 @@ object Helpers { } /** - * Compute the delay until we need to refresh the channel_update for our channel not to be considered stale by - * other nodes. - * - * If current update more than [[Channel.REFRESH_CHANNEL_UPDATE_INTERVAL]] old then the delay will be zero. - * - * @param currentUpdateTimestamp - * @return the delay until the next update - */ + * Compute the delay until we need to refresh the channel_update for our channel not to be considered stale by + * other nodes. + * + * If current update more than [[Channel.REFRESH_CHANNEL_UPDATE_INTERVAL]] old then the delay will be zero. + * + * @param currentUpdateTimestamp + * @return the delay until the next update + */ def nextChannelUpdateRefresh(currentUpdateTimestamp: Long)(implicit log: LoggingAdapter): FiniteDuration = { val age = Platform.currentTime.milliseconds - currentUpdateTimestamp.seconds val delay = 0.days.max(REFRESH_CHANNEL_UPDATE_INTERVAL - age) @@ -171,11 +171,11 @@ object Helpers { } /** - * - * @param remoteFeeratePerKw remote fee rate per kiloweight - * @param localFeeratePerKw local fee rate per kiloweight - * @return the "normalized" difference between local and remote fee rate, i.e. |remote - local| / avg(local, remote) - */ + * + * @param remoteFeeratePerKw remote fee rate per kiloweight + * @param localFeeratePerKw local fee rate per kiloweight + * @return the "normalized" difference between local and remote fee rate, i.e. |remote - local| / avg(local, remote) + */ def feeRateMismatch(remoteFeeratePerKw: Long, localFeeratePerKw: Long): Double = Math.abs((2.0 * (remoteFeeratePerKw - localFeeratePerKw)) / (localFeeratePerKw + remoteFeeratePerKw)) @@ -183,21 +183,21 @@ object Helpers { feeRateMismatch(networkFeeratePerKw, commitmentFeeratePerKw) > updateFeeMinDiffRatio /** - * - * @param remoteFeeratePerKw remote fee rate per kiloweight - * @param localFeeratePerKw local fee rate per kiloweight - * @param maxFeerateMismatchRatio maximum fee rate mismatch ratio - * @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 - */ + * + * @param remoteFeeratePerKw remote fee rate per kiloweight + * @param localFeeratePerKw local fee rate per kiloweight + * @param maxFeerateMismatchRatio maximum fee rate mismatch ratio + * @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 = feeRateMismatch(remoteFeeratePerKw, localFeeratePerKw) > maxFeerateMismatchRatio /** - * - * @param remoteFeeratePerKw remote fee rate per kiloweight - * @return true if the remote fee rate is too small - */ + * + * @param remoteFeeratePerKw remote fee rate per kiloweight + * @return true if the remote fee rate is too small + */ def isFeeTooSmall(remoteFeeratePerKw: Long): Boolean = { remoteFeeratePerKw < fr.acinq.eclair.MinimumFeeratePerKw } @@ -209,10 +209,10 @@ object Helpers { } /** - * This indicates whether our side of the channel is above the reserve requested by our counterparty. In other words, - * this tells if we can use the channel to make a payment. - * - */ + * This indicates whether our side of the channel is above the reserve requested by our counterparty. In other words, + * this tells if we can use the channel to make a payment. + * + */ def aboveReserve(commitments: Commitments)(implicit log: LoggingAdapter): Boolean = { val remoteCommit = commitments.remoteNextCommitInfo match { case Left(waitingForRevocation) => waitingForRevocation.nextRemoteCommit @@ -241,19 +241,19 @@ object Helpers { } /** - * Creates both sides's first commitment transaction - * - * @param localParams - * @param remoteParams - * @param pushMsat - * @param fundingTxHash - * @param fundingTxOutputIndex - * @param remoteFirstPerCommitmentPoint - * @return (localSpec, localTx, remoteSpec, remoteTx, fundingTxOutput) - */ + * Creates both sides's first commitment transaction + * + * @param localParams + * @param remoteParams + * @param pushMsat + * @param fundingTxHash + * @param fundingTxOutputIndex + * @param remoteFirstPerCommitmentPoint + * @return (localSpec, localTx, remoteSpec, remoteTx, fundingTxOutput) + */ def makeFirstCommitTxs(keyManager: KeyManager, temporaryChannelId: ByteVector32, localParams: LocalParams, remoteParams: RemoteParams, fundingAmount: Satoshi, pushMsat: MilliSatoshi, initialFeeratePerKw: Long, fundingTxHash: ByteVector32, fundingTxOutputIndex: Int, remoteFirstPerCommitmentPoint: PublicKey, maxFeerateMismatch: Double): (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx) = { val toLocalMsat = if (localParams.isFunder) fundingAmount.toMilliSatoshi - pushMsat else pushMsat - val toRemoteMsat = if (localParams.isFunder) pushMsat else fundingAmount.toMilliSatoshi - pushMsat + val toRemoteMsat = if (localParams.isFunder) pushMsat else fundingAmount.toMilliSatoshi - pushMsat val localSpec = CommitmentSpec(Set.empty[DirectedHtlc], feeratePerKw = initialFeeratePerKw, toLocal = toLocalMsat, toRemote = toRemoteMsat) val remoteSpec = CommitmentSpec(Set.empty[DirectedHtlc], feeratePerKw = initialFeeratePerKw, toLocal = toRemoteMsat, toRemote = toLocalMsat) @@ -279,14 +279,14 @@ object Helpers { } /** - * Tells whether or not their expected next remote commitment number matches with our data - * - * @param d - * @param nextRemoteRevocationNumber - * @return - * - true if parties are in sync or remote is behind - * - false if we are behind - */ + * Tells whether or not their expected next remote commitment number matches with our data + * + * @param d + * @param nextRemoteRevocationNumber + * @return + * - true if parties are in sync or remote is behind + * - false if we are behind + */ def checkLocalCommit(d: HasCommitments, nextRemoteRevocationNumber: Long): Boolean = { if (d.commitments.localCommit.index == nextRemoteRevocationNumber) { // they just sent a new commit_sig, we have received it but they didn't receive our revocation @@ -304,14 +304,14 @@ object Helpers { } /** - * Tells whether or not their expected next local commitment number matches with our data - * - * @param d - * @param nextLocalCommitmentNumber - * @return - * - true if parties are in sync or remote is behind - * - false if we are behind - */ + * Tells whether or not their expected next local commitment number matches with our data + * + * @param d + * @param nextLocalCommitmentNumber + * @return + * - true if parties are in sync or remote is behind + * - false if we are behind + */ def checkRemoteCommit(d: HasCommitments, nextLocalCommitmentNumber: Long): Boolean = { d.commitments.remoteNextCommitInfo match { case Left(waitingForRevocation) if nextLocalCommitmentNumber == waitingForRevocation.nextRemoteCommit.index => @@ -350,11 +350,11 @@ object Helpers { // @formatter:on /** - * Indicates whether local has anything at stake in this channel - * - * @param data - * @return true if channel was never open, or got closed immediately, had never any htlcs and local never had a positive balance - */ + * Indicates whether local has anything at stake in this channel + * + * @param data + * @return true if channel was never open, or got closed immediately, had never any htlcs and local never had a positive balance + */ def nothingAtStake(data: HasCommitments): Boolean = data.commitments.localCommit.index == 0 && data.commitments.localCommit.spec.toLocal == MilliSatoshi(0) && @@ -363,15 +363,15 @@ object Helpers { data.commitments.remoteNextCommitInfo.isRight /** - * As soon as a tx spending the funding tx has reached min_depth, we know what the closing type will be, before - * the whole closing process finishes(e.g. there may still be delayed or unconfirmed child transactions). It can - * save us from attempting to publish some transactions. - * - * Note that we can't tell for mutual close before it is already final, because only one tx needs to be confirmed. - * - * @param closing channel state data - * @return the channel closing type, if applicable - */ + * As soon as a tx spending the funding tx has reached min_depth, we know what the closing type will be, before + * the whole closing process finishes(e.g. there may still be delayed or unconfirmed child transactions). It can + * save us from attempting to publish some transactions. + * + * Note that we can't tell for mutual close before it is already final, because only one tx needs to be confirmed. + * + * @param closing channel state data + * @return the channel closing type, if applicable + */ def isClosingTypeAlreadyKnown(closing: DATA_CLOSING): Option[ClosingType] = closing match { case _ if closing.localCommitPublished.exists(lcp => lcp.irrevocablySpent.values.toSet.contains(lcp.commitTx.txid)) => Some(LocalClose) @@ -387,13 +387,13 @@ object Helpers { } /** - * Checks if a channel is closed (i.e. its closing tx has been confirmed) - * - * @param data channel state data - * @param additionalConfirmedTx_opt additional confirmed transaction; we need this for the mutual close scenario - * because we don't store the closing tx in the channel state - * @return the channel closing type, if applicable - */ + * Checks if a channel is closed (i.e. its closing tx has been confirmed) + * + * @param data channel state data + * @param additionalConfirmedTx_opt additional confirmed transaction; we need this for the mutual close scenario + * because we don't store the closing tx in the channel state + * @return the channel closing type, if applicable + */ def isClosed(data: HasCommitments, additionalConfirmedTx_opt: Option[Transaction]): Option[ClosingType] = data match { case closing: DATA_CLOSING if additionalConfirmedTx_opt.exists(closing.mutualClosePublished.contains) => Some(MutualClose) @@ -463,9 +463,9 @@ object Helpers { def checkClosingSignature(keyManager: KeyManager, commitments: Commitments, localScriptPubkey: ByteVector, remoteScriptPubkey: ByteVector, remoteClosingFee: Satoshi, remoteClosingSig: ByteVector64)(implicit log: LoggingAdapter): Try[Transaction] = { import commitments._ - val lastCommitFeeSatoshi = commitments.commitInput.txOut.amount.amount - commitments.localCommit.publishableTxs.commitTx.tx.txOut.map(_.amount.amount).sum - if (remoteClosingFee.amount > lastCommitFeeSatoshi) { - log.error(s"remote proposed a commit fee higher than the last commitment fee: remoteClosingFeeSatoshi=${remoteClosingFee.amount} lastCommitFeeSatoshi=$lastCommitFeeSatoshi") + val lastCommitFeeSatoshi = commitments.commitInput.txOut.amount - commitments.localCommit.publishableTxs.commitTx.tx.txOut.map(_.amount).sum + if (remoteClosingFee > lastCommitFeeSatoshi) { + log.error(s"remote proposed a commit fee higher than the last commitment fee: remoteClosingFeeSatoshi=${remoteClosingFee.toLong} lastCommitFeeSatoshi=$lastCommitFeeSatoshi") throw InvalidCloseFee(commitments.channelId, remoteClosingFee) } val (closingTx, closingSigned) = makeClosingTx(keyManager, commitments, localScriptPubkey, remoteScriptPubkey, remoteClosingFee) @@ -476,7 +476,7 @@ object Helpers { def generateTx(desc: String)(attempt: Try[TransactionWithInputInfo])(implicit log: LoggingAdapter): Option[TransactionWithInputInfo] = { attempt match { case Success(txinfo) => - log.info(s"tx generation success: desc=$desc txid=${txinfo.tx.txid} amount=${txinfo.tx.txOut.map(_.amount.amount).sum} tx=${txinfo.tx}") + log.info(s"tx generation success: desc=$desc txid=${txinfo.tx.txid} amount=${txinfo.tx.txOut.map(_.amount).sum} tx=${txinfo.tx}") Some(txinfo) case Failure(t: TxGenerationSkipped) => log.info(s"tx generation skipped: desc=$desc reason: ${t.getMessage}") @@ -488,13 +488,13 @@ object Helpers { } /** - * - * Claim all the HTLCs that we've received from our current commit tx. This will be - * done using 2nd stage HTLC transactions - * - * @param commitments our commitment data, which include payment preimages - * @return a list of transactions (one per HTLC that we can claim) - */ + * + * Claim all the HTLCs that we've received from our current commit tx. This will be + * done using 2nd stage HTLC transactions + * + * @param commitments our commitment data, which include payment preimages + * @return a list of transactions (one per HTLC that we can claim) + */ def claimCurrentLocalCommitTxOutputs(keyManager: KeyManager, commitments: Commitments, tx: Transaction, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): LocalCommitPublished = { import commitments._ require(localCommit.publishableTxs.commitTx.tx.txid == tx.txid, "txid mismatch, provided tx is not the current local commit tx") @@ -558,14 +558,14 @@ object Helpers { } /** - * - * Claim all the HTLCs that we've received from their current commit tx - * - * @param commitments our commitment data, which include payment preimages - * @param remoteCommit the remote commitment data to use to claim outputs (it can be their current or next commitment) - * @param tx the remote commitment transaction that has just been published - * @return a list of transactions (one per HTLC that we can claim) - */ + * + * Claim all the HTLCs that we've received from their current commit tx + * + * @param commitments our commitment data, which include payment preimages + * @param remoteCommit the remote commitment data to use to claim outputs (it can be their current or next commitment) + * @param tx the remote commitment transaction that has just been published + * @return a list of transactions (one per HTLC that we can claim) + */ def claimRemoteCommitTxOutputs(keyManager: KeyManager, commitments: Commitments, remoteCommit: RemoteCommit, tx: Transaction, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): RemoteCommitPublished = { import commitments.{commitInput, localParams, remoteParams} require(remoteCommit.txid == tx.txid, "txid mismatch, provided tx is not the current remote commit tx") @@ -613,16 +613,16 @@ object Helpers { } /** - * - * Claim our Main output only - * - * @param commitments either our current commitment data in case of usual remote uncooperative closing - * or our outdated commitment data in case of data loss protection procedure; in any case it is used only - * to get some constant parameters, not commitment data - * @param remotePerCommitmentPoint the remote perCommitmentPoint corresponding to this commitment - * @param tx the remote commitment transaction that has just been published - * @return a list of transactions (one per HTLC that we can claim) - */ + * + * Claim our Main output only + * + * @param commitments either our current commitment data in case of usual remote uncooperative closing + * or our outdated commitment data in case of data loss protection procedure; in any case it is used only + * to get some constant parameters, not commitment data + * @param remotePerCommitmentPoint the remote perCommitmentPoint corresponding to this commitment + * @param tx the remote commitment transaction that has just been published + * @return a list of transactions (one per HTLC that we can claim) + */ def claimRemoteCommitMainOutput(keyManager: KeyManager, commitments: Commitments, remotePerCommitmentPoint: PublicKey, tx: Transaction, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): RemoteCommitPublished = { val localPubkey = Generators.derivePubKey(keyManager.paymentPoint(commitments.localParams.channelKeyPath).publicKey, remotePerCommitmentPoint) @@ -645,14 +645,14 @@ object Helpers { } /** - * When an unexpected transaction spending the funding tx is detected: - * 1) we find out if the published transaction is one of remote's revoked txs - * 2) and then: - * a) if it is a revoked tx we build a set of transactions that will punish them by stealing all their funds - * b) otherwise there is nothing we can do - * - * @return a [[RevokedCommitPublished]] object containing penalty transactions if the tx is a revoked commitment - */ + * When an unexpected transaction spending the funding tx is detected: + * 1) we find out if the published transaction is one of remote's revoked txs + * 2) and then: + * a) if it is a revoked tx we build a set of transactions that will punish them by stealing all their funds + * b) otherwise there is nothing we can do + * + * @return a [[RevokedCommitPublished]] object containing penalty transactions if the tx is a revoked commitment + */ def claimRevokedRemoteCommitTxOutputs(keyManager: KeyManager, commitments: Commitments, tx: Transaction, db: ChannelsDb, feeEstimator: FeeEstimator, feeTargets: FeeTargets)(implicit log: LoggingAdapter): Option[RevokedCommitPublished] = { import commitments._ require(tx.txIn.size == 1, "commitment tx should have 1 input") @@ -702,15 +702,15 @@ object Helpers { // and finally we steal the htlc outputs var outputsAlreadyUsed = Set.empty[Int] // this is needed to handle cases where we have several identical htlcs - val htlcPenaltyTxs = tx.txOut.collect { case txOut if htlcsRedeemScripts.contains(txOut.publicKeyScript) => - val htlcRedeemScript = htlcsRedeemScripts(txOut.publicKeyScript) - generateTx("htlc-penalty")(Try { - val htlcPenalty = Transactions.makeHtlcPenaltyTx(tx, outputsAlreadyUsed, htlcRedeemScript, localParams.dustLimit, localParams.defaultFinalScriptPubKey, feeratePerKwPenalty) - outputsAlreadyUsed = outputsAlreadyUsed + htlcPenalty.input.outPoint.index.toInt - val sig = keyManager.sign(htlcPenalty, keyManager.revocationPoint(localParams.channelKeyPath), remotePerCommitmentSecret) - Transactions.addSigs(htlcPenalty, sig, remoteRevocationPubkey) - }) - }.toList.flatten + val htlcPenaltyTxs = tx.txOut.collect { case txOut if htlcsRedeemScripts.contains(txOut.publicKeyScript) => + val htlcRedeemScript = htlcsRedeemScripts(txOut.publicKeyScript) + generateTx("htlc-penalty")(Try { + val htlcPenalty = Transactions.makeHtlcPenaltyTx(tx, outputsAlreadyUsed, htlcRedeemScript, localParams.dustLimit, localParams.defaultFinalScriptPubKey, feeratePerKwPenalty) + outputsAlreadyUsed = outputsAlreadyUsed + htlcPenalty.input.outPoint.index.toInt + val sig = keyManager.sign(htlcPenalty, keyManager.revocationPoint(localParams.channelKeyPath), remotePerCommitmentSecret) + Transactions.addSigs(htlcPenalty, sig, remoteRevocationPubkey) + }) + }.toList.flatten RevokedCommitPublished( commitTx = tx, @@ -724,21 +724,21 @@ object Helpers { } /** - * Claims the output of an [[HtlcSuccessTx]] or [[HtlcTimeoutTx]] transaction using a revocation key. - * - * In case a revoked commitment with pending HTLCs is published, there are two ways the HTLC outputs can be taken as punishment: - * - by spending the corresponding output of the commitment tx, using [[HtlcPenaltyTx]] that we generate as soon as we detect that a revoked commit - * as been spent; note that those transactions will compete with [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] published by the counterparty. - * - by spending the delayed output of [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] if those get confirmed; because the output of these txes is protected by - * an OP_CSV delay, we will have time to spend them with a revocation key. In that case, we generate the spending transactions "on demand", - * this is the purpose of this method. - * - * @param keyManager - * @param commitments - * @param revokedCommitPublished - * @param htlcTx - * @return - */ + * Claims the output of an [[HtlcSuccessTx]] or [[HtlcTimeoutTx]] transaction using a revocation key. + * + * In case a revoked commitment with pending HTLCs is published, there are two ways the HTLC outputs can be taken as punishment: + * - by spending the corresponding output of the commitment tx, using [[HtlcPenaltyTx]] that we generate as soon as we detect that a revoked commit + * as been spent; note that those transactions will compete with [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] published by the counterparty. + * - by spending the delayed output of [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] if those get confirmed; because the output of these txes is protected by + * an OP_CSV delay, we will have time to spend them with a revocation key. In that case, we generate the spending transactions "on demand", + * this is the purpose of this method. + * + * @param keyManager + * @param commitments + * @param revokedCommitPublished + * @param htlcTx + * @return + */ def claimRevokedHtlcTxOutputs(keyManager: KeyManager, commitments: Commitments, revokedCommitPublished: RevokedCommitPublished, htlcTx: Transaction, feeEstimator: FeeEstimator)(implicit log: LoggingAdapter): (RevokedCommitPublished, Option[Transaction]) = { if (htlcTx.txIn.map(_.outPoint.txid).contains(revokedCommitPublished.commitTx.txid) && !(revokedCommitPublished.claimMainOutputTx ++ revokedCommitPublished.mainPenaltyTx ++ revokedCommitPublished.htlcPenaltyTxs).map(_.txid).toSet.contains(htlcTx.txid)) { @@ -781,18 +781,18 @@ object Helpers { } /** - * In CLOSING state, any time we see a new transaction, we try to extract a preimage from it in order to fulfill the - * corresponding incoming htlc in an upstream channel. - * - * Not doing that would result in us losing money, because the downstream node would pull money from one side, and - * the upstream node would get refunded after a timeout. - * - * @param localCommit - * @param tx - * @return a set of pairs (add, fulfills) if extraction was successful: - * - add is the htlc in the downstream channel from which we extracted the preimage - * - fulfill needs to be sent to the upstream channel - */ + * In CLOSING state, any time we see a new transaction, we try to extract a preimage from it in order to fulfill the + * corresponding incoming htlc in an upstream channel. + * + * Not doing that would result in us losing money, because the downstream node would pull money from one side, and + * the upstream node would get refunded after a timeout. + * + * @param localCommit + * @param tx + * @return a set of pairs (add, fulfills) if extraction was successful: + * - add is the htlc in the downstream channel from which we extracted the preimage + * - fulfill needs to be sent to the upstream channel + */ def extractPreimages(localCommit: LocalCommit, tx: Transaction)(implicit log: LoggingAdapter): Set[(UpdateAddHtlc, UpdateFulfillHtlc)] = { val paymentPreimages = tx.txIn.map(_.witness match { case ScriptWitness(Seq(localSig, paymentPreimage, htlcOfferedScript)) if paymentPreimage.size == 32 => @@ -818,14 +818,14 @@ object Helpers { } /** - * In CLOSING state, when we are notified that a transaction has been confirmed, we analyze it to find out if one or - * more htlcs have timed out and need to be failed in an upstream channel. - * - * @param localCommit - * @param localDustLimit - * @param tx a tx that has reached mindepth - * @return a set of htlcs that need to be failed upstream - */ + * In CLOSING state, when we are notified that a transaction has been confirmed, we analyze it to find out if one or + * more htlcs have timed out and need to be failed in an upstream channel. + * + * @param localCommit + * @param localDustLimit + * @param tx a tx that has reached mindepth + * @return a set of htlcs that need to be failed upstream + */ def timedoutHtlcs(localCommit: LocalCommit, localDustLimit: Satoshi, tx: Transaction)(implicit log: LoggingAdapter): Set[UpdateAddHtlc] = if (tx.txid == localCommit.publishableTxs.commitTx.tx.txid) { // the tx is a commitment tx, we can immediately fail all dust htlcs (they don't have an output in the tx) @@ -842,14 +842,14 @@ object Helpers { } /** - * In CLOSING state, when we are notified that a transaction has been confirmed, we analyze it to find out if one or - * more htlcs have timed out and need to be failed in an upstream channel. - * - * @param remoteCommit - * @param remoteDustLimit - * @param tx a tx that has reached mindepth - * @return a set of htlcs that need to be failed upstream - */ + * In CLOSING state, when we are notified that a transaction has been confirmed, we analyze it to find out if one or + * more htlcs have timed out and need to be failed in an upstream channel. + * + * @param remoteCommit + * @param remoteDustLimit + * @param tx a tx that has reached mindepth + * @return a set of htlcs that need to be failed upstream + */ def timedoutHtlcs(remoteCommit: RemoteCommit, remoteDustLimit: Satoshi, tx: Transaction)(implicit log: LoggingAdapter): Set[UpdateAddHtlc] = if (tx.txid == remoteCommit.txid) { // the tx is a commitment tx, we can immediately fail all dust htlcs (they don't have an output in the tx) @@ -866,14 +866,14 @@ object Helpers { } /** - * As soon as a local or remote commitment reaches min_depth, we know which htlcs will be settled on-chain (whether - * or not they actually have an output in the commitment tx). - * - * @param localCommit - * @param remoteCommit - * @param nextRemoteCommit_opt - * @param tx a transaction that is sufficiently buried in the blockchain - */ + * As soon as a local or remote commitment reaches min_depth, we know which htlcs will be settled on-chain (whether + * or not they actually have an output in the commitment tx). + * + * @param localCommit + * @param remoteCommit + * @param nextRemoteCommit_opt + * @param tx a transaction that is sufficiently buried in the blockchain + */ def onchainOutgoingHtlcs(localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[RemoteCommit], tx: Transaction): Set[UpdateAddHtlc] = { if (localCommit.publishableTxs.commitTx.tx.txid == tx.txid) { localCommit.spec.htlcs.filter(_.direction == OUT).map(_.add) @@ -887,17 +887,17 @@ object Helpers { } /** - * If a local commitment tx reaches min_depth, we need to fail the outgoing htlcs that only us had signed, because - * they will never reach the blockchain. - * - * Those are only present in the remote's commitment. - * - * @param localCommit - * @param remoteCommit - * @param tx - * @param log - * @return - */ + * If a local commitment tx reaches min_depth, we need to fail the outgoing htlcs that only us had signed, because + * they will never reach the blockchain. + * + * Those are only present in the remote's commitment. + * + * @param localCommit + * @param remoteCommit + * @param tx + * @param log + * @return + */ def overriddenOutgoingHtlcs(localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[RemoteCommit], tx: Transaction)(implicit log: LoggingAdapter): Set[UpdateAddHtlc] = if (localCommit.publishableTxs.commitTx.tx.txid == tx.txid) { // our commit got confirmed, so any htlc that we signed but they didn't sign will never reach the chain @@ -921,17 +921,17 @@ object Helpers { } else Set.empty /** - * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the - * local commit scenario and keep track of it. - * - * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be - * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't - * want to wait forever before declaring that the channel is CLOSED. - * - * @param localCommitPublished - * @param tx a transaction that has been irrevocably confirmed - * @return - */ + * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the + * local commit scenario and keep track of it. + * + * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be + * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't + * want to wait forever before declaring that the channel is CLOSED. + * + * @param localCommitPublished + * @param tx a transaction that has been irrevocably confirmed + * @return + */ def updateLocalCommitPublished(localCommitPublished: LocalCommitPublished, tx: Transaction) = { // even if our txes only have one input, maybe our counterparty uses a different scheme so we need to iterate // over all of them to check if they are relevant @@ -950,17 +950,17 @@ object Helpers { } /** - * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the - * remote commit scenario and keep track of it. - * - * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be - * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't - * want to wait forever before declaring that the channel is CLOSED. - * - * @param remoteCommitPublished - * @param tx a transaction that has been irrevocably confirmed - * @return - */ + * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the + * remote commit scenario and keep track of it. + * + * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be + * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't + * want to wait forever before declaring that the channel is CLOSED. + * + * @param remoteCommitPublished + * @param tx a transaction that has been irrevocably confirmed + * @return + */ def updateRemoteCommitPublished(remoteCommitPublished: RemoteCommitPublished, tx: Transaction) = { // even if our txes only have one input, maybe our counterparty uses a different scheme so we need to iterate // over all of them to check if they are relevant @@ -976,17 +976,17 @@ object Helpers { } /** - * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the - * revoked commit scenario and keep track of it. - * - * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be - * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't - * want to wait forever before declaring that the channel is CLOSED. - * - * @param revokedCommitPublished - * @param tx a transaction that has been irrevocably confirmed - * @return - */ + * In CLOSING state, when we are notified that a transaction has been confirmed, we check if this tx belongs in the + * revoked commit scenario and keep track of it. + * + * We need to keep track of all transactions spending the outputs of the commitment tx, because some outputs can be + * spent both by us and our counterparty. Because of that, some of our transactions may never confirm and we don't + * want to wait forever before declaring that the channel is CLOSED. + * + * @param revokedCommitPublished + * @param tx a transaction that has been irrevocably confirmed + * @return + */ def updateRevokedCommitPublished(revokedCommitPublished: RevokedCommitPublished, tx: Transaction) = { // even if our txes only have one input, maybe our counterparty uses a different scheme so we need to iterate // over all of them to check if they are relevant @@ -1005,13 +1005,13 @@ object Helpers { } /** - * A local commit is considered done when: - * - all commitment tx outputs that we can spend have been spent and confirmed (even if the spending tx was not ours) - * - all 3rd stage txes (txes spending htlc txes) have been confirmed - * - * @param localCommitPublished - * @return - */ + * A local commit is considered done when: + * - all commitment tx outputs that we can spend have been spent and confirmed (even if the spending tx was not ours) + * - all 3rd stage txes (txes spending htlc txes) have been confirmed + * + * @param localCommitPublished + * @return + */ def isLocalCommitDone(localCommitPublished: LocalCommitPublished) = { // is the commitment tx buried? (we need to check this because we may not have any outputs) val isCommitTxConfirmed = localCommitPublished.irrevocablySpent.values.toSet.contains(localCommitPublished.commitTx.txid) @@ -1026,12 +1026,12 @@ object Helpers { } /** - * A remote commit is considered done when all commitment tx outputs that we can spend have been spent and confirmed - * (even if the spending tx was not ours). - * - * @param remoteCommitPublished - * @return - */ + * A remote commit is considered done when all commitment tx outputs that we can spend have been spent and confirmed + * (even if the spending tx was not ours). + * + * @param remoteCommitPublished + * @return + */ def isRemoteCommitDone(remoteCommitPublished: RemoteCommitPublished) = { // is the commitment tx buried? (we need to check this because we may not have any outputs) val isCommitTxConfirmed = remoteCommitPublished.irrevocablySpent.values.toSet.contains(remoteCommitPublished.commitTx.txid) @@ -1042,12 +1042,12 @@ object Helpers { } /** - * A remote commit is considered done when all commitment tx outputs that we can spend have been spent and confirmed - * (even if the spending tx was not ours). - * - * @param revokedCommitPublished - * @return - */ + * A remote commit is considered done when all commitment tx outputs that we can spend have been spent and confirmed + * (even if the spending tx was not ours). + * + * @param revokedCommitPublished + * @return + */ def isRevokedCommitDone(revokedCommitPublished: RevokedCommitPublished) = { // is the commitment tx buried? (we need to check this because we may not have any outputs) val isCommitTxConfirmed = revokedCommitPublished.irrevocablySpent.values.toSet.contains(revokedCommitPublished.commitTx.txid) @@ -1062,17 +1062,17 @@ object Helpers { } /** - * This helper function tells if the utxo consumed by the given transaction has already been irrevocably spent (possibly by this very transaction) - * - * It can be useful to: - * - not attempt to publish this tx when we know this will fail - * - not watch for confirmations if we know the tx is already confirmed - * - not watch the corresponding utxo when we already know the final spending tx - * - * @param tx a tx with only one input - * @param irrevocablySpent a map of known spent outpoints - * @return true if we know for sure that the utxos consumed by the tx have already irrevocably been spent, false otherwise - */ + * This helper function tells if the utxo consumed by the given transaction has already been irrevocably spent (possibly by this very transaction) + * + * It can be useful to: + * - not attempt to publish this tx when we know this will fail + * - not watch for confirmations if we know the tx is already confirmed + * - not watch the corresponding utxo when we already know the final spending tx + * + * @param tx a tx with only one input + * @param irrevocablySpent a map of known spent outpoints + * @return true if we know for sure that the utxos consumed by the tx have already irrevocably been spent, false otherwise + */ def inputsAlreadySpent(tx: Transaction, irrevocablySpent: Map[OutPoint, ByteVector32]): Boolean = { require(tx.txIn.size == 1, "only tx with one input is supported") val outPoint = tx.txIn.head.outPoint @@ -1080,14 +1080,14 @@ object Helpers { } /** - * This helper function returns the fee paid by the given transaction. - * - * It relies on the current channel data to find the parent tx and compute the fee, and also provides a description. - * - * @param tx a tx for which we want to compute the fee - * @param d current channel data - * @return if the parent tx is found, a tuple (fee, description) - */ + * This helper function returns the fee paid by the given transaction. + * + * It relies on the current channel data to find the parent tx and compute the fee, and also provides a description. + * + * @param tx a tx for which we want to compute the fee + * @param d current channel data + * @return if the parent tx is found, a tuple (fee, description) + */ def networkFeePaid(tx: Transaction, d: DATA_CLOSING): Option[(Satoshi, String)] = { // only funder pays the fee if (d.commitments.localParams.isFunder) { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala index e5a1a83636..3ba11f5abd 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteNetworkDb.scala @@ -86,7 +86,7 @@ class SqliteNetworkDb(sqlite: Connection) extends NetworkDb { statement.setLong(1, c.shortChannelId.toLong) statement.setString(2, txid.toHex) statement.setBytes(3, channelAnnouncementCodec.encode(c).require.toByteArray) - statement.setLong(4, capacity.amount) + statement.setLong(4, capacity.toLong) statement.executeUpdate() } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index ad8022af71..d1bd17be45 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -606,8 +606,8 @@ object Peer { case object ResumeAnnouncements case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, fundingTxFeeratePerKw_opt: Option[Long], channelFlags: Option[Byte], timeout_opt: Option[Timeout]) { require(fundingSatoshis < Channel.MAX_FUNDING, s"fundingSatoshis must be less than ${Channel.MAX_FUNDING}") - require(pushMsat.toLong <= 1000 * fundingSatoshis.amount, s"pushMsat must be less or equal to fundingSatoshis") - require(fundingSatoshis.amount >= 0, s"fundingSatoshis must be positive") + require(pushMsat <= fundingSatoshis, s"pushMsat must be less or equal to fundingSatoshis") + require(fundingSatoshis.toLong >= 0, s"fundingSatoshis must be positive") require(pushMsat.toLong >= 0, s"pushMsat must be positive") fundingTxFeeratePerKw_opt.foreach(feeratePerKw => require(feeratePerKw >= MinimumFeeratePerKw, s"fee rate $feeratePerKw is below minimum $MinimumFeeratePerKw rate/kw")) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 56cc3d8443..2807faaed0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -158,7 +158,7 @@ package object eclair { */ val MaxEpochSeconds = Duration.fromNanos(Long.MaxValue).toSeconds - implicit class LongToBtcAmounts(l: Long) { + implicit class LongToBtcAmount(l: Long) { // @formatter:off def msat: MilliSatoshi = MilliSatoshi(l) def sat: Satoshi = Satoshi(l) @@ -190,10 +190,4 @@ package object eclair { // @formatter:on } - // TODO: we can remove that once bitcoin-lib offers it - implicit class MaxMinSatoshi(amount: Satoshi) { - def max(other: Satoshi): Satoshi = if (amount > other) amount else other - def min(other: Satoshi): Satoshi = if (amount < other) amount else other - } - } \ No newline at end of file diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala index 9ea53c8a1b..414a2f7491 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala @@ -30,8 +30,8 @@ import scodec.bits.ByteVector import scala.util.Try /** - * Created by PM on 15/12/2016. - */ + * Created by PM on 15/12/2016. + */ object Transactions { // @formatter:off @@ -69,38 +69,38 @@ object Transactions { // @formatter:on /** - * When *local* *current* [[CommitTx]] is published: - * - [[ClaimDelayedOutputTx]] spends to-local output of [[CommitTx]] after a delay - * - [[HtlcSuccessTx]] spends htlc-received outputs of [[CommitTx]] for which we have the preimage - * - [[ClaimDelayedOutputTx]] spends [[HtlcSuccessTx]] after a delay - * - [[HtlcTimeoutTx]] spends htlc-sent outputs of [[CommitTx]] after a timeout - * - [[ClaimDelayedOutputTx]] spends [[HtlcTimeoutTx]] after a delay - * - * When *remote* *current* [[CommitTx]] is published: - * - [[ClaimP2WPKHOutputTx]] spends to-local output of [[CommitTx]] - * - [[ClaimHtlcSuccessTx]] spends htlc-received outputs of [[CommitTx]] for which we have the preimage - * - [[ClaimHtlcTimeoutTx]] spends htlc-sent outputs of [[CommitTx]] after a timeout - * - * When *remote* *revoked* [[CommitTx]] is published: - * - [[ClaimP2WPKHOutputTx]] spends to-local output of [[CommitTx]] - * - [[MainPenaltyTx]] spends remote main output using the per-commitment secret - * - [[HtlcSuccessTx]] spends htlc-sent outputs of [[CommitTx]] for which they have the preimage (published by remote) - * - [[ClaimDelayedOutputPenaltyTx]] spends [[HtlcSuccessTx]] using the revocation secret (published by local) - * - [[HtlcTimeoutTx]] spends htlc-received outputs of [[CommitTx]] after a timeout (published by remote) - * - [[ClaimDelayedOutputPenaltyTx]] spends [[HtlcTimeoutTx]] using the revocation secret (published by local) - * - [[HtlcPenaltyTx]] spends competes with [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] for the same outputs (published by local) - */ + * When *local* *current* [[CommitTx]] is published: + * - [[ClaimDelayedOutputTx]] spends to-local output of [[CommitTx]] after a delay + * - [[HtlcSuccessTx]] spends htlc-received outputs of [[CommitTx]] for which we have the preimage + * - [[ClaimDelayedOutputTx]] spends [[HtlcSuccessTx]] after a delay + * - [[HtlcTimeoutTx]] spends htlc-sent outputs of [[CommitTx]] after a timeout + * - [[ClaimDelayedOutputTx]] spends [[HtlcTimeoutTx]] after a delay + * + * When *remote* *current* [[CommitTx]] is published: + * - [[ClaimP2WPKHOutputTx]] spends to-local output of [[CommitTx]] + * - [[ClaimHtlcSuccessTx]] spends htlc-received outputs of [[CommitTx]] for which we have the preimage + * - [[ClaimHtlcTimeoutTx]] spends htlc-sent outputs of [[CommitTx]] after a timeout + * + * When *remote* *revoked* [[CommitTx]] is published: + * - [[ClaimP2WPKHOutputTx]] spends to-local output of [[CommitTx]] + * - [[MainPenaltyTx]] spends remote main output using the per-commitment secret + * - [[HtlcSuccessTx]] spends htlc-sent outputs of [[CommitTx]] for which they have the preimage (published by remote) + * - [[ClaimDelayedOutputPenaltyTx]] spends [[HtlcSuccessTx]] using the revocation secret (published by local) + * - [[HtlcTimeoutTx]] spends htlc-received outputs of [[CommitTx]] after a timeout (published by remote) + * - [[ClaimDelayedOutputPenaltyTx]] spends [[HtlcTimeoutTx]] using the revocation secret (published by local) + * - [[HtlcPenaltyTx]] spends competes with [[HtlcSuccessTx]] and [[HtlcTimeoutTx]] for the same outputs (published by local) + */ /** - * these values are defined in the RFC - */ + * these values are defined in the RFC + */ val commitWeight = 724 val htlcTimeoutWeight = 663 val htlcSuccessWeight = 703 /** - * these values specific to us and used to estimate fees - */ + * these values specific to us and used to estimate fees + */ val claimP2WPKHOutputWeight = 438 val claimHtlcDelayedWeight = 483 val claimHtlcSuccessWeight = 571 @@ -111,12 +111,12 @@ object Transactions { def weight2fee(feeratePerKw: Long, weight: Int) = Satoshi((feeratePerKw * weight) / 1000) /** - * - * @param fee tx fee - * @param weight tx weight - * @return the fee rate (in Satoshi/Kw) for this tx - */ - def fee2rate(fee: Satoshi, weight: Int) = (fee.amount * 1000L) / weight + * + * @param fee tx fee + * @param weight tx weight + * @return the fee rate (in Satoshi/Kw) for this tx + */ + def fee2rate(fee: Satoshi, weight: Int) = (fee.toLong * 1000L) / weight def trimOfferedHtlcs(dustLimit: Satoshi, spec: CommitmentSpec): Seq[DirectedHtlc] = { val htlcTimeoutFee = weight2fee(spec.feeratePerKw, htlcTimeoutWeight) @@ -142,13 +142,13 @@ object Transactions { } /** - * - * @param commitTxNumber commit tx number - * @param isFunder true if local node is funder - * @param localPaymentBasePoint local payment base point - * @param remotePaymentBasePoint remote payment base point - * @return the obscured tx number as defined in BOLT #3 (a 48 bits integer) - */ + * + * @param commitTxNumber commit tx number + * @param isFunder true if local node is funder + * @param localPaymentBasePoint local payment base point + * @param remotePaymentBasePoint remote payment base point + * @return the obscured tx number as defined in BOLT #3 (a 48 bits integer) + */ def obscuredCommitTxNumber(commitTxNumber: Long, isFunder: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { // from BOLT 3: SHA256(payment-basepoint from open_channel || payment-basepoint from accept_channel) val h = if (isFunder) @@ -161,13 +161,13 @@ object Transactions { } /** - * - * @param commitTx commit tx - * @param isFunder true if local node is funder - * @param localPaymentBasePoint local payment base point - * @param remotePaymentBasePoint remote payment base point - * @return the actual commit tx number that was blinded and stored in locktime and sequence fields - */ + * + * @param commitTx commit tx + * @param isFunder true if local node is funder + * @param localPaymentBasePoint local payment base point + * @param remotePaymentBasePoint remote payment base point + * @return the actual commit tx number that was blinded and stored in locktime and sequence fields + */ def getCommitTxNumber(commitTx: Transaction, isFunder: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { val blind = obscuredCommitTxNumber(0, isFunder, localPaymentBasePoint, remotePaymentBasePoint) val obscured = decodeTxNumber(commitTx.txIn.head.sequence, commitTx.lockTime) @@ -175,11 +175,11 @@ object Transactions { } /** - * This is a trick to split and encode a 48-bit txnumber into the sequence and locktime fields of a tx - * - * @param txnumber commitment number - * @return (sequence, locktime) - */ + * This is a trick to split and encode a 48-bit txnumber into the sequence and locktime fields of a tx + * + * @param txnumber commitment number + * @return (sequence, locktime) + */ def encodeTxNumber(txnumber: Long): (Long, Long) = { require(txnumber <= 0xffffffffffffL, "txnumber must be lesser than 48 bits long") (0x80000000L | (txnumber >> 24), (txnumber & 0xffffffL) | 0x20000000) @@ -417,8 +417,8 @@ object Transactions { } /** - * We already have the redeemScript, no need to build it - */ + * We already have the redeemScript, no need to build it + */ def makeHtlcPenaltyTx(commitTx: Transaction, outputsAlreadyUsed: Set[Int], redeemScript: ByteVector, localDustLimit: Satoshi, localFinalScriptPubKey: ByteVector, feeratePerKw: Long): HtlcPenaltyTx = { val pubkeyScript = write(pay2wsh(redeemScript)) val outputIndex = findPubKeyScriptIndex(commitTx, pubkeyScript, outputsAlreadyUsed, amount_opt = None) @@ -467,7 +467,7 @@ object Transactions { def findPubKeyScriptIndex(tx: Transaction, pubkeyScript: ByteVector, outputsAlreadyUsed: Set[Int], amount_opt: Option[Satoshi]): Int = { val outputIndex = tx.txOut .zipWithIndex - .indexWhere { case (txOut, index) => amount_opt.map(_ == txOut.amount).getOrElse(true) && txOut.publicKeyScript == pubkeyScript && !outputsAlreadyUsed.contains(index)} // it's not enough to only resolve on pubkeyScript because we may have duplicates + .indexWhere { case (txOut, index) => amount_opt.map(_ == txOut.amount).getOrElse(true) && txOut.publicKeyScript == pubkeyScript && !outputsAlreadyUsed.contains(index) } // it's not enough to only resolve on pubkeyScript because we may have duplicates if (outputIndex >= 0) { outputIndex } else { @@ -476,14 +476,14 @@ object Transactions { } /** - * Default public key used for fee estimation - */ + * Default public key used for fee estimation + */ val PlaceHolderPubKey = PrivateKey(ByteVector32.One).publicKey /** - * This default sig takes 72B when encoded in DER (incl. 1B for the trailing sig hash), it is used for fee estimation - * It is 72 bytes because our signatures are normalized (low-s) and will take up 72 bytes at most in DER format - */ + * This default sig takes 72B when encoded in DER (incl. 1B for the trailing sig hash), it is used for fee estimation + * It is 72 bytes because our signatures are normalized (low-s) and will take up 72 bytes at most in DER format + */ val PlaceHolderSig = ByteVector64(ByteVector.fill(64)(0xaa)) assert(der(PlaceHolderSig).size == 72) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala index 375840f74c..fe2522df4b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala @@ -29,14 +29,13 @@ import scodec.bits.ByteVector import scala.util.{Failure, Random, Success, Try} - class ElectrumWalletBasicSpec extends FunSuite with Logging { import ElectrumWallet._ import ElectrumWalletBasicSpec._ val swipeRange = 10 - val dustLimit = 546 satoshi + val dustLimit = 546 sat val feeRatePerKw = 20000 val minimumFee = Satoshi(2000) @@ -176,7 +175,7 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { val state2 = addFunds(state1, state1.accountKeys(1), 2 btc) val state3 = addFunds(state2, state2.changeKeys(0), 0.5 btc) assert(state3.utxos.length == 3) - assert(state3.balance == (Satoshi(350000000),Satoshi(0))) + assert(state3.balance == (350000000 sat, 0 sat)) val (tx, fee) = state3.spendAll(Script.pay2wpkh(ByteVector.fill(20)(1)), feeRatePerKw) val Some((received, sent, Some(fee1))) = state3.computeTransactionDelta(tx) @@ -209,10 +208,10 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { object ElectrumWalletBasicSpec { /** - * - * @param actualFeeRate actual fee rate - * @param targetFeeRate target fee rate - * @return true if actual fee rate is within 10% of target - */ + * + * @param actualFeeRate actual fee rate + * @param targetFeeRate target fee rate + * @return true if actual fee rate is within 10% of target + */ def isFeerateOk(actualFeeRate: Long, targetFeeRate: Long): Boolean = Math.abs(actualFeeRate - targetFeeRate) < 0.1 * (actualFeeRate + targetFeeRate) } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala index b129f52192..126218bab9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala @@ -120,7 +120,7 @@ class BitcoinCoreFeeProviderSpec extends TestKit(ActorSystem("test")) with Bitco override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] = method match { case "estimatesmartfee" => val blocks = params(0).asInstanceOf[Int] - val feerate = satoshi2btc(Satoshi(fees(blocks))).amount + val feerate = satoshi2btc(Satoshi(fees(blocks))).toBigDecimal Future(JObject(List("feerate" -> JDecimal(feerate), "blocks" -> JInt(blocks)))) case _ => Future.failed(new RuntimeException(s"Test BasicBitcoinJsonRPCClient: method $method is not supported")) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimReceivedHtlcSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimReceivedHtlcSpec.scala index 37aa3d161e..942f48b49b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimReceivedHtlcSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimReceivedHtlcSpec.scala @@ -79,21 +79,21 @@ class ClaimReceivedHtlcSpec extends FunSuite { val tx = Transaction( version = 2, txIn = TxIn(OutPoint(ByteVector32.Zeroes, 0), ByteVector.empty, 0xffffffffL) :: Nil, - txOut = TxOut(10 satoshi, Script.pay2wsh(htlcScript)) :: Nil, + txOut = TxOut(10 sat, Script.pay2wsh(htlcScript)) :: Nil, lockTime = 0) // this tx tries to spend the previous tx val tx1 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, 0xffffffff) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = 0) test("Alice can spend this HTLC after a delay if she knows the payment hash") { val tx2 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, reltimeout + 1) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = abstimeout + 1) val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, tx.txOut(0).amount, 1, Alice.finalKey) @@ -107,7 +107,7 @@ class ClaimReceivedHtlcSpec extends FunSuite { val tx2 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, reltimeout + 1) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Bob.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Bob.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = abstimeout + 1) val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, tx.txOut(0).amount, 1, Bob.finalKey) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimSentHtlcSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimSentHtlcSpec.scala index 824aa1cc57..8cab7fe94b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimSentHtlcSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/ClaimSentHtlcSpec.scala @@ -77,21 +77,21 @@ class ClaimSentHtlcSpec extends FunSuite { val tx = Transaction( version = 2, txIn = TxIn(OutPoint(ByteVector32.Zeroes, 0), ByteVector.empty, 0xffffffffL) :: Nil, - txOut = TxOut(10 satoshi, Script.pay2wsh(htlcScript)) :: Nil, + txOut = TxOut(10 sat, Script.pay2wsh(htlcScript)) :: Nil, lockTime = 0) // this tx tries to spend the previous tx val tx1 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, 0xffffffff) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = 0) test("Alice can spend this HTLC after a delay") { val tx2 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, sequence = reltimeout + 1) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = abstimeout + 1) val sig = Transaction.signInput(tx2, 0, redeemScript, SIGHASH_ALL, tx.txOut(0).amount, 1, Alice.finalKey) @@ -105,7 +105,7 @@ class ClaimSentHtlcSpec extends FunSuite { val tx2 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, sequence = reltimeout + 1) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = abstimeout - 1) val sig = Transaction.signInput(tx2, 0, redeemScript, SIGHASH_ALL, tx.txOut(0).amount, 1, Alice.finalKey) @@ -122,7 +122,7 @@ class ClaimSentHtlcSpec extends FunSuite { val tx2 = Transaction( version = 2, txIn = TxIn(OutPoint(tx, 0), ByteVector.empty, sequence = reltimeout - 1) :: Nil, - txOut = TxOut(10 satoshi, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, + txOut = TxOut(10 sat, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey.value)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil, lockTime = abstimeout + 1) val sig = Transaction.signInput(tx2, 0, redeemScript, SIGHASH_ALL, tx.txOut(0).amount, 1, Alice.finalKey) diff --git a/pom.xml b/pom.xml index e5aa8bbc1d..a44eccbcb2 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 2.4.20 10.0.11 1.3.9 - 0.14 + 0.15-SNAPSHOT 24.0-android From 05f2c6a06f234bffa0f12b7630775a39f6c7da5e Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Fri, 23 Aug 2019 15:34:35 +0200 Subject: [PATCH 10/18] Fix eclair-node-gui build --- .../eclair/gui/controllers/OpenChannelController.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala index 361ba9337a..c038671808 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/OpenChannelController.scala @@ -76,9 +76,9 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage) extends Lo fundingSat.textProperty.addListener(new ChangeListener[String] { def changed(observable: ObservableValue[_ <: String], oldValue: String, newValue: String): Unit = { Try(CoinUtils.convertStringAmountToSat(newValue, fundingUnit.getValue)) match { - case Success(capacitySat) if capacitySat.amount <= 0 => + case Success(capacitySat) if capacitySat <= 0.sat => fundingSatError.setText("Capacity must be greater than 0") - case Success(capacitySat) if capacitySat.amount < 50000 => + case Success(capacitySat) if capacitySat < 50000.sat => fundingSatError.setText("Capacity is low and the channel may not be able to open") case Success(capacitySat) if capacitySat >= Channel.MAX_FUNDING => fundingSatError.setText(s"Capacity must be less than ${CoinUtils.formatAmountInUnit(Channel.MAX_FUNDING, FxApp.getUnit, withUnit = true)}") @@ -99,7 +99,7 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage) extends Lo (Try(CoinUtils.convertStringAmountToSat(fundingSat.getText, fundingUnit.getValue)), Try(if (Strings.isNullOrEmpty(pushMsatField.getText())) 0L else pushMsatField.getText().toLong), Try(if (Strings.isNullOrEmpty(feerateField.getText())) None else Some(feerateField.getText().toLong))) match { - case (Success(capacitySat), _, _) if capacitySat.amount <= 0 => + case (Success(capacitySat), _, _) if capacitySat <= 0.sat => fundingSatError.setText("Capacity must be greater than 0") case (Success(capacitySat), _, _) if capacitySat >= Channel.MAX_FUNDING => fundingSatError.setText(s"Capacity must be less than ${CoinUtils.formatAmountInUnit(Channel.MAX_FUNDING, FxApp.getUnit, withUnit = true)}") From d880e1b805e0bf3de0f232fa904c8d16bbd85ff1 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Fri, 23 Aug 2019 17:02:07 +0200 Subject: [PATCH 11/18] fixup! Fix eclair-node-gui build --- .../fee/BitcoinCoreFeeProvider.scala | 16 +++--- .../main/scala/fr/acinq/eclair/io/Peer.scala | 6 +-- .../fr/acinq/eclair/gui/GUIUpdater.scala | 2 +- .../ReceivePaymentController.scala | 50 +++++++++---------- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala index 947b7aa99d..759cab34dd 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProvider.scala @@ -24,18 +24,18 @@ import org.json4s.JsonAST._ import scala.concurrent.{ExecutionContext, Future} /** - * Created by PM on 09/07/2017. - */ + * Created by PM on 09/07/2017. + */ class BitcoinCoreFeeProvider(rpcClient: BitcoinJsonRPCClient, defaultFeerates: FeeratesPerKB)(implicit ec: ExecutionContext) extends FeeProvider { implicit val formats = DefaultFormats.withBigDecimal /** - * We need this to keep commitment tx fees in sync with the state of the network - * - * @param nBlocks number of blocks until tx is confirmed - * @return the current fee estimate in Satoshi/KB - */ + * We need this to keep commitment tx fees in sync with the state of the network + * + * @param nBlocks number of blocks until tx is confirmed + * @return the current fee estimate in Satoshi/KB + */ def estimateSmartFee(nBlocks: Int): Future[Long] = rpcClient.invoke("estimatesmartfee", nBlocks).map(BitcoinCoreFeeProvider.parseFeeEstimate) @@ -73,7 +73,7 @@ object BitcoinCoreFeeProvider { btc2satoshi(Btc(feerate.toLong)).toLong } case JArray(errors) => - val error = errors collect { case JString(error) => error } mkString ", " + val error = errors.collect { case JString(error) => error }.mkString(", ") throw new RuntimeException(s"estimatesmartfee failed: $error") case _ => throw new RuntimeException("estimatesmartfee failed") diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index d1bd17be45..2cc35988d0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -607,8 +607,8 @@ object Peer { case class OpenChannel(remoteNodeId: PublicKey, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, fundingTxFeeratePerKw_opt: Option[Long], channelFlags: Option[Byte], timeout_opt: Option[Timeout]) { require(fundingSatoshis < Channel.MAX_FUNDING, s"fundingSatoshis must be less than ${Channel.MAX_FUNDING}") require(pushMsat <= fundingSatoshis, s"pushMsat must be less or equal to fundingSatoshis") - require(fundingSatoshis.toLong >= 0, s"fundingSatoshis must be positive") - require(pushMsat.toLong >= 0, s"pushMsat must be positive") + require(fundingSatoshis >= 0.sat, s"fundingSatoshis must be positive") + require(pushMsat >= 0.msat, s"pushMsat must be positive") fundingTxFeeratePerKw_opt.foreach(feeratePerKw => require(feeratePerKw >= MinimumFeeratePerKw, s"fee rate $feeratePerKw is below minimum $MinimumFeeratePerKw rate/kw")) } case object GetPeerInfo @@ -642,7 +642,7 @@ object Peer { channelKeyPath, dustLimit = nodeParams.dustLimit, maxHtlcValueInFlightMsat = nodeParams.maxHtlcValueInFlightMsat, - channelReserve = Satoshi((nodeParams.reserveToFundingRatio * fundingAmount.toLong).toLong).max(nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit + channelReserve = (fundingAmount * nodeParams.reserveToFundingRatio).max(nodeParams.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit htlcMinimum = nodeParams.htlcMinimum, toSelfDelay = nodeParams.toRemoteDelayBlocks, // we choose their delay maxAcceptedHtlcs = nodeParams.maxAcceptedHtlcs, diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala index d63fb219f9..ec7798cd78 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala @@ -86,7 +86,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging val (channelPaneController, root) = createChannelPanel(channel, peer, remoteNodeId, isFunder, channelId) channelPaneController.updateBalance(currentData.commitments) val m1 = m + (channel -> channelPaneController) - val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.toLong).sum) + val totalBalance = m1.values.map(_.getBalance).sum runInGuiThread(() => { channelPaneController.refreshBalance() mainController.refreshTotalBalance(totalBalance) diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala index e9f360392f..87bacaf58f 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala @@ -24,19 +24,17 @@ import javafx.scene.image.{ImageView, WritableImage} import javafx.scene.layout.GridPane import javafx.stage.Stage -import fr.acinq.eclair.MilliSatoshi -import fr.acinq.eclair.CoinUtils -import fr.acinq.eclair.gui.{FxApp, Handlers} import fr.acinq.eclair.gui.utils._ -import fr.acinq.eclair.payment.PaymentRequest +import fr.acinq.eclair.gui.{FxApp, Handlers} +import fr.acinq.eclair.{CoinUtils, LongToBtcAmount, MilliSatoshi} import grizzled.slf4j.Logging import scala.concurrent.ExecutionContext.Implicits.global import scala.util.{Failure, Success, Try} /** - * Created by DPA on 23/09/2016. - */ + * Created by DPA on 23/09/2016. + */ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends Logging { @FXML var amount: TextField = _ @@ -60,18 +58,18 @@ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends @FXML def handleCopyInvoice(event: ActionEvent) = ContextMenuUtils.copyToClipboard(paymentRequestTextArea.getText) /** - * Generates a payment request from the amount/unit set in form. Displays an error if the generation fails. - * Amount field content must obviously be numeric. It is also validated against minimal/maximal HTLC values. - * - * @param event - */ + * Generates a payment request from the amount/unit set in form. Displays an error if the generation fails. + * Amount field content must obviously be numeric. It is also validated against minimal/maximal HTLC values. + * + * @param event + */ @FXML def handleGenerate(event: ActionEvent) = { clearError() amount.getText match { case "" => createPaymentRequest(None) case GUIValidators.amountDecRegex(_*) => Try(CoinUtils.convertStringAmountToMsat(amount.getText, unit.getValue)) match { - case Success(amountMsat) if amountMsat.toLong < 0 => + case Success(amountMsat) if amountMsat < 0.msat => handleError("Amount must be greater than 0") case Failure(_) => handleError("Amount is incorrect") @@ -82,10 +80,10 @@ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends } /** - * Display error message - * - * @param message - */ + * Display error message + * + * @param message + */ private def handleError(message: String): Unit = { paymentRequestTextArea.setText("") amountError.setText(message) @@ -99,11 +97,11 @@ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends } /** - * Ask eclair-core to create a Payment Request. If successful a QR code is generated and displayed, otherwise - * an error message is shown. - * - * @param amount_opt optional amount of the payment request, in millisatoshi - */ + * Ask eclair-core to create a Payment Request. If successful a QR code is generated and displayed, otherwise + * an error message is shown. + * + * @param amount_opt optional amount of the payment request, in millisatoshi + */ private def createPaymentRequest(amount_opt: Option[MilliSatoshi]) = { logger.debug(s"generate payment request for amount_opt=${amount_opt.getOrElse("N/A")} description=${description.getText()}") handlers.receive(amount_opt, description.getText) onComplete { @@ -122,11 +120,11 @@ class ReceivePaymentController(val handlers: Handlers, val stage: Stage) extends } /** - * Displays a QR Code from a QR code image. - * - * @param pr payment request described by the QR code - * @param image QR code source image - */ + * Displays a QR Code from a QR code image. + * + * @param pr payment request described by the QR code + * @param image QR code source image + */ private def displayPaymentRequestQR(pr: String, image: Option[WritableImage]) = Platform.runLater(new Runnable { def run = { paymentRequestTextArea.setText(pr) From 608a9deea996bd1b1097d10474ba6675603ae147 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Fri, 23 Aug 2019 17:21:00 +0200 Subject: [PATCH 12/18] Remove unnecessary calls to .toMilliSatoshi. Use built-in comparisons between BtcAmounts instead. --- .../src/main/scala/fr/acinq/eclair/channel/Helpers.scala | 4 ++-- .../scala/fr/acinq/eclair/transactions/Transactions.scala | 4 ++-- .../channel/states/a/WaitForOpenChannelStateSpec.scala | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index da46c04b1c..b77693a952 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -90,7 +90,7 @@ object Helpers { if (open.fundingSatoshis < nodeParams.minFundingSatoshis || open.fundingSatoshis >= Channel.MAX_FUNDING) throw InvalidFundingAmount(open.temporaryChannelId, open.fundingSatoshis, nodeParams.minFundingSatoshis, Channel.MAX_FUNDING) // BOLT #2: The receiving node MUST fail the channel if: push_msat is greater than funding_satoshis * 1000. - if (open.pushMsat > open.fundingSatoshis.toMilliSatoshi) throw InvalidPushAmount(open.temporaryChannelId, open.pushMsat, open.fundingSatoshis.toMilliSatoshi) + if (open.pushMsat > open.fundingSatoshis) throw InvalidPushAmount(open.temporaryChannelId, open.pushMsat, open.fundingSatoshis.toMilliSatoshi) // BOLT #2: The receiving node MUST fail the channel if: to_self_delay is unreasonably large. if (open.toSelfDelay > Channel.MAX_TO_SELF_DELAY || open.toSelfDelay > nodeParams.maxToLocalDelayBlocks) throw ToSelfDelayTooHigh(open.temporaryChannelId, open.toSelfDelay, nodeParams.maxToLocalDelayBlocks) @@ -107,7 +107,7 @@ object Helpers { // BOLT #2: The receiving node MUST fail the channel if both to_local and to_remote amounts for the initial commitment // transaction are less than or equal to channel_reserve_satoshis (see BOLT 3). val (toLocalMsat, toRemoteMsat) = (open.pushMsat, open.fundingSatoshis.toMilliSatoshi - open.pushMsat) - if (toLocalMsat < open.channelReserveSatoshis.toMilliSatoshi && toRemoteMsat < open.channelReserveSatoshis.toMilliSatoshi) { + if (toLocalMsat < open.channelReserveSatoshis && toRemoteMsat < open.channelReserveSatoshis) { throw ChannelReserveNotMet(open.temporaryChannelId, toLocalMsat, toRemoteMsat, open.channelReserveSatoshis) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala index 414a2f7491..4f6dc93c6d 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala @@ -122,7 +122,7 @@ object Transactions { val htlcTimeoutFee = weight2fee(spec.feeratePerKw, htlcTimeoutWeight) spec.htlcs .filter(_.direction == OUT) - .filter(htlc => htlc.add.amountMsat >= (dustLimit + htlcTimeoutFee).toMilliSatoshi) + .filter(htlc => htlc.add.amountMsat >= (dustLimit + htlcTimeoutFee)) .toSeq } @@ -130,7 +130,7 @@ object Transactions { val htlcSuccessFee = weight2fee(spec.feeratePerKw, htlcSuccessWeight) spec.htlcs .filter(_.direction == IN) - .filter(htlc => htlc.add.amountMsat >= (dustLimit + htlcSuccessFee).toMilliSatoshi) + .filter(htlc => htlc.add.amountMsat >= (dustLimit + htlcSuccessFee)) .toSeq } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala index 549ee6f692..65b861c4e0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala @@ -167,11 +167,11 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper import f._ val open = alice2bob.expectMsgType[OpenChannel] val fundingSatoshis = open.channelReserveSatoshis.toLong + 499 - val pushMsat = 500 * 1000 - bob ! open.copy(fundingSatoshis = Satoshi(fundingSatoshis), pushMsat = MilliSatoshi(pushMsat)) + val pushMsat = MilliSatoshi(500 * 1000) + bob ! open.copy(fundingSatoshis = Satoshi(fundingSatoshis), pushMsat = pushMsat) val error = bob2alice.expectMsgType[Error] // we check that the error uses the temporary channel id - assert(error === Error(open.temporaryChannelId, ChannelReserveNotMet(open.temporaryChannelId, Satoshi(500).toMilliSatoshi, (open.channelReserveSatoshis - Satoshi(1)).toMilliSatoshi, open.channelReserveSatoshis).getMessage)) + assert(error === Error(open.temporaryChannelId, ChannelReserveNotMet(open.temporaryChannelId, pushMsat, (open.channelReserveSatoshis - Satoshi(1)).toMilliSatoshi, open.channelReserveSatoshis).getMessage)) awaitCond(bob.stateName == CLOSED) } From eef4658e690003ab857e9a596f5f69924af712f8 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Mon, 26 Aug 2019 16:29:36 +0200 Subject: [PATCH 13/18] Switch to bitcoin-lib 0.15. Add some clarifying comments. --- eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala | 1 + eclair-core/src/main/scala/fr/acinq/eclair/package.scala | 1 + pom.xml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index f4b92e0072..0cbef30790 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -45,6 +45,7 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos def <(other: BtcAmount): Boolean = compare(other) < 0 def >(other: BtcAmount): Boolean = compare(other) > 0 + // We provide asymmetric min/max functions to provide more control on the return type. def max(other: MilliSatoshi): MilliSatoshi = if (this > other) this else other def max(other: BtcAmount): MilliSatoshi = if (this > other) this else other.toMilliSatoshi def min(other: MilliSatoshi): MilliSatoshi = if (this < other) this else other diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala index 2807faaed0..2349b2984c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/package.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/package.scala @@ -167,6 +167,7 @@ package object eclair { // @formatter:on } + // We implement Numeric to take advantage of operations such as sum, sort or min/max on iterables. implicit object NumericMilliSatoshi extends Numeric[MilliSatoshi] { // @formatter:off override def plus(x: MilliSatoshi, y: MilliSatoshi): MilliSatoshi = x + y diff --git a/pom.xml b/pom.xml index a44eccbcb2..3c8775b350 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 2.4.20 10.0.11 1.3.9 - 0.15-SNAPSHOT + 0.15 24.0-android From 3cc8303be678071a90b0a0175abc41329b0fd59b Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Tue, 27 Aug 2019 10:51:52 +0200 Subject: [PATCH 14/18] Use msat and sat postfix operators in tests. It's more readable than using constructors. --- .../main/scala/fr/acinq/eclair/Eclair.scala | 2 +- .../blockchain/electrum/ElectrumWallet.scala | 365 +++++++-------- .../blockchain/electrum/ElectrumWatcher.scala | 7 +- .../fr/acinq/eclair/channel/Channel.scala | 4 +- .../fr/acinq/eclair/channel/Commitments.scala | 22 +- .../fr/acinq/eclair/channel/Helpers.scala | 6 +- .../fr/acinq/eclair/payment/Autoprobe.scala | 4 +- .../eclair/payment/PaymentLifecycle.scala | 2 +- .../acinq/eclair/payment/PaymentRequest.scala | 173 +++---- .../fr/acinq/eclair/payment/Relayer.scala | 4 +- .../scala/fr/acinq/eclair/router/Graph.scala | 4 +- .../scala/fr/acinq/eclair/router/Router.scala | 2 +- .../acinq/eclair/transactions/Scripts.scala | 8 +- .../fr/acinq/eclair/wire/FailureMessage.scala | 4 +- .../fr/acinq/eclair/EclairImplSpec.scala | 60 +-- .../scala/fr/acinq/eclair/TestConstants.scala | 30 +- .../fr/acinq/eclair/api/ApiServiceSpec.scala | 20 +- .../eclair/api/JsonSerializersSpec.scala | 2 +- .../acinq/eclair/blockchain/TestWallet.scala | 10 +- .../bitcoind/BitcoinCoreWalletSpec.scala | 12 +- .../electrum/ElectrumWalletBasicSpec.scala | 16 +- .../ElectrumWalletSimulatedClientSpec.scala | 31 +- .../electrum/ElectrumWalletSpec.scala | 49 +- .../electrum/ElectrumWatcherSpec.scala | 10 +- .../acinq/eclair/channel/ThroughputSpec.scala | 2 +- .../states/StateTestsHelperMethods.scala | 4 +- .../a/WaitForAcceptChannelStateSpec.scala | 12 +- .../a/WaitForOpenChannelStateSpec.scala | 22 +- .../b/WaitForFundingCreatedStateSpec.scala | 6 +- .../c/WaitForFundingConfirmedStateSpec.scala | 11 +- .../channel/states/e/NormalStateSpec.scala | 293 ++++++------ .../channel/states/e/OfflineStateSpec.scala | 26 +- .../channel/states/f/ShutdownStateSpec.scala | 24 +- .../states/g/NegotiatingStateSpec.scala | 12 +- .../channel/states/h/ClosingStateSpec.scala | 22 +- .../acinq/eclair/db/SqliteAuditDbSpec.scala | 52 +-- .../acinq/eclair/db/SqliteNetworkDbSpec.scala | 15 +- .../eclair/db/SqlitePaymentsDbSpec.scala | 29 +- .../eclair/integration/IntegrationSpec.scala | 103 +++-- .../interop/rustytests/RustyTestsSpec.scala | 4 +- .../fr/acinq/eclair/io/HtlcReaperSpec.scala | 8 +- .../scala/fr/acinq/eclair/io/PeerSpec.scala | 2 +- .../eclair/payment/ChannelSelectionSpec.scala | 40 +- .../eclair/payment/HtlcGenerationSpec.scala | 24 +- .../eclair/payment/PaymentHandlerSpec.scala | 28 +- .../eclair/payment/PaymentLifecycleSpec.scala | 16 +- .../eclair/payment/PaymentRequestSpec.scala | 60 +-- .../fr/acinq/eclair/payment/RelayerSpec.scala | 45 +- .../AnnouncementsBatchValidationSpec.scala | 6 +- .../eclair/router/AnnouncementsSpec.scala | 10 +- .../acinq/eclair/router/BaseRouterSpec.scala | 26 +- .../fr/acinq/eclair/router/GraphSpec.scala | 80 ++-- .../eclair/router/RouteCalculationSpec.scala | 426 +++++++++--------- .../fr/acinq/eclair/router/RouterSpec.scala | 34 +- .../acinq/eclair/router/RoutingSyncSpec.scala | 4 +- .../transactions/CommitmentSpecSpec.scala | 31 +- .../eclair/transactions/TestVectorsSpec.scala | 78 ++-- .../transactions/TransactionsSpec.scala | 32 +- .../acinq/eclair/wire/ChannelCodecsSpec.scala | 40 +- .../wire/FailureMessageCodecsSpec.scala | 14 +- .../wire/LightningMessageCodecsSpec.scala | 14 +- .../acinq/eclair/wire/OnionCodecsSpec.scala | 4 +- .../fr/acinq/eclair/gui/GUIUpdater.scala | 4 +- 63 files changed, 1253 insertions(+), 1257 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala index 72c8b3ae6d..b5a6de6a9e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala @@ -128,7 +128,7 @@ class EclairImpl(appKit: Kit) extends Eclair { (appKit.switchboard ? Peer.OpenChannel( remoteNodeId = nodeId, fundingSatoshis = fundingAmount, - pushMsat = pushAmount_opt.getOrElse(MilliSatoshi(0)), + pushMsat = pushAmount_opt.getOrElse(0 msat), fundingTxFeeratePerKw_opt = fundingFeerateSatByte_opt.map(feerateByte2Kw), channelFlags = flags_opt.map(_.toByte), timeout_opt = Some(openTimeout))).mapTo[String] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWallet.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWallet.scala index 428623f9e3..c660595cb8 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWallet.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWallet.scala @@ -20,6 +20,7 @@ import akka.actor.{ActorRef, FSM, PoisonPill, Props} import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.DeterministicWallet.{ExtendedPrivateKey, derivePrivateKey, hardened} import fr.acinq.bitcoin.{Base58, Base58Check, Block, ByteVector32, Crypto, DeterministicWallet, OP_PUSHDATA, OutPoint, SIGHASH_ALL, Satoshi, Script, ScriptElt, ScriptWitness, SigVersion, Transaction, TxIn, TxOut} +import fr.acinq.eclair.LongToBtcAmount import fr.acinq.eclair.blockchain.bitcoind.rpc.Error import fr.acinq.eclair.blockchain.electrum.ElectrumClient._ import fr.acinq.eclair.blockchain.electrum.db.{HeaderDb, WalletDb} @@ -31,21 +32,21 @@ import scala.annotation.tailrec import scala.util.{Failure, Success, Try} /** - * Simple electrum wallet - * - * Typical workflow: - * - * client ---- header update ----> wallet - * client ---- status update ----> wallet - * client <--- ask history ----- wallet - * client ---- history ----> wallet - * client <--- ask tx ----- wallet - * client ---- tx ----> wallet - * - * @param seed - * @param client - * @param params - */ + * Simple electrum wallet + * + * Typical workflow: + * + * client ---- header update ----> wallet + * client ---- status update ----> wallet + * client <--- ask history ----- wallet + * client ---- history ----> wallet + * client <--- ask tx ----- wallet + * client ---- tx ----> wallet + * + * @param seed + * @param client + * @param params + */ class ElectrumWallet(seed: ByteVector, client: ActorRef, params: ElectrumWallet.WalletParameters) extends FSM[ElectrumWallet.State, ElectrumWallet.Data] { import Blockchain.RETARGETING_PERIOD @@ -65,13 +66,13 @@ class ElectrumWallet(seed: ByteVector, client: ActorRef, params: ElectrumWallet. // +--------------------------------------------+ /** - * If the wallet is ready and its state changed since the last time it was ready: - * - publish a `WalletReady` notification - * - persist state data - * - * @param data wallet data - * @return the input data with an updated 'last ready message' if needed - */ + * If the wallet is ready and its state changed since the last time it was ready: + * - publish a `WalletReady` notification + * - persist state data + * + * @param data wallet data + * @return the input data with an updated 'last ready message' if needed + */ def persistAndNotify(data: ElectrumWallet.Data): ElectrumWallet.Data = { if (data.isReady(swipeRange)) { data.lastReadyMessage match { @@ -289,11 +290,11 @@ class ElectrumWallet(seed: ByteVector, client: ActorRef, params: ElectrumWallet. pendingHeadersRequests1 ++= data.pendingHeadersRequests /** - * If we don't already have a header at this height, or a pending request to download the header chunk it's in, - * download this header chunk. - * We don't have this header because it's most likely older than our current checkpoint, downloading the whole header - * chunk (2016 headers) is quick and they're easy to verify. - */ + * If we don't already have a header at this height, or a pending request to download the header chunk it's in, + * download this header chunk. + * We don't have this header because it's most likely older than our current checkpoint, downloading the whole header + * chunk (2016 headers) is quick and they're easy to verify. + */ def downloadHeadersIfMissing(height: Int): Unit = { if (data.blockchain.getHeader(height).orElse(params.walletDb.getHeader(height)).isEmpty) { // we don't have this header, probably because it is older than our checkpoints @@ -423,7 +424,7 @@ class ElectrumWallet(seed: ByteVector, client: ActorRef, params: ElectrumWallet. case Event(CompleteTransaction(tx, feeRatePerKw), data) => Try(data.completeTransaction(tx, feeRatePerKw, minimumFee, dustLimit, allowSpendUnconfirmed)) match { case Success((data1, tx1, fee1)) => stay using data1 replying CompleteTransactionResponse(tx1, fee1, None) - case Failure(t) => stay replying CompleteTransactionResponse(tx, Satoshi(0), Some(t)) + case Failure(t) => stay replying CompleteTransactionResponse(tx, 0 sat, Some(t)) } case Event(SendAll(publicKeyScript, feeRatePerKw), data) => @@ -495,7 +496,7 @@ class ElectrumWallet(seed: ByteVector, client: ActorRef, params: ElectrumWallet. object ElectrumWallet { def props(seed: ByteVector, client: ActorRef, params: WalletParameters): Props = Props(new ElectrumWallet(seed, client, params)) - case class WalletParameters(chainHash: ByteVector32, walletDb: WalletDb, minimumFee: Satoshi = Satoshi(2000), dustLimit: Satoshi = Satoshi(546), swipeRange: Int = 10, allowSpendUnconfirmed: Boolean = true) + case class WalletParameters(chainHash: ByteVector32, walletDb: WalletDb, minimumFee: Satoshi = 2000 sat, dustLimit: Satoshi = 546 sat, swipeRange: Int = 10, allowSpendUnconfirmed: Boolean = true) // @formatter:off sealed trait State @@ -559,10 +560,10 @@ object ElectrumWallet { // @formatter:on /** - * - * @param key public key - * @return the address of the p2sh-of-p2wpkh script for this key - */ + * + * @param key public key + * @return the address of the p2sh-of-p2wpkh script for this key + */ def segwitAddress(key: PublicKey, chainHash: ByteVector32): String = { val script = Script.pay2wpkh(key) val hash = Crypto.hash160(Script.write(script)) @@ -577,17 +578,17 @@ object ElectrumWallet { def segwitAddress(key: PrivateKey, chainHash: ByteVector32): String = segwitAddress(key.publicKey, chainHash) /** - * - * @param key public key - * @return a p2sh-of-p2wpkh script for this key - */ + * + * @param key public key + * @return a p2sh-of-p2wpkh script for this key + */ def computePublicKeyScript(key: PublicKey) = Script.pay2sh(Script.pay2wpkh(key)) /** - * - * @param key public key - * @return the hash of the public key script for this key, as used by Electrum's hash-based methods - */ + * + * @param key public key + * @return the hash of the public key script for this key, as used by Electrum's hash-based methods + */ def computeScriptHashFromPublicKey(key: PublicKey): ByteVector32 = Crypto.sha256(Script.write(computePublicKeyScript(key))).reverse def accountPath(chainHash: ByteVector32): List[Long] = chainHash match { @@ -596,21 +597,21 @@ object ElectrumWallet { } /** - * use BIP49 (and not BIP44) since we use p2sh-of-p2wpkh - * - * @param master master key - * @return the BIP49 account key for this master key: m/49'/1'/0'/0 on testnet/regtest, m/49'/0'/0'/0 on mainnet - */ + * use BIP49 (and not BIP44) since we use p2sh-of-p2wpkh + * + * @param master master key + * @return the BIP49 account key for this master key: m/49'/1'/0'/0 on testnet/regtest, m/49'/0'/0'/0 on mainnet + */ def accountKey(master: ExtendedPrivateKey, chainHash: ByteVector32) = DeterministicWallet.derivePrivateKey(master, accountPath(chainHash) ::: 0L :: Nil) /** - * Compute the wallet's xpub - * - * @param master master key - * @param chainHash chain hash - * @return a (xpub, path) tuple where xpub is the encoded account public key, and path is the derivation path for the account key - */ + * Compute the wallet's xpub + * + * @param master master key + * @param chainHash chain hash + * @return a (xpub, path) tuple where xpub is the encoded account public key, and path is the derivation path for the account key + */ def computeXpub(master: ExtendedPrivateKey, chainHash: ByteVector32): (String, String) = { val xpub = DeterministicWallet.publicKey(DeterministicWallet.derivePrivateKey(master, accountPath(chainHash))) val prefix = chainHash match { @@ -621,11 +622,11 @@ object ElectrumWallet { } /** - * use BIP49 (and not BIP44) since we use p2sh-of-p2wpkh - * - * @param master master key - * @return the BIP49 change key for this master key: m/49'/1'/0'/1 on testnet/regtest, m/49'/0'/0'/1 on mainnet - */ + * use BIP49 (and not BIP44) since we use p2sh-of-p2wpkh + * + * @param master master key + * @return the BIP49 change key for this master key: m/49'/1'/0'/1 on testnet/regtest, m/49'/0'/0'/1 on mainnet + */ def changeKey(master: ExtendedPrivateKey, chainHash: ByteVector32) = DeterministicWallet.derivePrivateKey(master, accountPath(chainHash) ::: 1L :: Nil) def totalAmount(utxos: Seq[Utxo]): Satoshi = Satoshi(utxos.map(_.item.value).sum) @@ -633,18 +634,18 @@ object ElectrumWallet { def totalAmount(utxos: Set[Utxo]): Satoshi = totalAmount(utxos.toSeq) /** - * - * @param weight transaction weight - * @param feeRatePerKw fee rate - * @return the fee for this tx weight - */ + * + * @param weight transaction weight + * @param feeRatePerKw fee rate + * @return the fee for this tx weight + */ def computeFee(weight: Int, feeRatePerKw: Long): Satoshi = Satoshi((weight * feeRatePerKw) / 1000) /** - * - * @param txIn transaction input - * @return Some(pubkey) if this tx input spends a p2sh-of-p2wpkh(pub), None otherwise - */ + * + * @param txIn transaction input + * @return Some(pubkey) if this tx input spends a p2sh-of-p2wpkh(pub), None otherwise + */ def extractPubKeySpentFrom(txIn: TxIn): Option[PublicKey] = { Try { // we're looking for tx that spend a pay2sh-of-p2wkph output @@ -672,25 +673,25 @@ object ElectrumWallet { } /** - * Wallet state, which stores data returned by Electrum servers. - * Most items are indexed by script hash (i.e. by pubkey script sha256 hash). - * Height follows Electrum's conventions: - * - h > 0 means that the tx was confirmed at block #h - * - 0 means unconfirmed, but all input are confirmed - * < 0 means unconfirmed, and some inputs are unconfirmed as well - * - * @param blockchain blockchain - * @param accountKeys account keys - * @param changeKeys change keys - * @param status script hash -> status; "" means that the script hash has not been used yet - * @param transactions wallet transactions - * @param heights transactions heights - * @param history script hash -> history - * @param locks transactions which lock some of our utxos. - * @param pendingHistoryRequests requests pending a response from the electrum server - * @param pendingTransactionRequests requests pending a response from the electrum server - * @param pendingTransactions transactions received but not yet connected to their parents - */ + * Wallet state, which stores data returned by Electrum servers. + * Most items are indexed by script hash (i.e. by pubkey script sha256 hash). + * Height follows Electrum's conventions: + * - h > 0 means that the tx was confirmed at block #h + * - 0 means unconfirmed, but all input are confirmed + * < 0 means unconfirmed, and some inputs are unconfirmed as well + * + * @param blockchain blockchain + * @param accountKeys account keys + * @param changeKeys change keys + * @param status script hash -> status; "" means that the script hash has not been used yet + * @param transactions wallet transactions + * @param heights transactions heights + * @param history script hash -> history + * @param locks transactions which lock some of our utxos. + * @param pendingHistoryRequests requests pending a response from the electrum server + * @param pendingTransactionRequests requests pending a response from the electrum server + * @param pendingTransactions transactions received but not yet connected to their parents + */ case class Data(blockchain: Blockchain, accountKeys: Vector[ExtendedPrivateKey], changeKeys: Vector[ExtendedPrivateKey], @@ -720,10 +721,10 @@ object ElectrumWallet { lazy val utxos = history.keys.toSeq.map(scriptHash => getUtxos(scriptHash)).flatten /** - * The wallet is ready if all current keys have an empty status, and we don't have - * any history/tx request pending - * NB: swipeRange * 2 because we have account keys and change keys - */ + * The wallet is ready if all current keys have an empty status, and we don't have + * any history/tx request pending + * NB: swipeRange * 2 because we have account keys and change keys + */ def isReady(swipeRange: Int) = status.filter(_._2 == "").size >= swipeRange * 2 && pendingHistoryRequests.isEmpty && pendingTransactionRequests.isEmpty def readyMessage: WalletReady = { @@ -732,22 +733,22 @@ object ElectrumWallet { } /** - * - * @return the ids of transactions that belong to our wallet history for this script hash but that we don't have - * and have no pending requests for. - */ + * + * @return the ids of transactions that belong to our wallet history for this script hash but that we don't have + * and have no pending requests for. + */ def missingTransactions(scriptHash: ByteVector32): Set[ByteVector32] = { val txids = history.getOrElse(scriptHash, List()).map(_.tx_hash).filterNot(txhash => transactions.contains(txhash)).toSet txids -- pendingTransactionRequests } /** - * - * @return the current receive key. In most cases it will be a key that has not - * been used yet but it may be possible that we are still looking for - * unused keys and none is available yet. In this case we will return - * the latest account key. - */ + * + * @return the current receive key. In most cases it will be a key that has not + * been used yet but it may be possible that we are still looking for + * unused keys and none is available yet. In this case we will return + * the latest account key. + */ def currentReceiveKey = firstUnusedAccountKeys.headOption.getOrElse { // bad luck we are still looking for unused keys // use the first account key @@ -757,12 +758,12 @@ object ElectrumWallet { def currentReceiveAddress = segwitAddress(currentReceiveKey, chainHash) /** - * - * @return the current change key. In most cases it will be a key that has not - * been used yet but it may be possible that we are still looking for - * unused keys and none is available yet. In this case we will return - * the latest change key. - */ + * + * @return the current change key. In most cases it will be a key that has not + * been used yet but it may be possible that we are still looking for + * unused keys and none is available yet. In this case we will return + * the latest change key. + */ def currentChangeKey = firstUnusedChangeKeys.headOption.getOrElse { // bad luck we are still looking for unused keys // use the first account key @@ -776,11 +777,11 @@ object ElectrumWallet { def isSpend(txIn: TxIn, publicKey: PublicKey): Boolean = extractPubKeySpentFrom(txIn).contains(publicKey) /** - * - * @param txIn - * @param scriptHash - * @return true if txIn spends from an address that matches scriptHash - */ + * + * @param txIn + * @param scriptHash + * @return true if txIn spends from an address that matches scriptHash + */ def isSpend(txIn: TxIn, scriptHash: ByteVector32): Boolean = extractPubKeySpentFrom(txIn).exists(pub => computeScriptHashFromPublicKey(pub) == scriptHash) def isReceive(txOut: TxOut, scriptHash: ByteVector32): Boolean = publicScriptMap.get(txOut.publicKeyScript).exists(key => computeScriptHashFromPublicKey(key.publicKey) == scriptHash) @@ -790,11 +791,11 @@ object ElectrumWallet { def computeTransactionDepth(txid: ByteVector32): Long = heights.get(txid).map(height => if (height > 0) computeDepth(blockchain.tip.height, height) else 0).getOrElse(0) /** - * - * @param txid transaction id - * @param headerDb header db - * @return the timestamp of the block this tx was included in - */ + * + * @param txid transaction id + * @param headerDb header db + * @return the timestamp of the block this tx was included in + */ def computeTimestamp(txid: ByteVector32, headerDb: HeaderDb): Option[Long] = { for { height <- heights.get(txid) @@ -803,10 +804,10 @@ object ElectrumWallet { } /** - * - * @param scriptHash script hash - * @return the list of UTXOs for this script hash (including unconfirmed UTXOs) - */ + * + * @param scriptHash script hash + * @return the list of UTXOs for this script hash (including unconfirmed UTXOs) + */ def getUtxos(scriptHash: ByteVector32) = { history.get(scriptHash) match { case None => Seq() @@ -834,16 +835,16 @@ object ElectrumWallet { /** - * - * @param scriptHash script hash - * @return the (confirmed, unconfirmed) balance for this script hash. This balance may not - * be up-to-date if we have not received all data we've asked for yet. - */ + * + * @param scriptHash script hash + * @return the (confirmed, unconfirmed) balance for this script hash. This balance may not + * be up-to-date if we have not received all data we've asked for yet. + */ def balance(scriptHash: ByteVector32): (Satoshi, Satoshi) = { history.get(scriptHash) match { - case None => (Satoshi(0), Satoshi(0)) + case None => (0 sat, 0 sat) - case Some(items) if items.isEmpty => (Satoshi(0), Satoshi(0)) + case Some(items) if items.isEmpty => (0 sat, 0 sat) case Some(items) => val (confirmedItems, unconfirmedItems) = items.partition(_.height > 0) @@ -852,16 +853,16 @@ object ElectrumWallet { if (confirmedTxs.size + unconfirmedTxs.size < confirmedItems.size + unconfirmedItems.size) logger.warn(s"we have not received all transactions yet, balance will not be up to date") def findOurSpentOutputs(txs: Seq[Transaction]): Seq[TxOut] = { - val inputs = txs.map(_.txIn).flatten.filter(txIn => isSpend(txIn, scriptHash)) - val spentOutputs = inputs.map(_.outPoint).map(outPoint => transactions.get(outPoint.txid).map(_.txOut(outPoint.index.toInt))).flatten + val inputs = txs.flatMap(_.txIn).filter(txIn => isSpend(txIn, scriptHash)) + val spentOutputs = inputs.map(_.outPoint).flatMap(outPoint => transactions.get(outPoint.txid).map(_.txOut(outPoint.index.toInt))) spentOutputs } val confirmedSpents = findOurSpentOutputs(confirmedTxs) - val confirmedReceived = confirmedTxs.map(_.txOut).flatten.filter(txOut => isReceive(txOut, scriptHash)) + val confirmedReceived = confirmedTxs.flatMap(_.txOut).filter(txOut => isReceive(txOut, scriptHash)) val unconfirmedSpents = findOurSpentOutputs(unconfirmedTxs) - val unconfirmedReceived = unconfirmedTxs.map(_.txOut).flatten.filter(txOut => isReceive(txOut, scriptHash)) + val unconfirmedReceived = unconfirmedTxs.flatMap(_.txOut).filter(txOut => isReceive(txOut, scriptHash)) val confirmedBalance = confirmedReceived.map(_.amount).sum - confirmedSpents.map(_.amount).sum val unconfirmedBalance = unconfirmedReceived.map(_.amount).sum - unconfirmedSpents.map(_.amount).sum @@ -872,29 +873,29 @@ object ElectrumWallet { } /** - * - * @return the (confirmed, unconfirmed) balance for this wallet. This balance may not - * be up-to-date if we have not received all data we've asked for yet. - */ + * + * @return the (confirmed, unconfirmed) balance for this wallet. This balance may not + * be up-to-date if we have not received all data we've asked for yet. + */ lazy val balance: (Satoshi, Satoshi) = { // `.toList` is very important here: keys are returned in a Set-like structure, without the .toList we map // to another set-like structure that will remove duplicates, so if we have several script hashes with exactly the // same balance we don't return the correct aggregated balance val balances = (accountKeyMap.keys ++ changeKeyMap.keys).toList.map(scriptHash => balance(scriptHash)) - balances.foldLeft((Satoshi(0), Satoshi(0))) { + balances.foldLeft((0 sat, 0 sat)) { case ((confirmed, unconfirmed), (confirmed1, unconfirmed1)) => (confirmed + confirmed1, unconfirmed + unconfirmed1) } } /** - * Computes the effect of this transaction on the wallet - * - * @param tx input transaction - * @return an option: - * - Some(received, sent, fee) where sent if what the tx spends from us, received is what the tx sends to us, - * and fee is the fee for the tx) tuple where sent if what the tx spends from us, and received is what the tx sends to us - * - None if we are missing one or more parent txs - */ + * Computes the effect of this transaction on the wallet + * + * @param tx input transaction + * @return an option: + * - Some(received, sent, fee) where sent if what the tx spends from us, received is what the tx sends to us, + * and fee is the fee for the tx) tuple where sent if what the tx spends from us, and received is what the tx sends to us + * - None if we are missing one or more parent txs + */ def computeTransactionDelta(tx: Transaction): Option[(Satoshi, Satoshi, Option[Satoshi])] = { val ourInputs = tx.txIn.filter(isMine) // we need to make sure that for all inputs spending an output we control, we already have the parent tx @@ -912,12 +913,12 @@ object ElectrumWallet { } /** - * - * @param tx input transaction - * @param utxos input uxtos - * @return a tx where all utxos have been added as inputs, signed with dummy invalid signatures. This - * is used to estimate the weight of the signed transaction - */ + * + * @param tx input transaction + * @param utxos input uxtos + * @return a tx where all utxos have been added as inputs, signed with dummy invalid signatures. This + * is used to estimate the weight of the signed transaction + */ def addUtxosWithDummySig(tx: Transaction, utxos: Seq[Utxo]): Transaction = tx.copy(txIn = utxos.map { case utxo => // we use dummy signature here, because the result is only used to estimate fees @@ -928,11 +929,11 @@ object ElectrumWallet { }) /** - * - * @param amount amount we want to pay - * @param allowSpendUnconfirmed if true, use unconfirmed utxos - * @return a set of utxos with a total value that is greater than amount - */ + * + * @param amount amount we want to pay + * @param allowSpendUnconfirmed if true, use unconfirmed utxos + * @return a set of utxos with a total value that is greater than amount + */ def chooseUtxos(amount: Satoshi, allowSpendUnconfirmed: Boolean): Seq[Utxo] = { @tailrec def select(chooseFrom: Seq[Utxo], selected: Set[Utxo]): Set[Utxo] = { @@ -954,16 +955,16 @@ object ElectrumWallet { } /** - * - * @param tx input tx that has no inputs - * @param feeRatePerKw fee rate per kiloweight - * @param minimumFee minimum fee - * @param dustLimit dust limit - * @return a (state, tx, fee) tuple where state has been updated and tx is a complete, - * fully signed transaction that can be broadcast. - * our utxos spent by this tx are locked and won't be available for spending - * until the tx has been cancelled. If the tx is committed, they will be removed - */ + * + * @param tx input tx that has no inputs + * @param feeRatePerKw fee rate per kiloweight + * @param minimumFee minimum fee + * @param dustLimit dust limit + * @return a (state, tx, fee) tuple where state has been updated and tx is a complete, + * fully signed transaction that can be broadcast. + * our utxos spent by this tx are locked and won't be available for spending + * until the tx has been cancelled. If the tx is committed, they will be removed + */ def completeTransaction(tx: Transaction, feeRatePerKw: Long, minimumFee: Satoshi, dustLimit: Satoshi, allowSpendUnconfirmed: Boolean): (Data, Transaction, Satoshi) = { require(tx.txIn.isEmpty, "cannot complete a tx that already has inputs") require(feeRatePerKw >= 0, "fee rate cannot be negative") @@ -1013,19 +1014,19 @@ object ElectrumWallet { } /** - * unlocks input locked by a pending tx. call this method if the tx will not be used after all - * - * @param tx pending transaction - * @return an updated state - */ + * unlocks input locked by a pending tx. call this method if the tx will not be used after all + * + * @param tx pending transaction + * @return an updated state + */ def cancelTransaction(tx: Transaction): Data = this.copy(locks = this.locks - tx) /** - * remove all our utxos spent by this tx. call this method if the tx was broadcast successfully - * - * @param tx pending transaction - * @return an updated state - */ + * remove all our utxos spent by this tx. call this method if the tx was broadcast successfully + * + * @param tx pending transaction + * @return an updated state + */ def commitTransaction(tx: Transaction): Data = { // HACK! since we base our utxos computation on the history as seen by the electrum server (so that it is // reorg-proof out of the box), we need to update the history right away if we want to be able to build chained @@ -1045,14 +1046,14 @@ object ElectrumWallet { } /** - * spend all our balance, including unconfirmed utxos and locked utxos (i.e utxos - * that are used in funding transactions that have not been published yet - * - * @param publicKeyScript script to send all our funds to - * @param feeRatePerKw fee rate in satoshi per kiloweight - * @return a (tx, fee) tuple, tx is a signed transaction that spends all our balance and - * fee is the associated bitcoin network fee - */ + * spend all our balance, including unconfirmed utxos and locked utxos (i.e utxos + * that are used in funding transactions that have not been published yet + * + * @param publicKeyScript script to send all our funds to + * @param feeRatePerKw fee rate in satoshi per kiloweight + * @return a (tx, fee) tuple, tx is a signed transaction that spends all our balance and + * fee is the associated bitcoin network fee + */ def spendAll(publicKeyScript: ByteVector, feeRatePerKw: Long): (Transaction, Satoshi) = { // use confirmed and unconfirmed balance val amount = balance._1 + balance._2 diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala index 4f49a1f3cc..be45eb2b96 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcher.scala @@ -19,17 +19,16 @@ package fr.acinq.eclair.blockchain.electrum import java.net.InetSocketAddress import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props, Stash, Terminated} -import fr.acinq.bitcoin.{BlockHeader, ByteVector32, Satoshi, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.{BlockHeader, ByteVector32, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.electrum.ElectrumClient.{SSL, computeScriptHash} import fr.acinq.eclair.channel.{BITCOIN_FUNDING_DEPTHOK, BITCOIN_FUNDING_SPENT, BITCOIN_PARENT_TX_CONFIRMED} import fr.acinq.eclair.transactions.Scripts -import fr.acinq.eclair.{Globals, ShortChannelId, TxCoordinates} +import fr.acinq.eclair.{Globals, LongToBtcAmount, ShortChannelId, TxCoordinates} import scala.collection.SortedMap import scala.collection.immutable.Queue - class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLogging { client ! ElectrumClient.AddStatusListener(self) @@ -42,7 +41,7 @@ class ElectrumWatcher(client: ActorRef) extends Actor with Stash with ActorLoggi val fakeFundingTx = Transaction( version = 2, txIn = Seq.empty[TxIn], - txOut = List.fill(outputIndex + 1)(TxOut(Satoshi(0), pubkeyScript)), // quick and dirty way to be sure that the outputIndex'th output is of the expected format + txOut = List.fill(outputIndex + 1)(TxOut(0 sat, pubkeyScript)), // quick and dirty way to be sure that the outputIndex'th output is of the expected format lockTime = 0) sender ! ValidateResult(c, Right((fakeFundingTx, UtxoStatus.Unspent))) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala index 32a86553e0..239dfa1c4c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -48,11 +48,11 @@ object Channel { val ANNOUNCEMENTS_MINCONF = 6 // https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#requirements - val MAX_FUNDING = Satoshi(16777216L) // = 2^24 + val MAX_FUNDING = 16777216 sat // = 2^24 val MAX_ACCEPTED_HTLCS = 483 // we don't want the counterparty to use a dust limit lower than that, because they wouldn't only hurt themselves we may need them to publish their commit tx in certain cases (backup/restore) - val MIN_DUSTLIMIT = Satoshi(546) + val MIN_DUSTLIMIT = 546 sat // we won't exchange more than this many signatures when negotiating the closing fee val MAX_NEGOTIATION_ITERATIONS = 20 diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 8a8a85b92e..f94842645a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.channel import akka.event.LoggingAdapter import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, sha256} -import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, Satoshi} +import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto} import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets} import fr.acinq.eclair.crypto.{Generators, KeyManager, ShaChain, Sphinx} import fr.acinq.eclair.payment._ @@ -86,14 +86,14 @@ case class Commitments(channelVersion: ChannelVersion, lazy val availableBalanceForSend: MilliSatoshi = { val reduced = CommitmentSpec.reduce(remoteCommit.spec, remoteChanges.acked, localChanges.proposed) - val feesMsat = if (localParams.isFunder) commitTxFee(remoteParams.dustLimit, reduced).toMilliSatoshi else MilliSatoshi(0) - (reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat).max(MilliSatoshi(0)) + val feesMsat = if (localParams.isFunder) commitTxFee(remoteParams.dustLimit, reduced).toMilliSatoshi else 0.msat + (reduced.toRemote - remoteParams.channelReserve.toMilliSatoshi - feesMsat).max(0 msat) } lazy val availableBalanceForReceive: MilliSatoshi = { val reduced = CommitmentSpec.reduce(localCommit.spec, localChanges.acked, remoteChanges.proposed) - val feesMsat = if (localParams.isFunder) MilliSatoshi(0) else commitTxFee(localParams.dustLimit, reduced).toMilliSatoshi - (reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat).max(MilliSatoshi(0)) + val feesMsat = if (localParams.isFunder) 0.msat else commitTxFee(localParams.dustLimit, reduced).toMilliSatoshi + (reduced.toRemote - localParams.channelReserve.toMilliSatoshi - feesMsat).max(0 msat) } } @@ -157,9 +157,9 @@ object Commitments { // a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee // we look from remote's point of view, so if local is funder remote doesn't pay the fees - val fees = if (commitments1.localParams.isFunder) commitTxFee(commitments1.remoteParams.dustLimit, reduced) else Satoshi(0) + val fees = if (commitments1.localParams.isFunder) commitTxFee(commitments1.remoteParams.dustLimit, reduced) else 0.sat val missing = reduced.toRemote.truncateToSatoshi - commitments1.remoteParams.channelReserve - fees - if (missing < Satoshi(0)) { + if (missing < 0.sat) { return Left(InsufficientFunds(commitments.channelId, amount = cmd.amount, missing = -missing, reserve = commitments1.remoteParams.channelReserve, fees = fees)) } @@ -190,9 +190,9 @@ object Commitments { } // a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee - val fees = if (commitments1.localParams.isFunder) Satoshi(0) else Transactions.commitTxFee(commitments1.localParams.dustLimit, reduced) + val fees = if (commitments1.localParams.isFunder) 0.sat else Transactions.commitTxFee(commitments1.localParams.dustLimit, reduced) val missing = reduced.toRemote.truncateToSatoshi - commitments1.localParams.channelReserve - fees - if (missing < Satoshi(0)) { + if (missing < 0.sat) { throw InsufficientFunds(commitments.channelId, amount = add.amountMsat, missing = -missing, reserve = commitments1.localParams.channelReserve, fees = fees) } @@ -314,7 +314,7 @@ object Commitments { // we look from remote's point of view, so if local is funder remote doesn't pay the fees val fees = commitTxFee(commitments1.remoteParams.dustLimit, reduced) val missing = reduced.toRemote.truncateToSatoshi - commitments1.remoteParams.channelReserve - fees - if (missing < Satoshi(0)) { + if (missing < 0.sat) { throw CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.localParams.channelReserve, fees = fees) } @@ -348,7 +348,7 @@ object Commitments { // a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee val fees = commitTxFee(commitments1.remoteParams.dustLimit, reduced) val missing = reduced.toRemote.truncateToSatoshi - commitments1.localParams.channelReserve - fees - if (missing < Satoshi(0)) { + if (missing < 0.sat) { throw CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.localParams.channelReserve, fees = fees) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index b77693a952..15c999b26c 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.channel import akka.event.LoggingAdapter import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, ripemd160, sha256} import fr.acinq.bitcoin.Script._ -import fr.acinq.bitcoin.{OutPoint, _} +import fr.acinq.bitcoin._ import fr.acinq.eclair.blockchain.EclairWallet import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets} import fr.acinq.eclair.channel.Channel.REFRESH_CHANNEL_UPDATE_INTERVAL @@ -357,9 +357,9 @@ object Helpers { */ def nothingAtStake(data: HasCommitments): Boolean = data.commitments.localCommit.index == 0 && - data.commitments.localCommit.spec.toLocal == MilliSatoshi(0) && + data.commitments.localCommit.spec.toLocal == 0.msat && data.commitments.remoteCommit.index == 0 && - data.commitments.remoteCommit.spec.toRemote == MilliSatoshi(0) && + data.commitments.remoteCommit.spec.toRemote == 0.msat && data.commitments.remoteNextCommitInfo.isRight /** diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Autoprobe.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Autoprobe.scala index 71396e096e..899aed629b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Autoprobe.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Autoprobe.scala @@ -22,7 +22,7 @@ import fr.acinq.eclair.crypto.Sphinx.DecryptedFailurePacket import fr.acinq.eclair.payment.PaymentLifecycle.{PaymentFailed, PaymentResult, RemoteFailure, SendPayment} import fr.acinq.eclair.router.{Announcements, Data} import fr.acinq.eclair.wire.IncorrectOrUnknownPaymentDetails -import fr.acinq.eclair.{MilliSatoshi, NodeParams, randomBytes32, secureRandom} +import fr.acinq.eclair.{LongToBtcAmount, NodeParams, randomBytes32, secureRandom} import scala.concurrent.duration._ @@ -83,7 +83,7 @@ object Autoprobe { val PROBING_INTERVAL = 20 seconds - val PAYMENT_AMOUNT_MSAT = MilliSatoshi(100 * 1000) // this is below dust_limit so there won't be an output in the commitment tx + val PAYMENT_AMOUNT_MSAT = (100 * 1000) msat // this is below dust_limit so there won't be an output in the commitment tx object TickProbe diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentLifecycle.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentLifecycle.scala index a62424f4e0..839859bf2b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentLifecycle.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentLifecycle.scala @@ -207,7 +207,7 @@ object PaymentLifecycle { finalCltvExpiryDelta: CltvExpiryDelta = Channel.MIN_CLTV_EXPIRY_DELTA, maxAttempts: Int, routeParams: Option[RouteParams] = None) extends GenericSendPayment { - require(amount > MilliSatoshi(0), s"amountMsat must be > 0") + require(amount > 0.msat, s"amountMsat must be > 0") } sealed trait PaymentResult diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala index e5785764c2..4fa1712e49 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala @@ -29,16 +29,16 @@ import scala.concurrent.duration._ import scala.util.Try /** - * Lightning Payment Request - * see https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md - * - * @param prefix currency prefix; lnbc for bitcoin, lntb for bitcoin testnet - * @param amount amount to pay (empty string means no amount is specified) - * @param timestamp request timestamp (UNIX format) - * @param nodeId id of the node emitting the payment request - * @param tags payment tags; must include a single PaymentHash tag - * @param signature request signature that will be checked against node id - */ + * Lightning Payment Request + * see https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md + * + * @param prefix currency prefix; lnbc for bitcoin, lntb for bitcoin testnet + * @param amount amount to pay (empty string means no amount is specified) + * @param timestamp request timestamp (UNIX format) + * @param nodeId id of the node emitting the payment request + * @param tags payment tags; must include a single PaymentHash tag + * @param signature request signature that will be checked against node id + */ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestamp: Long, nodeId: PublicKey, tags: List[PaymentRequest.TaggedField], signature: ByteVector) { amount.map(a => require(a.toLong > 0, s"amount is not valid")) @@ -46,24 +46,24 @@ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestam require(tags.collect { case PaymentRequest.Description(_) | PaymentRequest.DescriptionHash(_) => {} }.size == 1, "there must be exactly one description tag or one description hash tag") /** - * - * @return the payment hash - */ + * + * @return the payment hash + */ lazy val paymentHash = tags.collectFirst { case p: PaymentRequest.PaymentHash => p }.get.hash /** - * - * @return the description of the payment, or its hash - */ + * + * @return the description of the payment, or its hash + */ lazy val description: Either[String, ByteVector32] = tags.collectFirst { case PaymentRequest.Description(d) => Left(d) case PaymentRequest.DescriptionHash(h) => Right(h) }.get /** - * - * @return the fallback address if any. It could be a script address, pubkey address, .. - */ + * + * @return the fallback address if any. It could be a script address, pubkey address, .. + */ def fallbackAddress(): Option[String] = tags.collectFirst { case f: PaymentRequest.FallbackAddress => PaymentRequest.FallbackAddress.toAddress(f, prefix) } @@ -84,9 +84,9 @@ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestam } /** - * - * @return the hash of this payment request - */ + * + * @return the hash of this payment request + */ def hash: ByteVector32 = { val hrp = s"${prefix}${Amount.encode(amount)}".getBytes("UTF-8") val data = Bolt11Data(timestamp, tags, ByteVector.fill(65)(0)) // fake sig that we are going to strip next @@ -96,10 +96,10 @@ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestam } /** - * - * @param priv private key - * @return a signed payment request - */ + * + * @param priv private key + * @return a signed payment request + */ def sign(priv: PrivateKey): PaymentRequest = { val sig64 = Crypto.sign(hash, priv) val (pub1, _) = Crypto.recoverPublicKey(sig64, hash) @@ -175,39 +175,39 @@ object PaymentRequest { // @formatter:on /** - * Payment Hash - * - * @param hash payment hash - */ + * Payment Hash + * + * @param hash payment hash + */ case class PaymentHash(hash: ByteVector32) extends TaggedField /** - * Description - * - * @param description a free-format string that will be included in the payment request - */ + * Description + * + * @param description a free-format string that will be included in the payment request + */ case class Description(description: String) extends TaggedField /** - * Hash - * - * @param hash hash that will be included in the payment request, and can be checked against the hash of a - * long description, an invoice, ... - */ + * Hash + * + * @param hash hash that will be included in the payment request, and can be checked against the hash of a + * long description, an invoice, ... + */ case class DescriptionHash(hash: ByteVector32) extends TaggedField /** - * Fallback Payment that specifies a fallback payment address to be used if LN payment cannot be processed - * - */ + * Fallback Payment that specifies a fallback payment address to be used if LN payment cannot be processed + * + */ case class FallbackAddress(version: Byte, data: ByteVector) extends TaggedField object FallbackAddress { /** - * - * @param address valid base58 or bech32 address - * @return a FallbackAddressTag instance - */ + * + * @param address valid base58 or bech32 address + * @return a FallbackAddressTag instance + */ def apply(address: String): FallbackAddress = { Try(fromBase58Address(address)).orElse(Try(fromBech32Address(address))).get } @@ -242,10 +242,11 @@ object PaymentRequest { } /** - * This returns a bitvector with the minimum size necessary to encode the long, left padded - * to have a length (in bits) multiples of 5 - * @param l - */ + * This returns a bitvector with the minimum size necessary to encode the long, left padded + * to have a length (in bits) multiples of 5 + * + * @param l + */ def long2bits(l: Long) = { val bin = BitVector.fromLong(l) var highest = -1 @@ -260,51 +261,51 @@ object PaymentRequest { } /** - * Extra hop contained in RoutingInfoTag - * - * @param nodeId start of the channel - * @param shortChannelId channel id - * @param feeBaseMsat node fixed fee - * @param feeProportionalMillionths node proportional fee - * @param cltvExpiryDelta node cltv expiry delta - */ - case class ExtraHop(nodeId: PublicKey, shortChannelId: ShortChannelId, feeBaseMsat: Long, feeProportionalMillionths: Long, cltvExpiryDelta: CltvExpiryDelta) + * Extra hop contained in RoutingInfoTag + * + * @param nodeId start of the channel + * @param shortChannelId channel id + * @param feeBase node fixed fee + * @param feeProportionalMillionths node proportional fee + * @param cltvExpiryDelta node cltv expiry delta + */ + case class ExtraHop(nodeId: PublicKey, shortChannelId: ShortChannelId, feeBase: MilliSatoshi, feeProportionalMillionths: Long, cltvExpiryDelta: CltvExpiryDelta) /** - * Routing Info - * - * @param path one or more entries containing extra routing information for a private route - */ + * Routing Info + * + * @param path one or more entries containing extra routing information for a private route + */ case class RoutingInfo(path: List[ExtraHop]) extends TaggedField /** - * Expiry Date - */ + * Expiry Date + */ case class Expiry(bin: BitVector) extends TaggedField { def toLong: Long = bin.toLong(signed = false) } object Expiry { /** - * @param seconds expiry data for this payment request - */ + * @param seconds expiry data for this payment request + */ def apply(seconds: Long): Expiry = Expiry(long2bits(seconds)) } /** - * Min final CLTV expiry - * - */ + * Min final CLTV expiry + * + */ case class MinFinalCltvExpiry(bin: BitVector) extends TaggedField { def toCltvExpiryDelta = CltvExpiryDelta(bin.toInt(signed = false)) } object MinFinalCltvExpiry { /** - * Min final CLTV expiry - * - * @param blocks min final cltv expiry, in blocks - */ + * Min final CLTV expiry + * + * @param blocks min final cltv expiry, in blocks + */ def apply(blocks: Long): MinFinalCltvExpiry = MinFinalCltvExpiry(long2bits(blocks)) } @@ -318,7 +319,7 @@ object PaymentRequest { val extraHopCodec: Codec[ExtraHop] = ( ("nodeId" | publicKey) :: ("shortChannelId" | shortchannelid) :: - ("fee_base_msat" | uint32) :: + ("fee_base_msat" | uint32.xmapc(l => MilliSatoshi(l))(_.toLong)) :: ("fee_proportional_millionth" | uint32) :: ("cltv_expiry_delta" | cltvExpiryDelta) ).as[ExtraHop] @@ -389,9 +390,9 @@ object PaymentRequest { object Amount { /** - * @param amount - * @return the unit allowing for the shortest representation possible - */ + * @param amount + * @return the unit allowing for the shortest representation possible + */ def unit(amount: MilliSatoshi): Char = amount.toLong * 10 match { // 1 milli-satoshis == 10 pico-bitcoin case pico if pico % 1000 > 0 => 'p' case pico if pico % 1000000 > 0 => 'n' @@ -429,10 +430,10 @@ object PaymentRequest { val eight2fiveCodec: Codec[List[Byte]] = list(ubyte(5)) /** - * - * @param input bech32-encoded payment request - * @return a payment request - */ + * + * @param input bech32-encoded payment request + * @return a payment request + */ def read(input: String): PaymentRequest = { // used only for data validation Bech32.decode(input) @@ -461,10 +462,10 @@ object PaymentRequest { } /** - * - * @param pr payment request - * @return a bech32-encoded payment request - */ + * + * @param pr payment request + * @return a bech32-encoded payment request + */ def write(pr: PaymentRequest): String = { // currency unit is Satoshi, but we compute amounts in Millisatoshis val hramount = Amount.encode(pr.amount) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala index ac1eff6719..8bd3959e94 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala @@ -28,7 +28,7 @@ import fr.acinq.eclair.db.OutgoingPaymentStatus import fr.acinq.eclair.payment.PaymentLifecycle.{PaymentFailed, PaymentSucceeded} import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, NodeParams, ShortChannelId, nodeFee} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, NodeParams, ShortChannelId, nodeFee} import grizzled.slf4j.Logging import scodec.{Attempt, DecodeResult} @@ -157,7 +157,7 @@ class Relayer(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorR case ForwardFulfill(fulfill, to, add) => to match { case Local(id, None) => - val feesPaid = MilliSatoshi(0) + val feesPaid = 0.msat context.system.eventStream.publish(PaymentSent(id, add.amountMsat, feesPaid, add.paymentHash, fulfill.paymentPreimage, fulfill.channelId)) // we sent the payment, but we probably restarted and the reference to the original sender was lost, // we publish the failure on the event stream and update the status in paymentDb diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala index b6a2a624a4..5bf20ccc64 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala @@ -318,7 +318,7 @@ object Graph { * @return the new amount updated with the necessary fees for this edge */ private def edgeFeeCost(edge: GraphEdge, amountWithFees: MilliSatoshi): MilliSatoshi = { - if (edgeHasZeroFee(edge)) amountWithFees + nodeFee(baseFee = MilliSatoshi(1), proportionalFee = 0, amountWithFees) + if (edgeHasZeroFee(edge)) amountWithFees + nodeFee(baseFee = 1 msat, proportionalFee = 0, amountWithFees) else amountWithFees + nodeFee(edge.update.feeBaseMsat, edge.update.feeProportionalMillionths, amountWithFees) } @@ -340,7 +340,7 @@ object Graph { val BLOCK_TIME_TWO_MONTHS = 8640 // Low/High bound for channel capacity - val CAPACITY_CHANNEL_LOW = MilliSatoshi(1000 * 1000L) // 1000 sat + val CAPACITY_CHANNEL_LOW = (1000 * 1000L) msat // 1000 sat val CAPACITY_CHANNEL_HIGH = Channel.MAX_FUNDING.toMilliSatoshi // Low/High bound for CLTV channel value diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala index a62112fca7..b1b3c81bc0 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala @@ -731,7 +731,7 @@ object Router { def toFakeUpdate(extraHop: ExtraHop): ChannelUpdate = // the `direction` bit in flags will not be accurate but it doesn't matter because it is not used // what matters is that the `disable` bit is 0 so that this update doesn't get filtered out - ChannelUpdate(signature = ByteVector64.Zeroes, chainHash = ByteVector32.Zeroes, extraHop.shortChannelId, Platform.currentTime.milliseconds.toSeconds, messageFlags = 0, channelFlags = 0, extraHop.cltvExpiryDelta, htlcMinimumMsat = MilliSatoshi(0), MilliSatoshi(extraHop.feeBaseMsat), extraHop.feeProportionalMillionths, None) + ChannelUpdate(signature = ByteVector64.Zeroes, chainHash = ByteVector32.Zeroes, extraHop.shortChannelId, Platform.currentTime.milliseconds.toSeconds, messageFlags = 0, channelFlags = 0, extraHop.cltvExpiryDelta, htlcMinimumMsat = 0 msat, extraHop.feeBase, extraHop.feeProportionalMillionths, None) def toFakeUpdates(extraRoute: Seq[ExtraHop], targetNodeId: PublicKey): Map[ChannelDesc, ChannelUpdate] = { // BOLT 11: "For each entry, the pubkey is the node ID of the start of the channel", and the last node is the destination diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala index 1e7c6f983e..4afa3195e9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.transactions import fr.acinq.bitcoin.Crypto.PublicKey import fr.acinq.bitcoin.Script._ import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, LexicographicalOrdering, LockTimeThreshold, OP_0, OP_1, OP_1NEGATE, OP_2, OP_CHECKLOCKTIMEVERIFY, OP_CHECKMULTISIG, OP_CHECKSEQUENCEVERIFY, OP_CHECKSIG, OP_DROP, OP_DUP, OP_ELSE, OP_ENDIF, OP_EQUAL, OP_EQUALVERIFY, OP_HASH160, OP_IF, OP_NOTIF, OP_PUSHDATA, OP_SIZE, OP_SWAP, Satoshi, Script, ScriptElt, ScriptWitness, Transaction, TxIn} -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount} import scodec.bits.ByteVector /** @@ -67,9 +67,9 @@ object Scripts { def applyFees(amount_us: Satoshi, amount_them: Satoshi, fee: Satoshi) = { val (amount_us1: Satoshi, amount_them1: Satoshi) = (amount_us, amount_them) match { - case (Satoshi(us), Satoshi(them)) if us >= fee.toLong / 2 && them >= fee.toLong / 2 => (Satoshi(us - fee.toLong / 2), Satoshi(them - fee.toLong / 2)) - case (Satoshi(us), Satoshi(them)) if us < fee.toLong / 2 => (Satoshi(0L), Satoshi(Math.max(0L, them - fee.toLong + us))) - case (Satoshi(us), Satoshi(them)) if them < fee.toLong / 2 => (Satoshi(Math.max(us - fee.toLong + them, 0L)), Satoshi(0L)) + case (us, them) if us >= fee / 2 && them >= fee / 2 => ((us - fee) / 2, (them - fee) / 2) + case (us, them) if us < fee / 2 => (0 sat, (them - fee + us).max(0 sat)) + case (us, them) if them < fee / 2 => ((us - fee + them).max(0 sat), 0 sat) } (amount_us1, amount_them1) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/FailureMessage.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/FailureMessage.scala index 166736d709..63a9dd6113 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/FailureMessage.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/FailureMessage.scala @@ -20,7 +20,7 @@ import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.crypto.Mac32 import fr.acinq.eclair.wire.CommonCodecs.{cltvExpiry, millisatoshi, sha256} import fr.acinq.eclair.wire.LightningMessageCodecs.{channelUpdateCodec, lightningMessageCodec} -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, MilliSatoshi} import scodec.codecs._ import scodec.{Attempt, Codec} @@ -91,7 +91,7 @@ object FailureMessageCodecs { .typecase(UPDATE | 13, (("expiry" | cltvExpiry) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[IncorrectCltvExpiry]) .typecase(UPDATE | 14, ("channelUpdate" | channelUpdateWithLengthCodec).as[ExpiryTooSoon]) .typecase(UPDATE | 20, (("messageFlags" | byte) :: ("channelFlags" | byte) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[ChannelDisabled]) - .typecase(PERM | 15, ("amountMsat" | withDefaultValue(optional(bitsRemaining, millisatoshi), MilliSatoshi(0))).as[IncorrectOrUnknownPaymentDetails]) + .typecase(PERM | 15, ("amountMsat" | withDefaultValue(optional(bitsRemaining, millisatoshi), 0 msat)).as[IncorrectOrUnknownPaymentDetails]) .typecase(PERM | 16, provide(IncorrectPaymentAmount)) .typecase(17, provide(FinalExpiryTooSoon)) .typecase(18, ("expiry" | cltvExpiry).as[FinalIncorrectCltvExpiry]) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala index 60376621bf..faf2a2a745 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala @@ -20,7 +20,7 @@ import akka.actor.ActorSystem import akka.testkit.{TestKit, TestProbe} import akka.util.Timeout import fr.acinq.bitcoin.Crypto.PublicKey -import fr.acinq.bitcoin.{ByteVector32, Crypto, Satoshi} +import fr.acinq.bitcoin.{ByteVector32, Crypto} import fr.acinq.eclair.TestConstants._ import fr.acinq.eclair.blockchain.TestWallet import fr.acinq.eclair.channel.{CMD_FORCECLOSE, Register, _} @@ -77,14 +77,14 @@ class EclairImplSpec extends TestKit(ActorSystem("mySystem")) with fixture.FunSu val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") // standard conversion - eclair.open(nodeId, fundingAmount = Satoshi(10000000L), pushAmount_opt = None, fundingFeerateSatByte_opt = Some(5), flags_opt = None, openTimeout_opt = None) + eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, fundingFeerateSatByte_opt = Some(5), flags_opt = None, openTimeout_opt = None) val open = switchboard.expectMsgType[OpenChannel] - assert(open.fundingTxFeeratePerKw_opt == Some(1250)) + assert(open.fundingTxFeeratePerKw_opt === Some(1250)) // check that minimum fee rate of 253 sat/bw is used - eclair.open(nodeId, fundingAmount = Satoshi(10000000L), pushAmount_opt = None, fundingFeerateSatByte_opt = Some(1), flags_opt = None, openTimeout_opt = None) + eclair.open(nodeId, fundingAmount = 10000000L sat, pushAmount_opt = None, fundingFeerateSatByte_opt = Some(1), flags_opt = None, openTimeout_opt = None) val open1 = switchboard.expectMsgType[OpenChannel] - assert(open1.fundingTxFeeratePerKw_opt == Some(MinimumFeeratePerKw)) + assert(open1.fundingTxFeeratePerKw_opt === Some(MinimumFeeratePerKw)) } test("call send with passing correct arguments") { f => @@ -93,37 +93,37 @@ class EclairImplSpec extends TestKit(ActorSystem("mySystem")) with fixture.FunSu val eclair = new EclairImpl(kit) val nodeId = PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87") - eclair.send(recipientNodeId = nodeId, amount = MilliSatoshi(123), paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = None) + eclair.send(recipientNodeId = nodeId, amount = 123 msat, paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = None) val send = paymentInitiator.expectMsgType[SendPayment] assert(send.targetNodeId == nodeId) - assert(send.amount == MilliSatoshi(123)) + assert(send.amount == 123.msat) assert(send.paymentHash == ByteVector32.Zeroes) assert(send.assistedRoutes == Seq.empty) // with assisted routes - val hints = Seq(Seq(ExtraHop(Bob.nodeParams.nodeId, ShortChannelId("569178x2331x1"), feeBaseMsat = 10, feeProportionalMillionths = 1, cltvExpiryDelta = CltvExpiryDelta(12)))) - eclair.send(recipientNodeId = nodeId, amount = MilliSatoshi(123), paymentHash = ByteVector32.Zeroes, assistedRoutes = hints, minFinalCltvExpiryDelta_opt = None) + val hints = Seq(Seq(ExtraHop(Bob.nodeParams.nodeId, ShortChannelId("569178x2331x1"), feeBase = 10 msat, feeProportionalMillionths = 1, cltvExpiryDelta = CltvExpiryDelta(12)))) + eclair.send(recipientNodeId = nodeId, amount = 123 msat, paymentHash = ByteVector32.Zeroes, assistedRoutes = hints, minFinalCltvExpiryDelta_opt = None) val send1 = paymentInitiator.expectMsgType[SendPayment] assert(send1.targetNodeId == nodeId) - assert(send1.amount == MilliSatoshi(123)) + assert(send1.amount == 123.msat) assert(send1.paymentHash == ByteVector32.Zeroes) assert(send1.assistedRoutes == hints) // with finalCltvExpiry - eclair.send(recipientNodeId = nodeId, amount = MilliSatoshi(123), paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = Some(CltvExpiryDelta(96))) + eclair.send(recipientNodeId = nodeId, amount = 123 msat, paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = Some(CltvExpiryDelta(96))) val send2 = paymentInitiator.expectMsgType[SendPayment] assert(send2.targetNodeId == nodeId) - assert(send2.amount == MilliSatoshi(123)) + assert(send2.amount == 123.msat) assert(send2.paymentHash == ByteVector32.Zeroes) assert(send2.finalCltvExpiryDelta == CltvExpiryDelta(96)) // with custom route fees parameters - eclair.send(recipientNodeId = nodeId, amount = MilliSatoshi(123), paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = None, feeThreshold_opt = Some(Satoshi(123)), maxFeePct_opt = Some(4.20)) + eclair.send(recipientNodeId = nodeId, amount = 123 msat, paymentHash = ByteVector32.Zeroes, assistedRoutes = Seq.empty, minFinalCltvExpiryDelta_opt = None, feeThreshold_opt = Some(123 sat), maxFeePct_opt = Some(4.20)) val send3 = paymentInitiator.expectMsgType[SendPayment] assert(send3.targetNodeId == nodeId) - assert(send3.amount == MilliSatoshi(123)) + assert(send3.amount == 123.msat) assert(send3.paymentHash == ByteVector32.Zeroes) - assert(send3.routeParams.get.maxFeeBase == Satoshi(123).toMilliSatoshi) // conversion sat -> msat + assert(send3.routeParams.get.maxFeeBase == 123000.msat) // conversion sat -> msat assert(send3.routeParams.get.maxFeePct == 4.20) } @@ -133,11 +133,11 @@ class EclairImplSpec extends TestKit(ActorSystem("mySystem")) with fixture.FunSu val (a, b, c, d, e) = (randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey) val updates = List( - makeUpdate(1L, a, b, feeBase = MilliSatoshi(0), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(13)), - makeUpdate(4L, a, e, feeBase = MilliSatoshi(0), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), - makeUpdate(2L, b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(500)), - makeUpdate(3L, c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(500)), - makeUpdate(7L, e, c, feeBase = MilliSatoshi(2), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)) + makeUpdate(1L, a, b, feeBase = 0 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(13)), + makeUpdate(4L, a, e, feeBase = 0 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), + makeUpdate(2L, b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(500)), + makeUpdate(3L, c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(500)), + makeUpdate(7L, e, c, feeBase = 2 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)) ).toMap val eclair = new EclairImpl(kit) @@ -181,15 +181,15 @@ class EclairImplSpec extends TestKit(ActorSystem("mySystem")) with fixture.FunSu val fallBackAddressRaw = "muhtvdmsnbQEPFuEmxcChX58fGvXaaUoVt" val eclair = new EclairImpl(kit) - eclair.receive("some desc", Some(MilliSatoshi(123L)), Some(456), Some(fallBackAddressRaw), None) + eclair.receive("some desc", Some(123 msat), Some(456), Some(fallBackAddressRaw), None) val receive = paymentHandler.expectMsgType[ReceivePayment] - assert(receive.amount_opt == Some(MilliSatoshi(123L))) - assert(receive.expirySeconds_opt == Some(456)) - assert(receive.fallbackAddress == Some(fallBackAddressRaw)) + assert(receive.amount_opt === Some(123 msat)) + assert(receive.expirySeconds_opt === Some(456)) + assert(receive.fallbackAddress === Some(fallBackAddressRaw)) // try with wrong address format - assertThrows[IllegalArgumentException](eclair.receive("some desc", Some(MilliSatoshi(123L)), Some(456), Some("wassa wassa"), None)) + assertThrows[IllegalArgumentException](eclair.receive("some desc", Some(123 msat), Some(456), Some("wassa wassa"), None)) } test("passing a payment_preimage to /createinvoice should result in an invoice with payment_hash=H(payment_preimage)") { fixture => @@ -245,14 +245,14 @@ class EclairImplSpec extends TestKit(ActorSystem("mySystem")) with fixture.FunSu val route = Seq(PublicKey(hex"030bb6a5e0c6b203c7e2180fb78c7ba4bdce46126761d8201b91ddac089cdecc87")) val eclair = new EclairImpl(kit) - eclair.sendToRoute(route, MilliSatoshi(1234), ByteVector32.One, CltvExpiryDelta(123)) + eclair.sendToRoute(route, 1234 msat, ByteVector32.One, CltvExpiryDelta(123)) val send = paymentInitiator.expectMsgType[SendPaymentToRoute] - assert(send.hops == route) - assert(send.amount == MilliSatoshi(1234)) - assert(send.finalCltvExpiryDelta == CltvExpiryDelta(123)) - assert(send.paymentHash == ByteVector32.One) + assert(send.hops === route) + assert(send.amount === 1234.msat) + assert(send.finalCltvExpiryDelta === CltvExpiryDelta(123)) + assert(send.paymentHash === ByteVector32.One) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index 188ec8794b..a8f6663a3d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair import java.sql.{Connection, DriverManager} import fr.acinq.bitcoin.Crypto.PrivateKey -import fr.acinq.bitcoin.{Block, ByteVector32, Satoshi, Script} +import fr.acinq.bitcoin.{Block, ByteVector32, Script} import fr.acinq.eclair.NodeParams.BITCOIND import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets, FeeratesPerKw, OnChainFeeConf} import fr.acinq.eclair.crypto.LocalKeyManager @@ -36,8 +36,8 @@ import scala.concurrent.duration._ */ object TestConstants { - val fundingSatoshis = Satoshi(1000000L) - val pushMsat = MilliSatoshi(200000000L) + val fundingSatoshis = 1000000L sat + val pushMsat = 200000000L msat val feeratePerKw = 10000L val emptyOnionPacket = wire.OnionRoutingPacket(0, ByteVector.fill(33)(0), ByteVector.fill(1300)(0), ByteVector32.Zeroes) @@ -70,7 +70,7 @@ object TestConstants { globalFeatures = ByteVector.empty, localFeatures = ByteVector(0), overrideFeatures = Map.empty, - dustLimit = Satoshi(1100), + dustLimit = 1100 sat, onChainFeeConf = OnChainFeeConf( feeTargets = FeeTargets(6, 2, 2, 6), feeEstimator = new TestFeeEstimator, @@ -81,11 +81,11 @@ object TestConstants { maxAcceptedHtlcs = 100, expiryDeltaBlocks = CltvExpiryDelta(144), fulfillSafetyBeforeTimeoutBlocks = CltvExpiryDelta(6), - htlcMinimum = MilliSatoshi(0), + htlcMinimum = 0 msat, minDepthBlocks = 3, toRemoteDelayBlocks = CltvExpiryDelta(144), maxToLocalDelayBlocks = CltvExpiryDelta(1000), - feeBase = MilliSatoshi(546000), + feeBase = 546000 msat, feeProportionalMillionth = 10, reserveToFundingRatio = 0.01, // note: not used (overridden below) maxReserveToFundingRatio = 0.05, @@ -101,12 +101,12 @@ object TestConstants { channelFlags = 1, watcherType = BITCOIND, paymentRequestExpiry = 1 hour, - minFundingSatoshis = Satoshi(1000L), + minFundingSatoshis = 1000 sat, routerConf = RouterConf( randomizeRouteSelection = false, channelExcludeDuration = 60 seconds, routerBroadcastInterval = 5 seconds, - searchMaxFeeBase = Satoshi(21), + searchMaxFeeBase = 21 sat, searchMaxFeePct = 0.03, searchMaxCltv = CltvExpiryDelta(2016), searchMaxRouteLength = 20, @@ -124,7 +124,7 @@ object TestConstants { defaultFinalScriptPubKey = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32).publicKey)), isFunder = true, fundingSatoshis).copy( - channelReserve = Satoshi(10000) // Bob will need to keep that much satoshis as direct payment + channelReserve = 10000 sat // Bob will need to keep that much satoshis as direct payment ) } @@ -140,7 +140,7 @@ object TestConstants { globalFeatures = ByteVector.empty, localFeatures = ByteVector.empty, // no announcement overrideFeatures = Map.empty, - dustLimit = Satoshi(1000), + dustLimit = 1000 sat, onChainFeeConf = OnChainFeeConf( feeTargets = FeeTargets(6, 2, 2, 6), feeEstimator = new TestFeeEstimator, @@ -151,11 +151,11 @@ object TestConstants { maxAcceptedHtlcs = 30, expiryDeltaBlocks = CltvExpiryDelta(144), fulfillSafetyBeforeTimeoutBlocks = CltvExpiryDelta(6), - htlcMinimum = MilliSatoshi(1000), + htlcMinimum = 1000 msat, minDepthBlocks = 3, toRemoteDelayBlocks = CltvExpiryDelta(144), maxToLocalDelayBlocks = CltvExpiryDelta(1000), - feeBase = MilliSatoshi(546000), + feeBase = 546000 msat, feeProportionalMillionth = 10, reserveToFundingRatio = 0.01, // note: not used (overridden below) maxReserveToFundingRatio = 0.05, @@ -171,12 +171,12 @@ object TestConstants { channelFlags = 1, watcherType = BITCOIND, paymentRequestExpiry = 1 hour, - minFundingSatoshis = Satoshi(1000L), + minFundingSatoshis = 1000 sat, routerConf = RouterConf( randomizeRouteSelection = false, channelExcludeDuration = 60 seconds, routerBroadcastInterval = 5 seconds, - searchMaxFeeBase = Satoshi(21), + searchMaxFeeBase = 21 sat, searchMaxFeePct = 0.03, searchMaxCltv = CltvExpiryDelta(2016), searchMaxRouteLength = 20, @@ -194,7 +194,7 @@ object TestConstants { defaultFinalScriptPubKey = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32).publicKey)), isFunder = false, fundingSatoshis).copy( - channelReserve = Satoshi(20000) // Alice will need to keep that much satoshis as direct payment + channelReserve = 20000 sat // Alice will need to keep that much satoshis as direct payment ) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala index ea93a65d7e..f88f72abca 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala @@ -148,8 +148,8 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock val eclair = mock[Eclair] val mockService = new MockService(eclair) eclair.usableBalances()(any[Timeout]) returns Future.successful(List( - UsableBalances(canSend = MilliSatoshi(100000000), canReceive = MilliSatoshi(20000000), shortChannelId = ShortChannelId(1), remoteNodeId = TestConstants.Alice.keyManager.nodeKey.publicKey, isPublic = true), - UsableBalances(canSend = MilliSatoshi(400000000), canReceive = MilliSatoshi(30000000), shortChannelId = ShortChannelId(2), remoteNodeId = TestConstants.Alice.keyManager.nodeKey.publicKey, isPublic = false) + UsableBalances(canSend = 100000000 msat, canReceive = 20000000 msat, shortChannelId = ShortChannelId(1), remoteNodeId = TestConstants.Alice.keyManager.nodeKey.publicKey, isPublic = true), + UsableBalances(canSend = 400000000 msat, canReceive = 30000000 msat, shortChannelId = ShortChannelId(2), remoteNodeId = TestConstants.Alice.keyManager.nodeKey.publicKey, isPublic = false) )) Post("/usablebalances") ~> @@ -270,7 +270,7 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock check { assert(handled) assert(status == OK) - eclair.send(any, MilliSatoshi(1258000), any, any, any, any, any, any)(any[Timeout]).wasCalled(once) + eclair.send(any, 1258000 msat, any, any, any, any, any, any)(any[Timeout]).wasCalled(once) } @@ -280,7 +280,7 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock check { assert(handled) assert(status == OK) - eclair.send(any, MilliSatoshi(123), any, any, any, any, Some(Satoshi(112233)), Some(2.34))(any[Timeout]).wasCalled(once) + eclair.send(any, 123 msat, any, any, any, any, Some(112233 sat), Some(2.34))(any[Timeout]).wasCalled(once) } } @@ -323,7 +323,7 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock assert(handled) assert(status == OK) assert(entityAs[String] == "\""+rawUUID+"\"") - eclair.sendToRoute(expectedRoute, MilliSatoshi(1234), ByteVector32.Zeroes, CltvExpiryDelta(190))(any[Timeout]).wasCalled(once) + eclair.sendToRoute(expectedRoute, 1234 msat, ByteVector32.Zeroes, CltvExpiryDelta(190))(any[Timeout]).wasCalled(once) } // this test uses CSV encoded route @@ -335,7 +335,7 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock assert(handled) assert(status == OK) assert(entityAs[String] == "\""+rawUUID+"\"") - eclair.sendToRoute(expectedRoute, MilliSatoshi(1234), ByteVector32.One, CltvExpiryDelta(190))(any[Timeout]).wasCalled(once) + eclair.sendToRoute(expectedRoute, 1234 msat, ByteVector32.One, CltvExpiryDelta(190))(any[Timeout]).wasCalled(once) } } @@ -357,25 +357,25 @@ class ApiServiceSpec extends FunSuite with ScalatestRouteTest with IdiomaticMock system.eventStream.publish(pf) wsClient.expectMessage(expectedSerializedPf) - val ps = PaymentSent(fixedUUID, amount = MilliSatoshi(21), feesPaid = MilliSatoshi(1), paymentHash = ByteVector32.Zeroes, paymentPreimage = ByteVector32.One, toChannelId = ByteVector32.Zeroes, timestamp = 1553784337711L) + val ps = PaymentSent(fixedUUID, amount = 21 msat, feesPaid = 1 msat, paymentHash = ByteVector32.Zeroes, paymentPreimage = ByteVector32.One, toChannelId = ByteVector32.Zeroes, timestamp = 1553784337711L) val expectedSerializedPs = """{"type":"payment-sent","id":"487da196-a4dc-4b1e-92b4-3e5e905e9f3f","amount":21,"feesPaid":1,"paymentHash":"0000000000000000000000000000000000000000000000000000000000000000","paymentPreimage":"0100000000000000000000000000000000000000000000000000000000000000","toChannelId":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":1553784337711}""" Serialization.write(ps)(mockService.formatsWithTypeHint) === expectedSerializedPs system.eventStream.publish(ps) wsClient.expectMessage(expectedSerializedPs) - val prel = PaymentRelayed(amountIn = MilliSatoshi(21), amountOut = MilliSatoshi(20), paymentHash = ByteVector32.Zeroes, fromChannelId = ByteVector32.Zeroes, ByteVector32.One, timestamp = 1553784963659L) + val prel = PaymentRelayed(amountIn = 21 msat, amountOut = 20 msat, paymentHash = ByteVector32.Zeroes, fromChannelId = ByteVector32.Zeroes, ByteVector32.One, timestamp = 1553784963659L) val expectedSerializedPrel = """{"type":"payment-relayed","amountIn":21,"amountOut":20,"paymentHash":"0000000000000000000000000000000000000000000000000000000000000000","fromChannelId":"0000000000000000000000000000000000000000000000000000000000000000","toChannelId":"0100000000000000000000000000000000000000000000000000000000000000","timestamp":1553784963659}""" Serialization.write(prel)(mockService.formatsWithTypeHint) === expectedSerializedPrel system.eventStream.publish(prel) wsClient.expectMessage(expectedSerializedPrel) - val precv = PaymentReceived(amount = MilliSatoshi(21), paymentHash = ByteVector32.Zeroes, fromChannelId = ByteVector32.One, timestamp = 1553784963659L) + val precv = PaymentReceived(amount = 21 msat, paymentHash = ByteVector32.Zeroes, fromChannelId = ByteVector32.One, timestamp = 1553784963659L) val expectedSerializedPrecv = """{"type":"payment-received","amount":21,"paymentHash":"0000000000000000000000000000000000000000000000000000000000000000","fromChannelId":"0100000000000000000000000000000000000000000000000000000000000000","timestamp":1553784963659}""" Serialization.write(precv)(mockService.formatsWithTypeHint) === expectedSerializedPrecv system.eventStream.publish(precv) wsClient.expectMessage(expectedSerializedPrecv) - val pset = PaymentSettlingOnChain(fixedUUID, amount = MilliSatoshi(21), paymentHash = ByteVector32.One, timestamp = 1553785442676L) + val pset = PaymentSettlingOnChain(fixedUUID, amount = 21 msat, paymentHash = ByteVector32.One, timestamp = 1553785442676L) val expectedSerializedPset = """{"type":"payment-settling-onchain","id":"487da196-a4dc-4b1e-92b4-3e5e905e9f3f","amount":21,"paymentHash":"0100000000000000000000000000000000000000000000000000000000000000","timestamp":1553785442676}""" Serialization.write(pset)(mockService.formatsWithTypeHint) === expectedSerializedPset system.eventStream.publish(pset) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/api/JsonSerializersSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/api/JsonSerializersSpec.scala index 38a6b6d7cc..16b3542fa5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/api/JsonSerializersSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/api/JsonSerializersSpec.scala @@ -78,7 +78,7 @@ class JsonSerializersSpec extends FunSuite with Matchers { test("type hints") { implicit val formats = JsonSupport.formats.withTypeHintFieldName("type") + CustomTypeHints(Map(classOf[PaymentSettlingOnChain] -> "payment-settling-onchain")) + new MilliSatoshiSerializer - val e1 = PaymentSettlingOnChain(UUID.randomUUID, MilliSatoshi(42), randomBytes32) + val e1 = PaymentSettlingOnChain(UUID.randomUUID, 42 msat, randomBytes32) assert(Serialization.writePretty(e1).contains("\"type\" : \"payment-settling-onchain\"")) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/TestWallet.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/TestWallet.scala index 825a609efa..9e0baf76f9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/TestWallet.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/TestWallet.scala @@ -16,15 +16,15 @@ package fr.acinq.eclair.blockchain -import fr.acinq.bitcoin.{ByteVector32, Crypto, OP_PUSHDATA, OutPoint, Satoshi, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.{ByteVector32, OutPoint, Satoshi, Transaction, TxIn, TxOut} +import fr.acinq.eclair.LongToBtcAmount import scodec.bits.ByteVector import scala.concurrent.Future -import scala.util.Try /** - * Created by PM on 06/07/2017. - */ + * Created by PM on 06/07/2017. + */ class TestWallet extends EclairWallet { var rolledback = Set.empty[Transaction] @@ -53,6 +53,6 @@ object TestWallet { txIn = TxIn(OutPoint(ByteVector32(ByteVector.fill(32)(1)), 42), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil, txOut = TxOut(amount, pubkeyScript) :: Nil, lockTime = 0) - MakeFundingTxResponse(fundingTx, 0, Satoshi(420)) + MakeFundingTxResponse(fundingTx, 0, 420 sat) } } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala index 50fb3666ef..c16c1d6e7d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreWalletSpec.scala @@ -21,12 +21,12 @@ import akka.actor.Status.Failure import akka.pattern.pipe import akka.testkit.{TestKit, TestProbe} import com.typesafe.config.ConfigFactory -import fr.acinq.bitcoin.{ByteVector32, Block, MilliBtc, OutPoint, Satoshi, Script, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.{Block, ByteVector32, MilliBtc, OutPoint, Satoshi, Script, Transaction, TxIn, TxOut} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.bitcoind.BitcoinCoreWallet.FundTransactionResponse import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, JsonRPCError} import fr.acinq.eclair.transactions.Scripts -import fr.acinq.eclair.{addressToPublicKeyScript, randomKey} +import fr.acinq.eclair.{LongToBtcAmount, addressToPublicKeyScript, randomKey} import grizzled.slf4j.Logging import org.json4s.JsonAST._ import org.json4s.{DefaultFormats, JString} @@ -125,7 +125,7 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe TxIn(OutPoint(unknownTxids(1), 0), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL), TxIn(OutPoint(unknownTxids(2), 0), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) ), - txOut = TxOut(Satoshi(1000000), addressToPublicKeyScript(address, Block.RegtestGenesisBlock.hash)) :: Nil, + txOut = TxOut(1000000 sat, addressToPublicKeyScript(address, Block.RegtestGenesisBlock.hash)) :: Nil, lockTime = 0) // signing it should fail, and the error message should contain the txids of the UTXOs that could not be used @@ -145,7 +145,7 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe val sender = TestProbe() wallet.getBalance.pipeTo(sender.ref) - assert(sender.expectMsgType[Satoshi] > Satoshi(0)) + assert(sender.expectMsgType[Satoshi] > 0.sat) wallet.getFinalAddress.pipeTo(sender.ref) val address = sender.expectMsgType[String] @@ -205,7 +205,7 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe val sender = TestProbe() wallet.getBalance.pipeTo(sender.ref) - assert(sender.expectMsgType[Satoshi] > Satoshi(0)) + assert(sender.expectMsgType[Satoshi] > 0.sat) wallet.getFinalAddress.pipeTo(sender.ref) val address = sender.expectMsgType[String] @@ -232,7 +232,7 @@ class BitcoinCoreWalletSpec extends TestKit(ActorSystem("test")) with BitcoindSe assert(sender.expectMsgType[Boolean]) wallet.getBalance.pipeTo(sender.ref) - assert(sender.expectMsgType[Satoshi] > Satoshi(0)) + assert(sender.expectMsgType[Satoshi] > 0.sat) } test("detect if tx has been doublespent") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala index fe2522df4b..f7d0fc6a06 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletBasicSpec.scala @@ -37,7 +37,7 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { val swipeRange = 10 val dustLimit = 546 sat val feeRatePerKw = 20000 - val minimumFee = Satoshi(2000) + val minimumFee = 2000 sat val master = DeterministicWallet.generate(ByteVector32(ByteVector.fill(32)(1))) val accountMaster = accountKey(master, Block.RegtestGenesisBlock.hash) @@ -132,10 +132,10 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { } test("use actual transaction weight to compute fees") { - val state1 = addFunds(state, (state.accountKeys(0), Satoshi(5000000)) :: (state.accountKeys(1), Satoshi(6000000)) :: (state.accountKeys(2), Satoshi(4000000)) :: Nil) + val state1 = addFunds(state, (state.accountKeys(0), 5000000 sat) :: (state.accountKeys(1), 6000000 sat) :: (state.accountKeys(2), 4000000 sat) :: Nil) { - val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(5000000), Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) + val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(5000000 sat, Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) val (state3, tx1, fee1) = state1.completeTransaction(tx, feeRatePerKw, minimumFee, dustLimit, true) val Some((_, _, Some(fee))) = state3.computeTransactionDelta(tx1) assert(fee == fee1) @@ -143,7 +143,7 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { assert(isFeerateOk(actualFeeRate, feeRatePerKw)) } { - val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(5000000) - dustLimit, Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) + val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(5000000.sat - dustLimit, Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) val (state3, tx1, fee1) = state1.completeTransaction(tx, feeRatePerKw, minimumFee, dustLimit, true) val Some((_, _, Some(fee))) = state3.computeTransactionDelta(tx1) assert(fee == fee1) @@ -152,7 +152,7 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { } { // with a huge fee rate that will force us to use an additional input when we complete our tx - val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(3000000), Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) + val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(3000000 sat, Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) val (state3, tx1, fee1) = state1.completeTransaction(tx, 100 * feeRatePerKw, minimumFee, dustLimit, true) val Some((_, _, Some(fee))) = state3.computeTransactionDelta(tx1) assert(fee == fee1) @@ -179,7 +179,7 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { val (tx, fee) = state3.spendAll(Script.pay2wpkh(ByteVector.fill(20)(1)), feeRatePerKw) val Some((received, sent, Some(fee1))) = state3.computeTransactionDelta(tx) - assert(received == Satoshi(0)) + assert(received === 0.sat) assert(fee == fee1) assert(tx.txOut.map(_.amount).sum + fee == state3.balance._1 + state3.balance._2) } @@ -189,12 +189,12 @@ class ElectrumWalletBasicSpec extends FunSuite with Logging { (0 to 10) foreach { _ => val funds = for (i <- 0 until random.nextInt(10)) yield { val index = random.nextInt(state.accountKeys.length) - val amount = dustLimit + Satoshi(random.nextInt(10000000)) + val amount = dustLimit + random.nextInt(10000000).sat (state.accountKeys(index), amount) } val state1 = addFunds(state, funds) (0 until 30) foreach { _ => - val amount = dustLimit + Satoshi(random.nextInt(10000000)) + val amount = dustLimit + random.nextInt(10000000).sat val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(amount, Script.pay2pkh(state1.accountKeys(0).publicKey)) :: Nil, lockTime = 0) Try(state1.completeTransaction(tx, feeRatePerKw, minimumFee, dustLimit, true)) match { case Success((state2, tx1, fee1)) => () diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSimulatedClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSimulatedClientSpec.scala index 99d5e9ba48..a8e960c91b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSimulatedClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSimulatedClientSpec.scala @@ -25,6 +25,7 @@ import akka.testkit.{TestActor, TestFSMRef, TestKit, TestProbe} import fr.acinq.bitcoin.Crypto.PublicKey import fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey import fr.acinq.bitcoin.{Block, BlockHeader, ByteVector32, Crypto, DeterministicWallet, MnemonicCode, OutPoint, Satoshi, Script, Transaction, TxIn, TxOut} +import fr.acinq.eclair.LongToBtcAmount import fr.acinq.eclair.blockchain.bitcoind.rpc.Error import fr.acinq.eclair.blockchain.electrum.ElectrumClient._ import fr.acinq.eclair.blockchain.electrum.ElectrumWallet._ @@ -35,10 +36,10 @@ import scodec.bits.ByteVector import scala.annotation.tailrec import scala.concurrent.duration._ - class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) with FunSuiteLike { import ElectrumWalletSimulatedClientSpec._ + val sender = TestProbe() val entropy = ByteVector32(ByteVector.fill(32)(1)) @@ -70,7 +71,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit } }) - val walletParameters = WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = Satoshi(5000)) + val walletParameters = WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = 5000 sat) val wallet = TestFSMRef(new ElectrumWallet(seed, client.ref, walletParameters)) // wallet sends a receive address notification as soon as it is created @@ -176,7 +177,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit wallet ! ScriptHashSubscriptionResponse(scriptHash, ByteVector32(ByteVector.fill(32)(1)).toHex) client.expectMsg(GetScriptHashHistory(scriptHash)) - val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(100000), ElectrumWallet.computePublicKeyScript(key.publicKey)) :: Nil, lockTime = 0) + val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(100000 sat, ElectrumWallet.computePublicKeyScript(key.publicKey)) :: Nil, lockTime = 0) wallet ! GetScriptHashHistoryResponse(scriptHash, TransactionHistoryItem(2, tx.txid) :: Nil) // wallet will generate a new address and the corresponding subscription @@ -209,9 +210,9 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit awaitCond(wallet.stateName == ElectrumWallet.DISCONNECTED) val ready = reconnect - assert(ready.unconfirmedBalance == Satoshi(0)) + assert(ready.unconfirmedBalance === 0.sat) } - + test("clear status when we have pending history requests") { while (client.msgAvailable) { client.receiveOne(100 milliseconds) @@ -239,7 +240,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit wallet ! ScriptHashSubscriptionResponse(scriptHash, ByteVector32(ByteVector.fill(32)(2)).toHex) client.expectMsg(GetScriptHashHistory(scriptHash)) - val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(100000), ElectrumWallet.computePublicKeyScript(key.publicKey)) :: Nil, lockTime = 0) + val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(100000 sat, ElectrumWallet.computePublicKeyScript(key.publicKey)) :: Nil, lockTime = 0) wallet ! GetScriptHashHistoryResponse(scriptHash, TransactionHistoryItem(2, tx.txid) :: Nil) // wallet will generate a new address and the corresponding subscription @@ -262,8 +263,8 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit val firstChangeKeys = (0 until walletParameters.swipeRange).map(i => derivePrivateKey(changeMaster, i)).toVector val data1 = Data(walletParameters, Blockchain.fromGenesisBlock(Block.RegtestGenesisBlock.hash, Block.RegtestGenesisBlock.header), firstAccountKeys, firstChangeKeys) - val amount1 = Satoshi(1000000) - val amount2 = Satoshi(1500000) + val amount1 = 1000000 sat + val amount2 = 1500000 sat // transactions that send funds to our wallet val wallettxs = Seq( @@ -278,7 +279,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit val tx1 = { val tx = Transaction(version = 2, txIn = TxIn(OutPoint(wallettxs(0), 0), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil, - txOut = walletOutput(wallettxs(0).txOut(0).amount - Satoshi(50000), data2.accountKeys(2).publicKey) :: walletOutput(Satoshi(50000), data2.changeKeys(0).publicKey) :: Nil, + txOut = walletOutput(wallettxs(0).txOut(0).amount - 50000.sat, data2.accountKeys(2).publicKey) :: walletOutput(50000 sat, data2.changeKeys(0).publicKey) :: Nil, lockTime = 0) data2.signTransaction(tx) } @@ -287,7 +288,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit val tx2 = { val tx = Transaction(version = 2, txIn = TxIn(OutPoint(wallettxs(1), 0), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil, - txOut = TxOut(wallettxs(1).txOut(0).amount - Satoshi(50000), Script.pay2wpkh(fr.acinq.eclair.randomKey.publicKey)) :: walletOutput(Satoshi(50000), data2.changeKeys(1).publicKey) :: Nil, + txOut = TxOut(wallettxs(1).txOut(0).amount - 50000.sat, Script.pay2wpkh(fr.acinq.eclair.randomKey.publicKey)) :: walletOutput(50000 sat, data2.changeKeys(1).publicKey) :: Nil, lockTime = 0) data2.signTransaction(tx) } @@ -303,7 +304,7 @@ class ElectrumWalletSimulatedClientSpec extends TestKit(ActorSystem("test")) wit client.setAutoPilot(new testkit.TestActor.AutoPilot { override def run(sender: ActorRef, msg: Any): TestActor.AutoPilot = { counter = msg match { - case _:ScriptHashSubscription => counter + case _: ScriptHashSubscription => counter case _ => counter + 1 } msg match { @@ -376,9 +377,9 @@ object ElectrumWalletSimulatedClientSpec { def walletOutput(amount: Satoshi, key: PublicKey) = TxOut(amount, ElectrumWallet.computePublicKeyScript(key)) - def addOutputs(tx: Transaction, amount: Satoshi, keys: PublicKey*): Transaction = keys.foldLeft(tx) { case (t, k) => t.copy(txOut = t.txOut :+ walletOutput(amount, k)) } + def addOutputs(tx: Transaction, amount: Satoshi, keys: PublicKey*): Transaction = keys.foldLeft(tx) { case (t, k) => t.copy(txOut = t.txOut :+ walletOutput(amount, k)) } - def addToHistory(history: Map[ByteVector32, List[ElectrumClient.TransactionHistoryItem]], scriptHash: ByteVector32, item : TransactionHistoryItem): Map[ByteVector32, List[ElectrumClient.TransactionHistoryItem]] = { + def addToHistory(history: Map[ByteVector32, List[ElectrumClient.TransactionHistoryItem]], scriptHash: ByteVector32, item: TransactionHistoryItem): Map[ByteVector32, List[ElectrumClient.TransactionHistoryItem]] = { history.get(scriptHash) match { case None => history + (scriptHash -> List(item)) case Some(items) if items.contains(item) => history @@ -386,7 +387,7 @@ object ElectrumWalletSimulatedClientSpec { } } - def updateStatus(data: ElectrumWallet.Data) : ElectrumWallet.Data = { + def updateStatus(data: ElectrumWallet.Data): ElectrumWallet.Data = { val status1 = data.history.mapValues(items => { val status = items.map(i => s"${i.tx_hash}:${i.height}:").mkString("") Crypto.sha256(ByteVector.view(status.getBytes())).toString() @@ -394,7 +395,7 @@ object ElectrumWalletSimulatedClientSpec { data.copy(status = status1) } - def addTransaction(data: ElectrumWallet.Data, tx: Transaction) : ElectrumWallet.Data = { + def addTransaction(data: ElectrumWallet.Data, tx: Transaction): ElectrumWallet.Data = { data.transactions.get(tx.txid) match { case Some(_) => data case None => diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala index 4771d98fe4..b7e26e7b98 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWalletSpec.scala @@ -16,14 +16,14 @@ package fr.acinq.eclair.blockchain.electrum - import java.net.InetSocketAddress import java.sql.DriverManager import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} import com.whisk.docker.DockerReadyChecker -import fr.acinq.bitcoin.{Block, Btc, ByteVector32, DeterministicWallet, MnemonicCode, Satoshi, Transaction, TxOut} +import fr.acinq.bitcoin.{Block, Btc, ByteVector32, DeterministicWallet, MnemonicCode, Transaction, TxOut} +import fr.acinq.eclair.LongToBtcAmount import fr.acinq.eclair.blockchain.bitcoind.BitcoinCoreWallet.{FundTransactionResponse, SignTransactionResponse} import fr.acinq.eclair.blockchain.bitcoind.{BitcoinCoreWallet, BitcoindService} import fr.acinq.eclair.blockchain.electrum.ElectrumClient.{BroadcastTransaction, BroadcastTransactionResponse, SSL} @@ -38,7 +38,6 @@ import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ - class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike with BitcoindService with ElectrumxService with BeforeAndAfterAll with Logging { import ElectrumWallet._ @@ -89,7 +88,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("wait until wallet is ready") { electrumClient = system.actorOf(Props(new ElectrumClientPool(Set(ElectrumServerAddress(new InetSocketAddress("localhost", electrumPort), SSL.OFF))))) - wallet = system.actorOf(Props(new ElectrumWallet(seed, electrumClient, WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = Satoshi(5000)))), "wallet") + wallet = system.actorOf(Props(new ElectrumWallet(seed, electrumClient, WalletParameters(Block.RegtestGenesisBlock.hash, new SqliteWalletDb(DriverManager.getConnection("jdbc:sqlite::memory:")), minimumFee = 5000 sat))), "wallet") val probe = TestProbe() awaitCond({ probe.send(wallet, GetData) @@ -113,7 +112,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike awaitCond({ val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) - unconfirmed1 == unconfirmed + Satoshi(100000000L) + unconfirmed1 == unconfirmed + 100000000.sat }, max = 30 seconds, interval = 1 second) // confirm our tx @@ -122,7 +121,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike awaitCond({ val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) - confirmed1 == confirmed + Satoshi(100000000L) + confirmed1 == confirmed + 100000000.sat }, max = 30 seconds, interval = 1 second) val GetCurrentReceiveAddressResponse(address1) = getCurrentAddress(probe) @@ -138,8 +137,8 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike probe.expectMsgType[JValue] awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) - confirmed1 == confirmed + Satoshi(250000000L) + val GetBalanceResponse(confirmed1, _) = getBalance(probe) + confirmed1 == confirmed + 250000000.sat }, max = 30 seconds, interval = 1 second) } @@ -149,7 +148,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike logger.info(s"initial balance: $confirmed $unconfirmed") // send money to our wallet - val amount = Satoshi(750000) + val amount = 750000 sat val GetCurrentReceiveAddressResponse(address) = getCurrentAddress(probe) val tx = Transaction(version = 2, txIn = Nil, @@ -159,14 +158,14 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike ), lockTime = 0L) val btcWallet = new BitcoinCoreWallet(bitcoinrpcclient) val future = for { - FundTransactionResponse(tx1, pos, fee) <- btcWallet.fundTransaction(tx, false, 10000) + FundTransactionResponse(tx1, _, _) <- btcWallet.fundTransaction(tx, false, 10000) SignTransactionResponse(tx2, true) <- btcWallet.signTransaction(tx1) txid <- btcWallet.publishTransaction(tx2) } yield txid - val txid = Await.result(future, 10 seconds) + Await.result(future, 10 seconds) awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) + val GetBalanceResponse(_, unconfirmed1) = getBalance(probe) unconfirmed1 == unconfirmed + amount + amount }, max = 30 seconds, interval = 1 second) @@ -174,7 +173,7 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike probe.expectMsgType[JValue] awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) + val GetBalanceResponse(confirmed1, _) = getBalance(probe) confirmed1 == confirmed + amount + amount }, max = 30 seconds, interval = 1 second) } @@ -193,27 +192,27 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val JString(txid) = probe.expectMsgType[JValue] logger.info(s"$txid sent 1 btc to us at $address") awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) - unconfirmed1 - unconfirmed == Satoshi(100000000L) + val GetBalanceResponse(_, unconfirmed1) = getBalance(probe) + unconfirmed1 - unconfirmed === 100000000L.sat }, max = 30 seconds, interval = 1 second) val TransactionReceived(tx, 0, received, sent, _, _) = listener.receiveOne(5 seconds) assert(tx.txid === ByteVector32.fromValidHex(txid)) - assert(received === Satoshi(100000000)) + assert(received === 100000000.sat) logger.info("generating a new block") probe.send(bitcoincli, BitcoinReq("generate", 1)) probe.expectMsgType[JValue] awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) - confirmed1 - confirmed == Satoshi(100000000L) + val GetBalanceResponse(confirmed1, _) = getBalance(probe) + confirmed1 - confirmed === 100000000.sat }, max = 30 seconds, interval = 1 second) awaitCond({ val msg = listener.receiveOne(5 seconds) msg match { - case TransactionConfidenceChanged(txid, 1, _) => true + case TransactionConfidenceChanged(_, 1, _) => true case _ => false } }, max = 30 seconds, interval = 1 second) @@ -221,14 +220,14 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike test("send money to someone else (we broadcast)") { val probe = TestProbe() - val GetBalanceResponse(confirmed, unconfirmed) = getBalance(probe) + val GetBalanceResponse(confirmed, _) = getBalance(probe) // create a tx that sends money to Bitcoin Core's address probe.send(bitcoincli, BitcoinReq("getnewaddress")) val JString(address) = probe.expectMsgType[JValue] val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(Btc(1), fr.acinq.eclair.addressToPublicKeyScript(address, Block.RegtestGenesisBlock.hash)) :: Nil, lockTime = 0L) probe.send(wallet, CompleteTransaction(tx, 20000)) - val CompleteTransactionResponse(tx1, fee1, None) = probe.expectMsgType[CompleteTransactionResponse] + val CompleteTransactionResponse(tx1, _, None) = probe.expectMsgType[CompleteTransactionResponse] // send it ourselves logger.info(s"sending 1 btc to $address with tx ${tx1.txid}") @@ -245,9 +244,9 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike }, max = 30 seconds, interval = 1 second) awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) + val GetBalanceResponse(confirmed1, _) = getBalance(probe) logger.debug(s"current balance is $confirmed1") - confirmed1 < confirmed - Btc(1) && confirmed1 > confirmed - Btc(1) - Satoshi(50000) + confirmed1 < confirmed - 1.btc && confirmed1 > confirmed - 1.btc - 50000.sat }, max = 30 seconds, interval = 1 second) } @@ -272,9 +271,9 @@ class ElectrumWalletSpec extends TestKit(ActorSystem("test")) with FunSuiteLike probe.expectMsgType[JValue] awaitCond({ - val GetBalanceResponse(confirmed1, unconfirmed1) = getBalance(probe) + val GetBalanceResponse(confirmed1, _) = getBalance(probe) logger.info(s"current balance is $confirmed $unconfirmed") - confirmed1 < confirmed - Btc(1) && confirmed1 > confirmed - Btc(1) - Satoshi(50000) + confirmed1 < confirmed - 1.btc && confirmed1 > confirmed - 1.btc - 50000.sat }, max = 30 seconds, interval = 1 second) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala index a5f963bd77..09c7ce7af5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/electrum/ElectrumWatcherSpec.scala @@ -21,11 +21,12 @@ import java.net.InetSocketAddress import akka.actor.{ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} import fr.acinq.bitcoin.Crypto.PrivateKey -import fr.acinq.bitcoin.{Base58, ByteVector32, OutPoint, SIGHASH_ALL, Satoshi, Script, ScriptFlags, ScriptWitness, SigVersion, Transaction, TxIn, TxOut} +import fr.acinq.bitcoin.{Base58, ByteVector32, OutPoint, SIGHASH_ALL, Script, ScriptFlags, ScriptWitness, SigVersion, Transaction, TxIn, TxOut} +import fr.acinq.eclair.LongToBtcAmount import fr.acinq.eclair.blockchain.bitcoind.BitcoindService import fr.acinq.eclair.blockchain.electrum.ElectrumClient.SSL import fr.acinq.eclair.blockchain.electrum.ElectrumClientPool.ElectrumServerAddress -import fr.acinq.eclair.blockchain.{GetTxWithMetaResponse, GetTxWithMeta, WatchConfirmed, WatchEventConfirmed, WatchEventSpent, WatchSpent} +import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.channel.{BITCOIN_FUNDING_DEPTHOK, BITCOIN_FUNDING_SPENT} import grizzled.slf4j.Logging import org.json4s.JsonAST.{JArray, JString, JValue} @@ -34,8 +35,7 @@ import scodec.bits._ import scala.concurrent.duration._ - -class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike with BitcoindService with ElectrumxService with BeforeAndAfterAll with Logging { +class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike with BitcoindService with ElectrumxService with BeforeAndAfterAll with Logging { override def beforeAll(): Unit = { logger.info("starting bitcoind") @@ -103,7 +103,7 @@ class ElectrumWatcherSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val spendingTx = { val tmp = Transaction(version = 2, txIn = TxIn(OutPoint(tx, pos), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil, - txOut = TxOut(tx.txOut(pos).amount - Satoshi(1000), publicKeyScript = Script.pay2wpkh(priv.publicKey)) :: Nil, + txOut = TxOut(tx.txOut(pos).amount - 1000.sat, publicKeyScript = Script.pay2wpkh(priv.publicKey)) :: Nil, lockTime = 0) val sig = Transaction.signInput(tmp, 0, Script.pay2pkh(priv.publicKey), SIGHASH_ALL, tx.txOut(pos).amount, SigVersion.SIGVERSION_WITNESS_V0, priv) val signedTx = tmp.updateWitness(0, ScriptWitness(sig :: priv.publicKey.value :: Nil)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala index b96005b4ec..bbb14daafc 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/ThroughputSpec.scala @@ -51,7 +51,7 @@ class ThroughputSpec extends FunSuite { case ('add, tgt: ActorRef) => val r = randomBytes32 val h = Crypto.sha256(r) - tgt ! CMD_ADD_HTLC(MilliSatoshi(1), h, CltvExpiry(1), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + tgt ! CMD_ADD_HTLC(1 msat, h, CltvExpiry(1), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) context.become(run(h2r + (h -> r))) case ('sig, tgt: ActorRef) => tgt ! CMD_SIGN diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala index e57ab6a199..1fd88717cb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/StateTestsHelperMethods.scala @@ -66,7 +66,7 @@ trait StateTestsHelperMethods extends TestKitBase { tags: Set[String] = Set.empty): Unit = { import setup._ val channelFlags = if (tags.contains("channels_public")) ChannelFlags.AnnounceChannel else ChannelFlags.Empty - val pushMsat = if (tags.contains("no_push_msat")) MilliSatoshi(0) else TestConstants.pushMsat + val pushMsat = if (tags.contains("no_push_msat")) 0.msat else TestConstants.pushMsat val (aliceParams, bobParams) = (Alice.channelParams, Bob.channelParams) val aliceInit = Init(aliceParams.globalFeatures, aliceParams.localFeatures) val bobInit = Init(bobParams.globalFeatures, bobParams.localFeatures) @@ -98,7 +98,7 @@ trait StateTestsHelperMethods extends TestKitBase { bob2blockchain.expectMsgType[WatchConfirmed] // deeply buried awaitCond(alice.stateName == NORMAL) awaitCond(bob.stateName == NORMAL) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == (pushMsat - TestConstants.Alice.channelParams.channelReserve).max(MilliSatoshi(0))) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == (pushMsat - TestConstants.Alice.channelParams.channelReserve).max(0 msat)) // x2 because alice and bob share the same relayer channelUpdateListener.expectMsgType[LocalChannelUpdate] channelUpdateListener.expectMsgType[LocalChannelUpdate] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala index ad69384c76..2abddc6e49 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.channel.Channel.TickChannelOpenTimeout 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.{CltvExpiryDelta, TestConstants, TestkitBaseClass} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, TestConstants, TestkitBaseClass} import org.scalatest.{Outcome, Tag} import scodec.bits.ByteVector @@ -83,7 +83,7 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp import f._ val accept = bob2alice.expectMsgType[AcceptChannel] // we don't want their dust limit to be below 546 - val lowDustLimitSatoshis = Satoshi(545) + val lowDustLimitSatoshis = 545.sat alice ! accept.copy(dustLimitSatoshis = lowDustLimitSatoshis) val error = alice2bob.expectMsgType[Error] assert(error === Error(accept.temporaryChannelId, DustLimitTooSmall(accept.temporaryChannelId, lowDustLimitSatoshis, Channel.MIN_DUSTLIMIT).getMessage)) @@ -104,7 +104,7 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp import f._ val accept = bob2alice.expectMsgType[AcceptChannel] // 30% is huge, recommended ratio is 1% - val reserveTooHigh = Satoshi((0.3 * TestConstants.fundingSatoshis.toLong).toLong) + val reserveTooHigh = TestConstants.fundingSatoshis * 0.3 alice ! accept.copy(channelReserveSatoshis = reserveTooHigh) val error = alice2bob.expectMsgType[Error] assert(error === Error(accept.temporaryChannelId, ChannelReserveTooHigh(accept.temporaryChannelId, reserveTooHigh, 0.3, 0.05).getMessage)) @@ -114,7 +114,7 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp test("recv AcceptChannel (reserve below dust limit)") { f => import f._ val accept = bob2alice.expectMsgType[AcceptChannel] - val reserveTooSmall = accept.dustLimitSatoshis - Satoshi(1) + val reserveTooSmall = accept.dustLimitSatoshis - 1.sat alice ! accept.copy(channelReserveSatoshis = reserveTooSmall) val error = alice2bob.expectMsgType[Error] assert(error === Error(accept.temporaryChannelId, DustLimitTooLarge(accept.temporaryChannelId, accept.dustLimitSatoshis, reserveTooSmall).getMessage)) @@ -125,7 +125,7 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp import f._ val accept = bob2alice.expectMsgType[AcceptChannel] val open = alice.stateData.asInstanceOf[DATA_WAIT_FOR_ACCEPT_CHANNEL].lastSent - val reserveTooSmall = open.dustLimitSatoshis - Satoshi(1) + val reserveTooSmall = open.dustLimitSatoshis - 1.sat alice ! accept.copy(channelReserveSatoshis = reserveTooSmall) val error = alice2bob.expectMsgType[Error] assert(error === Error(accept.temporaryChannelId, ChannelReserveBelowOurDustLimit(accept.temporaryChannelId, reserveTooSmall, open.dustLimitSatoshis).getMessage)) @@ -136,7 +136,7 @@ class WaitForAcceptChannelStateSpec extends TestkitBaseClass with StateTestsHelp import f._ val accept = bob2alice.expectMsgType[AcceptChannel] val open = alice.stateData.asInstanceOf[DATA_WAIT_FOR_ACCEPT_CHANNEL].lastSent - val dustTooBig = open.channelReserveSatoshis + Satoshi(1) + val dustTooBig = open.channelReserveSatoshis + 1.sat alice ! accept.copy(dustLimitSatoshis = dustTooBig) val error = alice2bob.expectMsgType[Error] assert(error === Error(accept.temporaryChannelId, DustLimitAboveOurChannelReserve(accept.temporaryChannelId, dustTooBig, open.channelReserveSatoshis).getMessage)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala index fa83e180d7..45b51bc665 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala @@ -17,12 +17,12 @@ package fr.acinq.eclair.channel.states.a import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.{Block, ByteVector32, Satoshi} +import fr.acinq.bitcoin.{Block, ByteVector32} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.wire.{Error, Init, OpenChannel} -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, TestConstants, TestkitBaseClass, ToMilliSatoshiConversion} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, TestConstants, TestkitBaseClass, ToMilliSatoshiConversion} import org.scalatest.Outcome import scala.concurrent.duration._ @@ -69,7 +69,7 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper test("recv OpenChannel (funding too low)") { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - val lowFunding = Satoshi(100) + val lowFunding = 100.sat bob ! open.copy(fundingSatoshis = lowFunding) val error = bob2alice.expectMsgType[Error] assert(error === Error(open.temporaryChannelId, InvalidFundingAmount(open.temporaryChannelId, lowFunding, Bob.nodeParams.minFundingSatoshis, Channel.MAX_FUNDING).getMessage)) @@ -79,7 +79,7 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper test("recv OpenChannel (funding too high)") { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - val highFundingMsat = Satoshi(100000000) + val highFundingMsat = 100000000.sat bob ! open.copy(fundingSatoshis = highFundingMsat) val error = bob2alice.expectMsgType[Error] assert(error.toAscii === Error(open.temporaryChannelId, InvalidFundingAmount(open.temporaryChannelId, highFundingMsat, Bob.nodeParams.minFundingSatoshis, Channel.MAX_FUNDING).getMessage).toAscii) @@ -99,7 +99,7 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper test("recv OpenChannel (invalid push_msat)") { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - val invalidPushMsat = MilliSatoshi(100000000000L) + val invalidPushMsat = 100000000000L.msat bob ! open.copy(pushMsat = invalidPushMsat) val error = bob2alice.expectMsgType[Error] assert(error === Error(open.temporaryChannelId, InvalidPushAmount(open.temporaryChannelId, invalidPushMsat, open.fundingSatoshis.toMilliSatoshi).getMessage)) @@ -120,7 +120,7 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper import f._ val open = alice2bob.expectMsgType[OpenChannel] // 30% is huge, recommended ratio is 1% - val reserveTooHigh = Satoshi((0.3 * TestConstants.fundingSatoshis.toLong).toLong) + val reserveTooHigh = TestConstants.fundingSatoshis * 0.3 bob ! open.copy(channelReserveSatoshis = reserveTooHigh) val error = bob2alice.expectMsgType[Error] assert(error === Error(open.temporaryChannelId, ChannelReserveTooHigh(open.temporaryChannelId, reserveTooHigh, 0.3, 0.05).getMessage)) @@ -155,7 +155,7 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper test("recv OpenChannel (reserve below dust)") { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - val reserveTooSmall = open.dustLimitSatoshis - Satoshi(1) + val reserveTooSmall = open.dustLimitSatoshis - 1.sat bob ! open.copy(channelReserveSatoshis = reserveTooSmall) val error = bob2alice.expectMsgType[Error] // we check that the error uses the temporary channel id @@ -166,12 +166,12 @@ class WaitForOpenChannelStateSpec extends TestkitBaseClass with StateTestsHelper test("recv OpenChannel (toLocal + toRemote below reserve)") { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - val fundingSatoshis = open.channelReserveSatoshis.toLong + 499 - val pushMsat = MilliSatoshi(500 * 1000) - bob ! open.copy(fundingSatoshis = Satoshi(fundingSatoshis), pushMsat = pushMsat) + val fundingSatoshis = open.channelReserveSatoshis + 499.sat + val pushMsat = (500 sat).toMilliSatoshi + bob ! open.copy(fundingSatoshis = fundingSatoshis, pushMsat = pushMsat) val error = bob2alice.expectMsgType[Error] // we check that the error uses the temporary channel id - assert(error === Error(open.temporaryChannelId, ChannelReserveNotMet(open.temporaryChannelId, pushMsat, (open.channelReserveSatoshis - Satoshi(1)).toMilliSatoshi, open.channelReserveSatoshis).getMessage)) + assert(error === Error(open.temporaryChannelId, ChannelReserveNotMet(open.temporaryChannelId, pushMsat, (open.channelReserveSatoshis - 1.sat).toMilliSatoshi, open.channelReserveSatoshis).getMessage)) awaitCond(bob.stateName == CLOSED) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala index 9a88921c3d..f34297725f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{MilliSatoshi, TestConstants, TestkitBaseClass} +import fr.acinq.eclair.{LongToBtcAmount, TestConstants, TestkitBaseClass} import org.scalatest.{Outcome, Tag} import scala.concurrent.duration._ @@ -41,7 +41,7 @@ class WaitForFundingCreatedStateSpec extends TestkitBaseClass with StateTestsHel val setup = init() import setup._ val (fundingSatoshis, pushMsat) = if (test.tags.contains("funder_below_reserve")) { - (Satoshi(1000100L), MilliSatoshi(1000000000L)) // toRemote = 100 satoshis + (1000100 sat, 1000000000L msat) // toRemote = 100 satoshis } else { (TestConstants.fundingSatoshis, TestConstants.pushMsat) } @@ -73,7 +73,7 @@ class WaitForFundingCreatedStateSpec extends TestkitBaseClass with StateTestsHel import f._ val fees = Satoshi(Transactions.commitWeight * TestConstants.feeratePerKw / 1000) val reserve = Bob.channelParams.channelReserve - val missing = Satoshi(100) - fees - reserve + val missing = 100.sat - fees - reserve val fundingCreated = alice2bob.expectMsgType[FundingCreated] alice2bob.forward(bob) val error = bob2alice.expectMsgType[Error] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala index d3ef649aab..11ca5510ef 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala @@ -18,22 +18,21 @@ package fr.acinq.eclair.channel.states.c import akka.actor.Status.Failure import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.{ByteVector32, Satoshi, Script, Transaction} -import fr.acinq.eclair.randomKey +import fr.acinq.bitcoin.{ByteVector32, Script, Transaction} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.transactions.Scripts.multiSig2of2 import fr.acinq.eclair.wire.{AcceptChannel, Error, FundingCreated, FundingLocked, FundingSigned, Init, OpenChannel} -import fr.acinq.eclair.{TestConstants, TestkitBaseClass} +import fr.acinq.eclair.{LongToBtcAmount, TestConstants, TestkitBaseClass, randomKey} import org.scalatest.Outcome import scala.concurrent.duration._ /** - * Created by PM on 05/07/2016. - */ + * Created by PM on 05/07/2016. + */ class WaitForFundingConfirmedStateSpec extends TestkitBaseClass with StateTestsHelperMethods { @@ -94,7 +93,7 @@ class WaitForFundingConfirmedStateSpec extends TestkitBaseClass with StateTestsH test("recv BITCOIN_FUNDING_DEPTHOK (bad funding amount)") { f => import f._ val fundingTx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CONFIRMED].fundingTx.get - val badOutputAmount = fundingTx.txOut(0).copy(amount = Satoshi(1234567)) + val badOutputAmount = fundingTx.txOut(0).copy(amount = 1234567.sat) val badFundingTx = fundingTx.copy(txOut = Seq(badOutputAmount)) alice ! WatchEventConfirmed(BITCOIN_FUNDING_DEPTHOK, 42000, 42, badFundingTx) awaitCond(alice.stateName == CLOSED) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index cb88d6cb5f..c38d884811 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -22,7 +22,7 @@ import akka.actor.Status import akka.actor.Status.Failure import akka.testkit.TestProbe import fr.acinq.bitcoin.Crypto.PrivateKey -import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, Satoshi, ScriptFlags, Transaction} +import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, ScriptFlags, Transaction} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.UInt64.Conversions._ import fr.acinq.eclair.blockchain._ @@ -69,7 +69,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val sender = TestProbe() val h = randomBytes32 - val add = CMD_ADD_HTLC(MilliSatoshi(50000000), h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") val htlc = alice2bob.expectMsgType[UpdateAddHtlc] @@ -87,7 +87,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val h = randomBytes32 for (i <- 0 until 10) { - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(50000000), h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc = alice2bob.expectMsgType[UpdateAddHtlc] assert(htlc.id == i && htlc.paymentHash == h) @@ -99,8 +99,8 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val sender = TestProbe() val h = randomBytes32 - val originHtlc = UpdateAddHtlc(channelId = randomBytes32, id = 5656, amountMsat = MilliSatoshi(50000000), cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, paymentHash = h, onionRoutingPacket = TestConstants.emptyOnionPacket) - val cmd = CMD_ADD_HTLC(originHtlc.amountMsat - MilliSatoshi(10000), h, originHtlc.cltvExpiry - CltvExpiryDelta(7), TestConstants.emptyOnionPacket, upstream = Right(originHtlc)) + val originHtlc = UpdateAddHtlc(channelId = randomBytes32, id = 5656, amountMsat = 50000000 msat, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, paymentHash = h, onionRoutingPacket = TestConstants.emptyOnionPacket) + val cmd = CMD_ADD_HTLC(originHtlc.amountMsat - 10000.msat, h, originHtlc.cltvExpiry - CltvExpiryDelta(7), TestConstants.emptyOnionPacket, upstream = Right(originHtlc)) sender.send(alice, cmd) sender.expectMsg("ok") val htlc = alice2bob.expectMsgType[UpdateAddHtlc] @@ -119,7 +119,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val currentBlockCount = Globals.blockCount.get val expiryTooSmall = CltvExpiry(currentBlockCount + 3) - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, expiryTooSmall, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, expiryTooSmall, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = ExpiryTooSmall(channelId(alice), Channel.MIN_CLTV_EXPIRY_DELTA.toCltvExpiry, expiryTooSmall, currentBlockCount) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -132,7 +132,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val currentBlockCount = Globals.blockCount.get val expiryTooBig = (Channel.MAX_CLTV_EXPIRY_DELTA + 1).toCltvExpiry - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, expiryTooBig, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, expiryTooBig, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = ExpiryTooBig(channelId(alice), maximum = Channel.MAX_CLTV_EXPIRY_DELTA.toCltvExpiry, actual = expiryTooBig, blockCount = currentBlockCount) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -143,9 +143,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(MilliSatoshi(50), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(50 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = HtlcValueTooSmall(channelId(alice), MilliSatoshi(1000), MilliSatoshi(50)) + val error = HtlcValueTooSmall(channelId(alice), 1000 msat, 50 msat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -156,7 +156,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val add = CMD_ADD_HTLC(MilliSatoshi(Int.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = InsufficientFunds(channelId(alice), amount = MilliSatoshi(Int.MaxValue), missing = Satoshi(1376443), reserve = Satoshi(20000), fees = Satoshi(8960)) + val error = InsufficientFunds(channelId(alice), amount = MilliSatoshi(Int.MaxValue), missing = 1376443 sat, reserve = 20000 sat, fees = 8960 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -165,18 +165,18 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(200000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(67600000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(67600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - val add = CMD_ADD_HTLC(MilliSatoshi(1000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = InsufficientFunds(channelId(alice), amount = MilliSatoshi(1000000), missing = Satoshi(1000), reserve = Satoshi(20000), fees = Satoshi(12400)) + val error = InsufficientFunds(channelId(alice), amount = 1000000 msat, missing = 1000 sat, reserve = 20000 sat, fees = 12400 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -185,15 +185,15 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(300000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(300000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) - val error = InsufficientFunds(channelId(alice), amount = MilliSatoshi(500000000), missing = Satoshi(332400), reserve = Satoshi(20000), fees = Satoshi(12400)) + val error = InsufficientFunds(channelId(alice), amount = 500000000 msat, missing = 332400 sat, reserve = 20000 sat, fees = 12400 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) alice2bob.expectNoMsg(200 millis) } @@ -202,7 +202,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - val add = CMD_ADD_HTLC(MilliSatoshi(151000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(bob, add) val error = HtlcValueTooHighInFlight(channelId(bob), maximum = 150000000, actual = 151000000) sender.expectMsg(Failure(AddHtlcFailed(channelId(bob), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -215,11 +215,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] // Bob accepts a maximum of 30 htlcs for (i <- 0 until 30) { - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] } - val add = CMD_ADD_HTLC(MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = TooManyAcceptedHtlcs(channelId(alice), maximum = 30) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -240,7 +240,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // this is over channel-capacity val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis.toMilliSatoshi * 2 / 3, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add2) - val error = InsufficientFunds(channelId(alice), add2.amount, Satoshi(564013), Satoshi(20000), Satoshi(10680)) + val error = InsufficientFunds(channelId(alice), add2.amount, 564013 sat, 20000 sat, 10680 sat) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add2.paymentHash, error, Local(add2.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add2)))) alice2bob.expectNoMsg(200 millis) } @@ -255,7 +255,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].localShutdown.isDefined && alice.stateData.asInstanceOf[DATA_NORMAL].remoteShutdown.isEmpty) // actual test starts here - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = NoMoreHtlcsClosingInProgress(channelId(alice)) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), Some(initialState.channelUpdate), Some(add)))) @@ -267,14 +267,14 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] // let's make alice send an htlc - val add1 = CMD_ADD_HTLC(MilliSatoshi(500000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add1 = CMD_ADD_HTLC(500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add1) sender.expectMsg("ok") // at the same time bob initiates a closing sender.send(bob, CMD_CLOSE(None)) sender.expectMsg("ok") // this command will be received by alice right after having received the shutdown - val add2 = CMD_ADD_HTLC(MilliSatoshi(100000000), randomBytes32, CltvExpiry(300000), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add2 = CMD_ADD_HTLC(100000000 msat, randomBytes32, CltvExpiry(300000), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) // messages cross alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) @@ -288,7 +288,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc") { f => import f._ val initialData = bob.stateData.asInstanceOf[DATA_NORMAL] - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(150000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) bob ! htlc awaitCond(bob.stateData == initialData.copy(commitments = initialData.commitments.copy(remoteChanges = initialData.commitments.remoteChanges.copy(proposed = initialData.commitments.remoteChanges.proposed :+ htlc), remoteNextHtlcId = 1))) // bob won't forward the add before it is cross-signed @@ -298,7 +298,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (unexpected id)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 42, MilliSatoshi(150000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 42, 150000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) bob ! htlc.copy(id = 0) bob ! htlc.copy(id = 1) bob ! htlc.copy(id = 2) @@ -315,10 +315,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (value too small)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(150), randomBytes32, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, 150 msat, randomBytes32, cltvExpiry = CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) alice2bob.forward(bob, htlc) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === HtlcValueTooSmall(channelId(bob), minimum = MilliSatoshi(1000), actual = MilliSatoshi(150)).getMessage) + assert(new String(error.data.toArray) === HtlcValueTooSmall(channelId(bob), minimum = 1000 msat, actual = 150 msat).getMessage) awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) @@ -333,7 +333,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(Long.MaxValue), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) alice2bob.forward(bob, htlc) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = MilliSatoshi(Long.MaxValue), missing = Satoshi(9223372036083735L), reserve = Satoshi(20000), fees = Satoshi(8960)).getMessage) + assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = MilliSatoshi(Long.MaxValue), missing = 9223372036083735L sat, reserve = 20000 sat, fees = 8960 sat).getMessage) awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) @@ -345,12 +345,12 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (insufficient funds w/ pending htlcs 1/2)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(400000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(200000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(167600000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 3, MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 400000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 200000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 167600000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 3, 10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = MilliSatoshi(10000000), missing = Satoshi(11720), reserve = Satoshi(20000), fees = Satoshi(14120)).getMessage) + assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = 10000000 msat, missing = 11720 sat, reserve = 20000 sat, fees = 14120 sat).getMessage) awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) @@ -362,11 +362,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (insufficient funds w/ pending htlcs 2/2)") { f => import f._ val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(300000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(300000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(500000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 0, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 1, 300000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 2, 500000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = MilliSatoshi(500000000), missing = Satoshi(332400), reserve = Satoshi(20000), fees = Satoshi(12400)).getMessage) + assert(new String(error.data.toArray) === InsufficientFunds(channelId(bob), amount = 500000000 msat, missing = 332400 sat, reserve = 20000 sat, fees = 12400 sat).getMessage) awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) @@ -378,7 +378,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateAddHtlc (over max inflight htlc value)") { f => import f._ val tx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx - alice2bob.forward(alice, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(151000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(alice, UpdateAddHtlc(ByteVector32.Zeroes, 0, 151000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) val error = alice2bob.expectMsgType[Error] assert(new String(error.data.toArray) === HtlcValueTooHighInFlight(channelId(alice), maximum = 150000000, actual = 151000000).getMessage) awaitCond(alice.stateName == CLOSING) @@ -394,9 +394,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx // Bob accepts a maximum of 30 htlcs for (i <- 0 until 30) { - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, i, MilliSatoshi(1000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, i, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) } - alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 30, MilliSatoshi(1000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) + alice2bob.forward(bob, UpdateAddHtlc(ByteVector32.Zeroes, 30, 1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket)) val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray) === TooManyAcceptedHtlcs(channelId(bob), maximum = 30).getMessage) awaitCond(bob.stateName == CLOSING) @@ -410,7 +410,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") val commitSig = alice2bob.expectMsgType[CommitSig] @@ -421,7 +421,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (two identical htlcs in each direction)") { f => import f._ val sender = TestProbe() - val add = CMD_ADD_HTLC(MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] @@ -460,10 +460,10 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val aliceMinOffer = Alice.nodeParams.dustLimit + weight2fee(TestConstants.feeratePerKw, htlcTimeoutWeight) val bobMinReceive = Bob.nodeParams.dustLimit + weight2fee(TestConstants.feeratePerKw, htlcSuccessWeight) val bobMinOffer = Bob.nodeParams.dustLimit + weight2fee(TestConstants.feeratePerKw, htlcTimeoutWeight) - val a2b_1 = bobMinReceive + Satoshi(10) // will be in alice and bob tx - val a2b_2 = bobMinReceive + Satoshi(20) // will be in alice and bob tx - val b2a_1 = aliceMinReceive + Satoshi(10) // will be in alice and bob tx - val b2a_2 = bobMinOffer + Satoshi(10) // will be only be in bob tx + val a2b_1 = bobMinReceive + 10.sat // will be in alice and bob tx + val a2b_2 = bobMinReceive + 20.sat // will be in alice and bob tx + val b2a_1 = aliceMinReceive + 10.sat // will be in alice and bob tx + val b2a_2 = bobMinOffer + 10.sat // will be only be in bob tx assert(a2b_1 > aliceMinOffer && a2b_1 > bobMinReceive) assert(a2b_2 > aliceMinOffer && a2b_2 > bobMinReceive) assert(b2a_1 > aliceMinReceive && b2a_1 > bobMinOffer) @@ -500,11 +500,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (htlcs with same pubkeyScript but different amounts)") { f => import f._ val sender = TestProbe() - val add = CMD_ADD_HTLC(MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) val epsilons = List(3, 1, 5, 7, 6) // unordered on purpose val htlcCount = epsilons.size for (i <- epsilons) { - sender.send(alice, add.copy(amount = MilliSatoshi(add.amount.toLong + i * 1000))) + sender.send(alice, add.copy(amount = add.amount + (i * 1000).msat)) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) @@ -532,7 +532,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (while waiting for RevokeAndAck (no pending changes)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo.isRight) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -550,7 +550,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_SIGN (while waiting for RevokeAndAck (with pending changes)") { f => import f._ val sender = TestProbe() - val (r1, htlc1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r1, htlc1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo.isRight) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -560,7 +560,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(waitForRevocation.reSignAsap === false) // actual test starts here - val (r2, htlc2) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r2, htlc2) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectNoMsg(300 millis) assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo === Left(waitForRevocation.copy(reSignAsap = true))) @@ -572,7 +572,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // channel starts with all funds on alice's side, so channel will be initially disabled on bob's side assert(Announcements.isEnabled(bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate.channelFlags) === false) // alice will send enough funds to bob to make it go above reserve - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_FULFILL_HTLC(htlc.id, r)) sender.expectMsg("ok") @@ -587,7 +587,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { sender.expectMsg("ok") bob2alice.expectMsgType[CommitSig] // it should update its channel_update - awaitCond(Announcements.isEnabled(bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate.channelFlags) == true) + awaitCond(Announcements.isEnabled(bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate.channelFlags)) // and broadcast it assert(listener.expectMsgType[LocalChannelUpdate].channelUpdate === bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate) } @@ -596,7 +596,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] sender.send(alice, CMD_SIGN) @@ -621,7 +621,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] sender.send(alice, CMD_SIGN) @@ -644,19 +644,19 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (r1, htlc1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r1, htlc1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r2, htlc2) = addHtlc(MilliSatoshi(8000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r2, htlc2) = addHtlc(8000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r3, htlc3) = addHtlc(MilliSatoshi(300000), bob, alice, bob2alice, alice2bob) // b->a (dust) + val (r3, htlc3) = addHtlc(300000 msat, bob, alice, bob2alice, alice2bob) // b->a (dust) - val (r4, htlc4) = addHtlc(MilliSatoshi(1000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r4, htlc4) = addHtlc(1000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r5, htlc5) = addHtlc(MilliSatoshi(50000000), bob, alice, bob2alice, alice2bob) // b->a (regular) + val (r5, htlc5) = addHtlc(50000000 msat, bob, alice, bob2alice, alice2bob) // b->a (regular) - val (r6, htlc6) = addHtlc(MilliSatoshi(500000), alice, bob, alice2bob, bob2alice) // a->b (dust) + val (r6, htlc6) = addHtlc(500000 msat, alice, bob, alice2bob, bob2alice) // a->b (dust) - val (r7, htlc7) = addHtlc(MilliSatoshi(4000000), bob, alice, bob2alice, alice2bob) // b->a (regular) + val (r7, htlc7) = addHtlc(4000000 msat, bob, alice, bob2alice, alice2bob) // b->a (regular) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -698,12 +698,12 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val r = randomBytes32 val h = Crypto.sha256(r) - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(50000000), h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc1 = alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(50000000), h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(50000000 msat, h, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) sender.expectMsg("ok") val htlc2 = alice2bob.expectMsgType[UpdateAddHtlc] alice2bob.forward(bob) @@ -715,7 +715,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { awaitCond(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.spec.htlcs.exists(h => h.add.id == htlc1.id && h.direction == IN)) assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.htlcTxsAndSigs.size == 2) assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.spec.toLocal == initialState.commitments.localCommit.spec.toLocal) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx.txOut.count(_.amount == Satoshi(50000)) == 2) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx.txOut.count(_.amount == 50000.sat) == 2) } ignore("recv CommitSig (no changes)") { f => @@ -737,7 +737,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CommitSig (invalid signature)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx // actual test begins @@ -754,7 +754,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx sender.send(alice, CMD_SIGN) @@ -775,7 +775,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) val tx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx sender.send(alice, CMD_SIGN) @@ -796,7 +796,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (one htlc sent)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -814,7 +814,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (one htlc received)") { f => import f._ val sender = TestProbe() - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -843,19 +843,19 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (multiple htlcs in both directions)") { f => import f._ val sender = TestProbe() - val (r1, htlc1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r1, htlc1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r2, htlc2) = addHtlc(MilliSatoshi(8000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r2, htlc2) = addHtlc(8000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r3, htlc3) = addHtlc(MilliSatoshi(300000), bob, alice, bob2alice, alice2bob) // b->a (dust) + val (r3, htlc3) = addHtlc(300000 msat, bob, alice, bob2alice, alice2bob) // b->a (dust) - val (r4, htlc4) = addHtlc(MilliSatoshi(1000000), alice, bob, alice2bob, bob2alice) // a->b (regular) + val (r4, htlc4) = addHtlc(1000000 msat, alice, bob, alice2bob, bob2alice) // a->b (regular) - val (r5, htlc5) = addHtlc(MilliSatoshi(50000000), bob, alice, bob2alice, alice2bob) // b->a (regular) + val (r5, htlc5) = addHtlc(50000000 msat, bob, alice, bob2alice, alice2bob) // b->a (regular) - val (r6, htlc6) = addHtlc(MilliSatoshi(500000), alice, bob, alice2bob, bob2alice) // a->b (dust) + val (r6, htlc6) = addHtlc(500000 msat, alice, bob, alice2bob, bob2alice) // a->b (dust) - val (r7, htlc7) = addHtlc(MilliSatoshi(4000000), bob, alice, bob2alice, alice2bob) // b->a (regular) + val (r7, htlc7) = addHtlc(4000000 msat, bob, alice, bob2alice, alice2bob) // b->a (regular) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -880,13 +880,13 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (with reSignAsap=true)") { f => import f._ val sender = TestProbe() - val (r1, htlc1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r1, htlc1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo.isRight) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] alice2bob.forward(bob) - val (r2, htlc2) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r2, htlc2) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectNoMsg(300 millis) assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo.left.toOption.get.reSignAsap === true) @@ -901,7 +901,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val tx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -938,7 +938,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (forward UpdateFailHtlc)") { f => import f._ val sender = TestProbe() - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_FAIL_HTLC(htlc.id, Right(PermanentChannelFailure))) sender.expectMsg("ok") @@ -967,7 +967,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevokeAndAck (forward UpdateFailMalformedHtlc)") { f => import f._ val sender = TestProbe() - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_FAIL_MALFORMED_HTLC(htlc.id, Sphinx.PaymentPacket.hash(htlc.onionRoutingPacket), FailureMessageCodecs.BADONION)) sender.expectMsg("ok") @@ -996,7 +996,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv RevocationTimeout") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -1013,7 +1013,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_FULFILL_HTLC") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1040,7 +1040,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_FULFILL_HTLC (invalid preimage)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1063,7 +1063,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFulfillHtlc") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_FULFILL_HTLC(htlc.id, r)) sender.expectMsg("ok") @@ -1083,7 +1083,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFulfillHtlc (sender has not signed htlc)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] @@ -1117,7 +1117,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFulfillHtlc (invalid preimage)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) relayerB.expectMsgType[ForwardAdd] val tx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx @@ -1138,7 +1138,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_FAIL_HTLC") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1176,7 +1176,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_FAIL_MALFORMED_HTLC") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1221,7 +1221,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFailHtlc") { f => import f._ val sender = TestProbe() - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_FAIL_HTLC(htlc.id, Right(PermanentChannelFailure))) sender.expectMsg("ok") @@ -1241,7 +1241,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() // Alice sends an HTLC to Bob, which they both sign - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // Bob fails the HTLC because he cannot parse it val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] @@ -1268,7 +1268,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFailMalformedHtlc (invalid failure_code)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1288,7 +1288,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv UpdateFailHtlc (sender has not signed htlc)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] @@ -1396,7 +1396,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { bob.feeEstimator.setFeerate(FeeratesPerKw.single(fee.feeratePerKw)) sender.send(bob, fee) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === CannotAffordFees(channelId(bob), missing = Satoshi(71620000L), reserve = Satoshi(20000L), fees = Satoshi(72400000L)).getMessage) + assert(new String(error.data.toArray) === CannotAffordFees(channelId(bob), missing = 71620000L sat, reserve = 20000L sat, fees = 72400000L sat).getMessage) awaitCond(bob.stateName == CLOSING) // channel should be advertised as down assert(channelUpdateListener.expectMsgType[LocalChannelDown].channelId === bob.stateData.asInstanceOf[DATA_CLOSING].channelId) @@ -1471,7 +1471,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_CLOSE (with unacked sent htlcs)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_CLOSE(None)) sender.expectMsg(Failure(CannotCloseWithUnsignedOutgoingHtlcs(channelId(bob)))) } @@ -1486,7 +1486,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_CLOSE (with signed sent htlcs)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_CLOSE(None)) sender.expectMsg("ok") @@ -1511,7 +1511,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_CLOSE (while waiting for a RevokeAndAck)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] @@ -1536,7 +1536,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Shutdown (with unacked sent htlcs)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_CLOSE(None)) bob2alice.expectMsgType[Shutdown] // actual test begins @@ -1557,7 +1557,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Shutdown (with unacked received htlcs)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) // actual test begins sender.send(bob, Shutdown(ByteVector32.Zeroes, TestConstants.Alice.channelParams.defaultFinalScriptPubKey)) bob2alice.expectMsgType[Error] @@ -1581,7 +1581,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Shutdown (with invalid final script and signed htlcs, in response to a Shutdown)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(bob, CMD_CLOSE(None)) bob2alice.expectMsgType[Shutdown] @@ -1597,7 +1597,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Shutdown (with signed htlcs)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1609,7 +1609,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Shutdown (while waiting for a RevokeAndAck)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] @@ -1628,14 +1628,14 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { sender.send(bob, CMD_CLOSE(None)) bob2alice.expectMsgType[Shutdown] // this is just so we have something to sign - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) // now we can sign sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] alice2bob.forward(bob) // adding an outgoing pending htlc - val (r1, htlc1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r1, htlc1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) // actual test begins // alice eventually gets bob's shutdown bob2alice.forward(alice) @@ -1665,7 +1665,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CurrentBlockCount (no htlc timed out)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1677,7 +1677,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CurrentBlockCount (an htlc timed out)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // actual test begins @@ -1696,7 +1696,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CurrentBlockCount (fulfilled signed htlc ignored by upstream peer)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val listener = TestProbe() @@ -1731,7 +1731,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CurrentBlockCount (fulfilled proposed htlc ignored by upstream peer)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val listener = TestProbe() @@ -1766,7 +1766,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CurrentBlockCount (fulfilled proposed htlc acked but not committed by upstream peer)") { f => import f._ val sender = TestProbe() - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val listener = TestProbe() @@ -1844,11 +1844,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (ra1, htlca1) = addHtlc(MilliSatoshi(250000000), alice, bob, alice2bob, bob2alice) - val (ra2, htlca2) = addHtlc(MilliSatoshi(100000000), alice, bob, alice2bob, bob2alice) - val (ra3, htlca3) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) - val (rb1, htlcb1) = addHtlc(MilliSatoshi(50000000), bob, alice, bob2alice, alice2bob) - val (rb2, htlcb2) = addHtlc(MilliSatoshi(55000000), bob, alice, bob2alice, alice2bob) + val (ra1, htlca1) = addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) + val (ra2, htlca2) = addHtlc(100000000 msat, alice, bob, alice2bob, bob2alice) + val (ra3, htlca3) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) + val (rb1, htlcb1) = addHtlc(50000000 msat, bob, alice, bob2alice, alice2bob) + val (rb2, htlcb2) = addHtlc(55000000 msat, bob, alice, bob2alice, alice2bob) crossSign(alice, bob, alice2bob, bob2alice) fulfillHtlc(1, ra2, bob, alice, bob2alice, alice2bob) fulfillHtlc(0, rb1, alice, bob, alice2bob, bob2alice) @@ -1880,7 +1880,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { claimHtlcTx.txOut(0).amount }).sum // at best we have a little less than 450 000 + 250 000 + 100 000 + 50 000 = 850 000 (because fees) - assert(amountClaimed == Satoshi(814880)) + assert(amountClaimed === 814880.sat) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(claimMain)) // claim-main @@ -1905,11 +1905,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (ra1, htlca1) = addHtlc(MilliSatoshi(250000000), alice, bob, alice2bob, bob2alice) - val (ra2, htlca2) = addHtlc(MilliSatoshi(100000000), alice, bob, alice2bob, bob2alice) - val (ra3, htlca3) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) - val (rb1, htlcb1) = addHtlc(MilliSatoshi(50000000), bob, alice, bob2alice, alice2bob) - val (rb2, htlcb2) = addHtlc(MilliSatoshi(55000000), bob, alice, bob2alice, alice2bob) + val (ra1, htlca1) = addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) + val (ra2, htlca2) = addHtlc(100000000 msat, alice, bob, alice2bob, bob2alice) + val (ra3, htlca3) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) + val (rb1, htlcb1) = addHtlc(50000000 msat, bob, alice, bob2alice, alice2bob) + val (rb2, htlcb2) = addHtlc(55000000 msat, bob, alice, bob2alice, alice2bob) crossSign(alice, bob, alice2bob, bob2alice) fulfillHtlc(1, ra2, bob, alice, bob2alice, alice2bob) fulfillHtlc(0, rb1, alice, bob, alice2bob, bob2alice) @@ -1948,7 +1948,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { claimHtlcTx.txOut(0).amount }).sum // at best we have a little less than 500 000 + 250 000 + 100 000 = 850 000 (because fees) - assert(amountClaimed == Satoshi(822310)) + assert(amountClaimed === 822310.sat) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(claimTxes(0))) // claim-main @@ -1971,7 +1971,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // bob = 200 000 def send(): Transaction = { // alice sends 8 000 sat - val (r, htlc) = addHtlc(MilliSatoshi(10000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(10000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx @@ -2010,16 +2010,15 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { htlcPenaltyTxs.foreach(htlcPenaltyTx => Transaction.correctlySpends(htlcPenaltyTx, Seq(revokedTx), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)) // two main outputs are 760 000 and 200 000 - assert(mainTx.txOut(0).amount == Satoshi(741500)) - assert(mainPenaltyTx.txOut(0).amount == Satoshi(195160)) - assert(htlcPenaltyTxs(0).txOut(0).amount == Satoshi(4540)) - assert(htlcPenaltyTxs(1).txOut(0).amount == Satoshi(4540)) - assert(htlcPenaltyTxs(2).txOut(0).amount == Satoshi(4540)) - assert(htlcPenaltyTxs(3).txOut(0).amount == Satoshi(4540)) + assert(mainTx.txOut(0).amount === 741500.sat) + assert(mainPenaltyTx.txOut(0).amount === 195160.sat) + assert(htlcPenaltyTxs(0).txOut(0).amount === 4540.sat) + assert(htlcPenaltyTxs(1).txOut(0).amount === 4540.sat) + assert(htlcPenaltyTxs(2).txOut(0).amount === 4540.sat) + assert(htlcPenaltyTxs(3).txOut(0).amount === 4540.sat) awaitCond(alice.stateName == CLOSING) assert(alice.stateData.asInstanceOf[DATA_CLOSING].revokedCommitPublished.size == 1) - } test("recv BITCOIN_FUNDING_SPENT (revoked commit with identical htlcs)") { f => @@ -2030,7 +2029,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // alice = 800 000 // bob = 200 000 - val add = CMD_ADD_HTLC(MilliSatoshi(10000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(10000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) sender.expectMsg("ok") alice2bob.expectMsgType[UpdateAddHtlc] @@ -2078,11 +2077,11 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv Error") { f => import f._ - val (ra1, htlca1) = addHtlc(MilliSatoshi(250000000), alice, bob, alice2bob, bob2alice) - val (ra2, htlca2) = addHtlc(MilliSatoshi(100000000), alice, bob, alice2bob, bob2alice) - val (ra3, htlca3) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) - val (rb1, htlcb1) = addHtlc(MilliSatoshi(50000000), bob, alice, bob2alice, alice2bob) - val (rb2, htlcb2) = addHtlc(MilliSatoshi(55000000), bob, alice, bob2alice, alice2bob) + val (ra1, htlca1) = addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) + val (ra2, htlca2) = addHtlc(100000000 msat, alice, bob, alice2bob, bob2alice) + val (ra3, htlca3) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) + val (rb1, htlcb1) = addHtlc(50000000 msat, bob, alice, bob2alice, alice2bob) + val (rb2, htlcb2) = addHtlc(55000000 msat, bob, alice, bob2alice, alice2bob) crossSign(alice, bob, alice2bob, bob2alice) fulfillHtlc(1, ra2, bob, alice, bob2alice, alice2bob) fulfillHtlc(0, rb1, alice, bob, alice2bob, bob2alice) @@ -2298,9 +2297,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() sender.send(alice, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 400000, 42, null)) val update1a = alice2bob.expectMsgType[ChannelUpdate] - assert(Announcements.isEnabled(update1a.channelFlags) == true) - val (_, htlc1) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) - val (_, htlc2) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) + assert(Announcements.isEnabled(update1a.channelFlags)) + val (_, htlc1) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) + val (_, htlc2) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) val aliceData = alice.stateData.asInstanceOf[DATA_NORMAL] assert(aliceData.commitments.localChanges.proposed.size == 2) @@ -2311,7 +2310,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(relayerA.expectMsgType[Status.Failure].cause.asInstanceOf[AddHtlcFailed].paymentHash === htlc2.paymentHash) val update2a = alice2bob.expectMsgType[ChannelUpdate] assert(channelUpdateListener.expectMsgType[LocalChannelUpdate].channelUpdate === update2a) - assert(Announcements.isEnabled(update2a.channelFlags) == false) + assert(!Announcements.isEnabled(update2a.channelFlags)) awaitCond(alice.stateName == OFFLINE) } @@ -2342,9 +2341,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { alice2bob.forward(bob) val update1a = channelUpdateListener.expectMsgType[LocalChannelUpdate] val update1b = channelUpdateListener.expectMsgType[LocalChannelUpdate] - assert(Announcements.isEnabled(update1a.channelUpdate.channelFlags) == true) - val (_, htlc1) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) - val (_, htlc2) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) + assert(Announcements.isEnabled(update1a.channelUpdate.channelFlags)) + val (_, htlc1) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) + val (_, htlc2) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) val aliceData = alice.stateData.asInstanceOf[DATA_NORMAL] assert(aliceData.commitments.localChanges.proposed.size == 2) @@ -2355,7 +2354,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { assert(relayerA.expectMsgType[Status.Failure].cause.asInstanceOf[AddHtlcFailed].paymentHash === htlc2.paymentHash) val update2a = channelUpdateListener.expectMsgType[LocalChannelUpdate] assert(update1a.channelUpdate.timestamp < update2a.channelUpdate.timestamp) - assert(Announcements.isEnabled(update2a.channelUpdate.channelFlags) == false) + assert(!Announcements.isEnabled(update2a.channelUpdate.channelFlags)) awaitCond(alice.stateName == OFFLINE) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala index 837fc54655..c02f85f58a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala @@ -31,7 +31,7 @@ import fr.acinq.eclair.payment.CommandBuffer.CommandSend import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.transactions.Transactions.HtlcSuccessTx import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, TestConstants, TestkitBaseClass, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, TestConstants, TestkitBaseClass, randomBytes32} import org.scalatest.Outcome import scala.concurrent.duration._ @@ -66,7 +66,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(1000000), ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(1000000 msat, ByteVector32.Zeroes, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) val ab_add_0 = alice2bob.expectMsgType[UpdateAddHtlc] // add ->b alice2bob.forward(bob) @@ -143,7 +143,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(1000000), randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(1000000 msat, randomBytes32, CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) val ab_add_0 = alice2bob.expectMsgType[UpdateAddHtlc] // add ->b alice2bob.forward(bob, ab_add_0) @@ -204,11 +204,11 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() - val (ra1, htlca1) = addHtlc(MilliSatoshi(250000000), alice, bob, alice2bob, bob2alice) + val (ra1, htlca1) = addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) - val (ra2, htlca2) = addHtlc(MilliSatoshi(100000000), alice, bob, alice2bob, bob2alice) + val (ra2, htlca2) = addHtlc(100000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) - val (ra3, htlca3) = addHtlc(MilliSatoshi(10000), alice, bob, alice2bob, bob2alice) + val (ra3, htlca3) = addHtlc(10000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val oldStateData = alice.stateData fulfillHtlc(htlca1.id, ra1, bob, alice, bob2alice, alice2bob) @@ -261,7 +261,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // we start by storing the current state val oldStateData = alice.stateData // then we add an htlc and sign it - addHtlc(MilliSatoshi(250000000), alice, bob, alice2bob, bob2alice) + addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") alice2bob.expectMsgType[CommitSig] @@ -347,7 +347,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { channelUpdateListener.expectNoMsg(300 millis) // we make alice update here relay fee - sender.send(alice, CMD_UPDATE_RELAY_FEE(MilliSatoshi(4200), 123456)) + sender.send(alice, CMD_UPDATE_RELAY_FEE(4200 msat, 123456)) sender.expectMsg("ok") // alice doesn't broadcast the new channel_update yet @@ -365,7 +365,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // then alice reaches NORMAL state, and after a delay she broadcasts the channel_update val channelUpdate = channelUpdateListener.expectMsgType[LocalChannelUpdate](20 seconds).channelUpdate - assert(channelUpdate.feeBaseMsat === MilliSatoshi(4200)) + assert(channelUpdate.feeBaseMsat === 4200.msat) assert(channelUpdate.feeProportionalMillionths === 123456) assert(Announcements.isEnabled(channelUpdate.channelFlags)) @@ -387,7 +387,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { channelUpdateListener.expectNoMsg(300 millis) // we attempt to send a payment - sender.send(alice, CMD_ADD_HTLC(MilliSatoshi(4200), randomBytes32, CltvExpiry(123456), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) + sender.send(alice, CMD_ADD_HTLC(4200 msat, randomBytes32, CltvExpiry(123456), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID()))) val failure = sender.expectMsgType[Status.Failure] val AddHtlcFailed(_, _, ChannelUnavailable(_), _, _, _) = failure.cause @@ -401,7 +401,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val register = TestProbe() val commandBuffer = TestActorRef(new CommandBuffer(bob.underlyingActor.nodeParams, register.ref)) - val (r, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val listener = TestProbe() @@ -442,7 +442,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() val register = TestProbe() val commandBuffer = TestActorRef(new CommandBuffer(bob.underlyingActor.nodeParams, register.ref)) - val (_, htlc) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (_, htlc) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) sender.send(alice, INPUT_DISCONNECTED) @@ -452,7 +452,7 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // We simulate a pending failure on that HTLC. // Even if we get close to expiring upstream we shouldn't close the channel, because we have nothing to lose. - sender.send(commandBuffer, CommandSend(htlc.channelId, htlc.id, CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(MilliSatoshi(0)))))) + sender.send(commandBuffer, CommandSend(htlc.channelId, htlc.id, CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(0 msat))))) sender.send(bob, CurrentBlockCount((htlc.cltvExpiry - bob.underlyingActor.nodeParams.fulfillSafetyBeforeTimeoutBlocks).toLong)) bob2blockchain.expectNoMsg(250 millis) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala index ef3d516f89..5b425eac08 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala @@ -21,7 +21,7 @@ import java.util.UUID import akka.actor.Status.Failure import akka.testkit.TestProbe import fr.acinq.bitcoin.Crypto.PrivateKey -import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, Satoshi, ScriptFlags, Transaction} +import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, ScriptFlags, Transaction} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw import fr.acinq.eclair.channel._ @@ -29,7 +29,7 @@ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.payment._ import fr.acinq.eclair.router.Hop import fr.acinq.eclair.wire.{CommitSig, Error, FailureMessageCodecs, PermanentChannelFailure, RevokeAndAck, Shutdown, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFee, UpdateFulfillHtlc} -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, TestConstants, TestkitBaseClass, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, TestConstants, TestkitBaseClass, randomBytes32} import org.scalatest.Outcome import scodec.bits.ByteVector @@ -54,7 +54,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { val sender = TestProbe() // alice sends an HTLC to bob val h1 = Crypto.sha256(r1) - val amount1 = MilliSatoshi(300000000) + val amount1 = 300000000 msat val expiry1 = CltvExpiryDelta(144).toCltvExpiry val cmd1 = PaymentLifecycle.buildCommand(UUID.randomUUID, amount1, expiry1, h1, Hop(null, TestConstants.Bob.nodeParams.nodeId, null) :: Nil)._1.copy(commit = false) sender.send(alice, cmd1) @@ -64,7 +64,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { awaitCond(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteChanges.proposed == htlc1 :: Nil) // alice sends another HTLC to bob val h2 = Crypto.sha256(r2) - val amount2 = MilliSatoshi(200000000) + val amount2 = 200000000 msat val expiry2 = CltvExpiryDelta(144).toCltvExpiry val cmd2 = PaymentLifecycle.buildCommand(UUID.randomUUID, amount2, expiry2, h2, Hop(null, TestConstants.Bob.nodeParams.nodeId, null) :: Nil)._1.copy(commit = false) sender.send(alice, cmd2) @@ -103,7 +103,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv CMD_ADD_HTLC") { f => import f._ val sender = TestProbe() - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), r1, cltvExpiry = CltvExpiry(300000), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, r1, cltvExpiry = CltvExpiry(300000), TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = ChannelUnavailable(channelId(alice)) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), None, Some(add)))) @@ -584,7 +584,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { bob.feeEstimator.setFeerate(FeeratesPerKw.single(fee.feeratePerKw)) sender.send(bob, fee) val error = bob2alice.expectMsgType[Error] - assert(new String(error.data.toArray) === CannotAffordFees(channelId(bob), missing = Satoshi(72120000L), reserve = Satoshi(20000L), fees = Satoshi(72400000L)).getMessage) + assert(new String(error.data.toArray) === CannotAffordFees(channelId(bob), missing = 72120000L sat, reserve = 20000L sat, fees = 72400000L sat).getMessage) awaitCond(bob.stateName == CLOSING) bob2blockchain.expectMsg(PublishAsap(tx)) // commit tx //bob2blockchain.expectMsgType[PublishAsap] // main delayed (removed because of the high fees) @@ -695,7 +695,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { claimHtlcTx.txOut(0).amount }).sum // htlc will timeout and be eventually refunded so we have a little less than fundingSatoshis - pushMsat = 1000000 - 200000 = 800000 (because fees) - assert(amountClaimed == Satoshi(774040)) + assert(amountClaimed === 774040.sat) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(claimTxes(0))) @@ -742,7 +742,7 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { claimHtlcTx.txOut(0).amount }).sum // htlc will timeout and be eventually refunded so we have a little less than fundingSatoshis - pushMsat - htlc1 = 1000000 - 200000 - 300 000 = 500000 (because fees) - assert(amountClaimed == Satoshi(481210)) + assert(amountClaimed === 481210.sat) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(bobCommitTx)) assert(alice2blockchain.expectMsgType[WatchConfirmed].event === BITCOIN_TX_CONFIRMED(claimTxes(0))) @@ -788,10 +788,10 @@ class ShutdownStateSpec extends TestkitBaseClass with StateTestsHelperMethods { Transaction.correctlySpends(htlc2PenaltyTx, Seq(revokedTx), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) // two main outputs are 300 000 and 200 000, htlcs are 300 000 and 200 000 - assert(mainTx.txOut(0).amount == Satoshi(284940)) - assert(mainPenaltyTx.txOut(0).amount == Satoshi(195160)) - assert(htlc1PenaltyTx.txOut(0).amount == Satoshi(194540)) - assert(htlc2PenaltyTx.txOut(0).amount == Satoshi(294540)) + assert(mainTx.txOut(0).amount === 284940.sat) + assert(mainPenaltyTx.txOut(0).amount === 195160.sat) + assert(htlc1PenaltyTx.txOut(0).amount === 194540.sat) + assert(htlc2PenaltyTx.txOut(0).amount === 294540.sat) awaitCond(alice.stateName == CLOSING) assert(alice.stateData.asInstanceOf[DATA_CLOSING].revokedCommitPublished.size == 1) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala index ee0c89eafc..ea25fabb63 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala @@ -21,7 +21,7 @@ import java.util.UUID import akka.actor.Status.Failure import akka.event.LoggingAdapter import akka.testkit.TestProbe -import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Satoshi} +import fr.acinq.bitcoin.{ByteVector32, ByteVector64} import fr.acinq.eclair.TestConstants.Bob import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw @@ -30,7 +30,7 @@ import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.payment.Local import fr.acinq.eclair.wire.{ClosingSigned, Error, Shutdown} -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, TestConstants, TestkitBaseClass} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, TestConstants, TestkitBaseClass} import org.scalatest.{Outcome, Tag} import scodec.bits.ByteVector @@ -85,7 +85,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods import f._ alice2bob.expectMsgType[ClosingSigned] val sender = TestProbe() - val add = CMD_ADD_HTLC(MilliSatoshi(5000000000L), ByteVector32(ByteVector.fill(32)(1)), cltvExpiry = CltvExpiry(300000), onion = TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(5000000000L msat, ByteVector32(ByteVector.fill(32)(1)), cltvExpiry = CltvExpiry(300000), onion = TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = ChannelUnavailable(channelId(alice)) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), None, Some(add)))) @@ -111,7 +111,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods private def testFeeConverge(f: FixtureParam) = { import f._ - var aliceCloseFee, bobCloseFee = Satoshi(0) + var aliceCloseFee, bobCloseFee = 0.sat do { aliceCloseFee = alice2bob.expectMsgType[ClosingSigned].feeSatoshis alice2bob.forward(bob) @@ -135,7 +135,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods val aliceCloseSig = alice2bob.expectMsgType[ClosingSigned] val sender = TestProbe() val tx = bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localCommit.publishableTxs.commitTx.tx - sender.send(bob, aliceCloseSig.copy(feeSatoshis = Satoshi(99000))) // sig doesn't matter, it is checked later + sender.send(bob, aliceCloseSig.copy(feeSatoshis = 99000 sat)) // sig doesn't matter, it is checked later val error = bob2alice.expectMsgType[Error] assert(new String(error.data.toArray).startsWith("invalid close fee: fee_satoshis=Satoshi(99000)")) bob2blockchain.expectMsg(PublishAsap(tx)) @@ -158,7 +158,7 @@ class NegotiatingStateSpec extends TestkitBaseClass with StateTestsHelperMethods test("recv BITCOIN_FUNDING_SPENT (counterparty's mutual close)") { f => import f._ - var aliceCloseFee, bobCloseFee = Satoshi(0) + var aliceCloseFee, bobCloseFee = 0.sat do { aliceCloseFee = alice2bob.expectMsgType[ClosingSigned].feeSatoshis alice2bob.forward(bob) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala index 4f5aa2afaf..e7362f5db7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala @@ -21,7 +21,7 @@ import java.util.UUID import akka.actor.Status import akka.actor.Status.Failure import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.{ByteVector32, OutPoint, Satoshi, ScriptFlags, Transaction, TxIn} +import fr.acinq.bitcoin.{ByteVector32, OutPoint, ScriptFlags, Transaction, TxIn} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw @@ -31,7 +31,7 @@ import fr.acinq.eclair.channel.{Data, State, _} import fr.acinq.eclair.payment._ import fr.acinq.eclair.transactions.{Scripts, Transactions} import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, TestConstants, TestkitBaseClass, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, TestConstants, TestkitBaseClass, randomBytes32} import org.scalatest.{Outcome, Tag} import scodec.bits.ByteVector @@ -86,8 +86,8 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { } else { within(30 seconds) { reachNormal(setup) - val bobCommitTxes: List[PublishableTxs] = (for (amt <- List(100000000, 200000000, 300000000)) yield { - val (r, htlc) = addHtlc(MilliSatoshi(amt), alice, bob, alice2bob, bob2alice) + val bobCommitTxes: List[PublishableTxs] = (for (amt <- List(100000000 msat, 200000000 msat, 300000000 msat)) yield { + val (r, htlc) = addHtlc(amt, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) relayerB.expectMsgType[ForwardAdd] val bobCommitTx1 = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs @@ -122,7 +122,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { bob2alice.expectMsgType[Shutdown] bob2alice.forward(alice) // agreeing on a closing fee - var aliceCloseFee, bobCloseFee = Satoshi(0) + var aliceCloseFee, bobCloseFee = 0.sat do { aliceCloseFee = alice2bob.expectMsgType[ClosingSigned].feeSatoshis alice2bob.forward(bob) @@ -299,7 +299,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { // actual test starts here val sender = TestProbe() - val add = CMD_ADD_HTLC(MilliSatoshi(500000000), ByteVector32(ByteVector.fill(32)(1)), cltvExpiry = CltvExpiry(300000), onion = TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) + val add = CMD_ADD_HTLC(500000000 msat, ByteVector32(ByteVector.fill(32)(1)), cltvExpiry = CltvExpiry(300000), onion = TestConstants.emptyOnionPacket, upstream = Left(UUID.randomUUID())) sender.send(alice, add) val error = ChannelUnavailable(channelId(alice)) sender.expectMsg(Failure(AddHtlcFailed(channelId(alice), add.paymentHash, error, Local(add.upstream.left.get, Some(sender.ref)), None, Some(add)))) @@ -378,7 +378,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { test("recv BITCOIN_OUTPUT_SPENT") { f => import f._ // alice sends an htlc to bob - val (ra1, htlca1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (ra1, htlca1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) relayerB.expectMsgType[ForwardAdd] // an error occurs and alice publishes her commit tx @@ -418,7 +418,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { system.eventStream.subscribe(listener.ref, classOf[LocalCommitConfirmed]) system.eventStream.subscribe(listener.ref, classOf[PaymentSettlingOnChain]) // alice sends an htlc to bob - val (ra1, htlca1) = addHtlc(MilliSatoshi(50000000), alice, bob, alice2bob, bob2alice) + val (ra1, htlca1) = addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) // an error occurs and alice publishes her commit tx val aliceCommitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx @@ -452,7 +452,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { system.eventStream.subscribe(listener.ref, classOf[PaymentSettlingOnChain]) val aliceCommitTx = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx // alice sends an htlc - val (r, htlc) = addHtlc(MilliSatoshi(4200000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(4200000 msat, alice, bob, alice2bob, bob2alice) // and signs it (but bob doesn't sign it) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -483,7 +483,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { system.eventStream.subscribe(listener.ref, classOf[PaymentSettlingOnChain]) val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.publishableTxs.commitTx.tx // alice sends an htlc - val (r, htlc) = addHtlc(MilliSatoshi(4200000), alice, bob, alice2bob, bob2alice) + val (r, htlc) = addHtlc(4200000 msat, alice, bob, alice2bob, bob2alice) // and signs it (but bob doesn't sign it) sender.send(alice, CMD_SIGN) sender.expectMsg("ok") @@ -544,7 +544,7 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods { import f._ val sender = TestProbe() val oldStateData = alice.stateData - val (ra1, htlca1) = addHtlc(MilliSatoshi(25000000), alice, bob, alice2bob, bob2alice) + val (ra1, htlca1) = addHtlc(25000000 msat, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) fulfillHtlc(htlca1.id, ra1, bob, alice, bob2alice, alice2bob) crossSign(bob, alice, bob2alice, alice2bob) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteAuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteAuditDbSpec.scala index 8892bf3adc..49dd366358 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteAuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteAuditDbSpec.scala @@ -18,18 +18,18 @@ package fr.acinq.eclair.db import java.util.UUID -import fr.acinq.bitcoin.{Satoshi, Transaction} +import fr.acinq.bitcoin.Transaction +import fr.acinq.eclair._ import fr.acinq.eclair.channel.Channel.{LocalError, RemoteError} import fr.acinq.eclair.channel.{AvailableBalanceChanged, ChannelErrorOccured, NetworkFeePaid} import fr.acinq.eclair.db.sqlite.SqliteAuditDb import fr.acinq.eclair.db.sqlite.SqliteUtils.{getVersion, using} -import fr.acinq.eclair.wire.{ChannelCodecs, ChannelCodecsSpec} -import fr.acinq.eclair._ import fr.acinq.eclair.payment.{PaymentReceived, PaymentRelayed, PaymentSent} +import fr.acinq.eclair.wire.{ChannelCodecs, ChannelCodecsSpec} import org.scalatest.FunSuite -import concurrent.duration._ import scala.compat.Platform +import scala.concurrent.duration._ class SqliteAuditDbSpec extends FunSuite { @@ -44,14 +44,14 @@ class SqliteAuditDbSpec extends FunSuite { val sqlite = TestConstants.sqliteInMemory() val db = new SqliteAuditDb(sqlite) - val e1 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, MilliSatoshi(42000), MilliSatoshi(1000), randomBytes32, randomBytes32, randomBytes32) - val e2 = PaymentReceived(MilliSatoshi(42000), randomBytes32, randomBytes32) - val e3 = PaymentRelayed(MilliSatoshi(42000), MilliSatoshi(1000), randomBytes32, randomBytes32, randomBytes32) - 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), MilliSatoshi(456123000), ChannelCodecsSpec.commitments) - val e8 = ChannelLifecycleEvent(randomBytes32, randomKey.publicKey, Satoshi(456123000), true, false, "mutual") + val e1 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, 42000 msat, 1000 msat, randomBytes32, randomBytes32, randomBytes32) + val e2 = PaymentReceived(42000 msat, randomBytes32, randomBytes32) + val e3 = PaymentRelayed(42000 msat, 1000 msat, randomBytes32, randomBytes32, randomBytes32) + val e4 = NetworkFeePaid(null, randomKey.publicKey, randomBytes32, Transaction(0, Seq.empty, Seq.empty, 0), 42 sat, "mutual") + val e5 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, 42000 msat, 1000 msat, randomBytes32, randomBytes32, randomBytes32, timestamp = 0) + val e6 = PaymentSent(ChannelCodecs.UNKNOWN_UUID, 42000 msat, 1000 msat, randomBytes32, randomBytes32, randomBytes32, timestamp = (Platform.currentTime.milliseconds + 10.minutes).toMillis) + val e7 = AvailableBalanceChanged(null, randomBytes32, ShortChannelId(500000, 42, 1), 456123000 msat, ChannelCodecsSpec.commitments) + val e8 = ChannelLifecycleEvent(randomBytes32, randomKey.publicKey, 456123000 sat, 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) @@ -86,20 +86,20 @@ class SqliteAuditDbSpec extends FunSuite { val c2 = randomBytes32 val c3 = randomBytes32 - db.add(PaymentRelayed(MilliSatoshi(46000), MilliSatoshi(44000), randomBytes32, randomBytes32, c1)) - db.add(PaymentRelayed(MilliSatoshi(41000), MilliSatoshi(40000), randomBytes32, randomBytes32, c1)) - db.add(PaymentRelayed(MilliSatoshi(43000), MilliSatoshi(42000), randomBytes32, randomBytes32, c1)) - db.add(PaymentRelayed(MilliSatoshi(42000), MilliSatoshi(40000), randomBytes32, randomBytes32, c2)) + db.add(PaymentRelayed(46000 msat, 44000 msat, randomBytes32, randomBytes32, c1)) + db.add(PaymentRelayed(41000 msat, 40000 msat, randomBytes32, randomBytes32, c1)) + db.add(PaymentRelayed(43000 msat, 42000 msat, randomBytes32, randomBytes32, c1)) + db.add(PaymentRelayed(42000 msat, 40000 msat, randomBytes32, randomBytes32, c2)) - db.add(NetworkFeePaid(null, n1, c1, Transaction(0, Seq.empty, Seq.empty, 0), Satoshi(100), "funding")) - db.add(NetworkFeePaid(null, n2, c2, Transaction(0, Seq.empty, Seq.empty, 0), Satoshi(200), "funding")) - db.add(NetworkFeePaid(null, n2, c2, Transaction(0, Seq.empty, Seq.empty, 0), Satoshi(300), "mutual")) - db.add(NetworkFeePaid(null, n3, c3, Transaction(0, Seq.empty, Seq.empty, 0), Satoshi(400), "funding")) + db.add(NetworkFeePaid(null, n1, c1, Transaction(0, Seq.empty, Seq.empty, 0), 100 sat, "funding")) + db.add(NetworkFeePaid(null, n2, c2, Transaction(0, Seq.empty, Seq.empty, 0), 200 sat, "funding")) + db.add(NetworkFeePaid(null, n2, c2, Transaction(0, Seq.empty, Seq.empty, 0), 300 sat, "mutual")) + db.add(NetworkFeePaid(null, n3, c3, Transaction(0, Seq.empty, Seq.empty, 0), 400 sat, "funding")) assert(db.stats.toSet === Set( - Stats(channelId = c1, avgPaymentAmount = Satoshi(42), paymentCount = 3, relayFee = Satoshi(4), networkFee = Satoshi(100)), - Stats(channelId = c2, avgPaymentAmount = Satoshi(40), paymentCount = 1, relayFee = Satoshi(2), networkFee = Satoshi(500)), - Stats(channelId = c3, avgPaymentAmount = Satoshi(0), paymentCount = 0, relayFee = Satoshi(0), networkFee = Satoshi(400)) + Stats(channelId = c1, avgPaymentAmount = 42 sat, paymentCount = 3, relayFee = 4 sat, networkFee = 100 sat), + Stats(channelId = c2, avgPaymentAmount = 40 sat, paymentCount = 1, relayFee = 2 sat, networkFee = 500 sat), + Stats(channelId = c3, avgPaymentAmount = 0 sat, paymentCount = 0, relayFee = 0 sat, networkFee = 400 sat) )) } @@ -129,9 +129,9 @@ class SqliteAuditDbSpec extends FunSuite { assert(getVersion(statement, "audit", 3) == 1) // we expect version 1 } - val ps = PaymentSent(UUID.randomUUID(), MilliSatoshi(42000), MilliSatoshi(1000), randomBytes32, randomBytes32, randomBytes32) - val ps1 = PaymentSent(UUID.randomUUID(), MilliSatoshi(42001), MilliSatoshi(1001), randomBytes32, randomBytes32, randomBytes32) - val ps2 = PaymentSent(UUID.randomUUID(), MilliSatoshi(42002), MilliSatoshi(1002), randomBytes32, randomBytes32, randomBytes32) + val ps = PaymentSent(UUID.randomUUID(), 42000 msat, 1000 msat, randomBytes32, randomBytes32, randomBytes32) + val ps1 = PaymentSent(UUID.randomUUID(), 42001 msat, 1001 msat, randomBytes32, randomBytes32, randomBytes32) + val ps2 = PaymentSent(UUID.randomUUID(), 42002 msat, 1002 msat, randomBytes32, randomBytes32, randomBytes32) val e1 = ChannelErrorOccured(null, randomBytes32, randomKey.publicKey, null, LocalError(new RuntimeException("oops")), true) val e2 = ChannelErrorOccured(null, randomBytes32, randomKey.publicKey, null, RemoteError(wire.Error(randomBytes32, "remote oops")), true) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteNetworkDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteNetworkDbSpec.scala index f326d3eb89..037032fb27 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteNetworkDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqliteNetworkDbSpec.scala @@ -20,11 +20,10 @@ import fr.acinq.bitcoin.{Block, Crypto, Satoshi} import fr.acinq.eclair.db.sqlite.SqliteNetworkDb import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire.{Color, NodeAddress, Tor2} -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, ShortChannelId, TestConstants, randomBytes32, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, TestConstants, randomBytes32, randomKey} import org.scalatest.FunSuite import org.sqlite.SQLiteException - class SqliteNetworkDbSpec extends FunSuite { val shortChannelIds = (42 to (5000 + 42)).map(i => ShortChannelId(i)) @@ -73,7 +72,7 @@ class SqliteNetworkDbSpec extends FunSuite { val txid_1 = randomBytes32 val txid_2 = randomBytes32 val txid_3 = randomBytes32 - val capacity = Satoshi(10000) + val capacity = 10000 sat assert(db.listChannels().toSet === Set.empty) db.addChannel(channel_1, txid_1, capacity) @@ -85,9 +84,9 @@ class SqliteNetworkDbSpec extends FunSuite { db.removeChannel(channel_2.shortChannelId) assert(db.listChannels().toSet === Set((channel_1, (txid_1, capacity)), (channel_3, (txid_3, capacity)))) - val channel_update_1 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(42), CltvExpiryDelta(5), MilliSatoshi(7000000), MilliSatoshi(50000), 100, MilliSatoshi(500000000L), true) - val channel_update_2 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(43), CltvExpiryDelta(5), MilliSatoshi(7000000), MilliSatoshi(50000), 100, MilliSatoshi(500000000L), true) - val channel_update_3 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(44), CltvExpiryDelta(5), MilliSatoshi(7000000), MilliSatoshi(50000), 100, MilliSatoshi(500000000L), true) + val channel_update_1 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) + val channel_update_2 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(43), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) + val channel_update_3 = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, ShortChannelId(44), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) assert(db.listChannelUpdates().toSet === Set.empty) db.addChannelUpdate(channel_update_1) @@ -107,10 +106,10 @@ class SqliteNetworkDbSpec extends FunSuite { val sig = Crypto.sign(randomBytes32, randomKey) val priv = randomKey val pub = priv.publicKey - val capacity = Satoshi(10000) + val capacity = 10000 sat val channels = shortChannelIds.map(id => Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, id, pub, pub, pub, pub, sig, sig, sig, sig)) - val template = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv, pub, ShortChannelId(42), CltvExpiryDelta(5), MilliSatoshi(7000000), MilliSatoshi(50000), 100, MilliSatoshi(500000000L), true) + val template = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv, pub, ShortChannelId(42), CltvExpiryDelta(5), 7000000 msat, 50000 msat, 100, 500000000L msat, true) val updates = shortChannelIds.map(id => template.copy(shortChannelId = id)) val txid = randomBytes32 channels.foreach(ca => db.addChannel(ca, txid, capacity)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqlitePaymentsDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqlitePaymentsDbSpec.scala index 86abf94cf0..ed8993cc77 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/SqlitePaymentsDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/SqlitePaymentsDbSpec.scala @@ -18,19 +18,18 @@ package fr.acinq.eclair.db import java.util.UUID -import fr.acinq.eclair.db.sqlite.SqliteUtils._ import fr.acinq.bitcoin.{Block, ByteVector32} import fr.acinq.eclair.TestConstants.Bob -import fr.acinq.eclair.{MilliSatoshi, TestConstants, payment, randomBytes32} +import fr.acinq.eclair.db.OutgoingPaymentStatus._ import fr.acinq.eclair.db.sqlite.SqlitePaymentsDb +import fr.acinq.eclair.db.sqlite.SqliteUtils._ import fr.acinq.eclair.payment.PaymentRequest +import fr.acinq.eclair.{LongToBtcAmount, TestConstants, randomBytes32} import org.scalatest.FunSuite import scodec.bits._ import scala.compat.Platform -import OutgoingPaymentStatus._ - -import concurrent.duration._ +import scala.concurrent.duration._ class SqlitePaymentsDbSpec extends FunSuite { @@ -53,7 +52,7 @@ class SqlitePaymentsDbSpec extends FunSuite { assert(getVersion(statement, "payments", 1) == 1) // version 1 is deployed now } - val oldReceivedPayment = IncomingPayment(ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), MilliSatoshi(123), 1233322) + val oldReceivedPayment = IncomingPayment(ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), 123 msat, 1233322) // insert old type record using(connection.prepareStatement("INSERT INTO payments VALUES (?, ?, ?)")) { statement => @@ -73,9 +72,9 @@ class SqlitePaymentsDbSpec extends FunSuite { assert(preMigrationDb.getIncomingPayment(oldReceivedPayment.paymentHash).isEmpty) // add a few rows - val ps1 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), None, amount = MilliSatoshi(12345), createdAt = 12345, None, PENDING) + val ps1 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), None, amount = 12345 msat, createdAt = 12345, None, PENDING) val i1 = PaymentRequest.read("lnbc10u1pw2t4phpp5ezwm2gdccydhnphfyepklc0wjkxhz0r4tctg9paunh2lxgeqhcmsdqlxycrqvpqwdshgueqvfjhggr0dcsry7qcqzpgfa4ecv7447p9t5hkujy9qgrxvkkf396p9zar9p87rv2htmeuunkhydl40r64n5s2k0u7uelzc8twxmp37nkcch6m0wg5tvvx69yjz8qpk94qf3") - val pr1 = IncomingPayment(i1.paymentHash, MilliSatoshi(12345678), 1513871928275L) + val pr1 = IncomingPayment(i1.paymentHash, 12345678 msat, 1513871928275L) preMigrationDb.addPaymentRequest(i1, ByteVector32.Zeroes) preMigrationDb.addIncomingPayment(pr1) @@ -101,7 +100,7 @@ class SqlitePaymentsDbSpec extends FunSuite { val db = new SqlitePaymentsDb(sqlite) // can't receive a payment without an invoice associated with it - assertThrows[IllegalArgumentException](db.addIncomingPayment(IncomingPayment(ByteVector32(hex"6e7e8018f05e169cf1d99e77dc22cb372d09f10b6a81f1eae410718c56cad188"), MilliSatoshi(12345678), 1513871928275L))) + assertThrows[IllegalArgumentException](db.addIncomingPayment(IncomingPayment(ByteVector32(hex"6e7e8018f05e169cf1d99e77dc22cb372d09f10b6a81f1eae410718c56cad188"), 12345678 msat, 1513871928275L))) val i1 = PaymentRequest.read("lnbc5450n1pw2t4qdpp5vcrf6ylgpettyng4ac3vujsk0zpc25cj0q3zp7l7w44zvxmpzh8qdzz2pshjmt9de6zqen0wgsr2dp4ypcxj7r9d3ejqct5ypekzar0wd5xjuewwpkxzcm99cxqzjccqp2rzjqtspxelp67qc5l56p6999wkatsexzhs826xmupyhk6j8lxl038t27z9tsqqqgpgqqqqqqqlgqqqqqzsqpcz8z8hmy8g3ecunle4n3edn3zg2rly8g4klsk5md736vaqqy3ktxs30ht34rkfkqaffzxmjphvd0637dk2lp6skah2hq09z6lrjna3xqp3d4vyd") val i2 = PaymentRequest.read("lnbc10u1pw2t4phpp5ezwm2gdccydhnphfyepklc0wjkxhz0r4tctg9paunh2lxgeqhcmsdqlxycrqvpqwdshgueqvfjhggr0dcsry7qcqzpgfa4ecv7447p9t5hkujy9qgrxvkkf396p9zar9p87rv2htmeuunkhydl40r64n5s2k0u7uelzc8twxmp37nkcch6m0wg5tvvx69yjz8qpk94qf3") @@ -109,8 +108,8 @@ class SqlitePaymentsDbSpec extends FunSuite { db.addPaymentRequest(i1, ByteVector32.Zeroes) db.addPaymentRequest(i2, ByteVector32.Zeroes) - val p1 = IncomingPayment(i1.paymentHash, MilliSatoshi(12345678), 1513871928275L) - val p2 = IncomingPayment(i2.paymentHash, MilliSatoshi(12345678), 1513871928275L) + val p1 = IncomingPayment(i1.paymentHash, 12345678 msat, 1513871928275L) + val p2 = IncomingPayment(i2.paymentHash, 12345678 msat, 1513871928275L) assert(db.listIncomingPayments() === Nil) db.addIncomingPayment(p1) db.addIncomingPayment(p2) @@ -123,8 +122,8 @@ class SqlitePaymentsDbSpec extends FunSuite { val db = new SqlitePaymentsDb(TestConstants.sqliteInMemory()) - val s1 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), None, amount = MilliSatoshi(12345), createdAt = 12345, None, PENDING) - val s2 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"08d47d5f7164d4b696e8f6b62a03094d4f1c65f16e9d7b11c4a98854707e55cf"), None, amount = MilliSatoshi(12345), createdAt = 12345, None, PENDING) + val s1 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"0f059ef9b55bb70cc09069ee4df854bf0fab650eee6f2b87ba26d1ad08ab114f"), None, amount = 12345 msat, createdAt = 12345, None, PENDING) + val s2 = OutgoingPayment(id = UUID.randomUUID(), paymentHash = ByteVector32(hex"08d47d5f7164d4b696e8f6b62a03094d4f1c65f16e9d7b11c4a98854707e55cf"), None, amount = 12345 msat, createdAt = 12345, None, PENDING) assert(db.listOutgoingPayments().isEmpty) db.addOutgoingPayment(s1) @@ -137,7 +136,7 @@ class SqlitePaymentsDbSpec extends FunSuite { assert(db.getOutgoingPayments(s2.paymentHash) === Seq(s2)) assert(db.getOutgoingPayments(ByteVector32.Zeroes) === Seq.empty) - val s3 = s2.copy(id = UUID.randomUUID(), amount = MilliSatoshi(88776655)) + val s3 = s2.copy(id = UUID.randomUUID(), amount = 88776655 msat) db.addOutgoingPayment(s3) db.updateOutgoingPayment(s3.id, FAILED) @@ -162,7 +161,7 @@ class SqlitePaymentsDbSpec extends FunSuite { val (paymentHash1, paymentHash2) = (randomBytes32, randomBytes32) - val i1 = PaymentRequest(chainHash = Block.TestnetGenesisBlock.hash, amount = Some(MilliSatoshi(123)), paymentHash = paymentHash1, privateKey = bob.nodeKey.privateKey, description = "Some invoice", expirySeconds = None, timestamp = someTimestamp) + val i1 = PaymentRequest(chainHash = Block.TestnetGenesisBlock.hash, amount = Some(123 msat), paymentHash = paymentHash1, privateKey = bob.nodeKey.privateKey, description = "Some invoice", expirySeconds = None, timestamp = someTimestamp) val i2 = PaymentRequest(chainHash = Block.TestnetGenesisBlock.hash, amount = None, paymentHash = paymentHash2, privateKey = bob.nodeKey.privateKey, description = "Some invoice", expirySeconds = Some(123456), timestamp = Platform.currentTime.milliseconds.toSeconds) // i2 doesn't expire diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala index fda650db0d..ef6993b0a5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala @@ -31,10 +31,9 @@ import fr.acinq.eclair.blockchain.{Watch, WatchConfirmed} import fr.acinq.eclair.channel.Channel.{BroadcastChannelUpdate, PeriodicRefresh} import fr.acinq.eclair.channel.Register.{Forward, ForwardShortId} import fr.acinq.eclair.channel._ -import fr.acinq.eclair._ import fr.acinq.eclair.crypto.Sphinx.DecryptedFailurePacket +import fr.acinq.eclair.io.Peer import fr.acinq.eclair.io.Peer.{Disconnect, PeerRoutingMessage} -import fr.acinq.eclair.io.{NodeURI, Peer} import fr.acinq.eclair.payment.PaymentLifecycle.{State => _, _} import fr.acinq.eclair.payment.{LocalPaymentHandler, PaymentRequest} import fr.acinq.eclair.router.Graph.WeightRatios @@ -43,7 +42,7 @@ import fr.acinq.eclair.router.{Announcements, AnnouncementsBatchValidationSpec, import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.transactions.Transactions.{HtlcSuccessTx, HtlcTimeoutTx} import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{Globals, Kit, Setup, randomBytes32} +import fr.acinq.eclair.{Globals, Kit, Setup, randomBytes32, _} import grizzled.slf4j.Logging import org.json4s.JsonAST.JValue import org.json4s.{DefaultFormats, JString} @@ -56,8 +55,8 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ /** - * Created by PM on 15/03/2017. - */ + * Created by PM on 15/03/2017. + */ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService with FunSuiteLike with BeforeAndAfterAll with Logging { @@ -157,7 +156,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService nodes("C").paymentHandler ! paymentHandlerC } - def connect(node1: Kit, node2: Kit, fundingSatoshis: Long, pushMsat: Long) = { + def connect(node1: Kit, node2: Kit, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi) = { val sender = TestProbe() val address = node2.nodeParams.publicAddresses.head sender.send(node1.switchboard, Peer.Connect( @@ -167,8 +166,8 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService sender.expectMsgAnyOf(10 seconds, "connected", "already connected") sender.send(node1.switchboard, Peer.OpenChannel( remoteNodeId = node2.nodeParams.nodeId, - fundingSatoshis = Satoshi(fundingSatoshis), - pushMsat = MilliSatoshi(pushMsat), + fundingSatoshis = fundingSatoshis, + pushMsat = pushMsat, fundingTxFeeratePerKw_opt = None, channelFlags = None, timeout_opt = None)) @@ -186,19 +185,19 @@ 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"), 11000000, 0) - connect(nodes("B"), nodes("C"), 2000000, 0) - connect(nodes("C"), nodes("D"), 5000000, 0) - connect(nodes("C"), nodes("D"), 5000000, 0) - connect(nodes("B"), nodes("E"), 10000000, 0) - connect(nodes("E"), nodes("C"), 10000000, 0) - connect(nodes("C"), nodes("F1"), 5000000, 0) - connect(nodes("C"), nodes("F2"), 5000000, 0) - 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) + connect(nodes("A"), nodes("B"), 11000000 sat, 0 msat) + connect(nodes("B"), nodes("C"), 2000000 sat, 0 msat) + connect(nodes("C"), nodes("D"), 5000000 sat, 0 msat) + connect(nodes("C"), nodes("D"), 5000000 sat, 0 msat) + connect(nodes("B"), nodes("E"), 10000000 sat, 0 msat) + connect(nodes("E"), nodes("C"), 10000000 sat, 0 msat) + connect(nodes("C"), nodes("F1"), 5000000 sat, 0 msat) + connect(nodes("C"), nodes("F2"), 5000000 sat, 0 msat) + connect(nodes("C"), nodes("F3"), 5000000 sat, 0 msat) + connect(nodes("C"), nodes("F4"), 5000000 sat, 0 msat) + connect(nodes("C"), nodes("F5"), 5000000 sat, 0 msat) + connect(nodes("B"), nodes("G"), 16000000 sat, 0 msat) + connect(nodes("G"), nodes("C"), 16000000 sat, 0 msat) val numberOfChannels = 13 val channelEndpointsCount = 2 * numberOfChannels @@ -258,7 +257,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService test("send an HTLC A->D") { val sender = TestProbe() - val amountMsat = MilliSatoshi(4200000) + val amountMsat = 4200000.msat // first we retrieve a payment hash from D sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] @@ -280,11 +279,11 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService sender.send(nodes("B").register, ForwardShortId(shortIdBC, CMD_GETINFO)) val commitmentBC = sender.expectMsgType[RES_GETINFO].data.asInstanceOf[DATA_NORMAL].commitments // we then forge a new channel_update for B-C... - val channelUpdateBC = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, nodes("B").nodeParams.privateKey, nodes("C").nodeParams.nodeId, shortIdBC, nodes("B").nodeParams.expiryDeltaBlocks + 1, nodes("C").nodeParams.htlcMinimum, nodes("B").nodeParams.feeBase, nodes("B").nodeParams.feeProportionalMillionth, MilliSatoshi(500000000L)) + val channelUpdateBC = Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, nodes("B").nodeParams.privateKey, nodes("C").nodeParams.nodeId, shortIdBC, nodes("B").nodeParams.expiryDeltaBlocks + 1, nodes("C").nodeParams.htlcMinimum, nodes("B").nodeParams.feeBase, nodes("B").nodeParams.feeProportionalMillionth, 500000000 msat) // ...and notify B's relayer sender.send(nodes("B").relayer, LocalChannelUpdate(system.deadLetters, commitmentBC.channelId, shortIdBC, commitmentBC.remoteParams.nodeId, None, channelUpdateBC, commitmentBC)) // we retrieve a payment hash from D - val amountMsat = MilliSatoshi(4200000) + val amountMsat = 4200000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] // then we make the actual payment, do not randomize the route to make sure we route through node B @@ -322,7 +321,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService test("send an HTLC A->D with an amount greater than capacity of B-C") { val sender = TestProbe() // first we retrieve a payment hash from D - val amountMsat = MilliSatoshi(300000000L) + val amountMsat = 300000000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] // then we make the payment (B-C has a smaller capacity than A-B and C-D) @@ -335,7 +334,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService test("send an HTLC A->D with an unknown payment hash") { val sender = TestProbe() - val pr = SendPayment(MilliSatoshi(100000000L), randomBytes32, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) + val pr = SendPayment(100000000 msat, randomBytes32, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) sender.send(nodes("A").paymentInitiator, pr) // A will receive an error from D and won't retry @@ -344,18 +343,18 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(MilliSatoshi(100000000L)))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat))) } test("send an HTLC A->D with a lower amount than requested") { val sender = TestProbe() // first we retrieve a payment hash from D for 2 mBTC - val amountMsat = MilliSatoshi(200000000L) + val amountMsat = 200000000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] // A send payment of only 1 mBTC - val sendReq = SendPayment(MilliSatoshi(100000000L), pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) + val sendReq = SendPayment(100000000 msat, pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) sender.send(nodes("A").paymentInitiator, sendReq) // A will first receive an IncorrectPaymentAmount error from D @@ -364,18 +363,18 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(failed.id == paymentId) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(MilliSatoshi(100000000L)))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(100000000 msat))) } test("send an HTLC A->D with too much overpayment") { val sender = TestProbe() // first we retrieve a payment hash from D for 2 mBTC - val amountMsat = MilliSatoshi(200000000L) + val amountMsat = 200000000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] // A send payment of 6 mBTC - val sendReq = SendPayment(MilliSatoshi(600000000L), pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) + val sendReq = SendPayment(600000000 msat, pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) sender.send(nodes("A").paymentInitiator, sendReq) // A will first receive an IncorrectPaymentAmount error from D @@ -384,18 +383,18 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService assert(paymentId == failed.id) assert(failed.paymentHash === pr.paymentHash) assert(failed.failures.size === 1) - assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(MilliSatoshi(600000000L)))) + assert(failed.failures.head.asInstanceOf[RemoteFailure].e === DecryptedFailurePacket(nodes("D").nodeParams.nodeId, IncorrectOrUnknownPaymentDetails(600000000 msat))) } test("send an HTLC A->D with a reasonable overpayment") { val sender = TestProbe() // first we retrieve a payment hash from D for 2 mBTC - val amountMsat = MilliSatoshi(200000000L) + val amountMsat = 200000000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] // A send payment of 3 mBTC, more than asked but it should still be accepted - val sendReq = SendPayment(MilliSatoshi(300000000L), pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) + val sendReq = SendPayment(300000000 msat, pr.paymentHash, nodes("D").nodeParams.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 5) sender.send(nodes("A").paymentInitiator, sendReq) sender.expectMsgType[UUID] } @@ -404,7 +403,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val sender = TestProbe() // there are two C-D channels with 5000000 sat, so we should be able to make 7 payments worth 1000000 sat each for (_ <- 0 until 7) { - val amountMsat = MilliSatoshi(1000000000L) + val amountMsat = 1000000000.msat sender.send(nodes("D").paymentHandler, ReceivePayment(Some(amountMsat), "1 payment")) val pr = sender.expectMsgType[PaymentRequest] @@ -418,7 +417,7 @@ 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() // first we retrieve a payment hash from C - val amountMsat = MilliSatoshi(2000) + val amountMsat = 2000.msat sender.send(nodes("C").paymentHandler, ReceivePayment(Some(amountMsat), "Change from coffee")) val pr = sender.expectMsgType[PaymentRequest](30 seconds) @@ -437,11 +436,11 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService /** - * We currently use p2pkh script Helpers.getFinalScriptPubKey - * - * @param scriptPubKey - * @return - */ + * We currently use p2pkh script Helpers.getFinalScriptPubKey + * + * @param scriptPubKey + * @return + */ def scriptPubKeyToAddress(scriptPubKey: ByteVector) = Script.parse(scriptPubKey) match { case OP_DUP :: OP_HASH160 :: OP_PUSHDATA(pubKeyHash, _) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil => Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pubKeyHash) @@ -468,7 +467,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val preimage = randomBytes32 val paymentHash = Crypto.sha256(preimage) // A sends a payment to F - val paymentReq = SendPayment(MilliSatoshi(100000000L), paymentHash, nodes("F1").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) + val paymentReq = SendPayment(100000000 msat, paymentHash, nodes("F1").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) val paymentSender = TestProbe() paymentSender.send(nodes("A").paymentInitiator, paymentReq) paymentSender.expectMsgType[UUID](30 seconds) @@ -548,7 +547,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val preimage = randomBytes32 val paymentHash = Crypto.sha256(preimage) // A sends a payment to F - val paymentReq = SendPayment(MilliSatoshi(100000000L), paymentHash, nodes("F2").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) + val paymentReq = SendPayment(100000000 msat, paymentHash, nodes("F2").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) val paymentSender = TestProbe() paymentSender.send(nodes("A").paymentInitiator, paymentReq) paymentSender.expectMsgType[UUID](30 seconds) @@ -625,7 +624,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val preimage: ByteVector = randomBytes32 val paymentHash = Crypto.sha256(preimage) // A sends a payment to F - val paymentReq = SendPayment(MilliSatoshi(100000000L), paymentHash, nodes("F3").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) + val paymentReq = SendPayment(100000000 msat, paymentHash, nodes("F3").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) val paymentSender = TestProbe() paymentSender.send(nodes("A").paymentInitiator, paymentReq) val paymentId = paymentSender.expectMsgType[UUID] @@ -687,7 +686,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val preimage: ByteVector = randomBytes32 val paymentHash = Crypto.sha256(preimage) // A sends a payment to F - val paymentReq = SendPayment(MilliSatoshi(100000000L), paymentHash, nodes("F4").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) + val paymentReq = SendPayment(100000000 msat, paymentHash, nodes("F4").nodeParams.nodeId, maxAttempts = 1, routeParams = integrationTestRouteParams) val paymentSender = TestProbe() paymentSender.send(nodes("A").paymentInitiator, paymentReq) val paymentId = paymentSender.expectMsgType[UUID](30 seconds) @@ -758,10 +757,10 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService val currentBlockCount = sender.expectMsgType[JValue](10 seconds).extract[Long] awaitCond(Globals.blockCount.get() == currentBlockCount, max = 20 seconds, interval = 1 second) // first we send 3 mBTC to F so that it has a balance - val amountMsat = MilliSatoshi(300000000L) + val amountMsat = 300000000.msat sender.send(paymentHandlerF, ReceivePayment(Some(amountMsat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] - val sendReq = SendPayment(MilliSatoshi(300000000L), pr.paymentHash, pr.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 1) + val sendReq = SendPayment(300000000 msat, pr.paymentHash, pr.nodeId, routeParams = integrationTestRouteParams, maxAttempts = 1) sender.send(nodes("A").paymentInitiator, sendReq) val paymentId = sender.expectMsgType[UUID] // we forward the htlc to the payment handler @@ -781,19 +780,19 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with BitcoindService } val buffer = TestProbe() - send(MilliSatoshi(100000000), paymentHandlerF, nodes("C").paymentInitiator) // will be left pending + send(100000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending forwardHandlerF.expectMsgType[UpdateAddHtlc] forwardHandlerF.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] - send(MilliSatoshi(110000000), paymentHandlerF, nodes("C").paymentInitiator) // will be left pending + send(110000000 msat, paymentHandlerF, nodes("C").paymentInitiator) // will be left pending forwardHandlerF.expectMsgType[UpdateAddHtlc] forwardHandlerF.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] - send(MilliSatoshi(120000000), paymentHandlerC, nodes("F5").paymentInitiator) + send(120000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) forwardHandlerC.expectMsgType[UpdateAddHtlc] forwardHandlerC.forward(buffer.ref) sigListener.expectMsgType[ChannelSignatureReceived] - send(MilliSatoshi(130000000), paymentHandlerC, nodes("F5").paymentInitiator) + send(130000000 msat, paymentHandlerC, nodes("F5").paymentInitiator) forwardHandlerC.expectMsgType[UpdateAddHtlc] forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index 9a0fbfde08..4a36b17faa 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -28,7 +28,7 @@ import fr.acinq.eclair.blockchain.fee.FeeratesPerKw import fr.acinq.eclair.channel._ import fr.acinq.eclair.payment.NoopPaymentHandler import fr.acinq.eclair.wire.Init -import fr.acinq.eclair.{Globals, MilliSatoshi, TestUtils} +import fr.acinq.eclair.{Globals, LongToBtcAmount, TestUtils} import org.scalatest.{BeforeAndAfterAll, Matchers, Outcome, fixture} import scala.concurrent.duration._ @@ -60,7 +60,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix val bobInit = Init(Bob.channelParams.globalFeatures, Bob.channelParams.localFeatures) // alice and bob will both have 1 000 000 sat feeEstimator.setFeerate(FeeratesPerKw.single(10000)) - alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, Satoshi(2000000), MilliSatoshi(1000000000), feeEstimator.getFeeratePerKw(target = 2), feeEstimator.getFeeratePerKw(target = 6), Alice.channelParams, pipe, bobInit, ChannelFlags.Empty) + alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, 2000000 sat, 1000000000 msat, feeEstimator.getFeeratePerKw(target = 2), feeEstimator.getFeeratePerKw(target = 6), Alice.channelParams, pipe, bobInit, ChannelFlags.Empty) bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, pipe, aliceInit) pipe ! (alice, bob) within(30 seconds) { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/HtlcReaperSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/HtlcReaperSpec.scala index 021c4048a2..3094c7db5d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/HtlcReaperSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/HtlcReaperSpec.scala @@ -20,7 +20,7 @@ import akka.actor.{ActorSystem, Props} import akka.testkit.{TestKit, TestProbe} import fr.acinq.eclair.channel._ import fr.acinq.eclair.wire.{ChannelCodecsSpec, TemporaryNodeFailure, UpdateAddHtlc} -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, TestConstants, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, TestConstants, randomBytes32} import org.scalatest.FunSuiteLike import scala.concurrent.duration._ @@ -36,11 +36,11 @@ class HtlcReaperSpec extends TestKit(ActorSystem("test")) with FunSuiteLike { 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, MilliSatoshi(20000), randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) - val add1 = UpdateAddHtlc(data.channelId, 1, MilliSatoshi(30000), randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) + val add0 = UpdateAddHtlc(data.channelId, 0, 20000 msat, randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) + val add1 = UpdateAddHtlc(data.channelId, 1, 30000 msat, randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) // unrelated htlc - val add99 = UpdateAddHtlc(randomBytes32, 0, MilliSatoshi(12345678), randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) + val add99 = UpdateAddHtlc(randomBytes32, 0, 12345678 msat, randomBytes32, CltvExpiry(100), TestConstants.emptyOnionPacket) val brokenHtlcs = Seq(add0, add1, add99) val brokenHtlcKiller = system.actorOf(Props[HtlcReaper], name = "htlc-reaper") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala index d53d86ddba..6ea0acb4b5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala @@ -247,7 +247,7 @@ class PeerSpec extends TestkitBaseClass with StateTestsHelperMethods { connect(remoteNodeId, authenticator, watcher, router, relayer, connection, transport, peer) assert(peer.stateData.channels.isEmpty) - probe.send(peer, Peer.OpenChannel(remoteNodeId, Satoshi(12300), MilliSatoshi(0), None, None, None)) + probe.send(peer, Peer.OpenChannel(remoteNodeId, 12300 sat, 0 msat, None, None, None)) awaitCond(peer.stateData.channels.nonEmpty) val channelCreated = probe.expectMsgType[ChannelCreated] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/ChannelSelectionSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/ChannelSelectionSpec.scala index 95e5928222..0599412083 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/ChannelSelectionSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/ChannelSelectionSpec.scala @@ -23,7 +23,7 @@ import fr.acinq.eclair.payment.HtlcGenerationSpec.makeCommitments import fr.acinq.eclair.payment.Relayer.{OutgoingChannel, RelayFailure, RelayPayload, RelaySuccess} import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, ShortChannelId, TestConstants, randomBytes32, randomKey} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, TestConstants, randomBytes32, randomKey} import org.scalatest.FunSuite import scala.collection.mutable @@ -33,17 +33,17 @@ class ChannelSelectionSpec extends FunSuite { /** * This is just a simplified helper function with random values for fields we are not using here */ - def dummyUpdate(shortChannelId: ShortChannelId, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: Long, feeProportionalMillionths: Long, htlcMaximumMsat: Long, enable: Boolean = true) = - Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, shortChannelId, cltvExpiryDelta, htlcMinimumMsat, MilliSatoshi(feeBaseMsat), feeProportionalMillionths, MilliSatoshi(htlcMaximumMsat), enable) + def dummyUpdate(shortChannelId: ShortChannelId, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, enable: Boolean = true) = + Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, randomKey, randomKey.publicKey, shortChannelId, cltvExpiryDelta, htlcMinimumMsat, feeBaseMsat, feeProportionalMillionths, htlcMaximumMsat, enable) test("convert to CMD_FAIL_HTLC/CMD_ADD_HTLC") { val relayPayload = RelayPayload( - add = UpdateAddHtlc(randomBytes32, 42, MilliSatoshi(1000000), randomBytes32, CltvExpiry(70), TestConstants.emptyOnionPacket), - payload = PerHopPayload(ShortChannelId(12345), amtToForward = MilliSatoshi(998900), outgoingCltvValue = CltvExpiry(60)), + add = UpdateAddHtlc(randomBytes32, 42, 1000000 msat, randomBytes32, CltvExpiry(70), TestConstants.emptyOnionPacket), + payload = PerHopPayload(ShortChannelId(12345), amtToForward = 998900 msat, outgoingCltvValue = CltvExpiry(60)), nextPacket = TestConstants.emptyOnionPacket // just a placeholder ) - val channelUpdate = dummyUpdate(ShortChannelId(12345), CltvExpiryDelta(10), MilliSatoshi(100), 1000, 100, 10000000, true) + val channelUpdate = dummyUpdate(ShortChannelId(12345), CltvExpiryDelta(10), 100 msat, 1000 msat, 100, 10000000 msat, true) implicit val log = akka.event.NoLogging @@ -55,36 +55,36 @@ class ChannelSelectionSpec extends FunSuite { val channelUpdate_disabled = channelUpdate.copy(channelFlags = Announcements.makeChannelFlags(true, enable = false)) assert(Relayer.relayOrFail(relayPayload, Some(channelUpdate_disabled)) === RelayFailure(CMD_FAIL_HTLC(relayPayload.add.id, Right(ChannelDisabled(channelUpdate_disabled.messageFlags, channelUpdate_disabled.channelFlags, channelUpdate_disabled)), commit = true))) // amount too low - val relayPayload_toolow = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = MilliSatoshi(99))) + val relayPayload_toolow = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = 99 msat)) assert(Relayer.relayOrFail(relayPayload_toolow, Some(channelUpdate)) === RelayFailure(CMD_FAIL_HTLC(relayPayload.add.id, Right(AmountBelowMinimum(relayPayload_toolow.payload.amtToForward, channelUpdate)), commit = true))) // incorrect cltv expiry val relayPayload_incorrectcltv = relayPayload.copy(payload = relayPayload.payload.copy(outgoingCltvValue = CltvExpiry(42))) assert(Relayer.relayOrFail(relayPayload_incorrectcltv, Some(channelUpdate)) === RelayFailure(CMD_FAIL_HTLC(relayPayload.add.id, Right(IncorrectCltvExpiry(relayPayload_incorrectcltv.payload.outgoingCltvValue, channelUpdate)), commit = true))) // insufficient fee - val relayPayload_insufficientfee = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = MilliSatoshi(998910))) + val relayPayload_insufficientfee = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = 998910 msat)) assert(Relayer.relayOrFail(relayPayload_insufficientfee, Some(channelUpdate)) === RelayFailure(CMD_FAIL_HTLC(relayPayload.add.id, Right(FeeInsufficient(relayPayload_insufficientfee.add.amountMsat, channelUpdate)), commit = true))) // note that a generous fee is ok! - val relayPayload_highfee = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = MilliSatoshi(900000))) + val relayPayload_highfee = relayPayload.copy(payload = relayPayload.payload.copy(amtToForward = 900000 msat)) assert(Relayer.relayOrFail(relayPayload_highfee, Some(channelUpdate)) === RelaySuccess(ShortChannelId(12345), CMD_ADD_HTLC(relayPayload_highfee.payload.amtToForward, relayPayload_highfee.add.paymentHash, relayPayload_highfee.payload.outgoingCltvValue, relayPayload_highfee.nextPacket, upstream = Right(relayPayload.add), commit = true))) } test("channel selection") { val relayPayload = RelayPayload( - add = UpdateAddHtlc(randomBytes32, 42, MilliSatoshi(1000000), randomBytes32, CltvExpiry(70), TestConstants.emptyOnionPacket), - payload = PerHopPayload(ShortChannelId(12345), amtToForward = MilliSatoshi(998900), outgoingCltvValue = CltvExpiry(60)), + add = UpdateAddHtlc(randomBytes32, 42, 1000000 msat, randomBytes32, CltvExpiry(70), TestConstants.emptyOnionPacket), + payload = PerHopPayload(ShortChannelId(12345), amtToForward = 998900 msat, outgoingCltvValue = CltvExpiry(60)), nextPacket = TestConstants.emptyOnionPacket // just a placeholder ) val (a, b) = (randomKey.publicKey, randomKey.publicKey) - val channelUpdate = dummyUpdate(ShortChannelId(12345), CltvExpiryDelta(10), MilliSatoshi(100), 1000, 100, 10000000, true) + val channelUpdate = dummyUpdate(ShortChannelId(12345), CltvExpiryDelta(10), 100 msat, 1000 msat, 100, 10000000 msat, true) val channelUpdates = Map( - ShortChannelId(11111) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, MilliSatoshi(100000000))), - ShortChannelId(12345) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, MilliSatoshi(20000000))), - ShortChannelId(22222) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, MilliSatoshi(10000000))), - ShortChannelId(33333) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, MilliSatoshi(100000))), - ShortChannelId(44444) -> OutgoingChannel(b, channelUpdate, makeCommitments(ByteVector32.Zeroes, MilliSatoshi(1000000))) + ShortChannelId(11111) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, 100000000 msat)), + ShortChannelId(12345) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, 20000000 msat)), + ShortChannelId(22222) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, 10000000 msat)), + ShortChannelId(33333) -> OutgoingChannel(a, channelUpdate, makeCommitments(ByteVector32.Zeroes, 100000 msat)), + ShortChannelId(44444) -> OutgoingChannel(b, channelUpdate, makeCommitments(ByteVector32.Zeroes, 1000000 msat)) ) val node2channels = new mutable.HashMap[PublicKey, mutable.Set[ShortChannelId]] with mutable.MultiMap[PublicKey, ShortChannelId] @@ -104,11 +104,11 @@ class ChannelSelectionSpec extends FunSuite { // all the suitable channels have been tried assert(Relayer.selectPreferredChannel(relayPayload, channelUpdates, node2channels, Seq(ShortChannelId(22222), ShortChannelId(12345), ShortChannelId(11111))) === None) // higher amount payment (have to increased incoming htlc amount for fees to be sufficient) - assert(Relayer.selectPreferredChannel(relayPayload.modify(_.add.amountMsat).setTo(MilliSatoshi(60000000)).modify(_.payload.amtToForward).setTo(MilliSatoshi(50000000)), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(11111))) + assert(Relayer.selectPreferredChannel(relayPayload.modify(_.add.amountMsat).setTo(60000000 msat).modify(_.payload.amtToForward).setTo(50000000 msat), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(11111))) // lower amount payment - assert(Relayer.selectPreferredChannel(relayPayload.modify(_.payload.amtToForward).setTo(MilliSatoshi(1000)), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(33333))) + assert(Relayer.selectPreferredChannel(relayPayload.modify(_.payload.amtToForward).setTo(1000 msat), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(33333))) // payment too high, no suitable channel found - assert(Relayer.selectPreferredChannel(relayPayload.modify(_.payload.amtToForward).setTo(MilliSatoshi(1000000000)), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(12345))) + assert(Relayer.selectPreferredChannel(relayPayload.modify(_.payload.amtToForward).setTo(1000000000 msat), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(12345))) // invalid cltv expiry, no suitable channel, we keep the requested one assert(Relayer.selectPreferredChannel(relayPayload.modify(_.payload.outgoingCltvValue).setTo(CltvExpiry(40)), channelUpdates, node2channels, Seq.empty) === Some(ShortChannelId(12345))) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala index 7015f849cf..0a82253054 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/HtlcGenerationSpec.scala @@ -26,7 +26,7 @@ import fr.acinq.eclair.crypto.Sphinx.{DecryptedPacket, PacketAndSecrets} import fr.acinq.eclair.payment.PaymentLifecycle._ import fr.acinq.eclair.router.Hop import fr.acinq.eclair.wire.{ChannelUpdate, OnionCodecs, PerHopPayload} -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, ShortChannelId, TestConstants, nodeFee, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, TestConstants, nodeFee, randomBytes32} import org.scalatest.FunSuite import scodec.bits.ByteVector @@ -37,9 +37,9 @@ import scodec.bits.ByteVector class HtlcGenerationSpec extends FunSuite { test("compute fees") { - val feeBaseMsat = MilliSatoshi(150000L) + val feeBaseMsat = 150000 msat val feeProportionalMillionth = 4L - val htlcAmountMsat = MilliSatoshi(42000000) + val htlcAmountMsat = 42000000 msat // spec: fee-base-msat + htlc-amount-msat * fee-proportional-millionths / 1000000 val ref = feeBaseMsat + htlcAmountMsat * feeProportionalMillionth / 1000000 val fee = nodeFee(feeBaseMsat, feeProportionalMillionth, htlcAmountMsat) @@ -149,10 +149,10 @@ class HtlcGenerationSpec extends FunSuite { object HtlcGenerationSpec { - def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = MilliSatoshi(50000000L), testAvailableBalanceForReceive: MilliSatoshi = MilliSatoshi(50000000L)) = + def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = 50000000 msat, testAvailableBalanceForReceive: MilliSatoshi = 50000000 msat) = new Commitments(ChannelVersion.STANDARD, null, null, 0.toByte, null, null, null, null, 0, 0, Map.empty, null, null, null, channelId) { - override lazy val availableBalanceForSend: MilliSatoshi = testAvailableBalanceForSend.max(MilliSatoshi(0)) - override lazy val availableBalanceForReceive: MilliSatoshi = testAvailableBalanceForReceive.max(MilliSatoshi(0)) + override lazy val availableBalanceForSend: MilliSatoshi = testAvailableBalanceForSend.max(0 msat) + override lazy val availableBalanceForReceive: MilliSatoshi = testAvailableBalanceForReceive.max(0 msat) } def randomExtendedPrivateKey: ExtendedPrivateKey = DeterministicWallet.generate(randomBytes32) @@ -160,11 +160,11 @@ object HtlcGenerationSpec { val (priv_a, priv_b, priv_c, priv_d, priv_e) = (TestConstants.Alice.keyManager.nodeKey, TestConstants.Bob.keyManager.nodeKey, randomExtendedPrivateKey, randomExtendedPrivateKey, randomExtendedPrivateKey) val (a, b, c, d, e) = (priv_a.publicKey, priv_b.publicKey, priv_c.publicKey, priv_d.publicKey, priv_e.publicKey) val sig = Crypto.sign(Crypto.sha256(ByteVector.empty), priv_a.privateKey) - val defaultChannelUpdate = ChannelUpdate(sig, Block.RegtestGenesisBlock.hash, ShortChannelId(0), 0, 1, 0, CltvExpiryDelta(0), MilliSatoshi(42000), MilliSatoshi(0), 0, Some(MilliSatoshi(500000000L))) - val channelUpdate_ab = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(1), cltvExpiryDelta = CltvExpiryDelta(4), feeBaseMsat = MilliSatoshi(642000), feeProportionalMillionths = 7) - val channelUpdate_bc = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(2), cltvExpiryDelta = CltvExpiryDelta(5), feeBaseMsat = MilliSatoshi(153000), feeProportionalMillionths = 4) - val channelUpdate_cd = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(3), cltvExpiryDelta = CltvExpiryDelta(10), feeBaseMsat = MilliSatoshi(60000), feeProportionalMillionths = 1) - val channelUpdate_de = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(4), cltvExpiryDelta = CltvExpiryDelta(7), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10) + val defaultChannelUpdate = ChannelUpdate(sig, Block.RegtestGenesisBlock.hash, ShortChannelId(0), 0, 1, 0, CltvExpiryDelta(0), 42000 msat, 0 msat, 0, Some(500000000 msat)) + val channelUpdate_ab = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(1), cltvExpiryDelta = CltvExpiryDelta(4), feeBaseMsat = 642000 msat, feeProportionalMillionths = 7) + val channelUpdate_bc = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(2), cltvExpiryDelta = CltvExpiryDelta(5), feeBaseMsat = 153000 msat, feeProportionalMillionths = 4) + val channelUpdate_cd = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(3), cltvExpiryDelta = CltvExpiryDelta(10), feeBaseMsat = 60000 msat, feeProportionalMillionths = 1) + val channelUpdate_de = defaultChannelUpdate.copy(shortChannelId = ShortChannelId(4), cltvExpiryDelta = CltvExpiryDelta(7), feeBaseMsat = 766000 msat, feeProportionalMillionths = 10) // simple route a -> b -> c -> d -> e @@ -174,7 +174,7 @@ object HtlcGenerationSpec { Hop(c, d, channelUpdate_cd) :: Hop(d, e, channelUpdate_de) :: Nil - val finalAmountMsat = MilliSatoshi(42000000L) + val finalAmountMsat = 42000000 msat val currentBlockCount = 420000 val finalExpiry = CltvExpiry(currentBlockCount) + Channel.MIN_CLTV_EXPIRY_DELTA val paymentPreimage = randomBytes32 diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala index ee772d3334..63576b4368 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentHandlerSpec.scala @@ -25,7 +25,7 @@ import fr.acinq.eclair.channel.{CMD_FAIL_HTLC, CMD_FULFILL_HTLC} import fr.acinq.eclair.payment.PaymentLifecycle.ReceivePayment import fr.acinq.eclair.payment.PaymentRequest.ExtraHop import fr.acinq.eclair.wire.{FinalExpiryTooSoon, UpdateAddHtlc} -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, ShortChannelId, TestConstants, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, TestConstants, randomKey} import org.scalatest.FunSuiteLike import scodec.bits.ByteVector @@ -44,7 +44,7 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val eventListener = TestProbe() system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived]) - val amountMsat = MilliSatoshi(42000) + val amountMsat = 42000 msat val expiry = CltvExpiryDelta(12).toCltvExpiry { @@ -97,19 +97,19 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived]) // negative amount should fail - sender.send(handler, ReceivePayment(Some(MilliSatoshi(-50)), "1 coffee")) + sender.send(handler, ReceivePayment(Some(-50 msat), "1 coffee")) val negativeError = sender.expectMsgType[Failure] assert(negativeError.cause.getMessage.contains("amount is not valid")) // amount = 0 should fail - sender.send(handler, ReceivePayment(Some(MilliSatoshi(0)), "1 coffee")) + sender.send(handler, ReceivePayment(Some(0 msat), "1 coffee")) val zeroError = sender.expectMsgType[Failure] assert(zeroError.cause.getMessage.contains("amount is not valid")) // success with 1 mBTC - sender.send(handler, ReceivePayment(Some(MilliSatoshi(100000000L)), "1 coffee")) + sender.send(handler, ReceivePayment(Some(100000000 msat), "1 coffee")) val pr = sender.expectMsgType[PaymentRequest] - assert(pr.amount.contains(MilliSatoshi(100000000L)) && pr.nodeId.toString == nodeParams.nodeId.toString) + assert(pr.amount.contains(100000000 msat) && pr.nodeId.toString == nodeParams.nodeId.toString) } test("Payment request generation should succeed when the amount is not set") { @@ -125,10 +125,10 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val handler = system.actorOf(LocalPaymentHandler.props(Alice.nodeParams)) val sender = TestProbe() - sender.send(handler, ReceivePayment(Some(MilliSatoshi(42000)), "1 coffee")) + sender.send(handler, ReceivePayment(Some(42000 msat), "1 coffee")) assert(sender.expectMsgType[PaymentRequest].expiry === Some(Alice.nodeParams.paymentRequestExpiry.toSeconds)) - sender.send(handler, ReceivePayment(Some(MilliSatoshi(42000)), "1 coffee with custom expiry", expirySeconds_opt = Some(60))) + sender.send(handler, ReceivePayment(Some(42000 msat), "1 coffee with custom expiry", expirySeconds_opt = Some(60))) assert(sender.expectMsgType[PaymentRequest].expiry === Some(60)) } @@ -138,16 +138,16 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val x = randomKey.publicKey val y = randomKey.publicKey - val extraHop_x_y = ExtraHop(x, ShortChannelId(1), 10, 11, CltvExpiryDelta(12)) - val extraHop_y_z = ExtraHop(y, ShortChannelId(2), 20, 21, CltvExpiryDelta(22)) - val extraHop_x_t = ExtraHop(x, ShortChannelId(3), 30, 31, CltvExpiryDelta(32)) + val extraHop_x_y = ExtraHop(x, ShortChannelId(1), 10 msat, 11, CltvExpiryDelta(12)) + val extraHop_y_z = ExtraHop(y, ShortChannelId(2), 20 msat, 21, CltvExpiryDelta(22)) + val extraHop_x_t = ExtraHop(x, ShortChannelId(3), 30 msat, 31, CltvExpiryDelta(32)) val route_x_z = extraHop_x_y :: extraHop_y_z :: Nil val route_x_t = extraHop_x_t :: Nil - sender.send(handler, ReceivePayment(Some(MilliSatoshi(42000)), "1 coffee with additional routing info", extraHops = List(route_x_z, route_x_t))) + sender.send(handler, ReceivePayment(Some(42000 msat), "1 coffee with additional routing info", extraHops = List(route_x_z, route_x_t))) assert(sender.expectMsgType[PaymentRequest].routingInfo === Seq(route_x_z, route_x_t)) - sender.send(handler, ReceivePayment(Some(MilliSatoshi(42000)), "1 coffee without routing info")) + sender.send(handler, ReceivePayment(Some(42000 msat), "1 coffee without routing info")) assert(sender.expectMsgType[PaymentRequest].routingInfo === Nil) } @@ -158,7 +158,7 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike val eventListener = TestProbe() system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived]) - val amountMsat = MilliSatoshi(42000) + val amountMsat = 42000 msat val expiry = CltvExpiryDelta(12).toCltvExpiry sender.send(handler, ReceivePayment(Some(amountMsat), "some desc", expirySeconds_opt = Some(0))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala index e2c1925073..feb6b560ea 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentLifecycleSpec.scala @@ -22,7 +22,7 @@ import akka.actor.FSM.{CurrentState, SubscribeTransitionCallBack, Transition} import akka.actor.Status import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.Script.{pay2wsh, write} -import fr.acinq.bitcoin.{Block, ByteVector32, Satoshi, Transaction, TxOut} +import fr.acinq.bitcoin.{Block, ByteVector32, Transaction, TxOut} import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.{UtxoStatus, ValidateRequest, ValidateResult, WatchSpentBasic} import fr.acinq.eclair.channel.Register.ForwardShortId @@ -42,7 +42,7 @@ import fr.acinq.eclair.wire._ class PaymentLifecycleSpec extends BaseRouterSpec { - val defaultAmountMsat = MilliSatoshi(142000000L) + val defaultAmountMsat = 142000000 msat test("send to route") { fixture => import fixture._ @@ -109,7 +109,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { paymentFSM ! SubscribeTransitionCallBack(monitor.ref) val CurrentState(_, WAITING_FOR_REQUEST) = monitor.expectMsgClass(classOf[CurrentState[_]]) - val request = SendPayment(defaultAmountMsat, randomBytes32, d, routeParams = Some(RouteParams(randomize = false, maxFeeBase = MilliSatoshi(100), maxFeePct = 0.0, routeMaxLength = 20, routeMaxCltv = CltvExpiryDelta(2016), ratios = None)), maxAttempts = 5) + val request = SendPayment(defaultAmountMsat, randomBytes32, d, routeParams = Some(RouteParams(randomize = false, maxFeeBase = 100 msat, maxFeePct = 0.0, routeMaxLength = 20, routeMaxCltv = CltvExpiryDelta(2016), ratios = None)), maxAttempts = 5) sender.send(paymentFSM, request) val Transition(_, WAITING_FOR_REQUEST, WAITING_FOR_ROUTE) = monitor.expectMsgClass(classOf[Transition[_]]) @@ -390,7 +390,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { val paymentOK = sender.expectMsgType[PaymentSucceeded] val PaymentSent(_, request.amount, fee, request.paymentHash, paymentOK.paymentPreimage, _, _) = eventListener.expectMsgType[PaymentSent] - assert(fee > MilliSatoshi(0)) + assert(fee > 0.msat) assert(fee === paymentOK.amount - request.amount) awaitCond(paymentDb.getOutgoingPayment(id).exists(_.status == OutgoingPaymentStatus.SUCCEEDED)) } @@ -409,15 +409,15 @@ class PaymentLifecycleSpec extends BaseRouterSpec { val ann_g = makeNodeAnnouncement(priv_g, "node-G", Color(-30, 10, -50), Nil) 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 = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(0), feeProportionalMillionths = 0, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_gb = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_g, b, channelId_bg, CltvExpiryDelta(9), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 8, htlcMaximumMsat = MilliSatoshi(500000000L)) + 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)) router ! PeerRoutingMessage(null, remoteNodeId, chan_bg) router ! PeerRoutingMessage(null, remoteNodeId, ann_g) router ! PeerRoutingMessage(null, remoteNodeId, channelUpdate_bg) router ! PeerRoutingMessage(null, remoteNodeId, channelUpdate_gb) watcher.expectMsg(ValidateRequest(chan_bg)) - watcher.send(router, ValidateResult(chan_bg, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_g)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + 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)))) watcher.expectMsgType[WatchSpentBasic] // actual test begins @@ -446,7 +446,7 @@ class PaymentLifecycleSpec extends BaseRouterSpec { // 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 - assert(fee === MilliSatoshi(0)) + assert(fee === 0.msat) assert(fee === paymentOK.amount - request.amount) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentRequestSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentRequestSpec.scala index 383575d897..9f7d2d1a24 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentRequestSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentRequestSpec.scala @@ -19,9 +19,9 @@ package fr.acinq.eclair.payment import java.nio.ByteOrder import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.{Block, Btc, ByteVector32, Crypto, MilliBtc, Protocol, Satoshi, _} +import fr.acinq.bitcoin.{Block, ByteVector32, Crypto, Protocol} import fr.acinq.eclair.payment.PaymentRequest._ -import fr.acinq.eclair.{MilliSatoshi, ShortChannelId, _} +import fr.acinq.eclair.{LongToBtcAmount, ShortChannelId, _} import org.scalatest.FunSuite import scodec.DecodeResult import scodec.bits._ @@ -38,23 +38,23 @@ class PaymentRequestSpec extends FunSuite { assert(nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) test("check minimal unit is used") { - assert('p' === Amount.unit(MilliSatoshi(1))) - assert('p' === Amount.unit(MilliSatoshi(99))) - assert('n' === Amount.unit(MilliSatoshi(100))) - assert('p' === Amount.unit(MilliSatoshi(101))) - assert('n' === Amount.unit(Satoshi(1).toMilliSatoshi)) - assert('u' === Amount.unit(Satoshi(100).toMilliSatoshi)) - assert('n' === Amount.unit(Satoshi(101).toMilliSatoshi)) - assert('u' === Amount.unit(Satoshi(1155400).toMilliSatoshi)) - assert('m' === Amount.unit(millibtc2satoshi(MilliBtc(1)).toMilliSatoshi)) - assert('m' === Amount.unit(millibtc2satoshi(MilliBtc(10)).toMilliSatoshi)) - assert('m' === Amount.unit(btc2satoshi(Btc(1)).toMilliSatoshi)) + assert('p' === Amount.unit(1 msat)) + assert('p' === Amount.unit(99 msat)) + assert('n' === Amount.unit(100 msat)) + assert('p' === Amount.unit(101 msat)) + assert('n' === Amount.unit((1 sat).toMilliSatoshi)) + assert('u' === Amount.unit((100 sat).toMilliSatoshi)) + assert('n' === Amount.unit((101 sat).toMilliSatoshi)) + assert('u' === Amount.unit((1155400 sat).toMilliSatoshi)) + assert('m' === Amount.unit((1 mbtc).toMilliSatoshi)) + assert('m' === Amount.unit((10 mbtc).toMilliSatoshi)) + assert('m' === Amount.unit((1 btc).toMilliSatoshi)) } test("check that we can still decode non-minimal amount encoding") { - assert(Some(MilliSatoshi(100000000)) == Amount.decode("1000u")) - assert(Some(MilliSatoshi(100000000)) == Amount.decode("1000000n")) - assert(Some(MilliSatoshi(100000000)) == Amount.decode("1000000000p")) + assert(Some(100000000 msat) === Amount.decode("1000u")) + assert(Some(100000000 msat) === Amount.decode("1000000n")) + assert(Some(100000000 msat) === Amount.decode("1000000000p")) } test("data string -> bitvector") { @@ -101,7 +101,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(250000000L))) + assert(pr.amount === Some(250000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -115,7 +115,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -129,7 +129,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98k6vcx9fz94w0qf237cm2rqv9pmn5lnexfvf5579slr4zq3u8kmczecytdx0xg9rwzngp7e6guwqpqlhssu04sucpnz4axcv2dstmknqq6jsk2l" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lntb") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -143,15 +143,15 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount === Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) assert(pr.description == Right(Crypto.sha256(ByteVector.view("One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon".getBytes)))) assert(pr.fallbackAddress === Some("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T")) assert(pr.routingInfo === List(List( - ExtraHop(PublicKey(hex"029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), ShortChannelId(72623859790382856L), 1, 20, CltvExpiryDelta(3)), - ExtraHop(PublicKey(hex"039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), ShortChannelId(217304205466536202L), 2, 30, CltvExpiryDelta(4)) + ExtraHop(PublicKey(hex"029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), ShortChannelId(72623859790382856L), 1 msat, 20, CltvExpiryDelta(3)), + ExtraHop(PublicKey(hex"039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), ShortChannelId(217304205466536202L), 2 msat, 30, CltvExpiryDelta(4)) ))) assert(Protocol.writeUInt64(0x0102030405060708L, ByteOrder.BIG_ENDIAN) == hex"0102030405060708") assert(Protocol.writeUInt64(0x030405060708090aL, ByteOrder.BIG_ENDIAN) == hex"030405060708090a") @@ -163,7 +163,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9kk822r8plup77n9yq5ep2dfpcydrjwzxs0la84v3tfw43t3vqhek7f05m6uf8lmfkjn7zv7enn76sq65d8u9lxav2pl6x3xnc2ww3lqpagnh0u" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -177,7 +177,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfppqw508d6qejxtdg4y5r3zarvary0c5xw7kknt6zz5vxa8yh8jrnlkl63dah48yh6eupakk87fjdcnwqfcyt7snnpuz7vp83txauq4c60sys3xyucesxjf46yqnpplj0saq36a554cp9wt865" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -192,7 +192,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qvnjha2auylmwrltv2pkp2t22uy8ura2xsdwhq5nm7s574xva47djmnj2xeycsu7u5v8929mvuux43j0cqhhf32wfyn2th0sv4t9x55sppz5we8" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -206,7 +206,7 @@ class PaymentRequestSpec extends FunSuite { val ref = "lnbc20m1pvjluezcqpvpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q90qkf3gd7fcqs0ewr7t3xf72ptmc4n38evg0xhy4p64nlg7hgrmq6g997tkrvezs8afs0x0y8v4vs8thwsk6knkvdfvfa7wmhhpcsxcqw0ny48" val pr = PaymentRequest.read(ref) assert(pr.prefix == "lnbc") - assert(pr.amount == Some(MilliSatoshi(2000000000L))) + assert(pr.amount === Some(2000000000 msat)) assert(pr.paymentHash.bytes == hex"0001020304050607080900010203040506070809000102030405060708090102") assert(pr.timestamp == 1496314658L) assert(pr.nodeId == PublicKey(hex"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad")) @@ -230,7 +230,7 @@ class PaymentRequestSpec extends FunSuite { assert(field1 == field) // Now with a payment request - val pr = PaymentRequest(chainHash = Block.LivenetGenesisBlock.hash, amount = Some(MilliSatoshi(123)), paymentHash = ByteVector32(ByteVector.fill(32)(1)), privateKey = priv, description = "Some invoice", expirySeconds = Some(123456), timestamp = 12345) + val pr = PaymentRequest(chainHash = Block.LivenetGenesisBlock.hash, amount = Some(123 msat), paymentHash = ByteVector32(ByteVector.fill(32)(1)), privateKey = priv, description = "Some invoice", expirySeconds = Some(123456), timestamp = 12345) val serialized = PaymentRequest.write(pr) val pr1 = PaymentRequest.read(serialized) @@ -240,7 +240,7 @@ class PaymentRequestSpec extends FunSuite { test("ignore unknown tags") { val pr = PaymentRequest( prefix = "lntb", - amount = Some(MilliSatoshi(100000L)), + amount = Some(100000 msat), timestamp = System.currentTimeMillis() / 1000L, nodeId = nodeId, tags = List( @@ -252,7 +252,7 @@ class PaymentRequestSpec extends FunSuite { val serialized = PaymentRequest write pr val pr1 = PaymentRequest read serialized - val Some(unknownTag) = pr1.tags.collectFirst { case u: UnknownTag21 => u } + val Some(_) = pr1.tags.collectFirst { case u: UnknownTag21 => u } } test("accept uppercase payment request") { @@ -264,7 +264,7 @@ class PaymentRequestSpec extends FunSuite { test("Pay 1 BTC without multiplier") { val ref = "lnbc11pdkmqhupp5n2ees808r98m0rh4472yyth0c5fptzcxmexcjznrzmq8xald0cgqdqsf4ujqarfwqsxymmccqp2xvtsv5tc743wgctlza8k3zlpxucl7f3kvjnjptv7xz0nkaww307sdyrvgke2w8kmq7dgz4lkasfn0zvplc9aa4gp8fnhrwfjny0j59sq42x9gp" val pr = PaymentRequest.read(ref) - assert(pr.amount.contains(MilliSatoshi(100000000000L))) + assert(pr.amount.contains(100000000000L msat)) } test("nonreg") { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/RelayerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/RelayerSpec.scala index e81aa59b2d..733c69d3d8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/RelayerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/RelayerSpec.scala @@ -20,13 +20,13 @@ import java.util.UUID import akka.actor.{ActorRef, Status} import akka.testkit.TestProbe -import fr.acinq.bitcoin.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.channel._ import fr.acinq.eclair.crypto.Sphinx import fr.acinq.eclair.payment.PaymentLifecycle.buildCommand import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, ShortChannelId, TestConstants, TestkitBaseClass, UInt64, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, ShortChannelId, TestConstants, TestkitBaseClass, UInt64, randomBytes32} import org.scalatest.Outcome import scodec.bits.ByteVector @@ -39,6 +39,7 @@ import scala.concurrent.duration._ class RelayerSpec extends TestkitBaseClass { // let's reuse the existing test data + import HtlcGenerationSpec._ case class FixtureParam(relayer: ActorRef, register: TestProbe, paymentHandler: TestProbe) @@ -90,7 +91,7 @@ class RelayerSpec extends TestkitBaseClass { // this is another channel B-C, with less balance (it will be preferred) val (channelId_bc_1, channelUpdate_bc_1) = (randomBytes32, channelUpdate_bc.copy(shortChannelId = ShortChannelId("500000x1x1"))) - relayer ! LocalChannelUpdate(null, channelId_bc_1, channelUpdate_bc_1.shortChannelId, c, None, channelUpdate_bc_1, makeCommitments(channelId_bc_1, MilliSatoshi(49000000L))) + relayer ! LocalChannelUpdate(null, channelId_bc_1, channelUpdate_bc_1.shortChannelId, c, None, channelUpdate_bc_1, makeCommitments(channelId_bc_1, 49000000 msat)) sender.send(relayer, ForwardAdd(add_ab)) @@ -100,7 +101,7 @@ class RelayerSpec extends TestkitBaseClass { assert(fwd1.message.upstream === Right(add_ab)) // channel returns an error - val origin = Relayed(channelId_ab, originHtlcId = 42, amountIn = MilliSatoshi(1100000), amountOut = MilliSatoshi(1000000)) + val origin = Relayed(channelId_ab, originHtlcId = 42, amountIn = 1100000 msat, amountOut = 1000000 msat) sender.send(relayer, Status.Failure(AddHtlcFailed(channelId_bc_1, paymentHash, HtlcValueTooHighInFlight(channelId_bc_1, UInt64(1000000000L), UInt64(1516977616L)), origin, Some(channelUpdate_bc_1), originalCommand = Some(fwd1.message)))) // second try @@ -248,7 +249,7 @@ class RelayerSpec extends TestkitBaseClass { val sender = TestProbe() // we use this to build a valid onion - val (cmd, _) = buildCommand(UUID.randomUUID(), channelUpdate_bc.htlcMinimumMsat - MilliSatoshi(1), finalExpiry, paymentHash, hops.map(hop => hop.copy(lastUpdate = hop.lastUpdate.copy(feeBaseMsat = MilliSatoshi(0), feeProportionalMillionths = 0)))) + val (cmd, _) = buildCommand(UUID.randomUUID(), channelUpdate_bc.htlcMinimumMsat - (1 msat), finalExpiry, paymentHash, hops.map(hop => hop.copy(lastUpdate = hop.lastUpdate.copy(feeBaseMsat = 0 msat, feeProportionalMillionths = 0)))) // and then manually build an htlc val add_ab = UpdateAddHtlc(channelId = channelId_ab, id = 123456, cmd.amount, cmd.paymentHash, cmd.cltvExpiry, cmd.onion) relayer ! LocalChannelUpdate(null, channelId_bc, channelUpdate_bc.shortChannelId, c, None, channelUpdate_bc, makeCommitments(channelId_bc)) @@ -311,7 +312,7 @@ class RelayerSpec extends TestkitBaseClass { val hops1 = hops.head :: Nil val (cmd, _) = buildCommand(UUID.randomUUID(), finalAmountMsat, finalExpiry, paymentHash, hops1) // and then manually build an htlc with a wrong expiry - val add_ab = UpdateAddHtlc(channelId = channelId_ab, id = 123456, cmd.amount - MilliSatoshi(1), cmd.paymentHash, cmd.cltvExpiry, cmd.onion) + val add_ab = UpdateAddHtlc(channelId = channelId_ab, id = 123456, cmd.amount - (1 msat), cmd.paymentHash, cmd.cltvExpiry, cmd.onion) relayer ! LocalChannelUpdate(null, channelId_bc, channelUpdate_bc.shortChannelId, c, None, channelUpdate_bc, makeCommitments(channelId_bc)) sender.send(relayer, ForwardAdd(add_ab)) @@ -350,7 +351,7 @@ class RelayerSpec extends TestkitBaseClass { val sender = TestProbe() val paymentHash = randomBytes32 - val origin = Relayed(channelId_ab, originHtlcId = 42, amountIn = MilliSatoshi(1100000), amountOut = MilliSatoshi(1000000)) + val origin = Relayed(channelId_ab, originHtlcId = 42, amountIn = 1100000 msat, amountOut = 1000000 msat) sender.send(relayer, Status.Failure(AddHtlcFailed(channelId_bc, paymentHash, ExpiryTooSmall(channelId_bc, CltvExpiry(100), CltvExpiry(0), 0), origin, Some(channelUpdate_bc), None))) assert(register.expectMsgType[Register.Forward[CMD_FAIL_HTLC]].message.reason === Right(ExpiryTooSoon(channelUpdate_bc))) @@ -358,7 +359,7 @@ class RelayerSpec extends TestkitBaseClass { sender.send(relayer, Status.Failure(AddHtlcFailed(channelId_bc, paymentHash, ExpiryTooBig(channelId_bc, CltvExpiry(100), CltvExpiry(200), 0), origin, Some(channelUpdate_bc), None))) assert(register.expectMsgType[Register.Forward[CMD_FAIL_HTLC]].message.reason === Right(ExpiryTooFar)) - sender.send(relayer, Status.Failure(AddHtlcFailed(channelId_bc, paymentHash, InsufficientFunds(channelId_bc, origin.amountOut, Satoshi(100), Satoshi(0), Satoshi(0)), origin, Some(channelUpdate_bc), None))) + sender.send(relayer, Status.Failure(AddHtlcFailed(channelId_bc, paymentHash, InsufficientFunds(channelId_bc, origin.amountOut, 100 sat, 0 sat, 0 sat), origin, Some(channelUpdate_bc), None))) assert(register.expectMsgType[Register.Forward[CMD_FAIL_HTLC]].message.reason === Right(TemporaryChannelFailure(channelUpdate_bc))) val channelUpdate_bc_disabled = channelUpdate_bc.copy(channelFlags = 2) @@ -383,9 +384,9 @@ class RelayerSpec extends TestkitBaseClass { system.eventStream.subscribe(eventListener.ref, classOf[PaymentEvent]) // we build a fake htlc for the downstream channel - val add_bc = UpdateAddHtlc(channelId = channelId_bc, id = 72, amountMsat = MilliSatoshi(10000000L), paymentHash = ByteVector32.Zeroes, CltvExpiry(4200), onionRoutingPacket = TestConstants.emptyOnionPacket) + val add_bc = UpdateAddHtlc(channelId = channelId_bc, id = 72, amountMsat = 10000000 msat, paymentHash = ByteVector32.Zeroes, CltvExpiry(4200), onionRoutingPacket = TestConstants.emptyOnionPacket) val fulfill_ba = UpdateFulfillHtlc(channelId = channelId_bc, id = 42, paymentPreimage = ByteVector32.Zeroes) - val origin = Relayed(channelId_ab, 150, MilliSatoshi(11000000L), MilliSatoshi(10000000L)) + val origin = Relayed(channelId_ab, 150, 11000000 msat, 10000000 msat) sender.send(relayer, ForwardFulfill(fulfill_ba, origin, add_bc)) val fwd = register.expectMsgType[Register.Forward[CMD_FULFILL_HTLC]] @@ -401,9 +402,9 @@ class RelayerSpec extends TestkitBaseClass { val sender = TestProbe() // we build a fake htlc for the downstream channel - val add_bc = UpdateAddHtlc(channelId = channelId_bc, id = 72, amountMsat = MilliSatoshi(10000000L), paymentHash = ByteVector32.Zeroes, CltvExpiry(4200), onionRoutingPacket = TestConstants.emptyOnionPacket) + val add_bc = UpdateAddHtlc(channelId = channelId_bc, id = 72, amountMsat = 10000000 msat, paymentHash = ByteVector32.Zeroes, CltvExpiry(4200), onionRoutingPacket = TestConstants.emptyOnionPacket) val fail_ba = UpdateFailHtlc(channelId = channelId_bc, id = 42, reason = Sphinx.FailurePacket.create(ByteVector32(ByteVector.fill(32)(1)), TemporaryChannelFailure(channelUpdate_cd))) - val origin = Relayed(channelId_ab, 150, MilliSatoshi(11000000L), MilliSatoshi(10000000L)) + val origin = Relayed(channelId_ab, 150, 11000000 msat, 10000000 msat) sender.send(relayer, ForwardFail(fail_ba, origin, add_bc)) val fwd = register.expectMsgType[Register.Forward[CMD_FAIL_HTLC]] @@ -414,31 +415,31 @@ class RelayerSpec extends TestkitBaseClass { test("get usable balances") { f => import f._ val sender = TestProbe() - relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab, makeCommitments(channelId_ab, MilliSatoshi(-2000), MilliSatoshi(300000))) - relayer ! LocalChannelUpdate(null, channelId_bc, channelUpdate_bc.shortChannelId, c, None, channelUpdate_bc, makeCommitments(channelId_bc, MilliSatoshi(400000), MilliSatoshi(-5000))) + relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab, makeCommitments(channelId_ab, -2000 msat, 300000 msat)) + relayer ! LocalChannelUpdate(null, channelId_bc, channelUpdate_bc.shortChannelId, c, None, channelUpdate_bc, makeCommitments(channelId_bc, 400000 msat, -5000 msat)) sender.send(relayer, GetUsableBalances) val usableBalances1 = sender.expectMsgType[Iterable[UsableBalances]] assert(usableBalances1.size === 2) - assert(usableBalances1.head.canSend === MilliSatoshi(0) && usableBalances1.head.canReceive === MilliSatoshi(300000) && usableBalances1.head.shortChannelId == channelUpdate_ab.shortChannelId) - assert(usableBalances1.last.canReceive === MilliSatoshi(0) && usableBalances1.last.canSend === MilliSatoshi(400000) && usableBalances1.last.shortChannelId == channelUpdate_bc.shortChannelId) + assert(usableBalances1.head.canSend === 0.msat && usableBalances1.head.canReceive === 300000.msat && usableBalances1.head.shortChannelId == channelUpdate_ab.shortChannelId) + assert(usableBalances1.last.canReceive === 0.msat && usableBalances1.last.canSend === 400000.msat && usableBalances1.last.shortChannelId == channelUpdate_bc.shortChannelId) - relayer ! AvailableBalanceChanged(null, channelId_bc, channelUpdate_bc.shortChannelId, MilliSatoshi(0), makeCommitments(channelId_bc, MilliSatoshi(200000), MilliSatoshi(500000))) + relayer ! AvailableBalanceChanged(null, channelId_bc, channelUpdate_bc.shortChannelId, 0 msat, makeCommitments(channelId_bc, 200000 msat, 500000 msat)) sender.send(relayer, GetUsableBalances) val usableBalances2 = sender.expectMsgType[Iterable[UsableBalances]] - assert(usableBalances2.last.canReceive === MilliSatoshi(500000) && usableBalances2.last.canSend === MilliSatoshi(200000)) + assert(usableBalances2.last.canReceive === 500000.msat && usableBalances2.last.canSend === 200000.msat) - relayer ! AvailableBalanceChanged(null, channelId_ab, channelUpdate_ab.shortChannelId, MilliSatoshi(0), makeCommitments(channelId_ab, MilliSatoshi(100000), MilliSatoshi(200000))) + relayer ! AvailableBalanceChanged(null, channelId_ab, channelUpdate_ab.shortChannelId, 0 msat, makeCommitments(channelId_ab, 100000 msat, 200000 msat)) relayer ! LocalChannelDown(null, channelId_bc, channelUpdate_bc.shortChannelId, c) sender.send(relayer, GetUsableBalances) val usableBalances3 = sender.expectMsgType[Iterable[UsableBalances]] - assert(usableBalances3.size === 1 && usableBalances3.head.canSend === MilliSatoshi(100000)) + assert(usableBalances3.size === 1 && usableBalances3.head.canSend === 100000.msat) - relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab.copy(channelFlags = 2), makeCommitments(channelId_ab, MilliSatoshi(100000), MilliSatoshi(200000))) + relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab.copy(channelFlags = 2), makeCommitments(channelId_ab, 100000 msat, 200000 msat)) sender.send(relayer, GetUsableBalances) val usableBalances4 = sender.expectMsgType[Iterable[UsableBalances]] assert(usableBalances4.isEmpty) - relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab, makeCommitments(channelId_ab, MilliSatoshi(100000), MilliSatoshi(200000))) + relayer ! LocalChannelUpdate(null, channelId_ab, channelUpdate_ab.shortChannelId, a, None, channelUpdate_ab, makeCommitments(channelId_ab, 100000 msat, 200000 msat)) sender.send(relayer, GetUsableBalances) val usableBalances5 = sender.expectMsgType[Iterable[UsableBalances]] assert(usableBalances5.size === 1) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala index 72da233fca..70b8c66899 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala @@ -27,7 +27,7 @@ import fr.acinq.eclair.blockchain.bitcoind.BitcoinCoreWallet import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, ExtendedBitcoinClient} import fr.acinq.eclair.transactions.Scripts import fr.acinq.eclair.wire.{ChannelAnnouncement, ChannelUpdate} -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, ShortChannelId, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, randomKey} import org.scalatest.FunSuite import scodec.bits.ByteVector @@ -84,7 +84,7 @@ object AnnouncementsBatchValidationSpec { val node2Key = randomKey val node1BitcoinKey = randomKey val node2BitcoinKey = randomKey - val amount = Satoshi(1000000) + val amount = 1000000 sat // first we publish the funding tx val wallet = new BitcoinCoreWallet(extendedBitcoinClient.rpcClient) val fundingPubkeyScript = Script.write(Script.pay2wsh(Scripts.multiSig2of2(node1BitcoinKey.publicKey, node2BitcoinKey.publicKey))) @@ -104,6 +104,6 @@ object AnnouncementsBatchValidationSpec { } def makeChannelUpdate(c: SimulatedChannel, shortChannelId: ShortChannelId): ChannelUpdate = - Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, c.node1Key, c.node2Key.publicKey, shortChannelId, CltvExpiryDelta(10), MilliSatoshi(1000), MilliSatoshi(10), 100, MilliSatoshi(500000000L)) + Announcements.makeChannelUpdate(Block.RegtestGenesisBlock.hash, c.node1Key, c.node2Key.publicKey, shortChannelId, CltvExpiryDelta(10), 1000 msat, 10 msat, 100, 500000000 msat) } \ No newline at end of file diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsSpec.scala index 5fd7b5e8f0..2e01c4d516 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsSpec.scala @@ -55,7 +55,7 @@ class AnnouncementsSpec extends FunSuite { } test("create valid signed channel update announcement") { - val ann = makeChannelUpdate(Block.RegtestGenesisBlock.hash, Alice.nodeParams.privateKey, randomKey.publicKey, ShortChannelId(45561L), Alice.nodeParams.expiryDeltaBlocks, Alice.nodeParams.htlcMinimum, Alice.nodeParams.feeBase, Alice.nodeParams.feeProportionalMillionth, MilliSatoshi(500000000L)) + val ann = makeChannelUpdate(Block.RegtestGenesisBlock.hash, Alice.nodeParams.privateKey, randomKey.publicKey, ShortChannelId(45561L), Alice.nodeParams.expiryDeltaBlocks, Alice.nodeParams.htlcMinimum, Alice.nodeParams.feeBase, Alice.nodeParams.feeProportionalMillionth, 500000000 msat) assert(checkSig(ann, Alice.nodeParams.nodeId)) assert(checkSig(ann, randomKey.publicKey) === false) } @@ -66,10 +66,10 @@ class AnnouncementsSpec extends FunSuite { // NB: node1 < node2 (public keys) assert(isNode1(node1_priv.publicKey, node2_priv.publicKey)) assert(!isNode1(node2_priv.publicKey, node1_priv.publicKey)) - val channelUpdate1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node1_priv, node2_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), MilliSatoshi(0), MilliSatoshi(0), 0, MilliSatoshi(500000000L), enable = true) - val channelUpdate1_disabled = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node1_priv, node2_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), MilliSatoshi(0), MilliSatoshi(0), 0, MilliSatoshi(500000000L), enable = false) - val channelUpdate2 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node2_priv, node1_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), MilliSatoshi(0), MilliSatoshi(0), 0, MilliSatoshi(500000000L), enable = true) - val channelUpdate2_disabled = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node2_priv, node1_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), MilliSatoshi(0), MilliSatoshi(0), 0, MilliSatoshi(500000000L), enable = false) + val channelUpdate1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node1_priv, node2_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), 0 msat, 0 msat, 0, 500000000 msat, enable = true) + val channelUpdate1_disabled = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node1_priv, node2_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), 0 msat, 0 msat, 0, 500000000 msat, enable = false) + val channelUpdate2 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node2_priv, node1_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), 0 msat, 0 msat, 0, 500000000 msat, enable = true) + val channelUpdate2_disabled = makeChannelUpdate(Block.RegtestGenesisBlock.hash, node2_priv, node1_priv.publicKey, ShortChannelId(0), CltvExpiryDelta(0), 0 msat, 0 msat, 0, 500000000 msat, enable = false) assert(channelUpdate1.channelFlags == 0) // ....00 assert(channelUpdate1_disabled.channelFlags == 2) // ....10 assert(channelUpdate2.channelFlags == 1) // ....01 diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/BaseRouterSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/BaseRouterSpec.scala index 46e7dffe93..628cc489a3 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/BaseRouterSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/BaseRouterSpec.scala @@ -20,7 +20,7 @@ import akka.actor.ActorRef import akka.testkit.TestProbe import fr.acinq.bitcoin.Crypto.PrivateKey import fr.acinq.bitcoin.Script.{pay2wsh, write} -import fr.acinq.bitcoin.{Block, ByteVector32, Satoshi, Transaction, TxOut} +import fr.acinq.bitcoin.{Block, ByteVector32, Transaction, TxOut} import fr.acinq.eclair.TestConstants.Alice import fr.acinq.eclair.blockchain.{UtxoStatus, ValidateRequest, ValidateResult, WatchSpentBasic} import fr.acinq.eclair.crypto.LocalKeyManager @@ -78,14 +78,14 @@ abstract class BaseRouterSpec extends TestkitBaseClass { val chan_cd = channelAnnouncement(channelId_cd, priv_c, priv_d, priv_funding_c, priv_funding_d) val chan_ef = channelAnnouncement(channelId_ef, priv_e, priv_f, priv_funding_e, priv_funding_f) - val channelUpdate_ab = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, b, channelId_ab, CltvExpiryDelta(7), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 10, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_ba = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, a, channelId_ab, CltvExpiryDelta(7), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 10, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_bc = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, c, channelId_bc, CltvExpiryDelta(5), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 1, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_cb = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, b, channelId_bc, CltvExpiryDelta(5), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 1, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_cd = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, d, channelId_cd, CltvExpiryDelta(3), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 4, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_dc = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_d, c, channelId_cd, CltvExpiryDelta(3), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 4, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_ef = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_e, f, channelId_ef, CltvExpiryDelta(9), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 8, htlcMaximumMsat = MilliSatoshi(500000000L)) - val channelUpdate_fe = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_f, e, channelId_ef, CltvExpiryDelta(9), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(10), feeProportionalMillionths = 8, htlcMaximumMsat = MilliSatoshi(500000000L)) + val channelUpdate_ab = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, b, channelId_ab, CltvExpiryDelta(7), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 10, htlcMaximumMsat = 500000000 msat) + val channelUpdate_ba = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, a, channelId_ab, CltvExpiryDelta(7), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 10, htlcMaximumMsat = 500000000 msat) + val channelUpdate_bc = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, c, channelId_bc, CltvExpiryDelta(5), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 1, htlcMaximumMsat = 500000000 msat) + val channelUpdate_cb = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, b, channelId_bc, CltvExpiryDelta(5), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 1, htlcMaximumMsat = 500000000 msat) + val channelUpdate_cd = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, d, channelId_cd, CltvExpiryDelta(3), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 4, htlcMaximumMsat = 500000000 msat) + val channelUpdate_dc = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_d, c, channelId_cd, CltvExpiryDelta(3), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 4, htlcMaximumMsat = 500000000 msat) + val channelUpdate_ef = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_e, f, channelId_ef, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 8, htlcMaximumMsat = 500000000 msat) + val channelUpdate_fe = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_f, e, channelId_ef, CltvExpiryDelta(9), htlcMinimumMsat = 0 msat, feeBaseMsat = 10 msat, feeProportionalMillionths = 8, htlcMaximumMsat = 500000000 msat) override def withFixture(test: OneArgTest): Outcome = { // the network will be a --(1)--> b ---(2)--> c --(3)--> d and e --(4)--> f (we are a) @@ -129,10 +129,10 @@ abstract class BaseRouterSpec extends TestkitBaseClass { watcher.expectMsg(ValidateRequest(chan_cd)) watcher.expectMsg(ValidateRequest(chan_ef)) // and answers with valid scripts - watcher.send(router, ValidateResult(chan_ab, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_b)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) - watcher.send(router, ValidateResult(chan_bc, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) - watcher.send(router, ValidateResult(chan_cd, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_c, funding_d)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) - watcher.send(router, ValidateResult(chan_ef, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_e, funding_f)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + watcher.send(router, ValidateResult(chan_ab, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_b)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + watcher.send(router, ValidateResult(chan_bc, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + watcher.send(router, ValidateResult(chan_cd, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_c, funding_d)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + watcher.send(router, ValidateResult(chan_ef, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_e, funding_f)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) // watcher receives watch-spent request watcher.expectMsgType[WatchSpentBasic] watcher.expectMsgType[WatchSpentBasic] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/GraphSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/GraphSpec.scala index 9730365850..50d7c754d1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/GraphSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/GraphSpec.scala @@ -17,10 +17,10 @@ package fr.acinq.eclair.router import fr.acinq.bitcoin.Crypto.PublicKey -import fr.acinq.eclair.{MilliSatoshi, ShortChannelId} import fr.acinq.eclair.router.Graph.GraphStructure.{DirectedGraph, GraphEdge} import fr.acinq.eclair.router.RouteCalculationSpec._ import fr.acinq.eclair.wire.ChannelUpdate +import fr.acinq.eclair.{LongToBtcAmount, ShortChannelId} import org.scalatest.FunSuite import scodec.bits._ @@ -37,21 +37,21 @@ class GraphSpec extends FunSuite { ) /** - * /--> D --\ - * A --> B --> C - * \-> E/ - * - * @return - */ + * /--> D --\ + * A --> B --> C + * \-> E/ + * + * @return + */ def makeTestGraph() = { val updates = Seq( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, a, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, c, MilliSatoshi(0), 0), - makeUpdate(5L, c, e, MilliSatoshi(0), 0), - makeUpdate(6L, b, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, a, d, 0 msat, 0), + makeUpdate(4L, d, c, 0 msat, 0), + makeUpdate(5L, c, e, 0 msat, 0), + makeUpdate(6L, b, e, 0 msat, 0) ) DirectedGraph.makeGraph(updates.toMap) @@ -72,11 +72,11 @@ class GraphSpec extends FunSuite { assert(otherGraph.vertexSet().size === 5) // add some edges to the graph - val (descAB, updateAB) = makeUpdate(1L, a, b, MilliSatoshi(0), 0) - val (descBC, updateBC) = makeUpdate(2L, b, c, MilliSatoshi(0), 0) - val (descAD, updateAD) = makeUpdate(3L, a, d, MilliSatoshi(0), 0) - val (descDC, updateDC) = makeUpdate(4L, d, c, MilliSatoshi(0), 0) - val (descCE, updateCE) = makeUpdate(5L, c, e, MilliSatoshi(0), 0) + val (descAB, updateAB) = makeUpdate(1L, a, b, 0 msat, 0) + val (descBC, updateBC) = makeUpdate(2L, b, c, 0 msat, 0) + val (descAD, updateAD) = makeUpdate(3L, a, d, 0 msat, 0) + val (descDC, updateDC) = makeUpdate(4L, d, c, 0 msat, 0) + val (descCE, updateCE) = makeUpdate(5L, c, e, 0 msat, 0) val graphWithEdges = graph .addEdge(descAB, updateAB) @@ -98,12 +98,12 @@ class GraphSpec extends FunSuite { test("instantiate a graph adding edges only") { - val edgeAB = edgeFromDesc(makeUpdate(1L, a, b, MilliSatoshi(0), 0)) - val (descBC, updateBC) = makeUpdate(2L, b, c, MilliSatoshi(0), 0) - val (descAD, updateAD) = makeUpdate(3L, a, d, MilliSatoshi(0), 0) - val (descDC, updateDC) = makeUpdate(4L, d, c, MilliSatoshi(0), 0) - val (descCE, updateCE) = makeUpdate(5L, c, e, MilliSatoshi(0), 0) - val (descBE, updateBE) = makeUpdate(6L, b, e, MilliSatoshi(0), 0) + val edgeAB = edgeFromDesc(makeUpdate(1L, a, b, 0 msat, 0)) + val (descBC, updateBC) = makeUpdate(2L, b, c, 0 msat, 0) + val (descAD, updateAD) = makeUpdate(3L, a, d, 0 msat, 0) + val (descDC, updateDC) = makeUpdate(4L, d, c, 0 msat, 0) + val (descCE, updateCE) = makeUpdate(5L, c, e, 0 msat, 0) + val (descBE, updateBE) = makeUpdate(6L, b, e, 0 msat, 0) val graph = DirectedGraph(edgeAB) .addEdge(descAD, updateAD) @@ -121,10 +121,10 @@ class GraphSpec extends FunSuite { test("containsEdge should return true if the graph contains that edge, false otherwise") { val updates = Seq( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ) val graph = DirectedGraph().addEdges(updates) @@ -144,10 +144,10 @@ class GraphSpec extends FunSuite { val graph = makeTestGraph() - val (descBE, _) = makeUpdate(6L, b, e, MilliSatoshi(0), 0) - val (descCE, _) = makeUpdate(5L, c, e, MilliSatoshi(0), 0) - val (descAD, _) = makeUpdate(3L, a, d, MilliSatoshi(0), 0) - val (descDC, _) = makeUpdate(4L, d, c, MilliSatoshi(0), 0) + val (descBE, _) = makeUpdate(6L, b, e, 0 msat, 0) + val (descCE, _) = makeUpdate(5L, c, e, 0 msat, 0) + val (descAD, _) = makeUpdate(3L, a, d, 0 msat, 0) + val (descDC, _) = makeUpdate(4L, d, c, 0 msat, 0) assert(graph.edgeSet().size === 6) @@ -161,15 +161,15 @@ class GraphSpec extends FunSuite { val withoutAnyIncomingEdgeInE = graph.removeEdges(Seq(descBE, descCE)) assert(withoutAnyIncomingEdgeInE.containsVertex(e)) - assert(withoutAnyIncomingEdgeInE.edgesOf(e).size == 0) + assert(withoutAnyIncomingEdgeInE.edgesOf(e).isEmpty) } test("should get an edge given two vertices") { // contains an edge A --> B val updates = Seq( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0) ) val graph = DirectedGraph().addEdges(updates) @@ -199,19 +199,19 @@ class GraphSpec extends FunSuite { assert(graph.edgesOf(a).size == 2) //now add a new edge a -> b but with a different channel update and a different ShortChannelId - val newEdgeForNewChannel = edgeFromDesc(makeUpdate(15L, a, b, MilliSatoshi(20), 0)) + val newEdgeForNewChannel = edgeFromDesc(makeUpdate(15L, a, b, 20 msat, 0)) val mutatedGraph = graph.addEdge(newEdgeForNewChannel) assert(mutatedGraph.edgesOf(a).size == 3) //if the ShortChannelId is the same we replace the edge and the update, this edge have an update with a different 'feeBaseMsat' - val edgeForTheSameChannel = edgeFromDesc(makeUpdate(15L, a, b, MilliSatoshi(30), 0)) + val edgeForTheSameChannel = edgeFromDesc(makeUpdate(15L, a, b, 30 msat, 0)) val mutatedGraph2 = mutatedGraph.addEdge(edgeForTheSameChannel) assert(mutatedGraph2.edgesOf(a).size == 3) // A --> B , A --> B , A --> D assert(mutatedGraph2.getEdgesBetween(a, b).size === 2) - assert(mutatedGraph2.getEdge(edgeForTheSameChannel).get.update.feeBaseMsat === MilliSatoshi(30)) + assert(mutatedGraph2.getEdge(edgeForTheSameChannel).get.update.feeBaseMsat === 30.msat) } test("remove a vertex with incoming edges and check those edges are removed too") { @@ -234,11 +234,11 @@ class GraphSpec extends FunSuite { def edgeFromDesc(tuple: (ChannelDesc, ChannelUpdate)): GraphEdge = GraphEdge(tuple._1, tuple._2) def descFromNodes(shortChannelId: Long, a: PublicKey, b: PublicKey): ChannelDesc = { - makeUpdate(shortChannelId, a, b, MilliSatoshi(0), 0)._1 + makeUpdate(shortChannelId, a, b, 0 msat, 0)._1 } def edgeFromNodes(shortChannelId: Long, a: PublicKey, b: PublicKey): GraphEdge = { - edgeFromDesc(makeUpdate(shortChannelId, a, b, MilliSatoshi(0), 0)) + edgeFromDesc(makeUpdate(shortChannelId, a, b, 0 msat, 0)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala index 958d0e4113..ceb4772d66 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouteCalculationSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.router.Graph.GraphStructure.{DirectedGraph, GraphEdge} import fr.acinq.eclair.router.Graph.{RichWeight, WeightRatios} import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{CltvExpiryDelta, Globals, MilliSatoshi, ShortChannelId, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, Globals, LongToBtcAmount, MilliSatoshi, ShortChannelId, randomKey} import org.scalatest.FunSuite import scodec.bits._ @@ -43,10 +43,10 @@ class RouteCalculationSpec extends FunSuite { test("calculate simple route") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(1), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(2L, b, c, MilliSatoshi(1), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(3L, c, d, MilliSatoshi(1), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(4L, d, e, MilliSatoshi(1), 10, cltvDelta = CltvExpiryDelta(1)) + makeUpdate(1L, a, b, 1 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(2L, b, c, 1 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(3L, c, d, 1 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(4L, d, e, 1 msat, 10, cltvDelta = CltvExpiryDelta(1)) ).toMap val g = makeGraph(updates) @@ -67,15 +67,15 @@ class RouteCalculationSpec extends FunSuite { // of the amount being paid val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(2L, b, c, MilliSatoshi(10), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(3L, c, d, MilliSatoshi(10), 10, cltvDelta = CltvExpiryDelta(1)), - makeUpdate(4L, d, e, MilliSatoshi(10), 10, cltvDelta = CltvExpiryDelta(1)) + makeUpdate(1L, a, b, 10 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(2L, b, c, 10 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(3L, c, d, 10 msat, 10, cltvDelta = CltvExpiryDelta(1)), + makeUpdate(4L, d, e, 10 msat, 10, cltvDelta = CltvExpiryDelta(1)) ).toMap val g = makeGraph(updates) - val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = MilliSatoshi(1))) + val route = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = 1 msat)) assert(route.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) } @@ -99,16 +99,16 @@ class RouteCalculationSpec extends FunSuite { // cost(AE) = 10007 -> A is source, shortest path found // cost(AB) = 10009 - val amount = MilliSatoshi(10000) - val expectedCost = MilliSatoshi(10007) + val amount = 10000 msat + val expectedCost = 10007 msat val updates = List( - makeUpdate(1L, a, b, feeBase = MilliSatoshi(1), feeProportionalMillionth = 200, minHtlc = MilliSatoshi(0)), - makeUpdate(4L, a, e, feeBase = MilliSatoshi(1), feeProportionalMillionth = 200, minHtlc = MilliSatoshi(0)), - makeUpdate(2L, b, c, feeBase = MilliSatoshi(1), feeProportionalMillionth = 300, minHtlc = MilliSatoshi(0)), - makeUpdate(3L, c, d, feeBase = MilliSatoshi(1), feeProportionalMillionth = 400, minHtlc = MilliSatoshi(0)), - makeUpdate(5L, e, f, feeBase = MilliSatoshi(1), feeProportionalMillionth = 400, minHtlc = MilliSatoshi(0)), - makeUpdate(6L, f, d, feeBase = MilliSatoshi(1), feeProportionalMillionth = 100, minHtlc = MilliSatoshi(0)) + makeUpdate(1L, a, b, feeBase = 1 msat, feeProportionalMillionth = 200, minHtlc = 0 msat), + makeUpdate(4L, a, e, feeBase = 1 msat, feeProportionalMillionth = 200, minHtlc = 0 msat), + makeUpdate(2L, b, c, feeBase = 1 msat, feeProportionalMillionth = 300, minHtlc = 0 msat), + makeUpdate(3L, c, d, feeBase = 1 msat, feeProportionalMillionth = 400, minHtlc = 0 msat), + makeUpdate(5L, e, f, feeBase = 1 msat, feeProportionalMillionth = 400, minHtlc = 0 msat), + makeUpdate(6L, f, d, feeBase = 1 msat, feeProportionalMillionth = 100, minHtlc = 0 msat) ).toMap val graph = makeGraph(updates) @@ -121,7 +121,7 @@ class RouteCalculationSpec extends FunSuite { assert(totalCost === expectedCost) // now channel 5 could route the amount (10000) but not the amount + fees (10007) - val (desc, update) = makeUpdate(5L, e, f, feeBase = MilliSatoshi(1), feeProportionalMillionth = 400, minHtlc = MilliSatoshi(0), maxHtlc = Some(MilliSatoshi(10005L))) + val (desc, update) = makeUpdate(5L, e, f, feeBase = 1 msat, feeProportionalMillionth = 400, minHtlc = 0 msat, maxHtlc = Some(10005 msat)) val graph1 = graph.addEdge(desc, update) val Success(route1) = Router.findRoute(graph1, a, d, amount, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) @@ -131,11 +131,11 @@ class RouteCalculationSpec extends FunSuite { test("calculate route considering the direct channel pays no fees") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(5), 0), // a -> b - makeUpdate(2L, a, d, MilliSatoshi(15), 0), // a -> d this goes a bit closer to the target and asks for higher fees but is a direct channel - makeUpdate(3L, b, c, MilliSatoshi(5), 0), // b -> c - makeUpdate(4L, c, d, MilliSatoshi(5), 0), // c -> d - makeUpdate(5L, d, e, MilliSatoshi(5), 0) // d -> e + makeUpdate(1L, a, b, 5 msat, 0), // a -> b + makeUpdate(2L, a, d, 15 msat, 0), // a -> d this goes a bit closer to the target and asks for higher fees but is a direct channel + makeUpdate(3L, b, c, 5 msat, 0), // b -> c + makeUpdate(4L, c, d, 5 msat, 0), // c -> d + makeUpdate(5L, d, e, 5 msat, 0) // d -> e ).toMap val g = makeGraph(updates) @@ -147,10 +147,10 @@ class RouteCalculationSpec extends FunSuite { test("calculate simple route (add and remove edges") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -173,10 +173,10 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, f, g, MilliSatoshi(0), 0), - makeUpdate(2L, g, h, MilliSatoshi(0), 0), - makeUpdate(3L, h, i, MilliSatoshi(0), 0), - makeUpdate(4L, f, h, MilliSatoshi(50), 0) // more expensive + makeUpdate(1L, f, g, 0 msat, 0), + makeUpdate(2L, g, h, 0 msat, 0), + makeUpdate(3L, h, i, 0 msat, 0), + makeUpdate(4L, f, h, 50 msat, 0) // more expensive ).toMap val graph = makeGraph(updates) @@ -196,10 +196,10 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, f, g, MilliSatoshi(0), 0), - makeUpdate(4L, f, i, MilliSatoshi(50), 0), // our starting node F has a direct channel with I - makeUpdate(2L, g, h, MilliSatoshi(0), 0), - makeUpdate(3L, h, i, MilliSatoshi(0), 0) + makeUpdate(1L, f, g, 0 msat, 0), + makeUpdate(4L, f, i, 50 msat, 0), // our starting node F has a direct channel with I + makeUpdate(2L, g, h, 0 msat, 0), + makeUpdate(3L, h, i, 0 msat, 0) ).toMap val graph = makeGraph(updates) @@ -217,10 +217,10 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, f, g, MilliSatoshi(1), 0), + makeUpdate(1L, f, g, 1 msat, 0), // the maximum htlc allowed by this channel is only 50msat greater than what we're sending - makeUpdate(2L, g, h, MilliSatoshi(1), 0, maxHtlc = Some(DEFAULT_AMOUNT_MSAT + MilliSatoshi(50))), - makeUpdate(3L, h, i, MilliSatoshi(1), 0) + makeUpdate(2L, g, h, 1 msat, 0, maxHtlc = Some(DEFAULT_AMOUNT_MSAT + 50.msat)), + makeUpdate(3L, h, i, 1 msat, 0) ).toMap val graph = makeGraph(updates) @@ -238,10 +238,10 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, f, g, MilliSatoshi(1), 0), + makeUpdate(1L, f, g, 1 msat, 0), // this channel requires a minimum amount that is larger than what we are sending - makeUpdate(2L, g, h, MilliSatoshi(1), 0, minHtlc = DEFAULT_AMOUNT_MSAT + MilliSatoshi(50)), - makeUpdate(3L, h, i, MilliSatoshi(1), 0) + makeUpdate(2L, g, h, 1 msat, 0, minHtlc = DEFAULT_AMOUNT_MSAT + 50.msat), + makeUpdate(3L, h, i, 1 msat, 0) ).toMap val graph = makeGraph(updates) @@ -260,10 +260,10 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, f, g, MilliSatoshi(0), 0), - makeUpdate(2L, g, h, MilliSatoshi(5), 5), // expensive g -> h channel - makeUpdate(6L, g, h, MilliSatoshi(0), 0), // cheap g -> h channel - makeUpdate(3L, h, i, MilliSatoshi(0), 0) + makeUpdate(1L, f, g, 0 msat, 0), + makeUpdate(2L, g, h, 5 msat, 5), // expensive g -> h channel + makeUpdate(6L, g, h, 0 msat, 0), // cheap g -> h channel + makeUpdate(3L, h, i, 0 msat, 0) ).toMap val graph = makeGraph(updates) @@ -275,11 +275,11 @@ class RouteCalculationSpec extends FunSuite { test("calculate longer but cheaper route") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0), - makeUpdate(5L, b, e, MilliSatoshi(10), 10) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0), + makeUpdate(5L, b, e, 10 msat, 10) ).toMap val g = makeGraph(updates) @@ -291,8 +291,8 @@ class RouteCalculationSpec extends FunSuite { test("no local channels") { val updates = List( - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -304,9 +304,9 @@ class RouteCalculationSpec extends FunSuite { test("route not found") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -318,8 +318,8 @@ class RouteCalculationSpec extends FunSuite { test("route not found (source OR target node not connected)") { val updates = List( - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(4L, c, d, MilliSatoshi(0), 0) + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(4L, c, d, 0 msat, 0) ).toMap val g = makeGraph(updates).addVertex(a).addVertex(e) @@ -334,15 +334,15 @@ class RouteCalculationSpec extends FunSuite { val lowAmount = DEFAULT_AMOUNT_MSAT / 10 val updatesHi = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0, maxHtlc = Some(DEFAULT_AMOUNT_MSAT)), - makeUpdate(3L, c, d, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0, maxHtlc = Some(DEFAULT_AMOUNT_MSAT)), + makeUpdate(3L, c, d, 0 msat, 0) ).toMap val updatesLo = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0, minHtlc = DEFAULT_AMOUNT_MSAT), - makeUpdate(3L, c, d, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0, minHtlc = DEFAULT_AMOUNT_MSAT), + makeUpdate(3L, c, d, 0 msat, 0) ).toMap val g = makeGraph(updatesHi) @@ -355,9 +355,9 @@ class RouteCalculationSpec extends FunSuite { test("route to self") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -369,10 +369,10 @@ class RouteCalculationSpec extends FunSuite { test("route to immediate neighbor") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -383,10 +383,10 @@ class RouteCalculationSpec extends FunSuite { test("directed graph") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap // a->e works, e->a fails @@ -404,14 +404,14 @@ class RouteCalculationSpec extends FunSuite { val DUMMY_SIG = Transactions.PlaceHolderSig - val uab = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(1L), 0L, 0, 0, CltvExpiryDelta(1), MilliSatoshi(42), MilliSatoshi(2500), 140, None) - val uba = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(1L), 1L, 0, 1, CltvExpiryDelta(1), MilliSatoshi(43), MilliSatoshi(2501), 141, None) - val ubc = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(2L), 1L, 0, 0, CltvExpiryDelta(1), MilliSatoshi(44), MilliSatoshi(2502), 142, None) - val ucb = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(2L), 1L, 0, 1, CltvExpiryDelta(1), MilliSatoshi(45), MilliSatoshi(2503), 143, None) - val ucd = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(3L), 1L, 1, 0, CltvExpiryDelta(1), MilliSatoshi(46), MilliSatoshi(2504), 144, Some(MilliSatoshi(500000000L))) - val udc = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(3L), 1L, 0, 1, CltvExpiryDelta(1), MilliSatoshi(47), MilliSatoshi(2505), 145, None) - val ude = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(4L), 1L, 0, 0, CltvExpiryDelta(1), MilliSatoshi(48), MilliSatoshi(2506), 146, None) - val ued = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(4L), 1L, 0, 1, CltvExpiryDelta(1), MilliSatoshi(49), MilliSatoshi(2507), 147, None) + val uab = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(1L), 0L, 0, 0, CltvExpiryDelta(1), 42 msat, 2500 msat, 140, None) + val uba = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(1L), 1L, 0, 1, CltvExpiryDelta(1), 43 msat, 2501 msat, 141, None) + val ubc = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(2L), 1L, 0, 0, CltvExpiryDelta(1), 44 msat, 2502 msat, 142, None) + val ucb = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(2L), 1L, 0, 1, CltvExpiryDelta(1), 45 msat, 2503 msat, 143, None) + val ucd = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(3L), 1L, 1, 0, CltvExpiryDelta(1), 46 msat, 2504 msat, 144, Some(500000000 msat)) + val udc = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(3L), 1L, 0, 1, CltvExpiryDelta(1), 47 msat, 2505 msat, 145, None) + val ude = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(4L), 1L, 0, 0, CltvExpiryDelta(1), 48 msat, 2506 msat, 146, None) + val ued = ChannelUpdate(DUMMY_SIG, Block.RegtestGenesisBlock.hash, ShortChannelId(4L), 1L, 0, 1, CltvExpiryDelta(1), 49 msat, 2507 msat, 147, None) val updates = Map( ChannelDesc(ShortChannelId(1L), a, b) -> uab, @@ -438,10 +438,10 @@ class RouteCalculationSpec extends FunSuite { val d = randomKey.publicKey val e = randomKey.publicKey - val extraHop1 = ExtraHop(a, ShortChannelId(1), 10, 11, CltvExpiryDelta(12)) - val extraHop2 = ExtraHop(b, ShortChannelId(2), 20, 21, CltvExpiryDelta(22)) - val extraHop3 = ExtraHop(c, ShortChannelId(3), 30, 31, CltvExpiryDelta(32)) - val extraHop4 = ExtraHop(d, ShortChannelId(4), 40, 41, CltvExpiryDelta(42)) + val extraHop1 = ExtraHop(a, ShortChannelId(1), 10 msat, 11, CltvExpiryDelta(12)) + val extraHop2 = ExtraHop(b, ShortChannelId(2), 20 msat, 21, CltvExpiryDelta(22)) + val extraHop3 = ExtraHop(c, ShortChannelId(3), 30 msat, 31, CltvExpiryDelta(32)) + val extraHop4 = ExtraHop(d, ShortChannelId(4), 40 msat, 41, CltvExpiryDelta(42)) val extraHops = extraHop1 :: extraHop2 :: extraHop3 :: extraHop4 :: Nil @@ -458,10 +458,10 @@ class RouteCalculationSpec extends FunSuite { test("blacklist routes") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(0), 0), - makeUpdate(2L, b, c, MilliSatoshi(0), 0), - makeUpdate(3L, c, d, MilliSatoshi(0), 0), - makeUpdate(4L, d, e, MilliSatoshi(0), 0) + makeUpdate(1L, a, b, 0 msat, 0), + makeUpdate(2L, b, c, 0 msat, 0), + makeUpdate(3L, c, d, 0 msat, 0), + makeUpdate(4L, d, e, 0 msat, 0) ).toMap val g = makeGraph(updates) @@ -470,7 +470,7 @@ class RouteCalculationSpec extends FunSuite { assert(route1.map(hops2Ids) === Failure(RouteNotFound)) // verify that we left the graph untouched - assert(g.containsEdge(makeUpdate(3L, c, d, MilliSatoshi(0), 0)._1)) // c -> d + assert(g.containsEdge(makeUpdate(3L, c, d, 0 msat, 0)._1)) // c -> d assert(g.containsVertex(c)) assert(g.containsVertex(d)) @@ -481,9 +481,9 @@ class RouteCalculationSpec extends FunSuite { test("route to a destination that is not in the graph (with assisted routes)") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10), - makeUpdate(2L, b, c, MilliSatoshi(10), 10), - makeUpdate(3L, c, d, MilliSatoshi(10), 10) + makeUpdate(1L, a, b, 10 msat, 10), + makeUpdate(2L, b, c, 10 msat, 10), + makeUpdate(3L, c, d, 10 msat, 10) ).toMap val g = makeGraph(updates) @@ -492,7 +492,7 @@ class RouteCalculationSpec extends FunSuite { assert(route.map(hops2Ids) === Failure(RouteNotFound)) // now we add the missing edge to reach the destination - val (extraDesc, extraUpdate) = makeUpdate(4L, d, e, MilliSatoshi(5), 5) + val (extraDesc, extraUpdate) = makeUpdate(4L, d, e, 5 msat, 5) val extraGraphEdges = Set(GraphEdge(extraDesc, extraUpdate)) val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS) @@ -502,25 +502,25 @@ class RouteCalculationSpec extends FunSuite { test("verify that extra hops takes precedence over known channels") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10), - makeUpdate(2L, b, c, MilliSatoshi(10), 10), - makeUpdate(3L, c, d, MilliSatoshi(10), 10), - makeUpdate(4L, d, e, MilliSatoshi(10), 10) + makeUpdate(1L, a, b, 10 msat, 10), + makeUpdate(2L, b, c, 10 msat, 10), + makeUpdate(3L, c, d, 10 msat, 10), + makeUpdate(4L, d, e, 10 msat, 10) ).toMap val g = makeGraph(updates) val route1 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS) assert(route1.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) - assert(route1.get(1).lastUpdate.feeBaseMsat == MilliSatoshi(10)) + assert(route1.get(1).lastUpdate.feeBaseMsat === 10.msat) - val (extraDesc, extraUpdate) = makeUpdate(2L, b, c, MilliSatoshi(5), 5) + val (extraDesc, extraUpdate) = makeUpdate(2L, b, c, 5 msat, 5) val extraGraphEdges = Set(GraphEdge(extraDesc, extraUpdate)) val route2 = Router.findRoute(g, a, e, DEFAULT_AMOUNT_MSAT, numRoutes = 1, extraEdges = extraGraphEdges, routeParams = DEFAULT_ROUTE_PARAMS) assert(route2.map(hops2Ids) === Success(1 :: 2 :: 3 :: 4 :: Nil)) - assert(route2.get(1).lastUpdate.feeBaseMsat == MilliSatoshi(5)) + assert(route2.get(1).lastUpdate.feeBaseMsat === 5.msat) } test("compute ignored channels") { @@ -543,15 +543,15 @@ class RouteCalculationSpec extends FunSuite { ) val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10), - makeUpdate(2L, b, c, MilliSatoshi(10), 10), - makeUpdate(2L, c, b, MilliSatoshi(10), 10), - makeUpdate(3L, c, d, MilliSatoshi(10), 10), - makeUpdate(4L, d, e, MilliSatoshi(10), 10), - makeUpdate(5L, f, g, MilliSatoshi(10), 10), - makeUpdate(6L, f, h, MilliSatoshi(10), 10), - makeUpdate(7L, h, i, MilliSatoshi(10), 10), - makeUpdate(8L, i, j, MilliSatoshi(10), 10) + makeUpdate(1L, a, b, 10 msat, 10), + makeUpdate(2L, b, c, 10 msat, 10), + makeUpdate(2L, c, b, 10 msat, 10), + makeUpdate(3L, c, d, 10 msat, 10), + makeUpdate(4L, d, e, 10 msat, 10), + makeUpdate(5L, f, g, 10 msat, 10), + makeUpdate(6L, f, h, 10 msat, 10), + makeUpdate(7L, h, i, 10 msat, 10), + makeUpdate(8L, i, j, 10 msat, 10) ).toMap val ignored = Router.getIgnoredChannelDesc(updates, ignoreNodes = Set(c, j, randomKey.publicKey)) @@ -571,7 +571,7 @@ class RouteCalculationSpec extends FunSuite { val updates = nodes .zip(nodes.drop(1)) // (0, 1) :: (1, 2) :: ... .zipWithIndex // ((0, 1), 0) :: ((1, 2), 1) :: ... - .map { case ((na, nb), index) => makeUpdate(index, na, nb, MilliSatoshi(5), 0) } + .map { case ((na, nb), index) => makeUpdate(index, na, nb, 5 msat, 0) } .toMap val g = makeGraph(updates) @@ -589,10 +589,10 @@ class RouteCalculationSpec extends FunSuite { val updates = nodes .zip(nodes.drop(1)) // (0, 1) :: (1, 2) :: ... .zipWithIndex // ((0, 1), 0) :: ((1, 2), 1) :: ... - .map { case ((na, nb), index) => makeUpdate(index, na, nb, MilliSatoshi(1), 0) } + .map { case ((na, nb), index) => makeUpdate(index, na, nb, 1 msat, 0) } .toMap - val updates2 = updates + makeUpdate(99, nodes(2), nodes(48), MilliSatoshi(1000), 0) // expensive shorter route + val updates2 = updates + makeUpdate(99, nodes(2), nodes(48), 1000 msat, 0) // expensive shorter route val g = makeGraph(updates2) @@ -605,12 +605,12 @@ class RouteCalculationSpec extends FunSuite { val f = randomKey.publicKey val g = makeGraph(List( - makeUpdate(1, a, b, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(50)), - makeUpdate(2, b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(50)), - makeUpdate(3, c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(50)), - makeUpdate(4, a, e, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(5, e, f, feeBase = MilliSatoshi(5), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(6, f, d, feeBase = MilliSatoshi(5), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)) + makeUpdate(1, a, b, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(50)), + makeUpdate(2, b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(50)), + makeUpdate(3, c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(50)), + makeUpdate(4, a, e, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(5, e, f, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(6, f, d, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)) ).toMap) val route = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxCltv = CltvExpiryDelta(28))) @@ -622,12 +622,12 @@ class RouteCalculationSpec extends FunSuite { val f = randomKey.publicKey val g = makeGraph(List( - makeUpdate(1, a, b, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(2, b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(3, c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(4, d, e, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(5, e, f, feeBase = MilliSatoshi(5), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(6, b, f, feeBase = MilliSatoshi(5), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)) + makeUpdate(1, a, b, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(2, b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(3, c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(4, d, e, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(5, e, f, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(6, b, f, feeBase = 5 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)) ).toMap) val route = Router.findRoute(g, a, f, DEFAULT_AMOUNT_MSAT, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(routeMaxLength = 3)) @@ -637,11 +637,11 @@ class RouteCalculationSpec extends FunSuite { test("ignore loops") { val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10), - makeUpdate(2L, b, c, MilliSatoshi(10), 10), - makeUpdate(3L, c, a, MilliSatoshi(10), 10), - makeUpdate(4L, c, d, MilliSatoshi(10), 10), - makeUpdate(5L, d, e, MilliSatoshi(10), 10) + makeUpdate(1L, a, b, 10 msat, 10), + makeUpdate(2L, b, c, 10 msat, 10), + makeUpdate(3L, c, a, 10 msat, 10), + makeUpdate(4L, c, d, 10 msat, 10), + makeUpdate(5L, d, e, 10 msat, 10) ).toMap val g = makeGraph(updates) @@ -654,13 +654,13 @@ class RouteCalculationSpec extends FunSuite { // the graph contains a possible 0-cost path that goes back on its steps ( e -> f, f -> e ) val updates = List( - makeUpdate(1L, a, b, MilliSatoshi(10), 10), // a -> b - makeUpdate(2L, b, c, MilliSatoshi(10), 10), - makeUpdate(4L, c, d, MilliSatoshi(10), 10), - makeUpdate(3L, b, e, MilliSatoshi(0), 0), // b -> e - makeUpdate(6L, e, f, MilliSatoshi(0), 0), // e -> f - makeUpdate(6L, f, e, MilliSatoshi(0), 0), // e <- f - makeUpdate(5L, e, d, MilliSatoshi(0), 0) // e -> d + makeUpdate(1L, a, b, 10 msat, 10), // a -> b + makeUpdate(2L, b, c, 10 msat, 10), + makeUpdate(4L, c, d, 10 msat, 10), + makeUpdate(3L, b, e, 0 msat, 0), // b -> e + makeUpdate(6L, e, f, 0 msat, 0), // e -> f + makeUpdate(6L, f, e, 0 msat, 0), // e <- f + makeUpdate(5L, e, d, 0 msat, 0) // e -> d ).toMap val g = makeGraph(updates) @@ -695,13 +695,13 @@ class RouteCalculationSpec extends FunSuite { val edges = Seq( - makeUpdate(1L, d, a, MilliSatoshi(1), 0), - makeUpdate(2L, d, e, MilliSatoshi(1), 0), - makeUpdate(3L, a, e, MilliSatoshi(1), 0), - makeUpdate(4L, e, b, MilliSatoshi(1), 0), - makeUpdate(5L, e, f, MilliSatoshi(1), 0), - makeUpdate(6L, b, c, MilliSatoshi(1), 0), - makeUpdate(7L, c, f, MilliSatoshi(1), 0) + makeUpdate(1L, d, a, 1 msat, 0), + makeUpdate(2L, d, e, 1 msat, 0), + makeUpdate(3L, a, e, 1 msat, 0), + makeUpdate(4L, e, b, 1 msat, 0), + makeUpdate(5L, e, f, 1 msat, 0), + makeUpdate(6L, b, c, 1 msat, 0), + makeUpdate(7L, c, f, 1 msat, 0) ).toMap val graph = DirectedGraph.makeGraph(edges) @@ -727,15 +727,15 @@ class RouteCalculationSpec extends FunSuite { val edges = Seq( - makeUpdate(10L, c, e, MilliSatoshi(2), 0), - makeUpdate(20L, c, d, MilliSatoshi(3), 0), - makeUpdate(30L, d, f, MilliSatoshi(4), 5), // D- > F has a higher cost to distinguish it from the 2nd cheapest route - makeUpdate(40L, e, d, MilliSatoshi(1), 0), - makeUpdate(50L, e, f, MilliSatoshi(2), 0), - makeUpdate(60L, e, g, MilliSatoshi(3), 0), - makeUpdate(70L, f, g, MilliSatoshi(2), 0), - makeUpdate(80L, f, h, MilliSatoshi(1), 0), - makeUpdate(90L, g, h, MilliSatoshi(2), 0) + makeUpdate(10L, c, e, 2 msat, 0), + makeUpdate(20L, c, d, 3 msat, 0), + makeUpdate(30L, d, f, 4 msat, 5), // D- > F has a higher cost to distinguish it from the 2nd cheapest route + makeUpdate(40L, e, d, 1 msat, 0), + makeUpdate(50L, e, f, 2 msat, 0), + makeUpdate(60L, e, g, 3 msat, 0), + makeUpdate(70L, f, g, 2 msat, 0), + makeUpdate(80L, f, h, 1 msat, 0), + makeUpdate(90L, g, h, 2 msat, 0) ) val graph = DirectedGraph().addEdges(edges) @@ -756,19 +756,19 @@ class RouteCalculationSpec extends FunSuite { // simple graph with only 2 possible paths from A to F val edges = Seq( - makeUpdate(1L, a, b, MilliSatoshi(1), 0), - makeUpdate(1L, b, a, MilliSatoshi(1), 0), - makeUpdate(2L, b, c, MilliSatoshi(1), 0), - makeUpdate(2L, c, b, MilliSatoshi(1), 0), - makeUpdate(3L, c, f, MilliSatoshi(1), 0), - makeUpdate(3L, f, c, MilliSatoshi(1), 0), - makeUpdate(4L, c, d, MilliSatoshi(1), 0), - makeUpdate(4L, d, c, MilliSatoshi(1), 0), - makeUpdate(41L, d, c, MilliSatoshi(1), 0), // there is more than one D -> C channel - makeUpdate(5L, d, e, MilliSatoshi(1), 0), - makeUpdate(5L, e, d, MilliSatoshi(1), 0), - makeUpdate(6L, e, f, MilliSatoshi(1), 0), - makeUpdate(6L, f, e, MilliSatoshi(1), 0) + makeUpdate(1L, a, b, 1 msat, 0), + makeUpdate(1L, b, a, 1 msat, 0), + makeUpdate(2L, b, c, 1 msat, 0), + makeUpdate(2L, c, b, 1 msat, 0), + makeUpdate(3L, c, f, 1 msat, 0), + makeUpdate(3L, f, c, 1 msat, 0), + makeUpdate(4L, c, d, 1 msat, 0), + makeUpdate(4L, d, c, 1 msat, 0), + makeUpdate(41L, d, c, 1 msat, 0), // there is more than one D -> C channel + makeUpdate(5L, d, e, 1 msat, 0), + makeUpdate(5L, e, d, 1 msat, 0), + makeUpdate(6L, e, f, 1 msat, 0), + makeUpdate(6L, f, e, 1 msat, 0) ) val graph = DirectedGraph().addEdges(edges) @@ -783,19 +783,19 @@ class RouteCalculationSpec extends FunSuite { test("select a random route below the requested fee") { - val strictFeeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = MilliSatoshi(7), maxFeePct = 0) + val strictFeeParams = DEFAULT_ROUTE_PARAMS.copy(maxFeeBase = 7 msat, maxFeePct = 0) // A -> B -> C -> D has total cost of 10000005 // A -> E -> C -> D has total cost of 11080003 !! // A -> E -> F -> D has total cost of 10000006 val g = makeGraph(List( - makeUpdate(1L, a, b, feeBase = MilliSatoshi(1), 0), - makeUpdate(4L, a, e, feeBase = MilliSatoshi(1), 0), - makeUpdate(2L, b, c, feeBase = MilliSatoshi(2), 0), - makeUpdate(3L, c, d, feeBase = MilliSatoshi(3), 0), - makeUpdate(5L, e, f, feeBase = MilliSatoshi(3), 0), - makeUpdate(6L, f, d, feeBase = MilliSatoshi(3), 0), - makeUpdate(7L, e, c, feeBase = MilliSatoshi(9), 0) + makeUpdate(1L, a, b, feeBase = 1 msat, 0), + makeUpdate(4L, a, e, feeBase = 1 msat, 0), + makeUpdate(2L, b, c, feeBase = 2 msat, 0), + makeUpdate(3L, c, d, feeBase = 3 msat, 0), + makeUpdate(5L, e, f, feeBase = 3 msat, 0), + makeUpdate(6L, f, d, feeBase = 3 msat, 0), + makeUpdate(7L, e, c, feeBase = 9 msat, 0) ).toMap) (for {_ <- 0 to 10} yield Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT, numRoutes = 3, routeParams = strictFeeParams)).map { @@ -805,25 +805,25 @@ class RouteCalculationSpec extends FunSuite { val routeCost = Graph.pathWeight(hops2Edges(someRoute), DEFAULT_AMOUNT_MSAT, isPartial = false, 0, None).cost - DEFAULT_AMOUNT_MSAT // over the three routes we could only get the 2 cheapest because the third is too expensive (over 7msat of fees) - assert(routeCost == MilliSatoshi(5) || routeCost == MilliSatoshi(6)) + assert(routeCost === 5.msat || routeCost === 6.msat) } } test("Use weight ratios to when computing the edge weight") { - val largeCapacity = MilliSatoshi(8000000000L) + val largeCapacity = 8000000000L msat // A -> B -> C -> D is 'fee optimized', lower fees route (totFees = 2, totCltv = 4000) // A -> E -> F -> D is 'timeout optimized', lower CLTV route (totFees = 3, totCltv = 18) // A -> E -> C -> D is 'capacity optimized', more recent channel/larger capacity route val updates = List( - makeUpdate(1L, a, b, feeBase = MilliSatoshi(0), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(13)), - makeUpdate(4L, a, e, feeBase = MilliSatoshi(0), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(12)), - makeUpdate(2L, b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(500)), - makeUpdate(3L, c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(500)), - makeUpdate(5L, e, f, feeBase = MilliSatoshi(2), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(6L, f, d, feeBase = MilliSatoshi(2), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, CltvExpiryDelta(9)), - makeUpdate(7L, e, c, feeBase = MilliSatoshi(2), 0, minHtlc = MilliSatoshi(0), maxHtlc = Some(largeCapacity), CltvExpiryDelta(12)) + makeUpdate(1L, a, b, feeBase = 0 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(13)), + makeUpdate(4L, a, e, feeBase = 0 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(12)), + makeUpdate(2L, b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(500)), + makeUpdate(3L, c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(500)), + makeUpdate(5L, e, f, feeBase = 2 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(6L, f, d, feeBase = 2 msat, 0, minHtlc = 0 msat, maxHtlc = None, CltvExpiryDelta(9)), + makeUpdate(7L, e, c, feeBase = 2 msat, 0, minHtlc = 0 msat, maxHtlc = Some(largeCapacity), CltvExpiryDelta(12)) ).toMap val g = makeGraph(updates) @@ -853,12 +853,12 @@ class RouteCalculationSpec extends FunSuite { val currentBlockHeight = 554000 val g = makeGraph(List( - makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x1"), a, b, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x4"), a, e, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"${currentBlockHeight - 3000}x0x2"), b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), // younger channel - makeUpdateShort(ShortChannelId(s"${currentBlockHeight - 3000}x0x3"), c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x5"), e, f, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x6"), f, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)) + makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x1"), a, b, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x4"), a, e, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"${currentBlockHeight - 3000}x0x2"), b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), // younger channel + makeUpdateShort(ShortChannelId(s"${currentBlockHeight - 3000}x0x3"), c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x5"), e, f, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"${currentBlockHeight}x0x6"), f, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)) ).toMap) Globals.blockCount.set(currentBlockHeight) @@ -875,12 +875,12 @@ class RouteCalculationSpec extends FunSuite { test("prefer a route with a smaller total CLTV if fees and score are the same") { val g = makeGraph(List( - makeUpdateShort(ShortChannelId(s"0x0x1"), a, b, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), - makeUpdateShort(ShortChannelId(s"0x0x4"), a, e, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), - makeUpdateShort(ShortChannelId(s"0x0x2"), b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(10)), // smaller CLTV - makeUpdateShort(ShortChannelId(s"0x0x3"), c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), - makeUpdateShort(ShortChannelId(s"0x0x5"), e, f, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), - makeUpdateShort(ShortChannelId(s"0x0x6"), f, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(12)) + makeUpdateShort(ShortChannelId(s"0x0x1"), a, b, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), + makeUpdateShort(ShortChannelId(s"0x0x4"), a, e, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), + makeUpdateShort(ShortChannelId(s"0x0x2"), b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(10)), // smaller CLTV + makeUpdateShort(ShortChannelId(s"0x0x3"), c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), + makeUpdateShort(ShortChannelId(s"0x0x5"), e, f, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)), + makeUpdateShort(ShortChannelId(s"0x0x6"), f, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(12)) ).toMap) @@ -899,12 +899,12 @@ class RouteCalculationSpec extends FunSuite { // A -> B -> C -> D is cheaper but has a total CLTV > 2016! // A -> E -> F -> D is more expensive but has a total CLTV < 2016 val g = makeGraph(List( - makeUpdateShort(ShortChannelId(s"0x0x1"), a, b, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"0x0x4"), a, e, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"0x0x2"), b, c, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(1000)), - makeUpdateShort(ShortChannelId(s"0x0x3"), c, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(900)), - makeUpdateShort(ShortChannelId(s"0x0x5"), e, f, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), - makeUpdateShort(ShortChannelId(s"0x0x6"), f, d, feeBase = MilliSatoshi(1), 0, minHtlc = MilliSatoshi(0), maxHtlc = None, cltvDelta = CltvExpiryDelta(144)) + makeUpdateShort(ShortChannelId(s"0x0x1"), a, b, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"0x0x4"), a, e, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"0x0x2"), b, c, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(1000)), + makeUpdateShort(ShortChannelId(s"0x0x3"), c, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(900)), + makeUpdateShort(ShortChannelId(s"0x0x5"), e, f, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)), + makeUpdateShort(ShortChannelId(s"0x0x6"), f, d, feeBase = 1 msat, 0, minHtlc = 0 msat, maxHtlc = None, cltvDelta = CltvExpiryDelta(144)) ).toMap) val Success(routeScoreOptimized) = Router.findRoute(g, a, d, DEFAULT_AMOUNT_MSAT / 2, numRoutes = 1, routeParams = DEFAULT_ROUTE_PARAMS.copy(ratios = Some(WeightRatios( @@ -921,22 +921,22 @@ class RouteCalculationSpec extends FunSuite { // This test have a channel (542280x2156x0) that according to heuristics is very convenient but actually useless to reach the target, // then if the cost function is not monotonic the path-finding breaks because the result path contains a loop. val updates = List( - ChannelDesc(ShortChannelId("565643x1216x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565643x1216x0"), 0, 1.toByte, 1.toByte, CltvExpiryDelta(144), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(1000), 100, Some(MilliSatoshi(15000000000L))), - ChannelDesc(ShortChannelId("565643x1216x0"), PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565643x1216x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(14), htlcMinimumMsat = MilliSatoshi(1), MilliSatoshi(1000), 10, Some(MilliSatoshi(4294967295L))), - ChannelDesc(ShortChannelId("542280x2156x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("542280x2156x0"), 0, 1.toByte, 1.toByte, CltvExpiryDelta(144), htlcMinimumMsat = MilliSatoshi(1000), feeBaseMsat = MilliSatoshi(1000), 100, Some(MilliSatoshi(16777000000L))), - ChannelDesc(ShortChannelId("542280x2156x0"), PublicKey(hex"03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("542280x2156x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(144), htlcMinimumMsat = MilliSatoshi(1), MilliSatoshi(667), 1, Some(MilliSatoshi(16777000000L))), - ChannelDesc(ShortChannelId("565779x2711x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565779x2711x0"), 0, 1.toByte, 3.toByte, CltvExpiryDelta(144), htlcMinimumMsat = MilliSatoshi(1), MilliSatoshi(1000), 100, Some(MilliSatoshi(230000000L))), - ChannelDesc(ShortChannelId("565779x2711x0"), PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565779x2711x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(144), htlcMinimumMsat = MilliSatoshi(1), MilliSatoshi(1000), 100, Some(MilliSatoshi(230000000L))) + ChannelDesc(ShortChannelId("565643x1216x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565643x1216x0"), 0, 1.toByte, 1.toByte, CltvExpiryDelta(144), htlcMinimumMsat = 0 msat, 1000 msat, 100, Some(15000000000L msat)), + ChannelDesc(ShortChannelId("565643x1216x0"), PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565643x1216x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(14), htlcMinimumMsat = 1 msat, 1000 msat, 10, Some(4294967295L msat)), + ChannelDesc(ShortChannelId("542280x2156x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("542280x2156x0"), 0, 1.toByte, 1.toByte, CltvExpiryDelta(144), htlcMinimumMsat = 1000 msat, 1000 msat, 100, Some(16777000000L msat)), + ChannelDesc(ShortChannelId("542280x2156x0"), PublicKey(hex"03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("542280x2156x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, 667 msat, 1, Some(16777000000L msat)), + ChannelDesc(ShortChannelId("565779x2711x0"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f"), PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565779x2711x0"), 0, 1.toByte, 3.toByte, CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, 1000 msat, 100, Some(230000000L msat)), + ChannelDesc(ShortChannelId("565779x2711x0"), PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96"), PublicKey(hex"03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")) -> ChannelUpdate(ByteVector64.Zeroes, ByteVector32.Zeroes, ShortChannelId("565779x2711x0"), 0, 1.toByte, 0.toByte, CltvExpiryDelta(144), htlcMinimumMsat = 1 msat, 1000 msat, 100, Some(230000000L msat)) ).toMap val g = DirectedGraph.makeGraph(updates) - val params = RouteParams(randomize = false, maxFeeBase = MilliSatoshi(21000), maxFeePct = 0.03, routeMaxCltv = CltvExpiryDelta(1008), routeMaxLength = 6, ratios = Some( + val params = RouteParams(randomize = false, maxFeeBase = 21000 msat, maxFeePct = 0.03, routeMaxCltv = CltvExpiryDelta(1008), routeMaxLength = 6, ratios = Some( WeightRatios(cltvDeltaFactor = 0.15, ageFactor = 0.35, capacityFactor = 0.5) )) val thisNode = PublicKey(hex"036d65409c41ab7380a43448f257809e7496b52bf92057c09c4f300cbd61c50d96") val targetNode = PublicKey(hex"024655b768ef40951b20053a5c4b951606d4d86085d51238f2c67c7dec29c792ca") - val amount = MilliSatoshi(351000) + val amount = 351000 msat Globals.blockCount.set(567634) // simulate mainnet block for heuristic val Success(route) = Router.findRoute(g, thisNode, targetNode, amount, 1, Set.empty, Set.empty, params) @@ -950,9 +950,9 @@ object RouteCalculationSpec { val noopBoundaries = { _: RichWeight => true } - val DEFAULT_AMOUNT_MSAT = MilliSatoshi(10000000) + val DEFAULT_AMOUNT_MSAT = 10000000 msat - val DEFAULT_ROUTE_PARAMS = RouteParams(randomize = false, maxFeeBase = MilliSatoshi(21000), maxFeePct = 0.03, routeMaxCltv = CltvExpiryDelta(2016), routeMaxLength = 6, ratios = None) + val DEFAULT_ROUTE_PARAMS = RouteParams(randomize = false, maxFeeBase = 21000 msat, maxFeePct = 0.03, routeMaxCltv = CltvExpiryDelta(2016), routeMaxLength = 6, ratios = None) val DUMMY_SIG = Transactions.PlaceHolderSig diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala index f5bddc0f68..9cb4c8d799 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RouterSpec.scala @@ -20,7 +20,7 @@ import akka.actor.Status.Failure import akka.testkit.TestProbe import fr.acinq.bitcoin.Crypto.PublicKey import fr.acinq.bitcoin.Script.{pay2wsh, write} -import fr.acinq.bitcoin.{Block, Satoshi, Transaction, TxOut} +import fr.acinq.bitcoin.{Block, Transaction, TxOut} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.channel.BITCOIN_FUNDING_EXTERNAL_CHANNEL_SPENT import fr.acinq.eclair.crypto.TransportHandler @@ -30,7 +30,7 @@ import fr.acinq.eclair.router.Announcements.makeChannelUpdate import fr.acinq.eclair.router.RouteCalculationSpec.DEFAULT_AMOUNT_MSAT import fr.acinq.eclair.transactions.Scripts import fr.acinq.eclair.wire.QueryShortChannelIds -import fr.acinq.eclair.{CltvExpiryDelta, Globals, MilliSatoshi, ShortChannelId, randomKey} +import fr.acinq.eclair.{CltvExpiryDelta, Globals, LongToBtcAmount, ShortChannelId, randomKey} import scodec.bits._ import scala.collection.SortedSet @@ -52,21 +52,21 @@ class RouterSpec extends BaseRouterSpec { val channelId_ac = ShortChannelId(420000, 5, 0) val chan_ac = channelAnnouncement(channelId_ac, priv_a, priv_c, priv_funding_a, priv_funding_c) - val update_ac = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId_ac, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L)) + val update_ac = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId_ac, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 500000000L msat) // a-x will not be found val priv_x = randomKey val chan_ax = channelAnnouncement(ShortChannelId(42001), priv_a, priv_x, priv_funding_a, randomKey) - val update_ax = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_x.publicKey, chan_ax.shortChannelId, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L)) + val update_ax = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_x.publicKey, chan_ax.shortChannelId, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 500000000L msat) // a-y will have an invalid script val priv_y = randomKey val priv_funding_y = randomKey val chan_ay = channelAnnouncement(ShortChannelId(42002), priv_a, priv_y, priv_funding_a, priv_funding_y) - val update_ay = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_y.publicKey, chan_ay.shortChannelId, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L)) + val update_ay = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_y.publicKey, chan_ay.shortChannelId, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 500000000L msat) // a-z will be spent val priv_z = randomKey val priv_funding_z = randomKey val chan_az = channelAnnouncement(ShortChannelId(42003), priv_a, priv_z, priv_funding_a, priv_funding_z) - val update_az = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_z.publicKey, chan_az.shortChannelId, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L)) + val update_az = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_z.publicKey, chan_az.shortChannelId, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 500000000L msat) router ! PeerRoutingMessage(null, remoteNodeId, chan_ac) router ! PeerRoutingMessage(null, remoteNodeId, chan_ax) @@ -81,14 +81,14 @@ class RouterSpec extends BaseRouterSpec { watcher.expectMsg(ValidateRequest(chan_ax)) watcher.expectMsg(ValidateRequest(chan_ay)) watcher.expectMsg(ValidateRequest(chan_az)) - watcher.send(router, ValidateResult(chan_ac, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))) + watcher.send(router, ValidateResult(chan_ac, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))) watcher.send(router, ValidateResult(chan_ax, Left(new RuntimeException(s"funding tx not found")))) - watcher.send(router, ValidateResult(chan_ay, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, randomKey.publicKey)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))) - watcher.send(router, ValidateResult(chan_az, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, priv_funding_z.publicKey)))) :: Nil, lockTime = 0), UtxoStatus.Spent(spendingTxConfirmed = true)))) + watcher.send(router, ValidateResult(chan_ay, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_a, randomKey.publicKey)))) :: Nil, lockTime = 0), UtxoStatus.Unspent))) + watcher.send(router, ValidateResult(chan_az, Right(Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_a, priv_funding_z.publicKey)))) :: Nil, lockTime = 0), UtxoStatus.Spent(spendingTxConfirmed = true)))) watcher.expectMsgType[WatchSpentBasic] watcher.expectNoMsg(1 second) - eventListener.expectMsg(ChannelsDiscovered(SingleChannelDiscovered(chan_ac, Satoshi(1000000)) :: Nil)) + eventListener.expectMsg(ChannelsDiscovered(SingleChannelDiscovered(chan_ac, 1000000 sat) :: Nil)) } test("properly announce lost channels and nodes") { fixture => @@ -184,9 +184,9 @@ class RouterSpec extends BaseRouterSpec { val x = PublicKey(hex"02999fa724ec3c244e4da52b4a91ad421dc96c9a810587849cd4b2469313519c73") val y = PublicKey(hex"03f1cb1af20fe9ccda3ea128e27d7c39ee27375c8480f11a87c17197e97541ca6a") val z = PublicKey(hex"0358e32d245ff5f5a3eb14c78c6f69c67cea7846bdf9aeeb7199e8f6fbb0306484") - val extraHop_cx = ExtraHop(c, ShortChannelId(1), 10, 11, CltvExpiryDelta(12)) - val extraHop_xy = ExtraHop(x, ShortChannelId(2), 10, 11, CltvExpiryDelta(12)) - val extraHop_yz = ExtraHop(y, ShortChannelId(3), 20, 21, CltvExpiryDelta(22)) + val extraHop_cx = ExtraHop(c, ShortChannelId(1), 10 msat, 11, CltvExpiryDelta(12)) + val extraHop_xy = ExtraHop(x, ShortChannelId(2), 10 msat, 11, CltvExpiryDelta(12)) + val extraHop_yz = ExtraHop(y, ShortChannelId(3), 20 msat, 21, CltvExpiryDelta(22)) sender.send(router, RouteRequest(a, z, DEFAULT_AMOUNT_MSAT, assistedRoutes = Seq(extraHop_cx :: extraHop_xy :: extraHop_yz :: Nil))) val res = sender.expectMsgType[RouteResponse] assert(res.hops.map(_.nodeId).toList === a :: b :: c :: x :: y :: Nil) @@ -201,7 +201,7 @@ class RouterSpec extends BaseRouterSpec { assert(res.hops.map(_.nodeId).toList === a :: b :: c :: Nil) assert(res.hops.last.nextNodeId === d) - val channelUpdate_cd1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, d, channelId_cd, CltvExpiryDelta(3), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(153000), feeProportionalMillionths = 4, htlcMaximumMsat = MilliSatoshi(500000000L), enable = false) + val channelUpdate_cd1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_c, d, channelId_cd, CltvExpiryDelta(3), 0 msat, 153000 msat, 4, 500000000L msat, enable = false) sender.send(router, PeerRoutingMessage(null, remoteNodeId, channelUpdate_cd1)) sender.expectMsg(TransportHandler.ReadAck(channelUpdate_cd1)) sender.send(router, RouteRequest(a, d, DEFAULT_AMOUNT_MSAT, routeParams = relaxedRouteParams)) @@ -257,20 +257,20 @@ class RouterSpec extends BaseRouterSpec { val channelId = ShortChannelId(blockHeight, 5, 0) val announcement = channelAnnouncement(channelId, priv_a, priv_c, priv_funding_a, priv_funding_c) val timestamp = (Platform.currentTime.milliseconds - 14.days - 1.day).toSeconds - val update = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId, CltvExpiryDelta(7), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, htlcMaximumMsat = MilliSatoshi(5), timestamp = timestamp) + val update = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 5 msat, timestamp = timestamp) val probe = TestProbe() probe.ignoreMsg { case _: TransportHandler.ReadAck => true } probe.send(router, PeerRoutingMessage(null, remoteNodeId, announcement)) watcher.expectMsgType[ValidateRequest] probe.send(router, PeerRoutingMessage(null, remoteNodeId, update)) - watcher.send(router, ValidateResult(announcement, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) + watcher.send(router, ValidateResult(announcement, Right((Transaction(version = 0, txIn = Nil, txOut = TxOut(1000000 sat, write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_c)))) :: Nil, lockTime = 0), UtxoStatus.Unspent)))) probe.send(router, TickPruneStaleChannels) val sender = TestProbe() sender.send(router, GetRoutingState) val state = sender.expectMsgType[RoutingState] - val update1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId, CltvExpiryDelta(7), htlcMinimumMsat = MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, htlcMaximumMsat = MilliSatoshi(500000000L), timestamp = Platform.currentTime.millisecond.toSeconds) + val update1 = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, c, channelId, CltvExpiryDelta(7), 0 msat, 766000 msat, 10, 500000000L msat, timestamp = Platform.currentTime.millisecond.toSeconds) // we want to make sure that transport receives the query val transport = TestProbe() diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala index 05db9102d3..b52c87cf5c 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/RoutingSyncSpec.scala @@ -130,8 +130,8 @@ object RoutingSyncSpec { val (priv_a, priv_b, priv_funding_a, priv_funding_b) = (randomKey, randomKey, randomKey, randomKey) val channelAnn_ab = channelAnnouncement(shortChannelId, priv_a, priv_b, priv_funding_a, priv_funding_b) val TxCoordinates(blockHeight, _, _) = ShortChannelId.coordinates(shortChannelId) - val channelUpdate_ab = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_b.publicKey, shortChannelId, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L), timestamp = blockHeight) - val channelUpdate_ba = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, priv_a.publicKey, shortChannelId, CltvExpiryDelta(7), MilliSatoshi(0), feeBaseMsat = MilliSatoshi(766000), feeProportionalMillionths = 10, MilliSatoshi(500000000L), timestamp = blockHeight) + val channelUpdate_ab = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_a, priv_b.publicKey, shortChannelId, CltvExpiryDelta(7), 0 msat, feeBaseMsat = 766000 msat, feeProportionalMillionths = 10, 500000000 msat, timestamp = blockHeight) + val channelUpdate_ba = makeChannelUpdate(Block.RegtestGenesisBlock.hash, priv_b, priv_a.publicKey, shortChannelId, CltvExpiryDelta(7), 0 msat, feeBaseMsat = 766000 msat, feeProportionalMillionths = 10, 500000000 msat, timestamp = blockHeight) 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) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/CommitmentSpecSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/CommitmentSpecSpec.scala index 4df1d50010..b0a3a3953d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/CommitmentSpecSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/CommitmentSpecSpec.scala @@ -18,52 +18,51 @@ package fr.acinq.eclair.transactions import fr.acinq.bitcoin.{ByteVector32, Crypto} import fr.acinq.eclair.wire.{UpdateAddHtlc, UpdateFailHtlc, UpdateFulfillHtlc} -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, TestConstants, randomBytes32} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, TestConstants, randomBytes32} import org.scalatest.FunSuite - class CommitmentSpecSpec extends FunSuite { test("add, fulfill and fail htlcs from the sender side") { - val spec = CommitmentSpec(htlcs = Set(), feeratePerKw = 1000, toLocal = MilliSatoshi(5000000), toRemote = MilliSatoshi(0)) + val spec = CommitmentSpec(htlcs = Set(), feeratePerKw = 1000, toLocal = 5000000 msat, toRemote = 0 msat) val R = randomBytes32 val H = Crypto.sha256(R) - val add1 = UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(2000 * 1000), H, CltvExpiry(400), TestConstants.emptyOnionPacket) + val add1 = UpdateAddHtlc(ByteVector32.Zeroes, 1, (2000 * 1000) msat, H, CltvExpiry(400), TestConstants.emptyOnionPacket) val spec1 = CommitmentSpec.reduce(spec, add1 :: Nil, Nil) - assert(spec1 === spec.copy(htlcs = Set(DirectedHtlc(OUT, add1)), toLocal = MilliSatoshi(3000000))) + assert(spec1 === spec.copy(htlcs = Set(DirectedHtlc(OUT, add1)), toLocal = 3000000 msat)) - val add2 = UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(1000 * 1000), H, CltvExpiry(400), TestConstants.emptyOnionPacket) + val add2 = UpdateAddHtlc(ByteVector32.Zeroes, 2, (1000 * 1000) msat, H, CltvExpiry(400), TestConstants.emptyOnionPacket) val spec2 = CommitmentSpec.reduce(spec1, add2 :: Nil, Nil) - assert(spec2 === spec1.copy(htlcs = Set(DirectedHtlc(OUT, add1), DirectedHtlc(OUT, add2)), toLocal = MilliSatoshi(2000000))) + assert(spec2 === spec1.copy(htlcs = Set(DirectedHtlc(OUT, add1), DirectedHtlc(OUT, add2)), toLocal = 2000000 msat)) val ful1 = UpdateFulfillHtlc(ByteVector32.Zeroes, add1.id, R) val spec3 = CommitmentSpec.reduce(spec2, Nil, ful1 :: Nil) - assert(spec3 === spec2.copy(htlcs = Set(DirectedHtlc(OUT, add2)), toRemote = MilliSatoshi(2000000))) + assert(spec3 === spec2.copy(htlcs = Set(DirectedHtlc(OUT, add2)), toRemote = 2000000 msat)) val fail1 = UpdateFailHtlc(ByteVector32.Zeroes, add2.id, R) val spec4 = CommitmentSpec.reduce(spec3, Nil, fail1 :: Nil) - assert(spec4 === spec3.copy(htlcs = Set(), toLocal = MilliSatoshi(3000000))) + assert(spec4 === spec3.copy(htlcs = Set(), toLocal = 3000000 msat)) } test("add, fulfill and fail htlcs from the receiver side") { - val spec = CommitmentSpec(htlcs = Set(), feeratePerKw = 1000, toLocal = MilliSatoshi(0), toRemote = MilliSatoshi(5000 * 1000)) + val spec = CommitmentSpec(htlcs = Set(), feeratePerKw = 1000, toLocal = 0 msat, toRemote = (5000 * 1000) msat) val R = randomBytes32 val H = Crypto.sha256(R) - val add1 = UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(2000 * 1000), H, CltvExpiry(400), TestConstants.emptyOnionPacket) + val add1 = UpdateAddHtlc(ByteVector32.Zeroes, 1, (2000 * 1000) msat, H, CltvExpiry(400), TestConstants.emptyOnionPacket) val spec1 = CommitmentSpec.reduce(spec, Nil, add1 :: Nil) - assert(spec1 === spec.copy(htlcs = Set(DirectedHtlc(IN, add1)), toRemote = MilliSatoshi(3000 * 1000))) + assert(spec1 === spec.copy(htlcs = Set(DirectedHtlc(IN, add1)), toRemote = (3000 * 1000 msat))) - val add2 = UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(1000 * 1000), H, CltvExpiry(400), TestConstants.emptyOnionPacket) + val add2 = UpdateAddHtlc(ByteVector32.Zeroes, 2, (1000 * 1000) msat, H, CltvExpiry(400), TestConstants.emptyOnionPacket) val spec2 = CommitmentSpec.reduce(spec1, Nil, add2 :: Nil) - assert(spec2 === spec1.copy(htlcs = Set(DirectedHtlc(IN, add1), DirectedHtlc(IN, add2)), toRemote = MilliSatoshi(2000 * 1000))) + assert(spec2 === spec1.copy(htlcs = Set(DirectedHtlc(IN, add1), DirectedHtlc(IN, add2)), toRemote = (2000 * 1000) msat)) val ful1 = UpdateFulfillHtlc(ByteVector32.Zeroes, add1.id, R) val spec3 = CommitmentSpec.reduce(spec2, ful1 :: Nil, Nil) - assert(spec3 === spec2.copy(htlcs = Set(DirectedHtlc(IN, add2)), toLocal = MilliSatoshi(2000 * 1000))) + assert(spec3 === spec2.copy(htlcs = Set(DirectedHtlc(IN, add2)), toLocal = (2000 * 1000) msat)) val fail1 = UpdateFailHtlc(ByteVector32.Zeroes, add2.id, R) val spec4 = CommitmentSpec.reduce(spec3, fail1 :: Nil, Nil) - assert(spec4 === spec3.copy(htlcs = Set(), toRemote = MilliSatoshi(3000 * 1000))) + assert(spec4 === spec3.copy(htlcs = Set(), toRemote = (3000 * 1000) msat)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala index aded1beb8a..a7f88649a9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala @@ -22,7 +22,7 @@ import fr.acinq.eclair.channel.Helpers.Funding import fr.acinq.eclair.crypto.Generators import fr.acinq.eclair.transactions.Transactions.{HtlcSuccessTx, HtlcTimeoutTx, TransactionWithInputInfo} import fr.acinq.eclair.wire.UpdateAddHtlc -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, TestConstants} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, TestConstants} import grizzled.slf4j.Logging import org.scalatest.FunSuite import scodec.bits._ @@ -66,7 +66,7 @@ class TestVectorsSpec extends FunSuite with Logging { object Local { val commitTxNumber = 42 val toSelfDelay = CltvExpiryDelta(144) - val dustLimit = Satoshi(546) + val dustLimit = 546 sat val payment_basepoint_secret = PrivateKey(hex"1111111111111111111111111111111111111111111111111111111111111111") val payment_basepoint = payment_basepoint_secret.publicKey val revocation_basepoint_secret = PrivateKey(hex"2222222222222222222222222222222222222222222222222222222222222222") @@ -108,7 +108,7 @@ class TestVectorsSpec extends FunSuite with Logging { object Remote { val commitTxNumber = 42 val toSelfDelay = CltvExpiryDelta(144) - val dustLimit = Satoshi(546) + val dustLimit = 546 sat val payment_basepoint_secret = PrivateKey(hex"4444444444444444444444444444444444444444444444444444444444444444") val payment_basepoint = payment_basepoint_secret.publicKey val revocation_basepoint_secret = PrivateKey(hex"2222222222222222222222222222222222222222222222222222222222222222") @@ -154,11 +154,11 @@ class TestVectorsSpec extends FunSuite with Logging { ) val htlcs = Seq( - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(1000000), Crypto.sha256(paymentPreimages(0)), CltvExpiry(500), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(2000000), Crypto.sha256(paymentPreimages(1)), CltvExpiry(501), TestConstants.emptyOnionPacket)), - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(2000000), Crypto.sha256(paymentPreimages(2)), CltvExpiry(502), TestConstants.emptyOnionPacket)), - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(3000000), Crypto.sha256(paymentPreimages(3)), CltvExpiry(503), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(4000000), Crypto.sha256(paymentPreimages(4)), CltvExpiry(504), TestConstants.emptyOnionPacket)) + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 1000000 msat, Crypto.sha256(paymentPreimages(0)), CltvExpiry(500), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 2000000 msat, Crypto.sha256(paymentPreimages(1)), CltvExpiry(501), TestConstants.emptyOnionPacket)), + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, 2000000 msat, Crypto.sha256(paymentPreimages(2)), CltvExpiry(502), TestConstants.emptyOnionPacket)), + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, 3000000 msat, Crypto.sha256(paymentPreimages(3)), CltvExpiry(503), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 4000000 msat, Crypto.sha256(paymentPreimages(4)), CltvExpiry(504), TestConstants.emptyOnionPacket)) ) val htlcScripts = htlcs.map(htlc => htlc.direction match { case OUT => Scripts.htlcOffered(Local.payment_privkey.publicKey, Remote.payment_privkey.publicKey, Local.revocation_pubkey, Crypto.ripemd160(htlc.add.paymentHash)) @@ -234,7 +234,7 @@ class TestVectorsSpec extends FunSuite with Logging { val (unsignedHtlcTimeoutTxs, unsignedHtlcSuccessTxs) = Transactions.makeHtlcTxs( commitTx.tx, - Satoshi(Local.dustLimit.toLong), + Local.dustLimit, Local.revocation_pubkey, Local.toSelfDelay, Local.delayed_payment_privkey.publicKey, Local.payment_privkey.publicKey, Remote.payment_privkey.publicKey, // note: we have payment_key = htlc_key @@ -286,9 +286,9 @@ class TestVectorsSpec extends FunSuite with Logging { test("simple commitment tx with no HTLCs") { val name = "simple commitment tx with no HTLCs" logger.info(s"name: $name") - val spec = CommitmentSpec(htlcs = Set.empty, feeratePerKw = 15000, toLocal = MilliSatoshi(7000000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = Set.empty, feeratePerKw = 15000, toLocal = 7000000000L msat, toRemote = 3000000000L msat) - val (commitTx, htlcTxs) = run(spec) + val (commitTx, _) = run(spec) assert(commitTx.tx.txOut.length == 2) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) @@ -297,9 +297,9 @@ class TestVectorsSpec extends FunSuite with Logging { test("commitment tx with all 5 htlcs untrimmed (minimum feerate)") { val name = "commitment tx with all 5 htlcs untrimmed (minimum feerate)" logger.info(s"name: $name") - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 0, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 0, toLocal = 6988000000L msat, toRemote = 3000000000L msat) - val (commitTx, htlcTxs) = run(spec) + val (commitTx, _) = run(spec) assert(commitTx.tx.txOut.length == 7) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) } @@ -308,13 +308,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 7 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") val feeratePerKw = 454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 7) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -322,13 +322,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 6 outputs untrimmed (minimum feerate)" logger.info(s"name: $name") val feeratePerKw = 454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 6) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -336,13 +336,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 6 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") val feeratePerKw = 1454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 6) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -350,13 +350,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 5 outputs untrimmed (minimum feerate)" logger.info(s"name: $name") val feeratePerKw = 1454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 5) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -364,13 +364,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 5 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") val feeratePerKw = 1454999 / Transactions.htlcTimeoutWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 5) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -378,13 +378,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 4 outputs untrimmed (minimum feerate)" logger.info(s"name: $name") val feeratePerKw = 1454999 / Transactions.htlcTimeoutWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 4) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -392,13 +392,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 4 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") val feeratePerKw = 2454999 / Transactions.htlcTimeoutWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 4) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -406,13 +406,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 3 outputs untrimmed (minimum feerate)" logger.info(s"name: $name") val feeratePerKw = 2454999 / Transactions.htlcTimeoutWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 3) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -420,13 +420,13 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 3 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") val feeratePerKw = 3454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 3) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } @@ -434,52 +434,52 @@ class TestVectorsSpec extends FunSuite with Logging { val name = "commitment tx with 2 outputs untrimmed (minimum feerate)" logger.info(s"name: $name") val feeratePerKw = 3454999 / Transactions.htlcSuccessWeight - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = feeratePerKw + 1, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 2) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } test("commitment tx with 2 outputs untrimmed (maximum feerate)") { val name = "commitment tx with 2 outputs untrimmed (maximum feerate)" logger.info(s"name: $name") - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651180, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651180, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 2) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } test("commitment tx with 1 output untrimmed (minimum feerate)") { val name = "commitment tx with 1 output untrimmed (minimum feerate)" logger.info(s"name: $name") - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651181, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651181, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 1) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } test("commitment tx with fee greater than funder amount") { val name = "commitment tx with fee greater than funder amount" logger.info(s"name: $name") - val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651936, toLocal = MilliSatoshi(6988000000L), toRemote = MilliSatoshi(3000000000L)) + val spec = CommitmentSpec(htlcs = htlcs.toSet, feeratePerKw = 9651936, toLocal = 6988000000L msat, toRemote = 3000000000L msat) val (commitTx, htlcTxs) = run(spec) assert(commitTx.tx.txOut.length == 1) assert(commitTx.tx == Transaction.read(results(name)("output commit_tx"))) - val check = (0 to 4).map(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).flatten.toSet.map { s: String => Transaction.read(s) } + val check = (0 to 4).flatMap(i => results(name).get(s"output htlc_success_tx $i").toSeq ++ results(name).get(s"output htlc_timeout_tx $i").toSeq).toSet.map { s: String => Transaction.read(s) } assert(htlcTxs.map(_.tx).toSet == check) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala index ddd1d4bab2..d02ce4c1d0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala @@ -63,14 +63,14 @@ class TransactionsSpec extends FunSuite with Logging { test("compute fees") { // see BOLT #3 specs val htlcs = Set( - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(5000000), ByteVector32.Zeroes, CltvExpiry(552), TestConstants.emptyOnionPacket)), - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(1000000), ByteVector32.Zeroes, CltvExpiry(553), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(7000000), ByteVector32.Zeroes, CltvExpiry(550), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(800000), ByteVector32.Zeroes, CltvExpiry(551), TestConstants.emptyOnionPacket)) + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, 5000000 msat, ByteVector32.Zeroes, CltvExpiry(552), TestConstants.emptyOnionPacket)), + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 0, 1000000 msat, ByteVector32.Zeroes, CltvExpiry(553), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 7000000 msat, ByteVector32.Zeroes, CltvExpiry(550), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 800000 msat, ByteVector32.Zeroes, CltvExpiry(551), TestConstants.emptyOnionPacket)) ) - val spec = CommitmentSpec(htlcs, feeratePerKw = 5000, toLocal = MilliSatoshi(0), toRemote = MilliSatoshi(0)) - val fee = Transactions.commitTxFee(Satoshi(546), spec) - assert(fee == Satoshi(5340)) + val spec = CommitmentSpec(htlcs, feeratePerKw = 5000, toLocal = 0 msat, toRemote = 0 msat) + val fee = Transactions.commitTxFee(546 sat, spec) + assert(fee === 5340.sat) } test("check pre-computed transaction weights") { @@ -81,7 +81,7 @@ class TransactionsSpec extends FunSuite with Logging { val remoteHtlcPriv = PrivateKey(randomBytes32) val localFinalPriv = PrivateKey(randomBytes32) val finalPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32).publicKey)) - val localDustLimit = Satoshi(546) + val localDustLimit = 546 sat val toLocalDelay = CltvExpiryDelta(144) val feeratePerKw = fr.acinq.eclair.MinimumFeeratePerKw @@ -89,7 +89,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimP2WPKHOutputTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimP2WPKHOutputTx val pubKeyScript = write(pay2wpkh(localPaymentPriv.publicKey)) - val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(20000), pubKeyScript) :: Nil, lockTime = 0) + val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(20000 sat, pubKeyScript) :: Nil, lockTime = 0) val claimP2WPKHOutputTx = makeClaimP2WPKHOutputTx(commitTx, localDustLimit, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) // we use dummy signatures to compute the weight val weight = Transaction.weight(addSigs(claimP2WPKHOutputTx, localPaymentPriv.publicKey, PlaceHolderSig).tx) @@ -101,7 +101,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimHtlcDelayedTx // first we create a fake htlcSuccessOrTimeoutTx tx, containing only the output that will be spent by the ClaimDelayedOutputTx val pubKeyScript = write(pay2wsh(toLocalDelayed(localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey))) - val htlcSuccessOrTimeoutTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(20000), pubKeyScript) :: Nil, lockTime = 0) + val htlcSuccessOrTimeoutTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(20000 sat, pubKeyScript) :: Nil, lockTime = 0) val claimHtlcDelayedTx = makeClaimDelayedOutputTx(htlcSuccessOrTimeoutTx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey, finalPubKeyScript, feeratePerKw) // we use dummy signatures to compute the weight val weight = Transaction.weight(addSigs(claimHtlcDelayedTx, PlaceHolderSig).tx) @@ -113,7 +113,7 @@ class TransactionsSpec extends FunSuite with Logging { // MainPenaltyTx // first we create a fake commitTx tx, containing only the output that will be spent by the MainPenaltyTx val pubKeyScript = write(pay2wsh(toLocalDelayed(localRevocationPriv.publicKey, toLocalDelay, localPaymentPriv.publicKey))) - val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(20000), pubKeyScript) :: Nil, lockTime = 0) + val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(20000 sat, pubKeyScript) :: Nil, lockTime = 0) val mainPenaltyTx = makeMainPenaltyTx(commitTx, localDustLimit, localRevocationPriv.publicKey, finalPubKeyScript, toLocalDelay, localPaymentPriv.publicKey, feeratePerKw) // we use dummy signatures to compute the weight val weight = Transaction.weight(addSigs(mainPenaltyTx, PlaceHolderSig).tx) @@ -125,7 +125,7 @@ class TransactionsSpec extends FunSuite with Logging { // HtlcPenaltyTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(20000 * 1000), sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) val redeemScript = htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), htlc.cltvExpiry) val pubKeyScript = write(pay2wsh(redeemScript)) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) @@ -140,7 +140,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimHtlcSuccessTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(20000 * 1000), sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) val pubKeyScript = write(pay2wsh(htlcOffered(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash)))) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val claimHtlcSuccessTx = makeClaimHtlcSuccessTx(commitTx, outputsAlreadyUsed = Set.empty, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw) @@ -154,7 +154,7 @@ class TransactionsSpec extends FunSuite with Logging { // ClaimHtlcTimeoutTx // first we create a fake commitTx tx, containing only the output that will be spent by the ClaimHtlcSuccessTx val paymentPreimage = randomBytes32 - val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(20000 * 1000), sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) + val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry, TestConstants.emptyOnionPacket) val pubKeyScript = write(pay2wsh(htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), htlc.cltvExpiry))) val commitTx = Transaction(version = 0, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val claimClaimHtlcTimeoutTx = makeClaimHtlcTimeoutTx(commitTx, outputsAlreadyUsed = Set.empty, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw) @@ -177,7 +177,7 @@ class TransactionsSpec extends FunSuite with Logging { val finalPubKeyScript = Script.write(Script.pay2wpkh(PrivateKey(randomBytes32).publicKey)) val commitInput = Funding.makeFundingInputInfo(randomBytes32, 0, Btc(1), localFundingPriv.publicKey, remoteFundingPriv.publicKey) val toLocalDelay = CltvExpiryDelta(144) - val localDustLimit = Satoshi(546) + val localDustLimit = 546 sat val feeratePerKw = 22000 // htlc1 and htlc2 are regular IN/OUT htlcs @@ -340,7 +340,7 @@ class TransactionsSpec extends FunSuite with Logging { val htlcRegex = """.*HTLC ([a-z]+) amount ([0-9]+).*""".r - val dustLimit = Satoshi(546) + val dustLimit = 546 sat case class TestSetup(name: String, dustLimit: Satoshi, spec: CommitmentSpec, expectedFee: Satoshi) val tests = testRegex.findAllIn(bolt3).map(s => { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/ChannelCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/ChannelCodecsSpec.scala index 6aa892b938..82e0074997 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/ChannelCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/ChannelCodecsSpec.scala @@ -172,17 +172,17 @@ class ChannelCodecsSpec extends FunSuite { val id = UUID.randomUUID() assert(originCodec.decodeValue(originCodec.encode(Local(id, Some(ActorSystem("system").deadLetters))).require).require === Local(id, None)) // TODO: add backward compatibility check - val relayed = Relayed(randomBytes32, 4324, MilliSatoshi(12000000L), MilliSatoshi(11000000L)) + val relayed = Relayed(randomBytes32, 4324, 12000000 msat, 11000000 msat) assert(originCodec.decodeValue(originCodec.encode(relayed).require).require === relayed) } test("encode/decode map of origins") { val map = Map( 1L -> Local(UUID.randomUUID(), None), - 42L -> Relayed(randomBytes32, 4324, MilliSatoshi(12000000L), MilliSatoshi(11000000L)), - 130L -> Relayed(randomBytes32, -45, MilliSatoshi(13000000L), MilliSatoshi(12000000L)), - 1000L -> Relayed(randomBytes32, 10, MilliSatoshi(14000000L), MilliSatoshi(13000000L)), - -32L -> Relayed(randomBytes32, 54, MilliSatoshi(15000000L), MilliSatoshi(14000000L)), + 42L -> Relayed(randomBytes32, 4324, 12000000 msat, 11000000 msat), + 130L -> Relayed(randomBytes32, -45, 13000000 msat, 12000000 msat), + 1000L -> Relayed(randomBytes32, 10, 14000000 msat, 13000000 msat), + -32L -> Relayed(randomBytes32, 54, 15000000 msat, 14000000 msat), -4L -> Local(UUID.randomUUID(), None)) assert(originsMapCodec.decodeValue(originsMapCodec.encode(map).require).require === map) } @@ -343,10 +343,10 @@ object ChannelCodecsSpec { val localParams = LocalParams( keyManager.nodeId, channelKeyPath = DeterministicWallet.KeyPath(Seq(42L)), - dustLimit = Satoshi(546), + dustLimit = 546 sat, maxHtlcValueInFlightMsat = UInt64(50000000), - channelReserve = Satoshi(10000), - htlcMinimum = MilliSatoshi(10000), + channelReserve = 10000 sat, + htlcMinimum = 10000 msat, toSelfDelay = CltvExpiryDelta(144), maxAcceptedHtlcs = 50, defaultFinalScriptPubKey = ByteVector.empty, @@ -356,10 +356,10 @@ object ChannelCodecsSpec { val remoteParams = RemoteParams( nodeId = randomKey.publicKey, - dustLimit = Satoshi(546), + dustLimit = 546 sat, maxHtlcValueInFlightMsat = UInt64(5000000), - channelReserve = Satoshi(10000), - htlcMinimum = MilliSatoshi(5000), + channelReserve = 10000 sat, + htlcMinimum = 5000 msat, toSelfDelay = CltvExpiryDelta(144), maxAcceptedHtlcs = 50, fundingPubKey = PrivateKey(ByteVector32(ByteVector.fill(32)(1)) :+ 1.toByte).publicKey, @@ -379,27 +379,27 @@ object ChannelCodecsSpec { ) val htlcs = Seq( - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, MilliSatoshi(1000000), Crypto.sha256(paymentPreimages(0)), CltvExpiry(500), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 1, MilliSatoshi(2000000), Crypto.sha256(paymentPreimages(1)), CltvExpiry(501), TestConstants.emptyOnionPacket)), - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 30, MilliSatoshi(2000000), Crypto.sha256(paymentPreimages(2)), CltvExpiry(502), TestConstants.emptyOnionPacket)), - DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 31, MilliSatoshi(3000000), Crypto.sha256(paymentPreimages(3)), CltvExpiry(503), TestConstants.emptyOnionPacket)), - DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 2, MilliSatoshi(4000000), Crypto.sha256(paymentPreimages(4)), CltvExpiry(504), TestConstants.emptyOnionPacket)) + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 0, 1000000 msat, Crypto.sha256(paymentPreimages(0)), CltvExpiry(500), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 1, 2000000 msat, Crypto.sha256(paymentPreimages(1)), CltvExpiry(501), TestConstants.emptyOnionPacket)), + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 30, 2000000 msat, Crypto.sha256(paymentPreimages(2)), CltvExpiry(502), TestConstants.emptyOnionPacket)), + DirectedHtlc(OUT, UpdateAddHtlc(ByteVector32.Zeroes, 31, 3000000 msat, Crypto.sha256(paymentPreimages(3)), CltvExpiry(503), TestConstants.emptyOnionPacket)), + DirectedHtlc(IN, UpdateAddHtlc(ByteVector32.Zeroes, 2, 4000000 msat, Crypto.sha256(paymentPreimages(4)), CltvExpiry(504), TestConstants.emptyOnionPacket)) ) 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, MilliSatoshi(50000000), MilliSatoshi(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, MilliSatoshi(50000), MilliSatoshi(700000)), ByteVector32(hex"0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey) + val localCommit = LocalCommit(0, CommitmentSpec(htlcs.toSet, 1500, 50000000 msat, 70000000 msat), 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 msat, 700000 msat), ByteVector32(hex"0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey) val commitments = Commitments(ChannelVersion.STANDARD, 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, MilliSatoshi(11000000L), MilliSatoshi(10000000L))), + originChannels = Map(42L -> Local(UUID.randomUUID, None), 15000L -> Relayed(ByteVector32(ByteVector.fill(32)(42)), 43, 11000000 msat, 10000000 msat)), 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), CltvExpiryDelta(42), MilliSatoshi(15), MilliSatoshi(575), 53, Channel.MAX_FUNDING.toMilliSatoshi) + val channelUpdate = Announcements.makeChannelUpdate(ByteVector32(ByteVector.fill(32)(1)), randomKey, randomKey.publicKey, ShortChannelId(142553), CltvExpiryDelta(42), 15 msat, 575 msat, 53, Channel.MAX_FUNDING.toMilliSatoshi) val normal = DATA_NORMAL(commitments, ShortChannelId(42), true, None, channelUpdate, None, None) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/FailureMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/FailureMessageCodecsSpec.scala index 01af3a32e2..615a7f1adf 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/FailureMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/FailureMessageCodecsSpec.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.wire import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64} import fr.acinq.eclair.crypto.Hmac256 import fr.acinq.eclair.wire.FailureMessageCodecs._ -import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, MilliSatoshi, ShortChannelId, randomBytes32, randomBytes64} +import fr.acinq.eclair.{CltvExpiry, CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId, randomBytes32, randomBytes64} import org.scalatest.FunSuite import scodec.bits._ @@ -36,8 +36,8 @@ class FailureMessageCodecsSpec extends FunSuite { cltvExpiryDelta = CltvExpiryDelta(100), messageFlags = 0, channelFlags = 1, - htlcMinimumMsat = MilliSatoshi(1000), - feeBaseMsat = MilliSatoshi(12), + htlcMinimumMsat = 1000 msat, + feeBaseMsat = 12 msat, feeProportionalMillionths = 76, htlcMaximumMsat = None) @@ -46,8 +46,8 @@ class FailureMessageCodecsSpec extends FunSuite { InvalidRealm :: TemporaryNodeFailure :: PermanentNodeFailure :: RequiredNodeFeatureMissing :: InvalidOnionVersion(randomBytes32) :: InvalidOnionHmac(randomBytes32) :: InvalidOnionKey(randomBytes32) :: InvalidOnionPayload(randomBytes32) :: TemporaryChannelFailure(channelUpdate) :: PermanentChannelFailure :: RequiredChannelFeatureMissing :: UnknownNextPeer :: - AmountBelowMinimum(MilliSatoshi(123456), channelUpdate) :: FeeInsufficient(MilliSatoshi(546463), channelUpdate) :: IncorrectCltvExpiry(CltvExpiry(1211), channelUpdate) :: ExpiryTooSoon(channelUpdate) :: - IncorrectOrUnknownPaymentDetails(MilliSatoshi(123456L)) :: IncorrectPaymentAmount :: FinalExpiryTooSoon :: FinalIncorrectCltvExpiry(CltvExpiry(1234)) :: ChannelDisabled(0, 1, channelUpdate) :: ExpiryTooFar :: Nil + AmountBelowMinimum(123456 msat, channelUpdate) :: FeeInsufficient(546463 msat, channelUpdate) :: IncorrectCltvExpiry(CltvExpiry(1211), channelUpdate) :: ExpiryTooSoon(channelUpdate) :: + IncorrectOrUnknownPaymentDetails(123456 msat) :: IncorrectPaymentAmount :: FinalExpiryTooSoon :: FinalIncorrectCltvExpiry(CltvExpiry(1234)) :: ChannelDisabled(0, 1, channelUpdate) :: ExpiryTooFar :: Nil msgs.foreach { msg => { @@ -75,7 +75,7 @@ class FailureMessageCodecsSpec extends FunSuite { val codec = failureOnionCodec(Hmac256(ByteVector32.Zeroes)) val testCases = Map( InvalidOnionKey(ByteVector32(hex"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a")) -> hex"41a824e2d630111669fa3e52b600a518f369691909b4e89205dc624ee17ed2c1 0022 c006 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a 00de 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - IncorrectOrUnknownPaymentDetails(MilliSatoshi(42)) -> hex"ba6e122b2941619e2106e8437bf525356ffc8439ac3b2245f68546e298a08cc6 000a 400f 000000000000002a 00f6 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + IncorrectOrUnknownPaymentDetails(42 msat) -> hex"ba6e122b2941619e2106e8437bf525356ffc8439ac3b2245f68546e298a08cc6 000a 400f 000000000000002a 00f6 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) for ((expected, bin) <- testCases) { @@ -112,7 +112,7 @@ class FailureMessageCodecsSpec extends FunSuite { test("support encoding of channel_update with/without type in failure messages") { val tmp_channel_failure_notype = hex"10070080cc3e80149073ed487c76e48e9622bf980f78267b8a34a3f61921f2d8fce6063b08e74f34a073a13f2097337e4915bb4c001f3b5c4d81e9524ed575e1f45782196fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000008260500041300005b91b52f0003000e00000000000003e80000000100000001" val tmp_channel_failure_withtype = hex"100700820102cc3e80149073ed487c76e48e9622bf980f78267b8a34a3f61921f2d8fce6063b08e74f34a073a13f2097337e4915bb4c001f3b5c4d81e9524ed575e1f45782196fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000008260500041300005b91b52f0003000e00000000000003e80000000100000001" - val ref = TemporaryChannelFailure(ChannelUpdate(ByteVector64(hex"cc3e80149073ed487c76e48e9622bf980f78267b8a34a3f61921f2d8fce6063b08e74f34a073a13f2097337e4915bb4c001f3b5c4d81e9524ed575e1f4578219"), Block.LivenetGenesisBlock.hash, ShortChannelId(0x826050004130000L), 1536275759, 0, 3, CltvExpiryDelta(14), MilliSatoshi(1000), MilliSatoshi(1), 1, None)) + val ref = TemporaryChannelFailure(ChannelUpdate(ByteVector64(hex"cc3e80149073ed487c76e48e9622bf980f78267b8a34a3f61921f2d8fce6063b08e74f34a073a13f2097337e4915bb4c001f3b5c4d81e9524ed575e1f4578219"), Block.LivenetGenesisBlock.hash, ShortChannelId(0x826050004130000L), 1536275759, 0, 3, CltvExpiryDelta(14), 1000 msat, 1 msat, 1, None)) val u = failureMessageCodec.decode(tmp_channel_failure_notype.toBitVector).require.value assert(u === ref) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/LightningMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/LightningMessageCodecsSpec.scala index a63a15f025..91b6740adb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/LightningMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/LightningMessageCodecsSpec.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.wire import java.net.{Inet4Address, InetAddress} import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} -import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64, Satoshi} +import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64} import fr.acinq.eclair._ import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire.LightningMessageCodecs._ @@ -52,15 +52,15 @@ class LightningMessageCodecsSpec extends FunSuite { } test("encode/decode all channel messages") { - val open = OpenChannel(randomBytes32, randomBytes32, Satoshi(3), MilliSatoshi(4), Satoshi(5), UInt64(6), Satoshi(7), MilliSatoshi(8), 9, CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), 0.toByte) - val accept = AcceptChannel(randomBytes32, Satoshi(3), UInt64(4), Satoshi(5), MilliSatoshi(6), 7, CltvExpiryDelta(8), 9, publicKey(1), point(2), point(3), point(4), point(5), point(6)) + val open = OpenChannel(randomBytes32, randomBytes32, 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, 9, CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), 0.toByte) + val accept = AcceptChannel(randomBytes32, 3 sat, UInt64(4), 5 sat, 6 msat, 7, CltvExpiryDelta(8), 9, publicKey(1), point(2), point(3), point(4), point(5), point(6)) val funding_created = FundingCreated(randomBytes32, bin32(0), 3, randomBytes64) val funding_signed = FundingSigned(randomBytes32, randomBytes64) val funding_locked = FundingLocked(randomBytes32, point(2)) val update_fee = UpdateFee(randomBytes32, 2) val shutdown = Shutdown(randomBytes32, bin(47, 0)) - val closing_signed = ClosingSigned(randomBytes32, Satoshi(2), randomBytes64) - val update_add_htlc = UpdateAddHtlc(randomBytes32, 2, MilliSatoshi(3), bin32(0), CltvExpiry(4), TestConstants.emptyOnionPacket) + val closing_signed = ClosingSigned(randomBytes32, 2 sat, randomBytes64) + val update_add_htlc = UpdateAddHtlc(randomBytes32, 2, 3 msat, bin32(0), CltvExpiry(4), TestConstants.emptyOnionPacket) val update_fulfill_htlc = UpdateFulfillHtlc(randomBytes32, 2, bin32(0)) val update_fail_htlc = UpdateFailHtlc(randomBytes32, 2, bin(154, 0)) val update_fail_malformed_htlc = UpdateFailMalformedHtlc(randomBytes32, 2, randomBytes32, 1111) @@ -68,7 +68,7 @@ class LightningMessageCodecsSpec extends FunSuite { val revoke_and_ack = RevokeAndAck(randomBytes32, scalar(0), point(1)) val channel_announcement = ChannelAnnouncement(randomBytes64, randomBytes64, randomBytes64, randomBytes64, bin(7, 9), Block.RegtestGenesisBlock.hash, ShortChannelId(1), randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey) val node_announcement = NodeAnnouncement(randomBytes64, bin(1, 2), 1, randomKey.publicKey, Color(100.toByte, 200.toByte, 300.toByte), "node-alias", IPv4(InetAddress.getByAddress(Array[Byte](192.toByte, 168.toByte, 1.toByte, 42.toByte)).asInstanceOf[Inet4Address], 42000) :: Nil) - val channel_update = ChannelUpdate(randomBytes64, Block.RegtestGenesisBlock.hash, ShortChannelId(1), 2, 42, 0, CltvExpiryDelta(3), MilliSatoshi(4), MilliSatoshi(5), 6, None) + val channel_update = ChannelUpdate(randomBytes64, Block.RegtestGenesisBlock.hash, ShortChannelId(1), 2, 42, 0, CltvExpiryDelta(3), 4 msat, 5 msat, 6, None) val announcement_signatures = AnnouncementSignatures(randomBytes32, ShortChannelId(42), randomBytes64, randomBytes64) val gossip_timestamp_filter = GossipTimestampFilter(Block.RegtestGenesisBlock.blockId, 100000, 1500) val query_short_channel_id = QueryShortChannelIds(Block.RegtestGenesisBlock.blockId, randomBytes(7515)) @@ -96,7 +96,7 @@ class LightningMessageCodecsSpec extends FunSuite { // this was generated by c-lightning val bin = hex"010258fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf1792306226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0005a100000200005bc75919010100060000000000000001000000010000000a000000003a699d00" val update = lightningMessageCodec.decode(bin.bits).require.value.asInstanceOf[ChannelUpdate] - assert(update === ChannelUpdate(ByteVector64(hex"58fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf17923"), ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), ShortChannelId(0x5a10000020000L), 1539791129, 1, 1, CltvExpiryDelta(6), MilliSatoshi(1), MilliSatoshi(1), 10, Some(MilliSatoshi(980000000L)))) + assert(update === ChannelUpdate(ByteVector64(hex"58fff7d0e987e2cdd560e3bb5a046b4efe7b26c969c2f51da1dceec7bcb8ae1b634790503d5290c1a6c51d681cf8f4211d27ed33a257dcc1102862571bf17923"), ByteVector32(hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"), ShortChannelId(0x5a10000020000L), 1539791129, 1, 1, CltvExpiryDelta(6), 1 msat, 1 msat, 10, Some(980000000 msat))) val nodeId = PublicKey(hex"03370c9bac836e557eb4f017fe8f9cc047f44db39c1c4e410ff0f7be142b817ae4") assert(Announcements.checkSig(update, nodeId)) val bin2 = ByteVector(lightningMessageCodec.encode(update).require.toByteArray) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/OnionCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/OnionCodecsSpec.scala index 43726c94fa..272b85fc26 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/OnionCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/OnionCodecsSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.wire import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.wire.OnionCodecs._ -import fr.acinq.eclair.{CltvExpiry, MilliSatoshi, ShortChannelId} +import fr.acinq.eclair.{CltvExpiry, LongToBtcAmount, ShortChannelId} import org.scalatest.FunSuite import scodec.bits.HexStringSyntax @@ -40,7 +40,7 @@ class OnionCodecsSpec extends FunSuite { } test("encode/decode per-hop payload") { - val payload = PerHopPayload(shortChannelId = ShortChannelId(42), amtToForward = MilliSatoshi(142000), outgoingCltvValue = CltvExpiry(500000)) + val payload = PerHopPayload(shortChannelId = ShortChannelId(42), amtToForward = 142000 msat, outgoingCltvValue = CltvExpiry(500000)) val bin = perHopPayloadCodec.encode(payload).require assert(bin.toByteVector.size === 33) val payload1 = perHopPayloadCodec.decode(bin).require.value diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala index ec7798cd78..2f996aa569 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/GUIUpdater.scala @@ -118,7 +118,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging case ChannelSignatureReceived(channel, commitments) if m.contains(channel) => val channelPaneController = m(channel) channelPaneController.updateBalance(commitments) - val totalBalance = MilliSatoshi(m.values.map(_.getBalance.toLong).sum) + val totalBalance = m.values.map(_.getBalance).sum runInGuiThread(() => { channelPaneController.refreshBalance() mainController.refreshTotalBalance(totalBalance) @@ -129,7 +129,7 @@ class GUIUpdater(mainController: MainController) extends Actor with ActorLogging log.debug(s"channel=${channelPaneController.channelId.getText} to be removed from gui") runInGuiThread(() => mainController.channelBox.getChildren.remove(channelPaneController.root)) val m1 = m - actor - val totalBalance = MilliSatoshi(m1.values.map(_.getBalance.toLong).sum) + val totalBalance = m1.values.map(_.getBalance).sum runInGuiThread(() => { mainController.refreshTotalBalance(totalBalance) }) From 45c8b66c701ebf13747c49638f28c0bce1fe7c46 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 28 Aug 2019 17:13:09 +0200 Subject: [PATCH 15/18] Add more msat postfix usage --- .../router/ChannelRangeQueriesSpec.scala | 18 ++++++------ .../wire/ExtendedQueriesCodecsSpec.scala | 28 +++++++++++++++---- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala index ca066c3e71..957250c7b6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/ChannelRangeQueriesSpec.scala @@ -16,9 +16,9 @@ package fr.acinq.eclair.router -import fr.acinq.bitcoin.{ByteVector32, Satoshi} +import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.wire.ReplyChannelRangeTlv._ -import fr.acinq.eclair.{MilliSatoshi, randomKey} +import fr.acinq.eclair.{LongToBtcAmount, randomKey} import org.scalatest.FunSuite import scala.collection.immutable.SortedMap @@ -76,22 +76,22 @@ class ChannelRangeQueriesSpec extends FunSuite { val a = randomKey.publicKey val b = randomKey.publicKey val ab = RouteCalculationSpec.makeChannel(123466L, a, b) - val (ab1, uab1) = RouteCalculationSpec.makeUpdateShort(ab.shortChannelId, ab.nodeId1, ab.nodeId2, MilliSatoshi(0), 0, timestamp = now) - val (ab2, uab2) = RouteCalculationSpec.makeUpdateShort(ab.shortChannelId, ab.nodeId2, ab.nodeId1, MilliSatoshi(0), 0, timestamp = now) + val (ab1, uab1) = RouteCalculationSpec.makeUpdateShort(ab.shortChannelId, ab.nodeId1, ab.nodeId2, 0 msat, 0, timestamp = now) + val (ab2, uab2) = RouteCalculationSpec.makeUpdateShort(ab.shortChannelId, ab.nodeId2, ab.nodeId1, 0 msat, 0, timestamp = now) val c = randomKey.publicKey val d = randomKey.publicKey val cd = RouteCalculationSpec.makeChannel(451312L, c, d) - val (cd1, ucd1) = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId1, cd.nodeId2, MilliSatoshi(0), 0, timestamp = now) - val (_, ucd2) = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId2, cd.nodeId1, MilliSatoshi(0), 0, timestamp = now) + val (cd1, ucd1) = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId1, cd.nodeId2, 0 msat, 0, timestamp = now) + val (_, ucd2) = RouteCalculationSpec.makeUpdateShort(cd.shortChannelId, cd.nodeId2, cd.nodeId1, 0 msat, 0, timestamp = now) val e = randomKey.publicKey val f = randomKey.publicKey val ef = RouteCalculationSpec.makeChannel(167514L, e, f) val channels = SortedMap( - ab.shortChannelId -> PublicChannel(ab, ByteVector32.Zeroes, Satoshi(0), Some(uab1), Some(uab2)), - cd.shortChannelId -> PublicChannel(cd, ByteVector32.Zeroes, Satoshi(0), Some(ucd1), None) + ab.shortChannelId -> PublicChannel(ab, ByteVector32.Zeroes, 0 sat, Some(uab1), Some(uab2)), + cd.shortChannelId -> PublicChannel(cd, ByteVector32.Zeroes, 0 sat, Some(ucd1), None) ) import fr.acinq.eclair.wire.QueryShortChannelIdsTlv.QueryFlagType._ @@ -106,7 +106,7 @@ class ChannelRangeQueriesSpec extends FunSuite { // different checksums, newer timestamps: we ask for the updates assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now)), Some(Checksums(154654604, 3692323747L)), true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now + 1)), Some(Checksums(1697591108L, 45664546)), true) === (INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) - assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(154654604, 45664546 + 6)), true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2| INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) + assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now + 1, now + 1)), Some(Checksums(154654604, 45664546 + 6)), true) === (INCLUDE_CHANNEL_UPDATE_1 | INCLUDE_CHANNEL_UPDATE_2 | INCLUDE_NODE_ANNOUNCEMENT_1 | INCLUDE_NODE_ANNOUNCEMENT_2)) // different checksums, older timestamps: we don't ask anything assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now - 1, now)), Some(Checksums(154654604, 3692323747L)), true) === 0) assert(Router.computeFlag(channels)(ab.shortChannelId, Some(Timestamps(now, now - 1)), Some(Checksums(1697591108L, 45664546)), true) === 0) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/ExtendedQueriesCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/ExtendedQueriesCodecsSpec.scala index 672439717b..91c5f3c8f6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/ExtendedQueriesCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/ExtendedQueriesCodecsSpec.scala @@ -1,10 +1,26 @@ +/* + * 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.wire import fr.acinq.bitcoin.{Block, ByteVector32, ByteVector64} import fr.acinq.eclair.router.Router import fr.acinq.eclair.wire.LightningMessageCodecs._ import fr.acinq.eclair.wire.ReplyChannelRangeTlv._ -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, ShortChannelId, UInt64} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, ShortChannelId, UInt64} import org.scalatest.FunSuite import scodec.bits.ByteVector @@ -102,9 +118,9 @@ class ExtendedQueriesCodecsSpec extends FunSuite { messageFlags = 0, channelFlags = 0, cltvExpiryDelta = CltvExpiryDelta(144), - htlcMinimumMsat = MilliSatoshi(0), + htlcMinimumMsat = 0 msat, htlcMaximumMsat = None, - feeBaseMsat = MilliSatoshi(1000), + feeBaseMsat = 1000 msat, feeProportionalMillionths = 10 ) val check = ByteVector.fromValidHex("010276df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c8029328206226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100005d50f933000000900000000000000000000003e80000000a") @@ -123,9 +139,9 @@ class ExtendedQueriesCodecsSpec extends FunSuite { messageFlags = 1, channelFlags = 0, cltvExpiryDelta = CltvExpiryDelta(48), - htlcMinimumMsat = MilliSatoshi(0), - htlcMaximumMsat = Some(MilliSatoshi(100000)), - feeBaseMsat = MilliSatoshi(100), + htlcMinimumMsat = 0 msat, + htlcMaximumMsat = Some(100000 msat), + feeBaseMsat = 100 msat, feeProportionalMillionths = 11 ) val check = ByteVector.fromValidHex("010206737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006d00000100005d50f935010000300000000000000000000000640000000b00000000000186a0") From a1f9d38d3b7e7bd3778ea4013074b9a96aeda7b0 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 28 Aug 2019 17:30:14 +0200 Subject: [PATCH 16/18] Small improvements and build fix --- eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala | 1 + .../main/scala/fr/acinq/eclair/payment/PaymentRequest.scala | 2 +- eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala | 2 +- .../channel/states/b/WaitForFundingCreatedStateSpec.scala | 4 ++-- .../eclair/gui/controllers/ReceivePaymentController.scala | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala index 0cbef30790..ff97d45565 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/MilliSatoshi.scala @@ -53,6 +53,7 @@ case class MilliSatoshi(private val underlying: Long) extends Ordered[MilliSatos def truncateToSatoshi: Satoshi = Satoshi(underlying / 1000) def toLong: Long = underlying + override def toString = s"$underlying msat" // @formatter:on } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala index 4fa1712e49..26e0e99277 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala @@ -319,7 +319,7 @@ object PaymentRequest { val extraHopCodec: Codec[ExtraHop] = ( ("nodeId" | publicKey) :: ("shortChannelId" | shortchannelid) :: - ("fee_base_msat" | uint32.xmapc(l => MilliSatoshi(l))(_.toLong)) :: + ("fee_base_msat" | millisatoshi32) :: ("fee_proportional_millionth" | uint32) :: ("cltv_expiry_delta" | cltvExpiryDelta) ).as[ExtraHop] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala index f46cbcfc06..09dffdfc76 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Graph.scala @@ -343,7 +343,7 @@ object Graph { val BLOCK_TIME_TWO_MONTHS = 8640 // Low/High bound for channel capacity - val CAPACITY_CHANNEL_LOW = (1000 * 1000L) msat // 1000 sat + val CAPACITY_CHANNEL_LOW = (1000 sat).toMilliSatoshi val CAPACITY_CHANNEL_HIGH = Channel.MAX_FUNDING.toMilliSatoshi // Low/High bound for CLTV channel value diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala index f34297725f..9b562ad040 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala @@ -24,7 +24,7 @@ import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire._ -import fr.acinq.eclair.{LongToBtcAmount, TestConstants, TestkitBaseClass} +import fr.acinq.eclair.{LongToBtcAmount, TestConstants, TestkitBaseClass, ToMilliSatoshiConversion} import org.scalatest.{Outcome, Tag} import scala.concurrent.duration._ @@ -41,7 +41,7 @@ class WaitForFundingCreatedStateSpec extends TestkitBaseClass with StateTestsHel val setup = init() import setup._ val (fundingSatoshis, pushMsat) = if (test.tags.contains("funder_below_reserve")) { - (1000100 sat, 1000000000L msat) // toRemote = 100 satoshis + (1000100 sat, (1000000 sat).toMilliSatoshi) // toLocal = 100 satoshis } else { (TestConstants.fundingSatoshis, TestConstants.pushMsat) } diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala index 3bc05a9c85..388cf57835 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/controllers/ReceivePaymentController.scala @@ -16,9 +16,9 @@ package fr.acinq.eclair.gui.controllers -import fr.acinq.eclair.{CoinUtils, MilliSatoshi} import fr.acinq.eclair.gui.utils._ import fr.acinq.eclair.gui.{FxApp, Handlers} +import fr.acinq.eclair.{CoinUtils, LongToBtcAmount, MilliSatoshi} import grizzled.slf4j.Logging import javafx.application.Platform import javafx.event.ActionEvent From d20a95cc9a1ef9689a0fa0235e3910255355f707 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 28 Aug 2019 18:04:35 +0200 Subject: [PATCH 17/18] Fix Rusty's test spec --- .../scenarii/01-offer1.script.expected | 24 +++++++------- .../scenarii/02-offer2.script.expected | 24 +++++++------- .../scenarii/03-fulfill1.script.expected | 16 +++++----- .../04-two-commits-onedir.script.expected | 16 +++++----- .../10-offers-crossover.script.expected | 32 +++++++++---------- .../11-commits-crossover.script.expected | 32 +++++++++---------- .../interop/rustytests/RustyTestsSpec.scala | 2 +- 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/eclair-core/src/test/resources/scenarii/01-offer1.script.expected b/eclair-core/src/test/resources/scenarii/01-offer1.script.expected index 5680bafccc..0fc65dcbb7 100644 --- a/eclair-core/src/test/resources/scenarii/01-offer1.script.expected +++ b/eclair-core/src/test/resources/scenarii/01-offer1.script.expected @@ -1,30 +1,30 @@ ***A*** LOCAL COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) + Offered htlcs: (0,1000000 msat) Received htlcs: - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 999000000 msat + Balance them: 1000000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: Offered htlcs: - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(999000000) + Received htlcs: (0,1000000 msat) + Balance us: 1000000000 msat + Balance them: 999000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 1: Offered htlcs: - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(999000000) + Received htlcs: (0,1000000 msat) + Balance us: 1000000000 msat + Balance them: 999000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) + Offered htlcs: (0,1000000 msat) Received htlcs: - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 999000000 msat + Balance them: 1000000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/resources/scenarii/02-offer2.script.expected b/eclair-core/src/test/resources/scenarii/02-offer2.script.expected index 2d71ea0dea..d31361786e 100644 --- a/eclair-core/src/test/resources/scenarii/02-offer2.script.expected +++ b/eclair-core/src/test/resources/scenarii/02-offer2.script.expected @@ -1,30 +1,30 @@ ***A*** LOCAL COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) (1,MilliSatoshi(2000000)) + Offered htlcs: (0,1000000 msat) (1,2000000 msat) Received htlcs: - Balance us: MilliSatoshi(997000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 997000000 msat + Balance them: 1000000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: Offered htlcs: - Received htlcs: (0,MilliSatoshi(1000000)) (1,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(997000000) + Received htlcs: (0,1000000 msat) (1,2000000 msat) + Balance us: 1000000000 msat + Balance them: 997000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 1: Offered htlcs: - Received htlcs: (0,MilliSatoshi(1000000)) (1,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(997000000) + Received htlcs: (0,1000000 msat) (1,2000000 msat) + Balance us: 1000000000 msat + Balance them: 997000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) (1,MilliSatoshi(2000000)) + Offered htlcs: (0,1000000 msat) (1,2000000 msat) Received htlcs: - Balance us: MilliSatoshi(997000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 997000000 msat + Balance them: 1000000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/resources/scenarii/03-fulfill1.script.expected b/eclair-core/src/test/resources/scenarii/03-fulfill1.script.expected index 3c3fff0fe3..a81561bc8f 100644 --- a/eclair-core/src/test/resources/scenarii/03-fulfill1.script.expected +++ b/eclair-core/src/test/resources/scenarii/03-fulfill1.script.expected @@ -3,28 +3,28 @@ LOCAL COMMITS: Commit 2: Offered htlcs: Received htlcs: - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(1001000000) + Balance us: 999000000 msat + Balance them: 1001000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: Offered htlcs: Received htlcs: - Balance us: MilliSatoshi(1001000000) - Balance them: MilliSatoshi(999000000) + Balance us: 1001000000 msat + Balance them: 999000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 2: Offered htlcs: Received htlcs: - Balance us: MilliSatoshi(1001000000) - Balance them: MilliSatoshi(999000000) + Balance us: 1001000000 msat + Balance them: 999000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: Offered htlcs: Received htlcs: - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(1001000000) + Balance us: 999000000 msat + Balance them: 1001000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/resources/scenarii/04-two-commits-onedir.script.expected b/eclair-core/src/test/resources/scenarii/04-two-commits-onedir.script.expected index 965efa4bc8..c309a14e41 100644 --- a/eclair-core/src/test/resources/scenarii/04-two-commits-onedir.script.expected +++ b/eclair-core/src/test/resources/scenarii/04-two-commits-onedir.script.expected @@ -3,28 +3,28 @@ LOCAL COMMITS: Commit 1: Offered htlcs: (0,1000000) (1,2000000) Received htlcs: - Balance us: MilliSatoshi(997000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 997000000 msat + Balance them: 1000000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: Offered htlcs: Received htlcs: (0,1000000) (1,2000000) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(997000000) + Balance us: 1000000000 msat + Balance them: 997000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 2: Offered htlcs: Received htlcs: (0,1000000) (1,2000000) - Balance us: MilliSatoshi(1000000000) - Balance them: MilliSatoshi(997000000) + Balance us: 1000000000 msat + Balance them: 997000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: Offered htlcs: (0,1000000) (1,2000000) Received htlcs: - Balance us: MilliSatoshi(997000000) - Balance them: MilliSatoshi(1000000000) + Balance us: 997000000 msat + Balance them: 1000000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/resources/scenarii/10-offers-crossover.script.expected b/eclair-core/src/test/resources/scenarii/10-offers-crossover.script.expected index 51469b487b..a259e358d1 100644 --- a/eclair-core/src/test/resources/scenarii/10-offers-crossover.script.expected +++ b/eclair-core/src/test/resources/scenarii/10-offers-crossover.script.expected @@ -1,30 +1,30 @@ ***A*** LOCAL COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) - Received htlcs: (0,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(998000000) + Offered htlcs: (0,1000000 msat) + Received htlcs: (0,2000000 msat) + Balance us: 999000000 msat + Balance them: 998000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(2000000)) - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(998000000) - Balance them: MilliSatoshi(999000000) + Offered htlcs: (0,2000000 msat) + Received htlcs: (0,1000000 msat) + Balance us: 998000000 msat + Balance them: 999000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(2000000)) - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(998000000) - Balance them: MilliSatoshi(999000000) + Offered htlcs: (0,2000000 msat) + Received htlcs: (0,1000000 msat) + Balance us: 998000000 msat + Balance them: 999000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 1: - Offered htlcs: (0,MilliSatoshi(1000000)) - Received htlcs: (0,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(998000000) + Offered htlcs: (0,1000000 msat) + Received htlcs: (0,2000000 msat) + Balance us: 999000000 msat + Balance them: 998000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/resources/scenarii/11-commits-crossover.script.expected b/eclair-core/src/test/resources/scenarii/11-commits-crossover.script.expected index 2c52101d82..f47357ea01 100644 --- a/eclair-core/src/test/resources/scenarii/11-commits-crossover.script.expected +++ b/eclair-core/src/test/resources/scenarii/11-commits-crossover.script.expected @@ -1,30 +1,30 @@ ***A*** LOCAL COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(1000000)) - Received htlcs: (0,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(998000000) + Offered htlcs: (0,1000000 msat) + Received htlcs: (0,2000000 msat) + Balance us: 999000000 msat + Balance them: 998000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(2000000)) - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(998000000) - Balance them: MilliSatoshi(999000000) + Offered htlcs: (0,2000000 msat) + Received htlcs: (0,1000000 msat) + Balance us: 998000000 msat + Balance them: 999000000 msat Fee rate: 10000 ***B*** LOCAL COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(2000000)) - Received htlcs: (0,MilliSatoshi(1000000)) - Balance us: MilliSatoshi(998000000) - Balance them: MilliSatoshi(999000000) + Offered htlcs: (0,2000000 msat) + Received htlcs: (0,1000000 msat) + Balance us: 998000000 msat + Balance them: 999000000 msat Fee rate: 10000 REMOTE COMMITS: Commit 2: - Offered htlcs: (0,MilliSatoshi(1000000)) - Received htlcs: (0,MilliSatoshi(2000000)) - Balance us: MilliSatoshi(999000000) - Balance them: MilliSatoshi(998000000) + Offered htlcs: (0,1000000 msat) + Received htlcs: (0,2000000 msat) + Balance us: 999000000 msat + Balance them: 998000000 msat Fee rate: 10000 diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index 4a36b17faa..67874c54c7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -90,7 +90,7 @@ class RustyTestsSpec extends TestKit(ActorSystem("test")) with Matchers with fix test("01-offer1") { f => assert(f.ref === f.res) } test("02-offer2") { f => assert(f.ref === f.res) } - //test("03-fulfill1") { f => assert(f.ref === f.res) } + test("03-fulfill1") { f => assert(f.ref === f.res) } // test("04-two-commits-onedir") { f => assert(f.ref === f.res) } DOES NOT PASS : we now automatically sign back when we receive a revocation and have acked changes // test("05-two-commits-in-flight") { f => assert(f.ref === f.res)} DOES NOT PASS : cannot send two commit in a row (without having first revocation) test("10-offers-crossover") { f => assert(f.ref === f.res) } From 276d95a8c2c638408e1f9b17bf1ddedfd757291e Mon Sep 17 00:00:00 2001 From: Bastien Teinturier Date: Wed, 28 Aug 2019 18:29:33 +0200 Subject: [PATCH 18/18] Use msat postfix in PaymentRequest --- .../main/scala/fr/acinq/eclair/payment/PaymentRequest.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala index 26e0e99277..5c31f7fb19 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentRequest.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.payment import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.{Base58, Base58Check, Bech32, Block, ByteVector32, ByteVector64, Crypto} import fr.acinq.eclair.payment.PaymentRequest._ -import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshi, ShortChannelId} +import fr.acinq.eclair.{CltvExpiryDelta, LongToBtcAmount, MilliSatoshi, ShortChannelId} import scodec.Codec import scodec.bits.{BitVector, ByteOrdering, ByteVector} import scodec.codecs.{list, ubyte} @@ -41,7 +41,7 @@ import scala.util.Try */ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestamp: Long, nodeId: PublicKey, tags: List[PaymentRequest.TaggedField], signature: ByteVector) { - amount.map(a => require(a.toLong > 0, s"amount is not valid")) + amount.map(a => require(a > 0.msat, s"amount is not valid")) require(tags.collect { case _: PaymentRequest.PaymentHash => {} }.size == 1, "there must be exactly one payment hash tag") require(tags.collect { case PaymentRequest.Description(_) | PaymentRequest.DescriptionHash(_) => {} }.size == 1, "there must be exactly one description tag or one description hash tag")