mirror of
https://github.com/ACINQ/eclair.git
synced 2025-02-22 14:22:39 +01:00
Reformat + optimized imports (#222)
* Reformat + optimized imports * Fixed unwanted modifications
This commit is contained in:
parent
df67157119
commit
bfa3e1c2ca
107 changed files with 589 additions and 452 deletions
|
@ -83,9 +83,9 @@
|
|||
<profile>
|
||||
<id>Mac</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>mac</family>
|
||||
</os>
|
||||
<os>
|
||||
<family>mac</family>
|
||||
</os>
|
||||
</activation>
|
||||
<properties>
|
||||
<bitcoind.url>https://bitcoin.org/bin/bitcoin-core-0.14.0/bitcoin-0.14.0-osx64.tar.gz
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
{
|
||||
"127.0.0.1": {"t":"51001", "s":"51002"},
|
||||
"10.0.2.2": {"t":"51001", "s":"51002"}
|
||||
"127.0.0.1": {
|
||||
"t": "51001",
|
||||
"s": "51002"
|
||||
},
|
||||
"10.0.2.2": {
|
||||
"t": "51001",
|
||||
"s": "51002"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
{
|
||||
"testnetnode.arihanc.com": {"t":"51001", "s":"51002"},
|
||||
"testnet.hsmiths.com": {"t":"53011", "s":"53012"},
|
||||
"electrum.akinbo.org": {"t":"51001", "s":"51002"}
|
||||
"testnetnode.arihanc.com": {
|
||||
"t": "51001",
|
||||
"s": "51002"
|
||||
},
|
||||
"testnet.hsmiths.com": {
|
||||
"t": "53011",
|
||||
"s": "53012"
|
||||
},
|
||||
"electrum.akinbo.org": {
|
||||
"t": "51001",
|
||||
"s": "51002"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,11 @@ import akka.event.{DiagnosticLoggingAdapter, LoggingAdapter}
|
|||
* See https://groups.google.com/forum/#!topic/akka-user/0CxR8CImr4Q
|
||||
*/
|
||||
trait FSMDiagnosticActorLogging[S, D] extends FSM[S, D] {
|
||||
|
||||
import akka.event.Logging._
|
||||
|
||||
val diagLog: DiagnosticLoggingAdapter = akka.event.Logging(this)
|
||||
|
||||
def mdc(currentMessage: Any): MDC = emptyMDC
|
||||
|
||||
override def log: LoggingAdapter = diagLog
|
||||
|
|
|
@ -2,7 +2,6 @@ package fr.acinq.eclair
|
|||
|
||||
|
||||
import java.util.BitSet
|
||||
import java.util.function.IntPredicate
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
|
||||
|
@ -20,14 +19,14 @@ object Features {
|
|||
* @param features feature bits
|
||||
* @return true if an initial dump of the routing table is requested
|
||||
*/
|
||||
def initialRoutingSync(features: BitSet) : Boolean = features.get(INITIAL_ROUTING_SYNC_BIT_OPTIONAL)
|
||||
def initialRoutingSync(features: BitSet): Boolean = features.get(INITIAL_ROUTING_SYNC_BIT_OPTIONAL)
|
||||
|
||||
/**
|
||||
*
|
||||
* @param features feature bits
|
||||
* @return true if an initial dump of the routing table is requested
|
||||
*/
|
||||
def initialRoutingSync(features: BinaryData) : Boolean = initialRoutingSync(BitSet.valueOf(features.reverse.toArray))
|
||||
def initialRoutingSync(features: BinaryData): Boolean = initialRoutingSync(BitSet.valueOf(features.reverse.toArray))
|
||||
|
||||
/**
|
||||
* Check that the features that we understand are correctly specified, and that there are no mandatory features that
|
||||
|
@ -35,7 +34,7 @@ object Features {
|
|||
*/
|
||||
def areSupported(bitset: BitSet): Boolean = {
|
||||
// for now there is no mandatory feature bit, so we don't support features with any even bit set
|
||||
for(i <- 0 until bitset.length() by 2) {
|
||||
for (i <- 0 until bitset.length() by 2) {
|
||||
if (bitset.get(i)) return false
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -57,8 +57,11 @@ case class NodeParams(extendedPrivateKey: ExtendedPrivateKey,
|
|||
object NodeParams {
|
||||
|
||||
sealed trait WatcherType
|
||||
|
||||
object BITCOIND extends WatcherType
|
||||
|
||||
object BITCOINJ extends WatcherType
|
||||
|
||||
object ELECTRUM extends WatcherType
|
||||
|
||||
/**
|
||||
|
|
|
@ -93,7 +93,7 @@ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), act
|
|||
}
|
||||
val stream = classOf[Setup].getResourceAsStream(addressesFile)
|
||||
val addresses = ElectrumClient.readServerAddresses(stream)
|
||||
val electrumClient = system.actorOf(SimpleSupervisor.props(Props(new ElectrumClient(addresses)), "electrum-client", SupervisorStrategy.Resume))
|
||||
val electrumClient = system.actorOf(SimpleSupervisor.props(Props(new ElectrumClient(addresses)), "electrum-client", SupervisorStrategy.Resume))
|
||||
Electrum(electrumClient)
|
||||
}
|
||||
|
||||
|
@ -190,10 +190,13 @@ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), act
|
|||
|
||||
}
|
||||
|
||||
|
||||
// @formatter:off
|
||||
sealed trait Bitcoin
|
||||
case class Bitcoind(extendedBitcoinClient: ExtendedBitcoinClient) extends Bitcoin
|
||||
case class Bitcoinj(bitcoinjKit: BitcoinjKit) extends Bitcoin
|
||||
case class Electrum(electrumClient: ActorRef) extends Bitcoin
|
||||
// @formatter:on
|
||||
|
||||
case class Kit(nodeParams: NodeParams,
|
||||
system: ActorSystem,
|
||||
|
|
|
@ -31,4 +31,5 @@ object UInt64 {
|
|||
|
||||
implicit def longToUint64(l: Long) = UInt64(l)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package fr.acinq.eclair.api
|
||||
|
||||
import fr.acinq.bitcoin.{BinaryData, Script, ScriptElt, Transaction}
|
||||
import fr.acinq.bitcoin.Crypto.{Point, PrivateKey, PublicKey, Scalar}
|
||||
import fr.acinq.bitcoin.{BinaryData, Transaction}
|
||||
import fr.acinq.eclair.channel.State
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo
|
||||
|
|
|
@ -95,7 +95,7 @@ trait Service extends Logging {
|
|||
(router ? 'nodes).mapTo[Iterable[NodeAnnouncement]].map(_.map(_.nodeId))
|
||||
case JsonRPCBody(_, _, "allchannels", _) =>
|
||||
(router ? 'channels).mapTo[Iterable[ChannelAnnouncement]].map(_.map(c => ChannelInfo(c.shortChannelId.toHexString, c.nodeId1, c.nodeId2)))
|
||||
case JsonRPCBody(_,_, "receive", JInt(amountMsat) :: JString(description) :: Nil) =>
|
||||
case JsonRPCBody(_, _, "receive", JInt(amountMsat) :: JString(description) :: Nil) =>
|
||||
(paymentHandler ? ReceivePayment(MilliSatoshi(amountMsat.toLong), description)).mapTo[PaymentRequest].map(PaymentRequest.write)
|
||||
case JsonRPCBody(_, _, "send", JInt(amountMsat) :: JString(paymentHash) :: JString(nodeId) :: Nil) =>
|
||||
(paymentInitiator ? SendPayment(amountMsat.toLong, paymentHash, PublicKey(nodeId))).mapTo[PaymentResult]
|
||||
|
|
|
@ -30,6 +30,7 @@ trait EclairWallet {
|
|||
|
||||
/**
|
||||
* Cancels this transaction: this probably translates to "release locks on utxos".
|
||||
*
|
||||
* @param tx
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -15,7 +15,7 @@ import scala.concurrent.{ExecutionContext, Future, Promise}
|
|||
|
||||
/**
|
||||
* Due to bitcoin-core wallet not fully supporting segwit txes yet, our current scheme is:
|
||||
* utxos <- parent-tx <- funding-tx
|
||||
* utxos <- parent-tx <- funding-tx
|
||||
*
|
||||
* With:
|
||||
* - utxos may be non-segwit
|
||||
|
@ -200,6 +200,7 @@ class BitcoinCoreWallet(rpcClient: BitcoinJsonRPCClient, watcher: ActorRef)(impl
|
|||
/**
|
||||
* We currently only put a lock on the parent tx inputs, and we publish the parent tx immediately so there is nothing
|
||||
* to do here.
|
||||
*
|
||||
* @param tx
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -7,8 +7,8 @@ import akka.actor.ActorSystem
|
|||
import com.google.common.util.concurrent.{FutureCallback, Futures}
|
||||
import fr.acinq.bitcoin.Transaction
|
||||
import fr.acinq.eclair.Globals
|
||||
import fr.acinq.eclair.blockchain.bitcoinj.BitcoinjKit._
|
||||
import fr.acinq.eclair.blockchain.CurrentBlockCount
|
||||
import fr.acinq.eclair.blockchain.bitcoinj.BitcoinjKit._
|
||||
import grizzled.slf4j.Logging
|
||||
import org.bitcoinj.core.TransactionConfidence.ConfidenceType
|
||||
import org.bitcoinj.core.listeners._
|
||||
|
@ -41,8 +41,8 @@ class BitcoinjKit(chain: String, datadir: File, staticPeers: List[InetSocketAddr
|
|||
val atCurrentHeight = atCurrentHeightPromise.future
|
||||
|
||||
// tells us when we are at current block height
|
||||
// private val syncedPromise = Promise[Boolean]()
|
||||
// val synced = syncedPromise.future
|
||||
// private val syncedPromise = Promise[Boolean]()
|
||||
// val synced = syncedPromise.future
|
||||
|
||||
private def updateBlockCount(blockCount: Int) = {
|
||||
// when synchronizing we don't want to advertise previous blocks
|
||||
|
@ -61,13 +61,13 @@ class BitcoinjKit(chain: String, datadir: File, staticPeers: List[InetSocketAddr
|
|||
peerGroup().setMinRequiredProtocolVersion(70015) // bitcoin core 0.13
|
||||
wallet().watchMode = true
|
||||
|
||||
// setDownloadListener(new DownloadProgressTracker {
|
||||
// override def doneDownload(): Unit = {
|
||||
// super.doneDownload()
|
||||
// // may be called multiple times
|
||||
// syncedPromise.trySuccess(true)
|
||||
// }
|
||||
// })
|
||||
// setDownloadListener(new DownloadProgressTracker {
|
||||
// override def doneDownload(): Unit = {
|
||||
// super.doneDownload()
|
||||
// // may be called multiple times
|
||||
// syncedPromise.trySuccess(true)
|
||||
// }
|
||||
// })
|
||||
|
||||
// we set the blockcount to the previous stored block height
|
||||
updateBlockCount(chain().getBestChainHeight)
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.bitcoinj.script.Script
|
|||
|
||||
import scala.collection.SortedMap
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
final case class NewConfidenceLevel(tx: Transaction, blockHeight: Int, confirmations: Int) extends BlockchainEvent
|
||||
|
@ -130,6 +129,7 @@ class BitcoinjWatcher(val kit: WalletAppKit)(implicit ec: ExecutionContext = Exe
|
|||
|
||||
/**
|
||||
* Bitcoinj needs hints to be able to detect transactions
|
||||
*
|
||||
* @param pubkeyScript
|
||||
* @return
|
||||
*/
|
||||
|
@ -177,6 +177,7 @@ class Broadcaster(kit: WalletAppKit) extends Actor with ActorLogging {
|
|||
}
|
||||
|
||||
case class BroadcastResult(tx: Transaction, result: Try[Boolean])
|
||||
|
||||
def broadcast(tx: Transaction) = {
|
||||
Context.propagate(kit.wallet().getContext)
|
||||
val bitcoinjTx = new org.bitcoinj.core.Transaction(kit.wallet().getParams, Transaction.write(tx))
|
||||
|
@ -189,5 +190,4 @@ class Broadcaster(kit: WalletAppKit) extends Actor with ActorLogging {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import grizzled.slf4j.Logging
|
|||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class ElectrumEclairWallet(val wallet: ActorRef)(implicit system: ActorSystem, ec: ExecutionContext, timeout: akka.util.Timeout) extends EclairWallet with Logging {
|
||||
class ElectrumEclairWallet(val wallet: ActorRef)(implicit system: ActorSystem, ec: ExecutionContext, timeout: akka.util.Timeout) extends EclairWallet with Logging {
|
||||
|
||||
override def getBalance = (wallet ? GetBalance).mapTo[GetBalanceResponse].map(balance => balance.confirmed + balance.unconfirmed)
|
||||
|
||||
|
@ -45,7 +45,7 @@ class ElectrumEclairWallet(val wallet: ActorRef)(implicit system: ActorSystem, e
|
|||
case CancelTransactionResponse(_) => false
|
||||
}
|
||||
|
||||
def sendPayment(amount: Satoshi, address: String, feeRatePerKw: Long) : Future[String] = {
|
||||
def sendPayment(amount: Satoshi, address: String, feeRatePerKw: Long): Future[String] = {
|
||||
val publicKeyScript = Base58Check.decode(address) match {
|
||||
case (Base58.Prefix.PubkeyAddressTestnet, pubKeyHash) => Script.pay2pkh(pubKeyHash)
|
||||
case (Base58.Prefix.ScriptAddressTestnet, scriptHash) => OP_HASH160 :: OP_PUSHDATA(scriptHash) :: OP_EQUAL :: Nil
|
||||
|
|
|
@ -342,6 +342,7 @@ 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
|
||||
*/
|
||||
|
@ -349,6 +350,7 @@ 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
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@ object FeeratesPerKw {
|
|||
|
||||
/**
|
||||
* Used in tests
|
||||
*
|
||||
* @param feeratePerKw
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,6 @@ import fr.acinq.bitcoin.Crypto.{PublicKey, ripemd160, sha256}
|
|||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.eclair.NodeParams.BITCOINJ
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.blockchain.WatchConfirmed.extractPublicKeyScript
|
||||
import fr.acinq.eclair.blockchain._
|
||||
import fr.acinq.eclair.channel.Helpers.{Closing, Funding}
|
||||
import fr.acinq.eclair.crypto.{Generators, ShaChain, Sphinx}
|
||||
|
|
|
@ -8,7 +8,7 @@ import fr.acinq.eclair.UInt64
|
|||
*/
|
||||
|
||||
class ChannelException(channelId: BinaryData, message: String) extends RuntimeException(message)
|
||||
|
||||
// @formatter:off
|
||||
case class DebugTriggeredException (channelId: BinaryData) extends ChannelException(channelId, "debug-mode triggered failure")
|
||||
case class ChannelReserveTooHigh (channelId: BinaryData, channelReserveSatoshis: Long, reserveToFundingRatio: Double, maxReserveToFundingRatio: Double) extends ChannelException(channelId, s"channelReserveSatoshis too high: reserve=$channelReserveSatoshis fundingRatio=$reserveToFundingRatio maxFundingRatio=$maxReserveToFundingRatio")
|
||||
case class ClosingInProgress (channelId: BinaryData) extends ChannelException(channelId, "cannot send new htlcs, closing in progress")
|
||||
|
@ -39,4 +39,5 @@ case class UnexpectedRevocation (channelId: BinaryData) extends C
|
|||
case class InvalidRevocation (channelId: BinaryData) extends ChannelException(channelId, "invalid revocation")
|
||||
case class CommitmentSyncError (channelId: BinaryData) extends ChannelException(channelId, "commitment sync error")
|
||||
case class RevocationSyncError (channelId: BinaryData) extends ChannelException(channelId, "revocation sync error")
|
||||
case class InvalidFailureCode (channelId: BinaryData) extends ChannelException(channelId, "UpdateFailMalformedHtlc message doesn't have BADONION bit set")
|
||||
case class InvalidFailureCode (channelId: BinaryData) extends ChannelException(channelId, "UpdateFailMalformedHtlc message doesn't have BADONION bit set")
|
||||
// @formatter:on
|
|
@ -1,7 +1,7 @@
|
|||
package fr.acinq.eclair.channel
|
||||
|
||||
import fr.acinq.bitcoin.Crypto.{Point, PrivateKey, sha256}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, Satoshi, Script, Transaction}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, Satoshi, Transaction}
|
||||
import fr.acinq.eclair.crypto.{Generators, ShaChain, Sphinx}
|
||||
import fr.acinq.eclair.payment.Origin
|
||||
import fr.acinq.eclair.transactions.Transactions._
|
||||
|
|
|
@ -2,7 +2,7 @@ package fr.acinq.eclair.channel
|
|||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef}
|
||||
import fr.acinq.eclair.NodeParams
|
||||
import fr.acinq.eclair.wire.{Error, LightningMessage}
|
||||
import fr.acinq.eclair.wire.LightningMessage
|
||||
|
||||
/**
|
||||
* Created by fabrice on 27/02/17.
|
||||
|
|
|
@ -490,6 +490,7 @@ 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
|
||||
*/
|
||||
|
@ -509,6 +510,7 @@ 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
|
||||
*/
|
||||
|
@ -524,6 +526,7 @@ 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
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,7 @@ class Register extends Actor with ActorLogging {
|
|||
}
|
||||
|
||||
object Register {
|
||||
|
||||
// @formatter:off
|
||||
case class Forward[T](channelId: BinaryData, message: T)
|
||||
case class ForwardShortId[T](shortChannelId: Long, message: T)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package fr.acinq.eclair.crypto
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import org.spongycastle.util.encoders.Hex
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
/**
|
||||
* Bit stream that can be written to and read at both ends (i.e. you can read from the end or the beginning of the stream)
|
||||
* @param bytes bits packed as bytes, the last byte is padded with 0s
|
||||
*
|
||||
* @param bytes bits packed as bytes, the last byte is padded with 0s
|
||||
* @param offstart offset at which the first bit is in the first byte
|
||||
* @param offend offset at which the last bit is in the last byte
|
||||
* @param offend offset at which the last bit is in the last byte
|
||||
*/
|
||||
case class BitStream(bytes: Vector[Byte], offstart: Int, offend: Int) {
|
||||
|
||||
|
@ -20,6 +20,7 @@ case class BitStream(bytes: Vector[Byte], offstart: Int, offend: Int) {
|
|||
def bitCount = 8 * bytes.length - offstart - offend
|
||||
|
||||
def isEmpty = bitCount == 0
|
||||
|
||||
/**
|
||||
* append a byte to a bitstream
|
||||
*
|
||||
|
@ -97,16 +98,17 @@ case class BitStream(bytes: Vector[Byte], offstart: Int, offend: Int) {
|
|||
BitStream(bytes.dropRight(2) :+ a1.toByte, offstart, offend) -> byte.toByte
|
||||
}
|
||||
|
||||
def popBytes(n: Int) : (BitStream, Seq[Byte]) = {
|
||||
def popBytes(n: Int): (BitStream, Seq[Byte]) = {
|
||||
@tailrec
|
||||
def loop(stream: BitStream, acc: Seq[Byte]) : (BitStream, Seq[Byte]) =
|
||||
def loop(stream: BitStream, acc: Seq[Byte]): (BitStream, Seq[Byte]) =
|
||||
if (acc.length == n) (stream, acc) else {
|
||||
val (stream1, value) = stream.popByte
|
||||
loop(stream1, acc :+ value)
|
||||
}
|
||||
val (stream1, value) = stream.popByte
|
||||
loop(stream1, acc :+ value)
|
||||
}
|
||||
|
||||
loop(this, Nil)
|
||||
}
|
||||
|
||||
/**
|
||||
* read the first bit from a bitstream
|
||||
*
|
||||
|
@ -117,7 +119,7 @@ case class BitStream(bytes: Vector[Byte], offstart: Int, offend: Int) {
|
|||
case _ => BitStream(bytes, offstart + 1, offend) -> firstBit
|
||||
}
|
||||
|
||||
def readBits(count: Int) : (BitStream, Seq[Bit]) = {
|
||||
def readBits(count: Int): (BitStream, Seq[Bit]) = {
|
||||
@tailrec
|
||||
def loop(stream: BitStream, acc: Seq[Bit]): (BitStream, Seq[Bit]) = if (acc.length == count) (stream, acc) else {
|
||||
val (stream1, bit) = stream.readBit
|
||||
|
@ -126,14 +128,15 @@ case class BitStream(bytes: Vector[Byte], offstart: Int, offend: Int) {
|
|||
|
||||
loop(this, Nil)
|
||||
}
|
||||
|
||||
/**
|
||||
* read the first byte from a bitstream
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
def readByte: (BitStream, Byte) = {
|
||||
val byte = ((bytes(0) << offstart) | (bytes(1) >>> (7 - offstart))) & 0xff
|
||||
BitStream(bytes.tail, offstart, offend) -> byte.toByte
|
||||
val byte = ((bytes(0) << offstart) | (bytes(1) >>> (7 - offstart))) & 0xff
|
||||
BitStream(bytes.tail, offstart, offend) -> byte.toByte
|
||||
}
|
||||
|
||||
def isSet(pos: Int): Boolean = {
|
||||
|
|
|
@ -3,8 +3,8 @@ package fr.acinq.eclair.crypto
|
|||
import java.math.BigInteger
|
||||
import java.nio.ByteOrder
|
||||
|
||||
import fr.acinq.eclair.randomBytes
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, Protocol}
|
||||
import fr.acinq.eclair.randomBytes
|
||||
import grizzled.slf4j.Logging
|
||||
import org.spongycastle.crypto.digests.SHA256Digest
|
||||
import org.spongycastle.crypto.macs.HMac
|
||||
|
|
|
@ -97,7 +97,7 @@ object ShaChain {
|
|||
}
|
||||
|
||||
|
||||
val shaChainCodec: Codec[ShaChain] = {
|
||||
val shaChainCodec: Codec[ShaChain] = {
|
||||
import scodec.Codec
|
||||
import scodec.bits.BitVector
|
||||
import scodec.codecs._
|
||||
|
@ -106,7 +106,7 @@ object ShaChain {
|
|||
val entryCodec = vectorOfN(uint16, bool) ~ LightningMessageCodecs.varsizebinarydata
|
||||
|
||||
// codec for a Map[Vector[Boolean], BinaryData]: write all k ->v pairs using the codec defined above
|
||||
val mapCodec: Codec[Map[Vector[Boolean], BinaryData]] = Codec[Map[Vector[Boolean], BinaryData]] (
|
||||
val mapCodec: Codec[Map[Vector[Boolean], BinaryData]] = Codec[Map[Vector[Boolean], BinaryData]](
|
||||
(m: Map[Vector[Boolean], BinaryData]) => vectorOfN(uint16, entryCodec).encode(m.toVector),
|
||||
(b: BitVector) => vectorOfN(uint16, entryCodec).decode(b).map(_.map(_.toMap))
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.nio.ByteOrder
|
|||
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, Protocol}
|
||||
import fr.acinq.eclair.wire.{ChannelUpdate, FailureMessage, FailureMessageCodecs, LightningMessageCodecs}
|
||||
import fr.acinq.eclair.wire.{FailureMessage, FailureMessageCodecs}
|
||||
import grizzled.slf4j.Logging
|
||||
import org.spongycastle.crypto.digests.SHA256Digest
|
||||
import org.spongycastle.crypto.macs.HMac
|
||||
|
@ -32,7 +32,7 @@ object Sphinx extends Logging {
|
|||
|
||||
// onion packet length
|
||||
val PacketLength = 1 + 33 + MacLength + MaxHops * (PayloadLength + MacLength)
|
||||
|
||||
|
||||
// last packet (all zeroes except for the version byte)
|
||||
val LAST_PACKET = Packet(Version, zeroes(33), zeroes(MacLength), zeroes(MaxHops * (PayloadLength + MacLength)))
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class TransportHandler[T: ClassTag](keyPair: KeyPair, rs: Option[BinaryData], co
|
|||
connection ! akka.io.Tcp.Register(self)
|
||||
|
||||
val out = context.actorOf(Props(new WriteAckSender(connection)))
|
||||
|
||||
def buf(message: BinaryData): ByteString = ByteString.fromArray(message)
|
||||
|
||||
// it means we initiate the dialog
|
||||
|
|
|
@ -17,6 +17,7 @@ trait NetworkDb {
|
|||
|
||||
/**
|
||||
* This method removes 1 channel announcement and 2 channel updates (at both ends of the same channel)
|
||||
*
|
||||
* @param shortChannelId
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package fr.acinq.eclair.db
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.channel.HasCommitments
|
||||
|
||||
/**
|
||||
* This database stores the preimages that we have received from downstream
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package fr.acinq.eclair.db.sqlite
|
||||
|
||||
import java.sql.{Connection, ResultSet}
|
||||
import java.sql.Connection
|
||||
|
||||
import fr.acinq.bitcoin.Crypto
|
||||
import fr.acinq.eclair.db.NetworkDb
|
||||
import fr.acinq.eclair.router.Announcements
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs.{channelAnnouncementCodec, channelUpdateCodec, nodeAnnouncementCodec}
|
||||
import fr.acinq.eclair.wire.{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement}
|
||||
import scodec.Codec
|
||||
import scodec.bits.BitVector
|
||||
|
||||
class SqliteNetworkDb(sqlite: Connection) extends NetworkDb {
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package fr.acinq.eclair.io
|
|||
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, OneForOneStrategy, Props, Status, SupervisorStrategy, Terminated}
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, OneForOneStrategy, Props, SupervisorStrategy}
|
||||
import akka.io.Tcp.SO.KeepAlive
|
||||
import akka.io.{IO, Tcp}
|
||||
import fr.acinq.eclair.NodeParams
|
||||
|
|
|
@ -2,9 +2,9 @@ package fr.acinq.eclair.payment
|
|||
|
||||
import akka.actor.{Actor, ActorLogging, Props, Status}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, MilliSatoshi}
|
||||
import fr.acinq.eclair.{Globals, NodeParams, randomBytes}
|
||||
import fr.acinq.eclair.channel.{CMD_FAIL_HTLC, CMD_FULFILL_HTLC, ExpiryTooSmall}
|
||||
import fr.acinq.eclair.channel.{CMD_FAIL_HTLC, CMD_FULFILL_HTLC}
|
||||
import fr.acinq.eclair.wire._
|
||||
import fr.acinq.eclair.{NodeParams, randomBytes}
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
|
@ -32,25 +32,25 @@ class LocalPaymentHandler(nodeParams: NodeParams) extends Actor with ActorLoggin
|
|||
}
|
||||
|
||||
case htlc: UpdateAddHtlc =>
|
||||
if (h2r.contains(htlc.paymentHash)) {
|
||||
if (h2r.contains(htlc.paymentHash)) {
|
||||
val r = h2r(htlc.paymentHash)._1
|
||||
val pr = h2r(htlc.paymentHash)._2
|
||||
// The htlc amount must be equal or greater than the requested amount. A slight overpaying is permitted, however
|
||||
// it must not be greater than two times the requested amount.
|
||||
// see https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages
|
||||
pr.amount match {
|
||||
case Some(amount) if MilliSatoshi(htlc.amountMsat) < amount => sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectPaymentAmount), commit = true)
|
||||
case Some(amount) if MilliSatoshi(htlc.amountMsat) > amount * 2 => sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectPaymentAmount), commit = true)
|
||||
case _ =>
|
||||
log.info(s"received payment for paymentHash=${htlc.paymentHash} amountMsat=${htlc.amountMsat}")
|
||||
// amount is correct or was not specified in the payment request
|
||||
sender ! CMD_FULFILL_HTLC(htlc.id, r, commit = true)
|
||||
context.system.eventStream.publish(PaymentReceived(MilliSatoshi(htlc.amountMsat), htlc.paymentHash))
|
||||
context.become(run(h2r - htlc.paymentHash))
|
||||
}
|
||||
} else {
|
||||
pr.amount match {
|
||||
case Some(amount) if MilliSatoshi(htlc.amountMsat) < amount => sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectPaymentAmount), commit = true)
|
||||
case Some(amount) if MilliSatoshi(htlc.amountMsat) > amount * 2 => sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectPaymentAmount), commit = true)
|
||||
case _ =>
|
||||
log.info(s"received payment for paymentHash=${htlc.paymentHash} amountMsat=${htlc.amountMsat}")
|
||||
// amount is correct or was not specified in the payment request
|
||||
sender ! CMD_FULFILL_HTLC(htlc.id, r, commit = true)
|
||||
context.system.eventStream.publish(PaymentReceived(MilliSatoshi(htlc.amountMsat), htlc.paymentHash))
|
||||
context.become(run(h2r - htlc.paymentHash))
|
||||
}
|
||||
} else {
|
||||
sender ! CMD_FAIL_HTLC(htlc.id, Right(UnknownPaymentHash), commit = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ object PaymentHop {
|
|||
/**
|
||||
*
|
||||
* @param reversePath sequence of Hops from recipient to a start of assisted path
|
||||
* @param msat an amount to send to a payment recipient
|
||||
* @param msat an amount to send to a payment recipient
|
||||
* @return a sequence of extra hops with a pre-calculated fee for a given msat amount
|
||||
*/
|
||||
def buildExtra(reversePath: Seq[Hop], msat: Long): Seq[ExtraHop] = (List.empty[ExtraHop] /: reversePath) {
|
||||
|
@ -29,13 +29,18 @@ object PaymentHop {
|
|||
|
||||
trait PaymentHop {
|
||||
def nextFee(msat: Long): Long
|
||||
|
||||
def shortChannelId: Long
|
||||
|
||||
def cltvExpiryDelta: Int
|
||||
|
||||
def nodeId: PublicKey
|
||||
}
|
||||
|
||||
case class Hop(nodeId: PublicKey, nextNodeId: PublicKey, lastUpdate: ChannelUpdate) extends PaymentHop {
|
||||
def nextFee(msat: Long): Long = PaymentHop.nodeFee(lastUpdate.feeBaseMsat, lastUpdate.feeProportionalMillionths, msat)
|
||||
|
||||
def cltvExpiryDelta: Int = lastUpdate.cltvExpiryDelta
|
||||
|
||||
def shortChannelId: Long = lastUpdate.shortChannelId
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package fr.acinq.eclair.payment
|
||||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, Props}
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
|
||||
/**
|
||||
|
|
|
@ -263,13 +263,13 @@ object PaymentRequest {
|
|||
case class ExpiryTag(seconds: Long) extends Tag {
|
||||
override def toInt5s = {
|
||||
val ints = writeUnsignedLong(seconds)
|
||||
Bech32.map('x') +: (writeSize(ints.size) ++ ints) }
|
||||
Bech32.map('x') +: (writeSize(ints.size) ++ ints)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Min final CLTV expiry
|
||||
*
|
||||
*
|
||||
* @param blocks min final cltv expiry, in blocks
|
||||
*/
|
||||
case class MinFinalCltvExpiryTag(blocks: Long) extends Tag {
|
||||
|
@ -418,8 +418,9 @@ object PaymentRequest {
|
|||
|
||||
/**
|
||||
* prepend an unsigned long value to a sequence of Int5s
|
||||
*
|
||||
* @param value input value
|
||||
* @param acc sequence of Int5 values
|
||||
* @param acc sequence of Int5 values
|
||||
* @return an update sequence of Int5s
|
||||
*/
|
||||
@tailrec
|
||||
|
@ -432,10 +433,11 @@ object PaymentRequest {
|
|||
/**
|
||||
* convert a tag data size to a sequence of Int5s. It * must * fit on a sequence
|
||||
* of 2 Int5 values
|
||||
*
|
||||
* @param size data size
|
||||
* @return size as a sequence of exactly 2 Int5 values
|
||||
*/
|
||||
def writeSize(size: Long) : Seq[Int5] = {
|
||||
def writeSize(size: Long): Seq[Int5] = {
|
||||
val output = writeUnsignedLong(size)
|
||||
// make sure that size is encoded on 2 int5 values
|
||||
output.length match {
|
||||
|
@ -448,8 +450,9 @@ object PaymentRequest {
|
|||
|
||||
/**
|
||||
* reads an unsigned long value from a sequence of Int5s
|
||||
*
|
||||
* @param length length of the sequence
|
||||
* @param ints sequence of Int5s
|
||||
* @param ints sequence of Int5s
|
||||
* @return an unsigned long value
|
||||
*/
|
||||
def readUnsignedLong(length: Int, ints: Seq[Int5]): Long = ints.take(length).foldLeft(0L) { case (acc, i) => acc * 32 + i }
|
||||
|
|
|
@ -79,6 +79,7 @@ object Announcements {
|
|||
* The creating node MUST set node-id-1 and node-id-2 to the public keys of the
|
||||
* two nodes who are operating the channel, such that node-id-1 is the numerically-lesser
|
||||
* of the two DER encoded keys sorted in ascending numerical order,
|
||||
*
|
||||
* @return true if localNodeId is node1
|
||||
*/
|
||||
def isNode1(localNodeId: BinaryData, remoteNodeId: BinaryData) = LexicographicalOrdering.isLessThan(localNodeId, remoteNodeId)
|
||||
|
@ -87,6 +88,7 @@ object Announcements {
|
|||
* BOLT 7:
|
||||
* The creating node [...] MUST set the direction bit of flags to 0 if
|
||||
* the creating node is node-id-1 in that message, otherwise 1.
|
||||
*
|
||||
* @return true if the node who sent these flags is node1
|
||||
*/
|
||||
def isNode1(flags: BinaryData) = !BitVector(flags.data).reverse.get(0)
|
||||
|
@ -94,6 +96,7 @@ object Announcements {
|
|||
/**
|
||||
* A node MAY create and send a channel_update with the disable bit set to
|
||||
* signal the temporary unavailability of a channel
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
def isEnabled(flags: BinaryData) = !BitVector(flags.data).reverse.get(1)
|
||||
|
|
|
@ -11,18 +11,18 @@ import fr.acinq.eclair._
|
|||
import fr.acinq.eclair.blockchain._
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.io.Peer
|
||||
import fr.acinq.eclair.payment.Hop
|
||||
import fr.acinq.eclair.transactions.Scripts
|
||||
import fr.acinq.eclair.wire._
|
||||
import fr.acinq.eclair.payment.Hop
|
||||
import org.jgrapht.alg.shortestpath.DijkstraShortestPath
|
||||
import org.jgrapht.ext._
|
||||
import org.jgrapht.graph.{DefaultDirectedGraph, DefaultEdge, SimpleGraph}
|
||||
|
||||
import scala.collection.JavaConversions._
|
||||
import scala.compat.Platform
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Random, Success, Try}
|
||||
import scala.concurrent.duration._
|
||||
|
||||
// @formatter:off
|
||||
|
||||
|
|
|
@ -7,4 +7,5 @@ package fr.acinq.eclair.router
|
|||
class RouterException(message: String) extends RuntimeException(message)
|
||||
|
||||
object RouteNotFound extends RouterException("Route not found")
|
||||
|
||||
object CannotRouteToSelf extends RouterException("Cannot route to self")
|
||||
|
|
|
@ -13,8 +13,10 @@ import scala.concurrent.duration.{FiniteDuration, _}
|
|||
*/
|
||||
class ThrottleForwarder(target: ActorRef, messages: Iterable[Any], chunkSize: Int, delay: FiniteDuration) extends Actor with ActorLogging {
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import ThrottleForwarder.Tick
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
val clock = context.system.scheduler.schedule(0 second, delay, self, Tick)
|
||||
|
||||
log.debug(s"sending messages=${messages.size} with chunkSize=$chunkSize and delay=$delay")
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package fr.acinq.eclair.transactions
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.wire._
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package fr.acinq.eclair.transactions
|
||||
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey, ripemd160}
|
||||
import fr.acinq.bitcoin.Crypto.{PublicKey, ripemd160}
|
||||
import fr.acinq.bitcoin.Script._
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto, LexicographicalOrdering, LockTimeThreshold, OP_0, OP_1, OP_1NEGATE, OP_2, OP_2DROP, OP_ADD, 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, OutPoint, SIGHASH_ALL, Satoshi, Script, ScriptElt, ScriptWitness, Transaction, TxIn, TxOut}
|
||||
import fr.acinq.bitcoin.{BinaryData, LexicographicalOrdering, LockTimeThreshold, OP_0, OP_1, OP_1NEGATE, OP_2, OP_2DROP, OP_ADD, 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}
|
||||
|
||||
/**
|
||||
* Created by PM on 02/12/2016.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package fr.acinq.eclair.wire
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs.{binarydata, uint64, channelUpdateCodec}
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs.{binarydata, channelUpdateCodec, uint64}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
|
|
|
@ -47,9 +47,13 @@ object FixedSizeStrictCodec {
|
|||
*/
|
||||
def bytesStrict(size: Int): Codec[ByteVector] = new Codec[ByteVector] {
|
||||
private val codec = new FixedSizeStrictCodec(size * 8L, codecs.bits).xmap[ByteVector](_.toByteVector, _.toBitVector)
|
||||
|
||||
def sizeBound = codec.sizeBound
|
||||
|
||||
def encode(b: ByteVector) = codec.encode(b)
|
||||
|
||||
def decode(b: BitVector) = codec.decode(b)
|
||||
|
||||
override def toString = s"bytesStrict($size)"
|
||||
}
|
||||
}
|
|
@ -6,8 +6,8 @@ import java.net.{Inet4Address, Inet6Address, InetAddress, InetSocketAddress}
|
|||
import fr.acinq.bitcoin.Crypto.{Point, PrivateKey, PublicKey, Scalar}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto}
|
||||
import fr.acinq.eclair.crypto.{Generators, Sphinx}
|
||||
import fr.acinq.eclair.{UInt64, wire}
|
||||
import fr.acinq.eclair.wire.FixedSizeStrictCodec.bytesStrict
|
||||
import fr.acinq.eclair.{UInt64, wire}
|
||||
import scodec.bits.{BitVector, ByteVector}
|
||||
import scodec.codecs._
|
||||
import scodec.{Attempt, Codec, Err}
|
||||
|
|
|
@ -32,9 +32,9 @@ case class Ping(pongLength: Int, data: BinaryData) extends SetupMessage
|
|||
case class Pong(data: BinaryData) extends SetupMessage
|
||||
|
||||
case class ChannelReestablish(
|
||||
channelId: BinaryData,
|
||||
nextLocalCommitmentNumber: Long,
|
||||
nextRemoteRevocationNumber: Long) extends ChannelMessage with HasChannelId
|
||||
channelId: BinaryData,
|
||||
nextLocalCommitmentNumber: Long,
|
||||
nextRemoteRevocationNumber: Long) extends ChannelMessage with HasChannelId
|
||||
|
||||
case class OpenChannel(chainHash: BinaryData,
|
||||
temporaryChannelId: BinaryData,
|
||||
|
|
|
@ -27,13 +27,13 @@ import java.util.Arrays;
|
|||
|
||||
/**
|
||||
* Implementation of the Curve25519 elliptic curve algorithm.
|
||||
*
|
||||
* <p>
|
||||
* This implementation is based on that from arduinolibs:
|
||||
* https://github.com/rweather/arduinolibs
|
||||
*
|
||||
* <p>
|
||||
* Differences in this version are due to using 26-bit limbs for the
|
||||
* representation instead of the 8/16/32-bit limbs in the original.
|
||||
*
|
||||
* <p>
|
||||
* References: http://cr.yp.to/ecdh.html, RFC 7748
|
||||
*/
|
||||
public final class Curve25519 {
|
||||
|
@ -61,25 +61,24 @@ public final class Curve25519 {
|
|||
/**
|
||||
* Constructs the temporary state holder for Curve25519 evaluation.
|
||||
*/
|
||||
private Curve25519()
|
||||
{
|
||||
private Curve25519() {
|
||||
// Allocate memory for all of the temporary variables we will need.
|
||||
x_1 = new int [NUM_LIMBS_255BIT];
|
||||
x_2 = new int [NUM_LIMBS_255BIT];
|
||||
x_3 = new int [NUM_LIMBS_255BIT];
|
||||
z_2 = new int [NUM_LIMBS_255BIT];
|
||||
z_3 = new int [NUM_LIMBS_255BIT];
|
||||
A = new int [NUM_LIMBS_255BIT];
|
||||
B = new int [NUM_LIMBS_255BIT];
|
||||
C = new int [NUM_LIMBS_255BIT];
|
||||
D = new int [NUM_LIMBS_255BIT];
|
||||
E = new int [NUM_LIMBS_255BIT];
|
||||
AA = new int [NUM_LIMBS_255BIT];
|
||||
BB = new int [NUM_LIMBS_255BIT];
|
||||
DA = new int [NUM_LIMBS_255BIT];
|
||||
CB = new int [NUM_LIMBS_255BIT];
|
||||
t1 = new long [NUM_LIMBS_510BIT];
|
||||
t2 = new int [NUM_LIMBS_510BIT];
|
||||
x_1 = new int[NUM_LIMBS_255BIT];
|
||||
x_2 = new int[NUM_LIMBS_255BIT];
|
||||
x_3 = new int[NUM_LIMBS_255BIT];
|
||||
z_2 = new int[NUM_LIMBS_255BIT];
|
||||
z_3 = new int[NUM_LIMBS_255BIT];
|
||||
A = new int[NUM_LIMBS_255BIT];
|
||||
B = new int[NUM_LIMBS_255BIT];
|
||||
C = new int[NUM_LIMBS_255BIT];
|
||||
D = new int[NUM_LIMBS_255BIT];
|
||||
E = new int[NUM_LIMBS_255BIT];
|
||||
AA = new int[NUM_LIMBS_255BIT];
|
||||
BB = new int[NUM_LIMBS_255BIT];
|
||||
DA = new int[NUM_LIMBS_255BIT];
|
||||
CB = new int[NUM_LIMBS_255BIT];
|
||||
t1 = new long[NUM_LIMBS_510BIT];
|
||||
t2 = new int[NUM_LIMBS_510BIT];
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,8 +101,8 @@ public final class Curve25519 {
|
|||
Arrays.fill(BB, 0);
|
||||
Arrays.fill(DA, 0);
|
||||
Arrays.fill(CB, 0);
|
||||
Arrays.fill(t1, 0L);
|
||||
Arrays.fill(t2, 0);
|
||||
Arrays.fill(t1, 0L);
|
||||
Arrays.fill(t2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,8 +111,7 @@ public final class Curve25519 {
|
|||
*
|
||||
* @param x The number to reduce, and the result.
|
||||
*/
|
||||
private void reduceQuick(int[] x)
|
||||
{
|
||||
private void reduceQuick(int[] x) {
|
||||
int index, carry;
|
||||
|
||||
// Perform a trial subtraction of (2^255 - 19) from "x" which is
|
||||
|
@ -142,12 +140,11 @@ public final class Curve25519 {
|
|||
* Reduce a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The value to be reduced. This array will be
|
||||
* modified during the reduction.
|
||||
* @param size The number of limbs in the high order half of x.
|
||||
* @param x The value to be reduced. This array will be
|
||||
* modified during the reduction.
|
||||
* @param size The number of limbs in the high order half of x.
|
||||
*/
|
||||
private void reduce(int[] result, int[] x, int size)
|
||||
{
|
||||
private void reduce(int[] result, int[] x, int size) {
|
||||
int index, limb, carry;
|
||||
|
||||
// Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
|
||||
|
@ -198,11 +195,10 @@ public final class Curve25519 {
|
|||
* Multiplies two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to multiply.
|
||||
* @param y The second number to multiply.
|
||||
* @param x The first number to multiply.
|
||||
* @param y The second number to multiply.
|
||||
*/
|
||||
private void mul(int[] result, int[] x, int[] y)
|
||||
{
|
||||
private void mul(int[] result, int[] x, int[] y) {
|
||||
int i, j;
|
||||
|
||||
// Multiply the two numbers to create the intermediate result.
|
||||
|
@ -220,10 +216,10 @@ public final class Curve25519 {
|
|||
|
||||
// Propagate carries and convert back into 26-bit words.
|
||||
v = t1[0];
|
||||
t2[0] = ((int)v) & 0x03FFFFFF;
|
||||
t2[0] = ((int) v) & 0x03FFFFFF;
|
||||
for (i = 1; i < NUM_LIMBS_510BIT; ++i) {
|
||||
v = (v >> 26) + t1[i];
|
||||
t2[i] = ((int)v) & 0x03FFFFFF;
|
||||
t2[i] = ((int) v) & 0x03FFFFFF;
|
||||
}
|
||||
|
||||
// Reduce the result modulo 2^255 - 19.
|
||||
|
@ -234,10 +230,9 @@ public final class Curve25519 {
|
|||
* Squares a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to square.
|
||||
* @param x The number to square.
|
||||
*/
|
||||
private void square(int[] result, int[] x)
|
||||
{
|
||||
private void square(int[] result, int[] x) {
|
||||
mul(result, x, x);
|
||||
}
|
||||
|
||||
|
@ -245,19 +240,18 @@ public final class Curve25519 {
|
|||
* Multiplies a number by the a24 constant, modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The number to multiply by a24.
|
||||
* @param x The number to multiply by a24.
|
||||
*/
|
||||
private void mulA24(int[] result, int[] x)
|
||||
{
|
||||
private void mulA24(int[] result, int[] x) {
|
||||
long a24 = 121665;
|
||||
long carry = 0;
|
||||
int index;
|
||||
for (index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
carry += a24 * x[index];
|
||||
t2[index] = ((int)carry) & 0x03FFFFFF;
|
||||
t2[index] = ((int) carry) & 0x03FFFFFF;
|
||||
carry >>= 26;
|
||||
}
|
||||
t2[NUM_LIMBS_255BIT] = ((int)carry) & 0x03FFFFFF;
|
||||
t2[NUM_LIMBS_255BIT] = ((int) carry) & 0x03FFFFFF;
|
||||
reduce(result, t2, 1);
|
||||
}
|
||||
|
||||
|
@ -265,11 +259,10 @@ public final class Curve25519 {
|
|||
* Adds two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to add.
|
||||
* @param y The second number to add.
|
||||
* @param x The first number to add.
|
||||
* @param y The second number to add.
|
||||
*/
|
||||
private void add(int[] result, int[] x, int[] y)
|
||||
{
|
||||
private void add(int[] result, int[] x, int[] y) {
|
||||
int index, carry;
|
||||
carry = x[0] + y[0];
|
||||
result[0] = carry & 0x03FFFFFF;
|
||||
|
@ -284,11 +277,10 @@ public final class Curve25519 {
|
|||
* Subtracts two numbers modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result.
|
||||
* @param x The first number to subtract.
|
||||
* @param y The second number to subtract.
|
||||
* @param x The first number to subtract.
|
||||
* @param y The second number to subtract.
|
||||
*/
|
||||
private void sub(int[] result, int[] x, int[] y)
|
||||
{
|
||||
private void sub(int[] result, int[] x, int[] y) {
|
||||
int index, borrow;
|
||||
|
||||
// Subtract y from x to generate the intermediate result.
|
||||
|
@ -316,11 +308,10 @@ public final class Curve25519 {
|
|||
* Conditional swap of two values.
|
||||
*
|
||||
* @param select Set to 1 to swap, 0 to leave as-is.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*/
|
||||
private static void cswap(int select, int[] x, int[] y)
|
||||
{
|
||||
private static void cswap(int select, int[] x, int[] y) {
|
||||
int dummy;
|
||||
select = -select;
|
||||
for (int index = 0; index < NUM_LIMBS_255BIT; ++index) {
|
||||
|
@ -334,10 +325,9 @@ public final class Curve25519 {
|
|||
* Raise x to the power of (2^250 - 1).
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private void pow250(int[] result, int[] x)
|
||||
{
|
||||
private void pow250(int[] result, int[] x) {
|
||||
int i, j;
|
||||
|
||||
// The big-endian hexadecimal expansion of (2^250 - 1) is:
|
||||
|
@ -375,10 +365,9 @@ public final class Curve25519 {
|
|||
* Computes the reciprocal of a number modulo 2^255 - 19.
|
||||
*
|
||||
* @param result The result. Must not overlap with x.
|
||||
* @param x The argument.
|
||||
* @param x The argument.
|
||||
*/
|
||||
private void recip(int[] result, int[] x)
|
||||
{
|
||||
private void recip(int[] result, int[] x) {
|
||||
// The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
|
||||
// The big-endian hexadecimal expansion of (p - 2) is:
|
||||
// 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
|
||||
|
@ -401,8 +390,7 @@ public final class Curve25519 {
|
|||
*
|
||||
* @param s The 32-byte secret key.
|
||||
*/
|
||||
private void evalCurve(byte[] s)
|
||||
{
|
||||
private void evalCurve(byte[] s) {
|
||||
int sposn = 31;
|
||||
int sbit = 6;
|
||||
int svalue = s[sposn] | 0x40;
|
||||
|
@ -411,7 +399,7 @@ public final class Curve25519 {
|
|||
|
||||
// Iterate over all 255 bits of "s" from the highest to the lowest.
|
||||
// We ignore the high bit of the 256-bit representation of "s".
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
// Conditional swaps on entry to this bit but only if we
|
||||
// didn't swap on the previous bit.
|
||||
select = (svalue >> sbit) & 0x01;
|
||||
|
@ -464,14 +452,13 @@ public final class Curve25519 {
|
|||
/**
|
||||
* Evaluates the Curve25519 curve.
|
||||
*
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param result Buffer to place the result of the evaluation into.
|
||||
* @param offset Offset into the result buffer.
|
||||
* @param privateKey The private key to use in the evaluation.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
* @param publicKey The public key to use in the evaluation, or null
|
||||
* if the base point of the curve should be used.
|
||||
*/
|
||||
public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey)
|
||||
{
|
||||
public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey) {
|
||||
Curve25519 state = new Curve25519();
|
||||
try {
|
||||
// Unpack the public key value. If null, use 9 as the base point.
|
||||
|
@ -501,11 +488,11 @@ public final class Curve25519 {
|
|||
}
|
||||
|
||||
// Initialize the other temporary variables.
|
||||
Arrays.fill(state.x_2, 0); // x_2 = 1
|
||||
Arrays.fill(state.x_2, 0); // x_2 = 1
|
||||
state.x_2[0] = 1;
|
||||
Arrays.fill(state.z_2, 0); // z_2 = 0
|
||||
Arrays.fill(state.z_2, 0); // z_2 = 0
|
||||
System.arraycopy(state.x_1, 0, state.x_3, 0, state.x_1.length); // x_3 = x_1
|
||||
Arrays.fill(state.z_3, 0); // z_3 = 1
|
||||
Arrays.fill(state.z_3, 0); // z_3 = 1
|
||||
state.z_3[0] = 1;
|
||||
|
||||
// Evaluate the curve for every bit of the private key.
|
||||
|
@ -520,9 +507,9 @@ public final class Curve25519 {
|
|||
int bit = (index * 8) % 26;
|
||||
int word = (index * 8) / 26;
|
||||
if (bit <= (26 - 8))
|
||||
result[offset + index] = (byte)(state.x_2[word] >> bit);
|
||||
result[offset + index] = (byte) (state.x_2[word] >> bit);
|
||||
else
|
||||
result[offset + index] = (byte)((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
|
||||
result[offset + index] = (byte) ((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
|
||||
}
|
||||
} finally {
|
||||
// Clean up all temporary state before we exit.
|
||||
|
|
|
@ -2,7 +2,7 @@ package fr.acinq.eclair
|
|||
|
||||
import java.nio.ByteOrder
|
||||
|
||||
import fr.acinq.bitcoin.{BinaryData, Protocol}
|
||||
import fr.acinq.bitcoin.Protocol
|
||||
import fr.acinq.eclair.Features._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
|
|
|
@ -2,7 +2,6 @@ package fr.acinq.eclair
|
|||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, Stash}
|
||||
import fr.acinq.eclair.channel.Commitments.msg2String
|
||||
import fr.acinq.eclair.channel.{INPUT_DISCONNECTED, INPUT_RECONNECTED}
|
||||
import fr.acinq.eclair.wire.LightningMessage
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,7 +23,9 @@ object TestConstants {
|
|||
val seed = BinaryData("01" * 32)
|
||||
val master = DeterministicWallet.generate(seed)
|
||||
val extendedPrivateKey = DeterministicWallet.derivePrivateKey(master, DeterministicWallet.hardened(46) :: DeterministicWallet.hardened(0) :: Nil)
|
||||
|
||||
def sqlite = DriverManager.getConnection("jdbc:sqlite::memory:")
|
||||
|
||||
def nodeParams = NodeParams(
|
||||
extendedPrivateKey = extendedPrivateKey,
|
||||
privateKey = extendedPrivateKey.privateKey,
|
||||
|
@ -58,7 +60,9 @@ object TestConstants {
|
|||
channelFlags = 1,
|
||||
channelExcludeDuration = 5 seconds,
|
||||
watcherType = BITCOIND)
|
||||
|
||||
def id = nodeParams.privateKey.publicKey
|
||||
|
||||
def channelParams = Peer.makeChannelParams(
|
||||
nodeParams = nodeParams,
|
||||
defaultFinalScriptPubKey = Script.write(Script.pay2wpkh(PrivateKey(Array.fill[Byte](32)(4), compressed = true).publicKey)),
|
||||
|
@ -72,7 +76,9 @@ object TestConstants {
|
|||
val seed = BinaryData("02" * 32)
|
||||
val master = DeterministicWallet.generate(seed)
|
||||
val extendedPrivateKey = DeterministicWallet.derivePrivateKey(master, DeterministicWallet.hardened(46) :: DeterministicWallet.hardened(0) :: Nil)
|
||||
|
||||
def sqlite = DriverManager.getConnection("jdbc:sqlite::memory:")
|
||||
|
||||
def nodeParams = NodeParams(
|
||||
extendedPrivateKey = extendedPrivateKey,
|
||||
privateKey = extendedPrivateKey.privateKey,
|
||||
|
@ -107,7 +113,9 @@ object TestConstants {
|
|||
channelFlags = 1,
|
||||
channelExcludeDuration = 5 seconds,
|
||||
watcherType = BITCOIND)
|
||||
|
||||
def id = nodeParams.privateKey.publicKey
|
||||
|
||||
def channelParams = Peer.makeChannelParams(
|
||||
nodeParams = nodeParams,
|
||||
defaultFinalScriptPubKey = Script.write(Script.pay2wpkh(PrivateKey(Array.fill[Byte](32)(5), compressed = true).publicKey)),
|
||||
|
|
|
@ -5,8 +5,8 @@ import akka.testkit.{TestKit, TestProbe}
|
|||
import fr.acinq.bitcoin.{BinaryData, Crypto, Transaction}
|
||||
import grizzled.slf4j.Logging
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.{BeforeAndAfterAll, FunSuiteLike}
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.scalatest.{BeforeAndAfterAll, FunSuiteLike}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
|
@ -14,6 +14,7 @@ import scala.concurrent.duration._
|
|||
class ElectrumClientSpec extends TestKit(ActorSystem("test")) with FunSuiteLike with Logging with BeforeAndAfterAll {
|
||||
|
||||
import ElectrumClient._
|
||||
|
||||
var client: ActorRef = _
|
||||
val probe = TestProbe()
|
||||
val referenceTx = Transaction.read("0200000003947e307df3ab452d23f02b5a65f4ada1804ee733e168e6197b0bd6cc79932b6c010000006a473044022069346ec6526454a481690a3664609f9e8032c34553015cfa2e9b25ebb420a33002206998f21a2aa771ad92a0c1083f4181a3acdb0d42ca51d01be1309da2ffb9cecf012102b4568cc6ee751f6d39f4a908b1fcffdb878f5f784a26a48c0acb0acff9d88e3bfeffffff966d9d969cd5f95bfd53003a35fcc1a50f4fb51f211596e6472583fdc5d38470000000006b4830450221009c9757515009c5709b5b678d678185202b817ef9a69ffb954144615ab11762210220732216384da4bf79340e9c46d0effba6ba92982cca998adfc3f354cec7715f800121035f7c3e077108035026f4ebd5d6ca696ef088d4f34d45d94eab4c41202ec74f9bfefffffff8d5062f5b04455c6cfa7e3f250e5a4fb44308ba2b86baf77f9ad0d782f57071010000006a47304402207f9f7dd91fe537a26d5554105977e3949a5c8c4ef53a6a3bff6da2d36eff928f02202b9427bef487a1825fd0c3c6851d17d5f19e6d73dfee22bf06db591929a2044d012102b4568cc6ee751f6d39f4a908b1fcffdb878f5f784a26a48c0acb0acff9d88e3bfeffffff02809698000000000017a914c82753548fdf4be1c3c7b14872c90b5198e67eaa876e642500000000001976a914e2365ec29471b3e271388b22eadf0e7f54d307a788ac6f771200")
|
||||
|
@ -73,6 +74,6 @@ class ElectrumClientSpec extends TestKit(ActorSystem("test")) with FunSuiteLike
|
|||
test("list script unspents") {
|
||||
probe.send(client, ScriptHashListUnspent(scriptHash))
|
||||
val ScriptHashListUnspentResponse(scriptHash1, unspents) = probe.expectMsgType[ScriptHashListUnspentResponse]
|
||||
assert(unspents.contains(UnspentItem("3903726806aa044fe59f40e42eed71bded068b43aaa9e2d716e38b7825412de0", 0, 10000000L,1210224L)))
|
||||
assert(unspents.contains(UnspentItem("3903726806aa044fe59f40e42eed71bded068b43aaa9e2d716e38b7825412de0", 0, 10000000L, 1210224L)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package fr.acinq.eclair.blockchain.electrum
|
||||
|
||||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.Crypto.PrivateKey
|
||||
import fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey
|
||||
import fr.acinq.bitcoin._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ElectrumWalletBasicSpec extends FunSuite {
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import org.json4s.JsonAST._
|
|||
import scala.concurrent.duration._
|
||||
import scala.sys.process._
|
||||
|
||||
class ElectrumWalletSpec extends IntegrationSpec{
|
||||
class ElectrumWalletSpec extends IntegrationSpec {
|
||||
|
||||
import ElectrumWallet._
|
||||
|
||||
val entropy = BinaryData("01" * 32)
|
||||
|
@ -107,7 +108,7 @@ class ElectrumWalletSpec extends IntegrationSpec{
|
|||
|
||||
awaitCond({
|
||||
val msg = listener.receiveOne(5 seconds)
|
||||
msg == TransactionConfidenceChanged(BinaryData(txid),1)
|
||||
msg == TransactionConfidenceChanged(BinaryData(txid), 1)
|
||||
}, max = 30 seconds, interval = 1 second)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ import scala.concurrent.Await
|
|||
class EarnDotComFeeProviderSpec extends FunSuite {
|
||||
|
||||
import EarnDotComFeeProvider._
|
||||
|
||||
import org.json4s.jackson.JsonMethods.parse
|
||||
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
val sample_response =
|
||||
|
@ -53,8 +53,8 @@ class EarnDotComFeeProviderSpec extends FunSuite {
|
|||
}
|
||||
|
||||
test("make sure API hasn't changed") {
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
implicit val system = ActorSystem()
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
val provider = new EarnDotComFeeProvider()
|
||||
|
|
|
@ -4,8 +4,8 @@ import org.junit.runner.RunWith
|
|||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.util.Random
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
|
@ -15,6 +15,7 @@ class FallbackFeeProviderSpec extends FunSuite {
|
|||
|
||||
/**
|
||||
* This provider returns a constant value, but fails after ttl tries
|
||||
*
|
||||
* @param ttl
|
||||
* @param feeratesPerByte
|
||||
*/
|
||||
|
@ -25,7 +26,7 @@ class FallbackFeeProviderSpec extends FunSuite {
|
|||
if (i < ttl) {
|
||||
i = i + 1
|
||||
Future.successful(feeratesPerByte)
|
||||
} else Future.failed(new RuntimeException())
|
||||
} else Future.failed(new RuntimeException())
|
||||
}
|
||||
|
||||
def dummyFeerates = FeeratesPerByte(Random.nextInt(10000), Random.nextInt(10000), Random.nextInt(10000), Random.nextInt(10000), Random.nextInt(10000), Random.nextInt(10000))
|
||||
|
@ -39,7 +40,7 @@ class FallbackFeeProviderSpec extends FunSuite {
|
|||
val provider5 = new FailingFeeProvider(5, dummyFeerates) // fails after 5 tries
|
||||
val provider7 = new FailingFeeProvider(Int.MaxValue, dummyFeerates) // "never" fails
|
||||
|
||||
val fallbackFeeProvider = new FallbackFeeProvider(provider0 :: provider1 :: provider3 :: provider5 :: provider7 :: Nil)
|
||||
val fallbackFeeProvider = new FallbackFeeProvider(provider0 :: provider1 :: provider3 :: provider5 :: provider7 :: Nil)
|
||||
|
||||
assert(await(fallbackFeeProvider.getFeerates) === provider1.feeratesPerByte)
|
||||
|
||||
|
@ -58,5 +59,4 @@ class FallbackFeeProviderSpec extends FunSuite {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ import fr.acinq.eclair.blockchain._
|
|||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKw
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.Sphinx
|
||||
import fr.acinq.eclair.payment.PaymentLifecycle
|
||||
import fr.acinq.eclair.payment.Hop
|
||||
import fr.acinq.eclair.payment.{Hop, PaymentLifecycle}
|
||||
import fr.acinq.eclair.wire._
|
||||
import fr.acinq.eclair.{Globals, TestConstants}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package fr.acinq.eclair.channel.states.a
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.eclair.TestConstants.{Alice, Bob}
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
|
|
|
@ -210,7 +210,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
|||
test("recv CMD_ADD_HTLC (while waiting for a revocation)") { case (alice, _, alice2bob, _, _, _, relayer) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
val add1 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2/3 * 1000, "11" * 32, 400144)
|
||||
val add1 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2 / 3 * 1000, "11" * 32, 400144)
|
||||
sender.send(alice, add1)
|
||||
sender.expectMsg("ok")
|
||||
alice2bob.expectMsgType[UpdateAddHtlc]
|
||||
|
@ -218,7 +218,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
|||
sender.expectMsg("ok")
|
||||
alice2bob.expectMsgType[CommitSig]
|
||||
// this is over channel-capacity
|
||||
val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2/3 * 1000, "22" * 32, 400144)
|
||||
val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2 / 3 * 1000, "22" * 32, 400144)
|
||||
sender.send(alice, add2)
|
||||
//sender.expectMsgType[Failure]
|
||||
relayer.expectMsgType[ForwardLocalFail]
|
||||
|
|
|
@ -8,8 +8,7 @@ import fr.acinq.eclair.blockchain._
|
|||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKw
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.channel.{Data, State, _}
|
||||
import fr.acinq.eclair.payment._
|
||||
import fr.acinq.eclair.payment.{ForwardAdd, ForwardLocalFail, Local, PaymentLifecycle}
|
||||
import fr.acinq.eclair.payment.{ForwardAdd, ForwardLocalFail, Local, PaymentLifecycle, _}
|
||||
import fr.acinq.eclair.wire.{CommitSig, Error, FailureMessageCodecs, PermanentChannelFailure, RevokeAndAck, Shutdown, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFee, UpdateFulfillHtlc}
|
||||
import fr.acinq.eclair.{Globals, TestConstants, TestkitBaseClass}
|
||||
import org.junit.runner.RunWith
|
||||
|
|
|
@ -2,12 +2,12 @@ package fr.acinq.eclair.channel.states.g
|
|||
|
||||
import akka.actor.Status.Failure
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.eclair.{Globals, TestkitBaseClass}
|
||||
import fr.acinq.eclair.blockchain._
|
||||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKw
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.channel.{Data, State, _}
|
||||
import fr.acinq.eclair.wire.{ClosingSigned, Error, Shutdown}
|
||||
import fr.acinq.eclair.{Globals, TestkitBaseClass}
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.Tag
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
|
|
@ -7,7 +7,6 @@ import fr.acinq.eclair.TestkitBaseClass
|
|||
import fr.acinq.eclair.blockchain._
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.channel.{Data, State, _}
|
||||
import fr.acinq.eclair.payment.HtlcGenerationSpec.paymentPreimage
|
||||
import fr.acinq.eclair.payment.{AckFulfillCmd, ForwardAdd, ForwardFulfill}
|
||||
import fr.acinq.eclair.transactions.Scripts
|
||||
import fr.acinq.eclair.wire._
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.spongycastle.util.encoders.Hex
|
|||
*/
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class BitStreamSpec extends FunSuite {
|
||||
|
||||
import BitStream._
|
||||
|
||||
test("add bits") {
|
||||
|
|
|
@ -2,10 +2,10 @@ package fr.acinq.eclair.crypto
|
|||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.crypto.Noise._
|
||||
import org.spongycastle.crypto.ec.CustomNamedCurves
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.spongycastle.crypto.ec.CustomNamedCurves
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class NoiseSpec extends FunSuite {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package fr.acinq.eclair.crypto
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto}
|
||||
import fr.acinq.eclair.wire._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
|
@ -102,23 +102,23 @@ class SphinxSpec extends FunSuite {
|
|||
// node #4 want to reply with an error message
|
||||
val error = createErrorPacket(sharedSecret4, TemporaryNodeFailure)
|
||||
assert(error == BinaryData("a5e6bd0c74cb347f10cce367f949098f2457d14c046fd8a22cb96efb30b0fdcda8cb9168b50f2fd45edd73c1b0c8b33002df376801ff58aaa94000bf8a86f92620f343baef38a580102395ae3abf9128d1047a0736ff9b83d456740ebbb4aeb3aa9737f18fb4afb4aa074fb26c4d702f42968888550a3bded8c05247e045b866baef0499f079fdaeef6538f31d44deafffdfd3afa2fb4ca9082b8f1c465371a9894dd8c243fb4847e004f5256b3e90e2edde4c9fb3082ddfe4d1e734cacd96ef0706bf63c9984e22dc98851bcccd1c3494351feb458c9c6af41c0044bea3c47552b1d992ae542b17a2d0bba1a096c78d169034ecb55b6e3a7263c26017f033031228833c1daefc0dedb8cf7c3e37c9c37ebfe42f3225c326e8bcfd338804c145b16e34e4"))
|
||||
// assert(error == BinaryData("69b1e5a3e05a7b5478e6529cd1749fdd8c66da6f6db42078ff8497ac4e117e91a8cb9168b58f2fd45edd73c1b0c8b33002df376801ff58aaa94000bf8a86f92620f343baef38a580102395ae3abf9128d1047a0736ff9b83d456740ebbb4aeb3aa9737f18fb4afb4aa074fb26c4d702f42968888550a3bded8c05247e045b866baef0499f079fdaeef6538f31d44deafffdfd3afa2fb4ca9082b8f1c465371a9894dd8c2"))
|
||||
// assert(error == BinaryData("69b1e5a3e05a7b5478e6529cd1749fdd8c66da6f6db42078ff8497ac4e117e91a8cb9168b58f2fd45edd73c1b0c8b33002df376801ff58aaa94000bf8a86f92620f343baef38a580102395ae3abf9128d1047a0736ff9b83d456740ebbb4aeb3aa9737f18fb4afb4aa074fb26c4d702f42968888550a3bded8c05247e045b866baef0499f079fdaeef6538f31d44deafffdfd3afa2fb4ca9082b8f1c465371a9894dd8c2"))
|
||||
// error sent back to 3, 2, 1 and 0
|
||||
val error1 = forwardErrorPacket(error, sharedSecret3)
|
||||
assert(error1 == BinaryData("c49a1ce81680f78f5f2000cda36268de34a3f0a0662f55b4e837c83a8773c22aa081bab1616a0011585323930fa5b9fae0c85770a2279ff59ec427ad1bbff9001c0cd1497004bd2a0f68b50704cf6d6a4bf3c8b6a0833399a24b3456961ba00736785112594f65b6b2d44d9f5ea4e49b5e1ec2af978cbe31c67114440ac51a62081df0ed46d4a3df295da0b0fe25c0115019f03f15ec86fabb4c852f83449e812f141a9395b3f70b766ebbd4ec2fae2b6955bd8f32684c15abfe8fd3a6261e52650e8807a92158d9f1463261a925e4bfba44bd20b166d532f0017185c3a6ac7957adefe45559e3072c8dc35abeba835a8cb01a71a15c736911126f27d46a36168ca5ef7dccd4e2886212602b181463e0dd30185c96348f9743a02aca8ec27c0b90dca270"))
|
||||
// assert(error1 == BinaryData("08cd44478211b8a4370ab1368b5ffe8c9c92fb830ff4ad6e3b0a316df9d24176a081bab161ea0011585323930fa5b9fae0c85770a2279ff59ec427ad1bbff9001c0cd1497004bd2a0f68b50704cf6d6a4bf3c8b6a0833399a24b3456961ba00736785112594f65b6b2d44d9f5ea4e49b5e1ec2af978cbe31c67114440ac51a62081df0ed46d4a3df295da0b0fe25c0115019f03f15ec86fabb4c852f83449e812f141a93"))
|
||||
// assert(error1 == BinaryData("08cd44478211b8a4370ab1368b5ffe8c9c92fb830ff4ad6e3b0a316df9d24176a081bab161ea0011585323930fa5b9fae0c85770a2279ff59ec427ad1bbff9001c0cd1497004bd2a0f68b50704cf6d6a4bf3c8b6a0833399a24b3456961ba00736785112594f65b6b2d44d9f5ea4e49b5e1ec2af978cbe31c67114440ac51a62081df0ed46d4a3df295da0b0fe25c0115019f03f15ec86fabb4c852f83449e812f141a93"))
|
||||
|
||||
val error2 = forwardErrorPacket(error1, sharedSecret2)
|
||||
assert(error2 == BinaryData("a5d3e8634cfe78b2307d87c6d90be6fe7855b4f2cc9b1dfb19e92e4b79103f61ff9ac25f412ddfb7466e74f81b3e545563cdd8f5524dae873de61d7bdfccd496af2584930d2b566b4f8d3881f8c043df92224f38cf094cfc09d92655989531524593ec6d6caec1863bdfaa79229b5020acc034cd6deeea1021c50586947b9b8e6faa83b81fbfa6133c0af5d6b07c017f7158fa94f0d206baf12dda6b68f785b773b360fd0497e16cc402d779c8d48d0fa6315536ef0660f3f4e1865f5b38ea49c7da4fd959de4e83ff3ab686f059a45c65ba2af4a6a79166aa0f496bf04d06987b6d2ea205bdb0d347718b9aeff5b61dfff344993a275b79717cd815b6ad4c0beb568c4ac9c36ff1c315ec1119a1993c4b61e6eaa0375e0aaf738ac691abd3263bf937e3"))
|
||||
// assert(error2 == BinaryData("6984b0ccd86f37995857363df13670acd064bfd1a540e521cad4d71c07b1bc3dff9ac25f41addfb7466e74f81b3e545563cdd8f5524dae873de61d7bdfccd496af2584930d2b566b4f8d3881f8c043df92224f38cf094cfc09d92655989531524593ec6d6caec1863bdfaa79229b5020acc034cd6deeea1021c50586947b9b8e6faa83b81fbfa6133c0af5d6b07c017f7158fa94f0d206baf12dda6b68f785b773b360fd"))
|
||||
// assert(error2 == BinaryData("6984b0ccd86f37995857363df13670acd064bfd1a540e521cad4d71c07b1bc3dff9ac25f41addfb7466e74f81b3e545563cdd8f5524dae873de61d7bdfccd496af2584930d2b566b4f8d3881f8c043df92224f38cf094cfc09d92655989531524593ec6d6caec1863bdfaa79229b5020acc034cd6deeea1021c50586947b9b8e6faa83b81fbfa6133c0af5d6b07c017f7158fa94f0d206baf12dda6b68f785b773b360fd"))
|
||||
|
||||
val error3 = forwardErrorPacket(error2, sharedSecret1)
|
||||
assert(error3 == BinaryData("aac3200c4968f56b21f53e5e374e3a2383ad2b1b6501bbcc45abc31e59b26881b7dfadbb56ec8dae8857add94e6702fb4c3a4de22e2e669e1ed926b04447fc73034bb730f4932acd62727b75348a648a1128744657ca6a4e713b9b646c3ca66cac02cdab44dd3439890ef3aaf61708714f7375349b8da541b2548d452d84de7084bb95b3ac2345201d624d31f4d52078aa0fa05a88b4e20202bd2b86ac5b52919ea305a8949de95e935eed0319cf3cf19ebea61d76ba92532497fcdc9411d06bcd4275094d0a4a3c5d3a945e43305a5a9256e333e1f64dbca5fcd4e03a39b9012d197506e06f29339dfee3331995b21615337ae060233d39befea925cc262873e0530408e6990f1cbd233a150ef7b004ff6166c70c68d9f8c853c1abca640b8660db2921"))
|
||||
// assert(error3 == BinaryData("669478a3ddf9ba4049df8fa51f73ac712b9c20380cda431696963a492713ebddb7dfadbb566c8dae8857add94e6702fb4c3a4de22e2e669e1ed926b04447fc73034bb730f4932acd62727b75348a648a1128744657ca6a4e713b9b646c3ca66cac02cdab44dd3439890ef3aaf61708714f7375349b8da541b2548d452d84de7084bb95b3ac2345201d624d31f4d52078aa0fa05a88b4e20202bd2b86ac5b52919ea305a8"))
|
||||
// assert(error3 == BinaryData("669478a3ddf9ba4049df8fa51f73ac712b9c20380cda431696963a492713ebddb7dfadbb566c8dae8857add94e6702fb4c3a4de22e2e669e1ed926b04447fc73034bb730f4932acd62727b75348a648a1128744657ca6a4e713b9b646c3ca66cac02cdab44dd3439890ef3aaf61708714f7375349b8da541b2548d452d84de7084bb95b3ac2345201d624d31f4d52078aa0fa05a88b4e20202bd2b86ac5b52919ea305a8"))
|
||||
|
||||
val error4 = forwardErrorPacket(error3, sharedSecret0)
|
||||
assert(error4 == BinaryData("9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d"))
|
||||
// assert(error4 == BinaryData("500d8596f76d3045bfdbf99914b98519fe76ea130dc22338c473ab68d74378b13a06a19f891145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366"))
|
||||
// assert(error4 == BinaryData("500d8596f76d3045bfdbf99914b98519fe76ea130dc22338c473ab68d74378b13a06a19f891145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366"))
|
||||
|
||||
|
||||
// origin parses error packet and can see that it comes from node #4
|
||||
|
|
|
@ -6,10 +6,10 @@ import fr.acinq.eclair.channel.Helpers.Funding
|
|||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.{ShaChain, Sphinx}
|
||||
import fr.acinq.eclair.payment.{Local, Relayed}
|
||||
import fr.acinq.eclair.{UInt64, randomKey}
|
||||
import fr.acinq.eclair.transactions.Transactions.CommitTx
|
||||
import fr.acinq.eclair.transactions._
|
||||
import fr.acinq.eclair.wire.{ChannelCodecs, CommitSig, UpdateAddHtlc}
|
||||
import fr.acinq.eclair.wire.{ChannelCodecs, UpdateAddHtlc}
|
||||
import fr.acinq.eclair.{UInt64, randomKey}
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
|
|
@ -7,7 +7,6 @@ import fr.acinq.bitcoin.{Block, Crypto}
|
|||
import fr.acinq.eclair.db.sqlite.SqliteNetworkDb
|
||||
import fr.acinq.eclair.randomKey
|
||||
import fr.acinq.eclair.router.Announcements
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs.channelAnnouncementCodec
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
|
|
@ -364,6 +364,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
|||
|
||||
/**
|
||||
* We currently use p2pkh script Helpers.getFinalScriptPubKey
|
||||
*
|
||||
* @param scriptPubKey
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package fr.acinq.eclair.interop.rustytests
|
||||
|
||||
import java.io.{BufferedWriter, File, FileWriter}
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, Stash}
|
||||
import fr.acinq.bitcoin.{BinaryData, Crypto}
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.transactions.{IN, OUT}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package fr.acinq.eclair.payment
|
|||
import fr.acinq.bitcoin.{BinaryData, Block, Crypto}
|
||||
import fr.acinq.eclair.crypto.Sphinx
|
||||
import fr.acinq.eclair.crypto.Sphinx.{PacketAndSecrets, ParsedPacket}
|
||||
import fr.acinq.eclair.payment.PaymentHop.nodeFee
|
||||
import fr.acinq.eclair.payment.PaymentLifecycle._
|
||||
import fr.acinq.eclair.randomKey
|
||||
import fr.acinq.eclair.payment.PaymentHop.nodeFee
|
||||
import fr.acinq.eclair.wire.{ChannelUpdate, LightningMessageCodecs, PerHopPayload}
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package fr.acinq.eclair.payment
|
||||
|
||||
import akka.actor.FSM.{CurrentState, SubscribeTransitionCallBack, Transition}
|
||||
import akka.actor.Status.Failure
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.MilliSatoshi
|
||||
import fr.acinq.eclair.Globals
|
||||
|
@ -12,7 +11,6 @@ import fr.acinq.eclair.router._
|
|||
import fr.acinq.eclair.wire._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.scalatest.matchers.FailureMessage
|
||||
|
||||
/**
|
||||
* Created by PM on 29/08/2016.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package fr.acinq.eclair.router
|
||||
|
||||
import fr.acinq.bitcoin.{BinaryData, Block}
|
||||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.{BinaryData, Block}
|
||||
import fr.acinq.eclair.TestConstants.Alice
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.router.Announcements._
|
||||
|
|
|
@ -92,9 +92,9 @@ abstract class BaseRouterSpec extends TestkitBaseClass {
|
|||
// and answers with valid scripts
|
||||
watcher.send(router, ParallelGetResponse(
|
||||
IndividualResult(chan_ab, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_a, funding_b)))) :: Nil, lockTime = 0)), true) ::
|
||||
IndividualResult(chan_bc, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_c)))) :: Nil, lockTime = 0)), true) ::
|
||||
IndividualResult(chan_cd, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_c, funding_d)))) :: Nil, lockTime = 0)), true) ::
|
||||
IndividualResult(chan_ef, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_e, funding_f)))) :: Nil, lockTime = 0)), true) :: Nil
|
||||
IndividualResult(chan_bc, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_b, funding_c)))) :: Nil, lockTime = 0)), true) ::
|
||||
IndividualResult(chan_cd, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_c, funding_d)))) :: Nil, lockTime = 0)), true) ::
|
||||
IndividualResult(chan_ef, Some(Transaction(version = 0, txIn = Nil, txOut = TxOut(Satoshi(1000000), write(pay2wsh(Scripts.multiSig2of2(funding_e, funding_f)))) :: Nil, lockTime = 0)), true) :: Nil
|
||||
))
|
||||
// watcher receives watch-spent request
|
||||
watcher.expectMsgType[WatchSpentBasic]
|
||||
|
|
|
@ -3,9 +3,9 @@ package fr.acinq.eclair.router
|
|||
import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
|
||||
import fr.acinq.bitcoin.{BinaryData, Block, Crypto, MilliSatoshi}
|
||||
import fr.acinq.eclair.payment.PaymentRequest.ExtraHop
|
||||
import fr.acinq.eclair.{Globals, randomKey, toShortId}
|
||||
import fr.acinq.eclair.wire.{ChannelAnnouncement, ChannelUpdate, PerHopPayload}
|
||||
import fr.acinq.eclair.payment._
|
||||
import fr.acinq.eclair.wire.{ChannelAnnouncement, ChannelUpdate, PerHopPayload}
|
||||
import fr.acinq.eclair.{Globals, randomKey, toShortId}
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
@ -49,7 +49,7 @@ class RouteCalculationSpec extends FunSuite {
|
|||
ChannelDesc(5L, d, e)
|
||||
)
|
||||
|
||||
val routes = for(i <- 0 until 10) yield Router.findRouteDijkstra(a, e, channels)
|
||||
val routes = for (i <- 0 until 10) yield Router.findRouteDijkstra(a, e, channels)
|
||||
assert(routes.exists(_ != routes.head))
|
||||
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ class RouteCalculationSpec extends FunSuite {
|
|||
val extraRoute = PaymentHop.buildExtra(reverseRoute, amount.amount)
|
||||
|
||||
assert(extraRoute === List(ExtraHop(PublicKey("02f0b230e53723ccc331db140edc518be1ee5ab29a508104a4be2f5be922c928e8"), 24412456671576064L, 547005, 144),
|
||||
ExtraHop(PublicKey("032b4af42b5e8089a7a06005ead9ac4667527390ee39c998b7b0307f0d81d7f4ac") ,23366821113626624L, 547000, 144)))
|
||||
ExtraHop(PublicKey("032b4af42b5e8089a7a06005ead9ac4667527390ee39c998b7b0307f0d81d7f4ac"), 23366821113626624L, 547000, 144)))
|
||||
|
||||
// Sender side
|
||||
|
||||
|
@ -223,11 +223,16 @@ class RouteCalculationSpec extends FunSuite {
|
|||
test("stale channels pruning") {
|
||||
// set current block height
|
||||
Globals.blockCount.set(500000)
|
||||
|
||||
// we only care about timestamps
|
||||
def channelAnnouncement(shortChannelId: Long) = ChannelAnnouncement("", "", "", "", "", "", shortChannelId, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey, randomKey.publicKey)
|
||||
|
||||
def channelUpdate(shortChannelId: Long, timestamp: Long) = ChannelUpdate("", "", shortChannelId, timestamp, "", 0, 0, 0, 0)
|
||||
|
||||
def desc(shortChannelId: Long) = ChannelDesc(shortChannelId, randomKey.publicKey, randomKey.publicKey)
|
||||
|
||||
def daysAgoInBlocks(daysAgo: Int): Int = Globals.blockCount.get().toInt - 144 * daysAgo
|
||||
|
||||
def daysAgoInSeconds(daysAgo: Int): Long = Platform.currentTime / 1000 - daysAgo * 24 * 3600
|
||||
|
||||
// a is an old channel with an old channel update => PRUNED
|
||||
|
|
|
@ -13,7 +13,6 @@ import fr.acinq.eclair.{randomKey, toShortId}
|
|||
import org.junit.runner.RunWith
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package fr.acinq.eclair.transactions
|
||||
|
||||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.bitcoin.Crypto.{Point, PrivateKey, PublicKey, Scalar}
|
||||
import fr.acinq.bitcoin._
|
||||
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 org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ import java.net.{InetAddress, InetSocketAddress}
|
|||
import fr.acinq.bitcoin.Crypto.{PrivateKey, Scalar}
|
||||
import fr.acinq.bitcoin.{BinaryData, Block, Crypto}
|
||||
import fr.acinq.eclair.crypto.Sphinx
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs._
|
||||
import fr.acinq.eclair.{UInt64, randomBytes, randomKey}
|
||||
import fr.acinq.eclair.wire.LightningMessageCodecs.{lightningMessageCodec, rgb, socketaddress, uint64ex, zeropaddedstring}
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
<GridPane styleClass="grid" prefWidth="400.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="140.0" prefWidth="150.0" maxWidth="180.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="30.0" prefWidth="30.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="30.0" prefWidth="30.0"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="40.0" prefWidth="60.0" maxWidth="60.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="30.0" prefWidth="40.0" />
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="30.0" prefWidth="40.0"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
|
||||
|
@ -24,8 +24,9 @@
|
|||
<HBox GridPane.columnSpan="4" GridPane.columnIndex="0" alignment="CENTER" spacing="10.0">
|
||||
<children>
|
||||
<TextField fx:id="channelId" text="N/A" editable="false" styleClass="noteditable, text-strong"
|
||||
HBox.hgrow="ALWAYS" focusTraversable="false" />
|
||||
<HBox GridPane.columnIndex="4" GridPane.halignment="RIGHT" alignment="CENTER_RIGHT" HBox.hgrow="NEVER" spacing="5.0">
|
||||
HBox.hgrow="ALWAYS" focusTraversable="false"/>
|
||||
<HBox GridPane.columnIndex="4" GridPane.halignment="RIGHT" alignment="CENTER_RIGHT"
|
||||
HBox.hgrow="NEVER" spacing="5.0">
|
||||
<children>
|
||||
<Button fx:id="close" mnemonicParsing="false" styleClass="close-channel" text="Close"/>
|
||||
</children>
|
||||
|
@ -42,11 +43,13 @@
|
|||
GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="2"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Your balance (milliBTC)" GridPane.rowIndex="3"/>
|
||||
<TextField fx:id="amountUs" text="N/A" focusTraversable="false" editable="false" styleClass="noteditable"
|
||||
<TextField fx:id="amountUs" text="N/A" focusTraversable="false" editable="false"
|
||||
styleClass="noteditable"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="3"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Capacity (milliBTC)" GridPane.rowIndex="4"/>
|
||||
<TextField fx:id="capacity" text="N/A" focusTraversable="false" editable="false" styleClass="noteditable"
|
||||
<TextField fx:id="capacity" text="N/A" focusTraversable="false" editable="false"
|
||||
styleClass="noteditable"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Funder" GridPane.columnIndex="2" GridPane.rowIndex="3"/>
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.scene.shape.Rectangle?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<AnchorPane fx:id="root" minHeight="300.0" prefHeight="400.0" styleClass="root" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import java.net.URL?>
|
||||
<AnchorPane fx:id="root" minHeight="300.0" prefHeight="400.0" styleClass="root" xmlns="http://javafx.com/javafx/8"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<BorderPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0">
|
||||
<BorderPane AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0"
|
||||
AnchorPane.bottomAnchor="0">
|
||||
<center>
|
||||
<TabPane tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
|
||||
<tabs>
|
||||
|
@ -40,12 +41,17 @@
|
|||
<VBox spacing="10.0" styleClass="grid">
|
||||
<children>
|
||||
<TableView fx:id="networkNodesTable" minHeight="50.0" prefHeight="5000.0">
|
||||
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/></columnResizePolicy>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
<columns>
|
||||
<TableColumn fx:id="networkNodesRGBColumn" minWidth="20.0" prefWidth="20.0" maxWidth="20.0" text="" sortable="false"/>
|
||||
<TableColumn fx:id="networkNodesAliasColumn" minWidth="80.0" prefWidth="180.0" maxWidth="300.0" text="Alias"/>
|
||||
<TableColumn fx:id="networkNodesRGBColumn" minWidth="20.0"
|
||||
prefWidth="20.0" maxWidth="20.0" text="" sortable="false"/>
|
||||
<TableColumn fx:id="networkNodesAliasColumn" minWidth="80.0"
|
||||
prefWidth="180.0" maxWidth="300.0" text="Alias"/>
|
||||
<TableColumn fx:id="networkNodesIdColumn" text="Node Id"/>
|
||||
<TableColumn fx:id="networkNodesIPColumn" minWidth="150.0" prefWidth="250.0" maxWidth="300.0" text="IP"/>
|
||||
<TableColumn fx:id="networkNodesIPColumn" minWidth="150.0"
|
||||
prefWidth="250.0" maxWidth="300.0" text="IP"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
|
@ -57,11 +63,16 @@
|
|||
<VBox spacing="10.0" styleClass="grid">
|
||||
<children>
|
||||
<TableView fx:id="networkChannelsTable" minHeight="50.0" prefHeight="5000.0">
|
||||
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/></columnResizePolicy>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
<columns>
|
||||
<TableColumn fx:id="networkChannelsIdColumn" minWidth="120.0" prefWidth="170.0" maxWidth="300.0" text="Short Channel Id"/>
|
||||
<TableColumn fx:id="networkChannelsIdColumn" minWidth="120.0"
|
||||
prefWidth="170.0" maxWidth="300.0"
|
||||
text="Short Channel Id"/>
|
||||
<TableColumn fx:id="networkChannelsNode1Column" text="Node 1"/>
|
||||
<TableColumn fx:id="networkChannelsDirectionsColumn" minWidth="30.0" prefWidth="30.0" maxWidth="30.0"/>
|
||||
<TableColumn fx:id="networkChannelsDirectionsColumn" minWidth="30.0"
|
||||
prefWidth="30.0" maxWidth="30.0"/>
|
||||
<TableColumn fx:id="networkChannelsNode2Column" text="Node 2"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
@ -73,51 +84,89 @@
|
|||
<content>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<TabPane AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0"
|
||||
styleClass="activities-tab" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
|
||||
<TabPane AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
|
||||
AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0"
|
||||
styleClass="activities-tab" tabClosingPolicy="UNAVAILABLE"
|
||||
BorderPane.alignment="CENTER">
|
||||
<tabs>
|
||||
<Tab fx:id="paymentSentTab" closable="false" text="Sent">
|
||||
<TableView fx:id="paymentSentTable" minHeight="50.0" prefHeight="5000.0">
|
||||
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/></columnResizePolicy>
|
||||
<TableView fx:id="paymentSentTable" minHeight="50.0"
|
||||
prefHeight="5000.0">
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
<columns>
|
||||
<TableColumn fx:id="paymentSentDateColumn" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0" text="Date"/>
|
||||
<TableColumn fx:id="paymentSentAmountColumn" text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentSentFeesColumn" text="Fees Paid (msat)"
|
||||
styleClass="align-right" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentSentHashColumn" text="Payment Hash"/>
|
||||
<TableColumn fx:id="paymentSentDateColumn" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0" text="Date"/>
|
||||
<TableColumn fx:id="paymentSentAmountColumn"
|
||||
text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentSentFeesColumn"
|
||||
text="Fees Paid (msat)"
|
||||
styleClass="align-right" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentSentHashColumn"
|
||||
text="Payment Hash"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</Tab>
|
||||
<Tab fx:id="paymentReceivedTab" closable="false" text="Received">
|
||||
<TableView fx:id="paymentReceivedTable" minHeight="50.0" prefHeight="5000.0">
|
||||
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/></columnResizePolicy>
|
||||
<TableView fx:id="paymentReceivedTable" minHeight="50.0"
|
||||
prefHeight="5000.0">
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
<columns>
|
||||
<TableColumn fx:id="paymentReceivedDateColumn" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0" text="Date"/>
|
||||
<TableColumn fx:id="paymentReceivedAmountColumn" text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentReceivedHashColumn" text="Payment Hash"/>
|
||||
<TableColumn fx:id="paymentReceivedDateColumn"
|
||||
resizable="false" minWidth="150.0"
|
||||
prefWidth="150.0" maxWidth="150.0"
|
||||
text="Date"/>
|
||||
<TableColumn fx:id="paymentReceivedAmountColumn"
|
||||
text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentReceivedHashColumn"
|
||||
text="Payment Hash"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</Tab>
|
||||
<Tab fx:id="paymentRelayedTab" closable="false" text="Relayed">
|
||||
<TableView fx:id="paymentRelayedTable" minHeight="50.0" prefHeight="5000.0">
|
||||
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/></columnResizePolicy>
|
||||
<TableView fx:id="paymentRelayedTable" minHeight="50.0"
|
||||
prefHeight="5000.0">
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
<columns>
|
||||
<TableColumn fx:id="paymentRelayedDateColumn" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0" text="Date"/>
|
||||
<TableColumn fx:id="paymentRelayedAmountColumn" text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentRelayedFeesColumn" text="Fees Earned (msat)"
|
||||
styleClass="align-right" resizable="false" minWidth="150.0" prefWidth="150.0" maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentRelayedHashColumn" text="Payment Hash"/>
|
||||
<TableColumn fx:id="paymentRelayedDateColumn"
|
||||
resizable="false" minWidth="150.0"
|
||||
prefWidth="150.0" maxWidth="150.0"
|
||||
text="Date"/>
|
||||
<TableColumn fx:id="paymentRelayedAmountColumn"
|
||||
text="Amount (msat)"
|
||||
styleClass="align-right" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentRelayedFeesColumn"
|
||||
text="Fees Earned (msat)"
|
||||
styleClass="align-right" resizable="false"
|
||||
minWidth="150.0" prefWidth="150.0"
|
||||
maxWidth="150.0"/>
|
||||
<TableColumn fx:id="paymentRelayedHashColumn"
|
||||
text="Payment Hash"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
<Label AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" textAlignment="RIGHT"
|
||||
<Label AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
|
||||
textAlignment="RIGHT"
|
||||
maxWidth="180.0" wrapText="true" styleClass="activity-disclaimer"
|
||||
text="Payment history will be cleared when the node is shut down." />
|
||||
text="Payment history will be cleared when the node is shut down."/>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
|
@ -130,8 +179,11 @@
|
|||
<children>
|
||||
<HBox alignment="CENTER_LEFT" HBox.hgrow="ALWAYS" onContextMenuRequested="#openNodeIdContext">
|
||||
<children>
|
||||
<ImageView fitHeight="16.0" fitWidth="27.0" opacity="0.52" pickOnBounds="true" preserveRatio="true">
|
||||
<image><Image url="@../commons/images/eclair-shape.png"/></image>
|
||||
<ImageView fitHeight="16.0" fitWidth="27.0" opacity="0.52" pickOnBounds="true"
|
||||
preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../commons/images/eclair-shape.png"/>
|
||||
</image>
|
||||
</ImageView>
|
||||
<Label fx:id="labelNodeId" text="N/A"/>
|
||||
</children>
|
||||
|
@ -139,7 +191,7 @@
|
|||
<HBox alignment="CENTER_LEFT" HBox.hgrow="SOMETIMES" minWidth="80.0">
|
||||
<children>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Rectangle fx:id="rectRGB" width="7" height="7" fill="transparent" />
|
||||
<Rectangle fx:id="rectRGB" width="7" height="7" fill="transparent"/>
|
||||
<Label fx:id="labelAlias" text="N/A"/>
|
||||
</children>
|
||||
</HBox>
|
||||
|
@ -190,7 +242,8 @@
|
|||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Tools">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#handleExportDot" text="Export Graph to .dot"/>
|
||||
<MenuItem mnemonicParsing="false" onAction="#handleExportDot"
|
||||
text="Export Graph to .dot"/>
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Help">
|
||||
|
@ -203,28 +256,35 @@
|
|||
</top>
|
||||
</BorderPane>
|
||||
<StackPane fx:id="blocker" styleClass="blocker-cover" opacity="0" visible="false" alignment="CENTER"
|
||||
AnchorPane.topAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0" AnchorPane.rightAnchor="0">
|
||||
AnchorPane.topAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0"
|
||||
AnchorPane.rightAnchor="0">
|
||||
<children>
|
||||
<HBox fx:id="blockerDialog" opacity="0" styleClass="blocker-dialog" fillHeight="false" alignment="CENTER_LEFT" spacing="20"
|
||||
minWidth="430.0" minHeight="100.0" prefWidth="430.0" prefHeight="100.0" maxWidth="430.0" maxHeight="100.0">
|
||||
<HBox fx:id="blockerDialog" opacity="0" styleClass="blocker-dialog" fillHeight="false"
|
||||
alignment="CENTER_LEFT" spacing="20"
|
||||
minWidth="430.0" minHeight="100.0" prefWidth="430.0" prefHeight="100.0" maxWidth="430.0"
|
||||
maxHeight="100.0">
|
||||
<children>
|
||||
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../commons/images/connection_icon.png" />
|
||||
<Image url="@../commons/images/connection_icon.png"/>
|
||||
</image>
|
||||
</ImageView>
|
||||
<VBox spacing="10.0" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<TextFlow>
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong" text="Lost connection to " />
|
||||
<Text fx:id="blockerDialogTitleEngineName" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong" />
|
||||
<Text strokeType="OUTSIDE" styleClass="text-strong" strokeWidth="0.0" text="..." />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong"
|
||||
text="Lost connection to "/>
|
||||
<Text fx:id="blockerDialogTitleEngineName" strokeType="OUTSIDE"
|
||||
strokeWidth="0.0" styleClass="text-strong"/>
|
||||
<Text strokeType="OUTSIDE" styleClass="text-strong" strokeWidth="0.0"
|
||||
text="..."/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
<TextFlow>
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-sm" text="Please check your connection." />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-sm"
|
||||
text="Please check your connection."/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
</children>
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<GridPane fx:id="rootPane" minWidth="300.0" prefWidth="300.0" maxWidth="300.0"
|
||||
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
|
||||
opacity="0" onMouseEntered="#handleMouseEnter" onMouseExited="#handleMouseExit">
|
||||
|
@ -29,9 +26,11 @@
|
|||
<Image url="@../commons/images/eclair-square.png"/>
|
||||
</image>
|
||||
</ImageView>
|
||||
<Button fx:id="closeButton" maxHeight="18.0" maxWidth="18.0" minHeight="18.0" minWidth="18.0" mnemonicParsing="false"
|
||||
styleClass="notification-close" text="" GridPane.columnIndex="2" />
|
||||
<Label fx:id="messageLabel" styleClass="notification-message" text="N/A" wrapText="false" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1"/>
|
||||
<Button fx:id="closeButton" maxHeight="18.0" maxWidth="18.0" minHeight="18.0" minWidth="18.0"
|
||||
mnemonicParsing="false"
|
||||
styleClass="notification-close" text="" GridPane.columnIndex="2"/>
|
||||
<Label fx:id="messageLabel" styleClass="notification-message" text="N/A" wrapText="false"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1"/>
|
||||
</children>
|
||||
<styleClass>
|
||||
<String fx:value="grid"/>
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<?import java.net.URL?>
|
||||
<VBox fx:id="notifsVBox" spacing="10.0"
|
||||
style="-fx-background-color: transparent" styleClass="notifications-box"
|
||||
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<stylesheets>
|
||||
<URL value="@../commons/globals.css" />
|
||||
<URL value="@main.css" />
|
||||
</stylesheets>
|
||||
<stylesheets>
|
||||
<URL value="@../commons/globals.css"/>
|
||||
<URL value="@main.css"/>
|
||||
</stylesheets>
|
||||
</VBox>
|
||||
|
|
|
@ -1,64 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<GridPane prefWidth="500.0" prefHeight="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" minWidth="10.0" maxWidth="120.0" />
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" minWidth="10.0" prefWidth="180.0" />
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" minWidth="10.0" maxWidth="120.0"/>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" minWidth="10.0" prefWidth="180.0"/>
|
||||
</columnConstraints>
|
||||
<children>
|
||||
<ImageView fitHeight="120.0" fitWidth="120.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER">
|
||||
<ImageView fitHeight="120.0" fitWidth="120.0" pickOnBounds="true" preserveRatio="true"
|
||||
GridPane.halignment="CENTER">
|
||||
<image>
|
||||
<Image url="@../commons/images/eclair-square.png" />
|
||||
<Image url="@../commons/images/eclair-square.png"/>
|
||||
</image>
|
||||
</ImageView>
|
||||
<VBox spacing="10.0" styleClass="about-content" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<TextFlow>
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong" text="Eclair v" />
|
||||
<Text fx:id="version" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong" text="Unknown" />
|
||||
<Text strokeType="OUTSIDE" styleClass="text-sm" strokeWidth="0.0" text=" brought to you by " />
|
||||
<Text onMouseClicked="#openACINQPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link" text="ACINQ" />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong" text="Eclair v"/>
|
||||
<Text fx:id="version" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="text-strong"
|
||||
text="Unknown"/>
|
||||
<Text strokeType="OUTSIDE" styleClass="text-sm" strokeWidth="0.0" text=" brought to you by "/>
|
||||
<Text onMouseClicked="#openACINQPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link"
|
||||
text="ACINQ"/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
<TextFlow layoutX="10.0" layoutY="90.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Eclair follows " />
|
||||
<Text onMouseClicked="#openLNRFCPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link" text="the Lightning Network specifications" />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="." />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Eclair follows "/>
|
||||
<Text onMouseClicked="#openLNRFCPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link"
|
||||
text="the Lightning Network specifications"/>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="."/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
<TextFlow layoutX="10.0" layoutY="10.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="The source code is available from " />
|
||||
<Text onMouseClicked="#openGithubPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link" text="GitHub" />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="." />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="The source code is available from "/>
|
||||
<Text onMouseClicked="#openGithubPage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link"
|
||||
text="GitHub"/>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="."/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
<TextFlow layoutX="10.0" layoutY="90.0" styleClass="">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Licensed under " />
|
||||
<Text onMouseClicked="#openApacheLicencePage" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="link" text="the Apache 2 License" />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="." />
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Licensed under "/>
|
||||
<Text onMouseClicked="#openApacheLicencePage" strokeType="OUTSIDE" strokeWidth="0.0"
|
||||
styleClass="link" text="the Apache 2 License"/>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="."/>
|
||||
</children>
|
||||
</TextFlow>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<styleClass>
|
||||
<String fx:value="grid" />
|
||||
<String fx:value="grid"/>
|
||||
</styleClass>
|
||||
<stylesheets>
|
||||
<URL value="@../commons/globals.css" />
|
||||
<URL value="@../commons/globals.css"/>
|
||||
</stylesheets>
|
||||
</GridPane>
|
||||
|
|
|
@ -1,89 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
|
||||
<GridPane styleClass="grid" prefWidth="550.0" prefHeight="350.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<GridPane styleClass="grid" prefWidth="550.0" prefHeight="350.0" xmlns="http://javafx.com/javafx/8"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="10.0" prefWidth="180.0" halignment="RIGHT" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="180.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="160.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="10.0" prefWidth="180.0" halignment="RIGHT"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="180.0"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="160.0"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="SOMETIMES" maxHeight="10.0"/>
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="SOMETIMES" minHeight="30.0" valignment="BOTTOM"/>
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
<RowConstraints vgrow="SOMETIMES"/>
|
||||
</rowConstraints>
|
||||
<children>
|
||||
|
||||
<VBox alignment="CENTER_RIGHT" GridPane.rowIndex="0">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Target Node URI" />
|
||||
<Label styleClass="label-description" text="Address of the node" textAlignment="RIGHT" wrapText="true" />
|
||||
<Label styleClass="text-strong" text="Target Node URI"/>
|
||||
<Label styleClass="label-description" text="Address of the node" textAlignment="RIGHT" wrapText="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
<TextField fx:id="host" prefWidth="313.0" promptText="pubkey@host:port"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="0" />
|
||||
<Label fx:id="hostError" opacity="0.0" styleClass="text-error, text-error-downward" text="Generic Invalid URI" mouseTransparent="true"
|
||||
GridPane.rowIndex="0" GridPane.columnIndex="1" GridPane.columnSpan="2" />
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="0"/>
|
||||
<Label fx:id="hostError" opacity="0.0" styleClass="text-error, text-error-downward" text="Generic Invalid URI"
|
||||
mouseTransparent="true"
|
||||
GridPane.rowIndex="0" GridPane.columnIndex="1" GridPane.columnSpan="2"/>
|
||||
|
||||
<CheckBox fx:id="simpleConnection" mnemonicParsing="false" text="Simple connection (no channel)" styleClass="text-sm"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1" />
|
||||
<CheckBox fx:id="simpleConnection" mnemonicParsing="false" text="Simple connection (no channel)"
|
||||
styleClass="text-sm"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1"/>
|
||||
|
||||
<VBox alignment="CENTER_RIGHT" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Capacity" />
|
||||
<Label styleClass="label-description" text="Funding capacity of the channel" textAlignment="RIGHT" wrapText="true" />
|
||||
<Label styleClass="text-strong" text="Capacity"/>
|
||||
<Label styleClass="label-description" text="Funding capacity of the channel" textAlignment="RIGHT"
|
||||
wrapText="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
<TextField fx:id="fundingSatoshis" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||
<TextField fx:id="fundingSatoshis" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
|
||||
<ComboBox fx:id="unit" prefWidth="150.0" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<String fx:id="milliBTC" fx:value="milliBTC" />
|
||||
<String fx:id="Satoshi" fx:value="Satoshi" />
|
||||
<String fx:id="milliSatoshi" fx:value="milliSatoshi" />
|
||||
<String fx:id="milliBTC" fx:value="milliBTC"/>
|
||||
<String fx:id="Satoshi" fx:value="Satoshi"/>
|
||||
<String fx:id="milliSatoshi" fx:value="milliSatoshi"/>
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ComboBox>
|
||||
<Label fx:id="fundingSatoshisError" opacity="0.0" styleClass="text-error, text-error-downward" text="Generic Invalid Funding"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="2" />
|
||||
<Label fx:id="fundingSatoshisError" opacity="0.0" styleClass="text-error, text-error-downward"
|
||||
text="Generic Invalid Funding"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="2"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Optional Parameters" wrapText="true" GridPane.columnIndex="0" GridPane.rowIndex="3" />
|
||||
<Separator styleClass="options-separator" GridPane.columnIndex="1" GridPane.rowIndex="3" GridPane.columnSpan="2"/>
|
||||
<Label styleClass="text-muted" text="Optional Parameters" wrapText="true" GridPane.columnIndex="0"
|
||||
GridPane.rowIndex="3"/>
|
||||
<Separator styleClass="options-separator" GridPane.columnIndex="1" GridPane.rowIndex="3"
|
||||
GridPane.columnSpan="2"/>
|
||||
|
||||
<VBox alignment="CENTER_RIGHT" GridPane.rowIndex="4">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Push Amount (msat)" />
|
||||
<Label styleClass="label-description" text="Sent when opening channel" textAlignment="RIGHT" wrapText="true" />
|
||||
<Label styleClass="text-strong" text="Push Amount (msat)"/>
|
||||
<Label styleClass="label-description" text="Sent when opening channel" textAlignment="RIGHT"
|
||||
wrapText="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
<TextField fx:id="pushMsat" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Label fx:id="pushMsatError" opacity="0.0" styleClass="text-error, text-error-downward" text="Generic Invalid Push"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<CheckBox fx:id="publicChannel" mnemonicParsing="true" selected="true" styleClass="text-sm" text="Public Channel"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="5" />
|
||||
<TextField fx:id="pushMsat" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
<Label fx:id="pushMsatError" opacity="0.0" styleClass="text-error, text-error-downward"
|
||||
text="Generic Invalid Push"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
<CheckBox fx:id="publicChannel" mnemonicParsing="true" selected="true" styleClass="text-sm"
|
||||
text="Public Channel"
|
||||
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="5"/>
|
||||
|
||||
<Button fx:id="button" defaultButton="true" mnemonicParsing="false" onAction="#handleOpen" text="Connect"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="6" GridPane.valignment="BOTTOM" />
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="6" GridPane.valignment="BOTTOM"/>
|
||||
<Button cancelButton="true" mnemonicParsing="false" onAction="#handleClose" styleClass="cancel" text="Cancel"
|
||||
GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="6" GridPane.valignment="BOTTOM" />
|
||||
GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="6"
|
||||
GridPane.valignment="BOTTOM"/>
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@../commons/globals.css" />
|
||||
<URL value="@../commons/globals.css"/>
|
||||
</stylesheets>
|
||||
</GridPane>
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
<children>
|
||||
<GridPane styleClass="grid">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="250.0" minWidth="10.0" prefWidth="250.0"/>
|
||||
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="250.0" minWidth="10.0"
|
||||
prefWidth="250.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="120.0"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="120.0"/>
|
||||
</columnConstraints>
|
||||
|
@ -22,35 +23,41 @@
|
|||
<children>
|
||||
<VBox alignment="TOP_RIGHT" GridPane.rowIndex="0">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Amount to receive" />
|
||||
<Label styleClass="label-description" wrapText="true" textAlignment="RIGHT" text="Maximum of ~0.042 BTC" />
|
||||
<Label styleClass="text-strong" text="Amount to receive"/>
|
||||
<Label styleClass="label-description" wrapText="true" textAlignment="RIGHT"
|
||||
text="Maximum of ~0.042 BTC"/>
|
||||
</children>
|
||||
</VBox>
|
||||
<TextField fx:id="amount" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
|
||||
<ComboBox fx:id="unit" GridPane.columnIndex="2" GridPane.rowIndex="0" GridPane.halignment="RIGHT">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<String fx:id="milliBTC" fx:value="milliBTC" />
|
||||
<String fx:id="Satoshi" fx:value="Satoshi" />
|
||||
<String fx:id="milliSatoshi" fx:value="milliSatoshi" />
|
||||
<String fx:id="milliBTC" fx:value="milliBTC"/>
|
||||
<String fx:id="Satoshi" fx:value="Satoshi"/>
|
||||
<String fx:id="milliSatoshi" fx:value="milliSatoshi"/>
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ComboBox>
|
||||
<Label fx:id="amountError" opacity="0.0" styleClass="text-error, text-error-downward" text="Generic Invalid Amount"
|
||||
<Label fx:id="amountError" opacity="0.0" styleClass="text-error, text-error-downward"
|
||||
text="Generic Invalid Amount"
|
||||
mouseTransparent="true" GridPane.rowIndex="0" GridPane.columnIndex="1" GridPane.columnSpan="2"/>
|
||||
|
||||
<VBox alignment="TOP_RIGHT" GridPane.rowIndex="1" GridPane.columnIndex="0">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Optional description" />
|
||||
<Label styleClass="label-description" wrapText="true" textAlignment="RIGHT" text="Can be left empty" />
|
||||
<Label styleClass="text-strong" text="Optional description"/>
|
||||
<Label styleClass="label-description" wrapText="true" textAlignment="RIGHT"
|
||||
text="Can be left empty"/>
|
||||
</children>
|
||||
</VBox>
|
||||
<TextArea fx:id="description" GridPane.columnIndex="1" GridPane.rowIndex="1" GridPane.columnSpan="2" wrapText="true" prefHeight="50.0" />
|
||||
<TextArea fx:id="description" GridPane.columnIndex="1" GridPane.rowIndex="1" GridPane.columnSpan="2"
|
||||
wrapText="true" prefHeight="50.0"/>
|
||||
|
||||
<Button defaultButton="true" mnemonicParsing="false" onAction="#handleGenerate" prefHeight="29.0"
|
||||
prefWidth="95.0" text="Generate" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
|
||||
<Button cancelButton="true" mnemonicParsing="false" onAction="#handleClose" styleClass="cancel" text="Close"
|
||||
GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="2" opacity="0" focusTraversable="false"/>
|
||||
<Button cancelButton="true" mnemonicParsing="false" onAction="#handleClose" styleClass="cancel"
|
||||
text="Close"
|
||||
GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="2" opacity="0"
|
||||
focusTraversable="false"/>
|
||||
|
||||
</children>
|
||||
</GridPane>
|
||||
|
@ -69,12 +76,14 @@
|
|||
<children>
|
||||
<HBox spacing="10.0" alignment="CENTER_LEFT">
|
||||
<children>
|
||||
<Label text="Invoice:" styleClass="text-strong" />
|
||||
<Button mnemonicParsing="false" onAction="#handleCopyInvoice" styleClass="copy-clipboard"
|
||||
text="Copy to Clipboard" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||
<Label text="Invoice:" styleClass="text-strong"/>
|
||||
<Button mnemonicParsing="false" onAction="#handleCopyInvoice"
|
||||
styleClass="copy-clipboard"
|
||||
text="Copy to Clipboard" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
|
||||
</children>
|
||||
</HBox>
|
||||
<TextArea fx:id="paymentRequestTextArea" prefHeight="200.0" editable="false" styleClass="noteditable, text-sm, text-mono" wrapText="true" />
|
||||
<TextArea fx:id="paymentRequestTextArea" prefHeight="200.0" editable="false"
|
||||
styleClass="noteditable, text-sm, text-mono" wrapText="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
<?import javafx.scene.layout.*?>
|
||||
<?import java.lang.String?>
|
||||
<?import java.net.URL?>
|
||||
<GridPane fx:id="nodeId" prefWidth="450.0" prefHeight="450.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<GridPane fx:id="nodeId" prefWidth="450.0" prefHeight="450.0" xmlns="http://javafx.com/javafx/8"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" minWidth="10.0" prefWidth="110.0"/>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" minWidth="10.0" prefWidth="250.0"/>
|
||||
|
@ -28,13 +29,16 @@
|
|||
styleClass="text-error" GridPane.columnSpan="2" GridPane.rowIndex="2"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Amount (msat)" GridPane.halignment="RIGHT" GridPane.rowIndex="3"/>
|
||||
<TextField fx:id="amountField" focusTraversable="false" editable="false" styleClass="noteditable" text="0" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
|
||||
<TextField fx:id="amountField" focusTraversable="false" editable="false" styleClass="noteditable" text="0"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="3"/>
|
||||
|
||||
<Label styleClass="text-muted" text="Node Id" GridPane.halignment="RIGHT" GridPane.rowIndex="4"/>
|
||||
<TextField fx:id="nodeIdField" focusTraversable="false" editable="false" styleClass="noteditable" text="N/A" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
<TextField fx:id="nodeIdField" focusTraversable="false" editable="false" styleClass="noteditable" text="N/A"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
|
||||
<Label styleClass="text-muted" text="hash" GridPane.halignment="RIGHT" GridPane.rowIndex="5"/>
|
||||
<TextField fx:id="hashField" focusTraversable="false" editable="false" styleClass="noteditable" text="N/A" GridPane.columnIndex="1" GridPane.rowIndex="5"/>
|
||||
<TextField fx:id="hashField" focusTraversable="false" editable="false" styleClass="noteditable" text="N/A"
|
||||
GridPane.columnIndex="1" GridPane.rowIndex="5"/>
|
||||
|
||||
<Separator GridPane.columnSpan="2" GridPane.rowIndex="6"/>
|
||||
|
||||
|
|
|
@ -3,47 +3,53 @@
|
|||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.effect.BoxBlur?>
|
||||
<?import javafx.scene.image.*?>
|
||||
<?import javafx.scene.effect.DropShadow?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.scene.effect.DropShadow?>
|
||||
<Pane fx:id="splash" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
|
||||
prefHeight="457.0" prefWidth="760.0" style="-fx-background-color: transparent"
|
||||
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<ImageView fx:id="imgBlurred" fitHeight="0" fitWidth="300.0" layoutX="176.0" layoutY="115.0" pickOnBounds="true" preserveRatio="true">
|
||||
<ImageView fx:id="imgBlurred" fitHeight="0" fitWidth="300.0" layoutX="176.0" layoutY="115.0" pickOnBounds="true"
|
||||
preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../commons/images/eclair-fit.png" />
|
||||
<Image url="@../commons/images/eclair-fit.png"/>
|
||||
</image>
|
||||
<effect>
|
||||
<BoxBlur height="114.75" width="92.44" />
|
||||
<BoxBlur height="114.75" width="92.44"/>
|
||||
</effect>
|
||||
</ImageView>
|
||||
<ImageView fx:id="img" fitHeight="0" fitWidth="409.0" layoutX="176.0" layoutY="114.0" opacity="0.0" pickOnBounds="true" preserveRatio="true">
|
||||
<ImageView fx:id="img" fitHeight="0" fitWidth="409.0" layoutX="176.0" layoutY="114.0" opacity="0.0"
|
||||
pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../commons/images/eclair-fit.png" />
|
||||
<Image url="@../commons/images/eclair-fit.png"/>
|
||||
</image>
|
||||
</ImageView>
|
||||
<VBox fx:id="errorBox" opacity="0.0" alignment="CENTER" layoutX="196.0" prefWidth="370.0" prefHeight="457.0">
|
||||
<children>
|
||||
<VBox prefWidth="370.0" styleClass="error-box" spacing="10">
|
||||
<effect>
|
||||
<DropShadow offsetX="5.0" offsetY="5.0" radius="25.0" color="rgba(0,0,0,.4)" blurType="GAUSSIAN"/>
|
||||
<DropShadow offsetX="5.0" offsetY="5.0" radius="25.0" color="rgba(0,0,0,.4)"
|
||||
blurType="GAUSSIAN"/>
|
||||
</effect>
|
||||
<children>
|
||||
<VBox fx:id="logBox" VBox.vgrow="ALWAYS" styleClass="log-box">
|
||||
<children>
|
||||
</children>
|
||||
</VBox>
|
||||
<Label onMouseClicked="#openGithubPage" VBox.vgrow="NEVER" styleClass="link" text="Consult our readme to get started." />
|
||||
<Button fx:id="closeButton" VBox.vgrow="NEVER" mnemonicParsing="false" onAction="#closeAndKill" text="Close" cancelButton="true" />
|
||||
<Label onMouseClicked="#openGithubPage" VBox.vgrow="NEVER" styleClass="link"
|
||||
text="Consult our readme to get started."/>
|
||||
<Button fx:id="closeButton" VBox.vgrow="NEVER" mnemonicParsing="false" onAction="#closeAndKill"
|
||||
text="Close" cancelButton="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@../commons/globals.css" />
|
||||
<URL value="@splash.css" />
|
||||
<URL value="@../commons/globals.css"/>
|
||||
<URL value="@splash.css"/>
|
||||
</stylesheets>
|
||||
</Pane>
|
||||
|
|
|
@ -12,7 +12,9 @@ import fr.acinq.eclair.gui.controllers.SplashController
|
|||
import grizzled.slf4j.Logging
|
||||
|
||||
sealed trait AppNotificationType
|
||||
|
||||
case object SuccessAppNotification extends AppNotificationType
|
||||
|
||||
case object InfoAppNotification extends AppNotificationType
|
||||
|
||||
case class AppNotification(notificationType: AppNotificationType, message: String) extends PreloaderNotification
|
||||
|
|
|
@ -12,7 +12,6 @@ import fr.acinq.bitcoin.Crypto.PublicKey
|
|||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.eclair.blockchain.bitcoind.zmq.ZMQActor.{ZMQConnected, ZMQDisconnected}
|
||||
import fr.acinq.eclair.blockchain.electrum.ElectrumClient.{ElectrumConnected, ElectrumDisconnected}
|
||||
import fr.acinq.eclair.blockchain.electrum.ElectrumWallet
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.gui.controllers._
|
||||
import fr.acinq.eclair.gui.utils.CoinFormat
|
||||
|
|
|
@ -7,8 +7,8 @@ import java.util.Locale
|
|||
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import fr.acinq.bitcoin.{BinaryData, MilliSatoshi}
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
import fr.acinq.bitcoin.{BinaryData, MilliSatoshi}
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.gui.controllers._
|
||||
import fr.acinq.eclair.gui.utils.GUIValidators
|
||||
|
@ -16,8 +16,8 @@ import fr.acinq.eclair.io.Switchboard.{NewChannel, NewConnection}
|
|||
import fr.acinq.eclair.payment._
|
||||
import grizzled.slf4j.Logging
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ class Handlers(fKit: Future[Kit])(implicit ec: ExecutionContext = ExecutionConte
|
|||
|
||||
private var notifsController: Option[NotificationsController] = None
|
||||
|
||||
def initNotifications (controller: NotificationsController) = {
|
||||
def initNotifications(controller: NotificationsController) = {
|
||||
notifsController = Option(controller)
|
||||
}
|
||||
|
||||
|
@ -67,21 +67,23 @@ class Handlers(fKit: Future[Kit])(implicit ec: ExecutionContext = ExecutionConte
|
|||
kit <- fKit
|
||||
res <- (kit.paymentInitiator ? request).mapTo[PaymentResult]
|
||||
} yield res)
|
||||
.onComplete {
|
||||
case Success(_: PaymentSucceeded) =>
|
||||
val message = s"${NumberFormat.getInstance(Locale.getDefault).format(amountMsat/1000)} satoshis"
|
||||
notification("Payment Sent", message, NOTIFICATION_SUCCESS)
|
||||
case Success(PaymentFailed(_, failures)) =>
|
||||
val message = s"${failures.lastOption match {
|
||||
case Some(LocalFailure(t)) => t.getMessage
|
||||
case Some(RemoteFailure(_, e)) => e.failureMessage
|
||||
case _ => "Unknown error"
|
||||
}} (${failures.size} attempts)"
|
||||
notification("Payment Failed", message, NOTIFICATION_ERROR)
|
||||
case Failure(t) =>
|
||||
val message = t.getMessage
|
||||
notification("Payment Failed", message, NOTIFICATION_ERROR)
|
||||
}
|
||||
.onComplete {
|
||||
case Success(_: PaymentSucceeded) =>
|
||||
val message = s"${NumberFormat.getInstance(Locale.getDefault).format(amountMsat / 1000)} satoshis"
|
||||
notification("Payment Sent", message, NOTIFICATION_SUCCESS)
|
||||
case Success(PaymentFailed(_, failures)) =>
|
||||
val message = s"${
|
||||
failures.lastOption match {
|
||||
case Some(LocalFailure(t)) => t.getMessage
|
||||
case Some(RemoteFailure(_, e)) => e.failureMessage
|
||||
case _ => "Unknown error"
|
||||
}
|
||||
} (${failures.size} attempts)"
|
||||
notification("Payment Failed", message, NOTIFICATION_ERROR)
|
||||
case Failure(t) =>
|
||||
val message = t.getMessage
|
||||
notification("Payment Failed", message, NOTIFICATION_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
def receive(amountMsat: MilliSatoshi, description: String): Future[String] = for {
|
||||
|
@ -108,12 +110,12 @@ class Handlers(fKit: Future[Kit])(implicit ec: ExecutionContext = ExecutionConte
|
|||
/**
|
||||
* Displays a system notification if the system supports it.
|
||||
*
|
||||
* @param title Title of the notification
|
||||
* @param message main message of the notification, will not wrap
|
||||
* @param title Title of the notification
|
||||
* @param message main message of the notification, will not wrap
|
||||
* @param notificationType type of the message, default to NONE
|
||||
* @param showAppName true if you want the notification title to be preceded by "Eclair - ". True by default
|
||||
* @param showAppName true if you want the notification title to be preceded by "Eclair - ". True by default
|
||||
*/
|
||||
def notification (title: String, message: String, notificationType: NotificationType = NOTIFICATION_NONE, showAppName: Boolean = true) = {
|
||||
def notification(title: String, message: String, notificationType: NotificationType = NOTIFICATION_NONE, showAppName: Boolean = true) = {
|
||||
notifsController.map(_.addNotification(if (showAppName) s"Eclair - $title" else title, message, notificationType))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package fr.acinq.eclair.gui.controllers
|
||||
|
||||
import javafx.fxml.FXML
|
||||
import javafx.application.HostServices
|
||||
import javafx.fxml.FXML
|
||||
import javafx.scene.text.Text
|
||||
|
||||
import grizzled.slf4j.Logging
|
||||
|
||||
/**
|
||||
|
@ -11,11 +12,16 @@ import grizzled.slf4j.Logging
|
|||
class AboutController(hostServices: HostServices) extends Logging {
|
||||
|
||||
@FXML var version: Text = _
|
||||
|
||||
@FXML def initialize = {
|
||||
version.setText(getClass.getPackage.getImplementationVersion)
|
||||
}
|
||||
|
||||
@FXML def openApacheLicencePage = hostServices.showDocument("https://www.apache.org/licenses/LICENSE-2.0")
|
||||
|
||||
@FXML def openACINQPage = hostServices.showDocument("https://acinq.co")
|
||||
|
||||
@FXML def openGithubPage = hostServices.showDocument("https://github.com/ACINQ/eclair")
|
||||
|
||||
@FXML def openLNRFCPage = hostServices.showDocument("https://github.com/lightningnetwork/lightning-rfc")
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class ChannelPaneController(val theirNodeIdValue: String) extends Logging {
|
|||
if (contextMenu != null) contextMenu.hide
|
||||
}
|
||||
|
||||
def updateRemoteNodeAlias (alias: String) {
|
||||
def updateRemoteNodeAlias(alias: String) {
|
||||
Option(nodeId).map((n: TextField) => n.setText(s"$theirNodeIdValue ($alias)"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ class MainController(val handlers: Handlers, val hostServices: HostServices) ext
|
|||
val directionImage = new ImageView
|
||||
directionImage.setFitWidth(20)
|
||||
directionImage.setFitHeight(20)
|
||||
|
||||
override def updateItem(item: ChannelInfo, empty: Boolean): Unit = {
|
||||
super.updateItem(item, empty)
|
||||
if (item == null || empty) {
|
||||
|
@ -224,19 +225,19 @@ class MainController(val handlers: Handlers, val hostServices: HostServices) ext
|
|||
setText(null)
|
||||
} else {
|
||||
item match {
|
||||
case ChannelInfo(_ , Some(true), Some(true)) =>
|
||||
case ChannelInfo(_, Some(true), Some(true)) =>
|
||||
directionImage.setImage(new Image("/gui/commons/images/in-out-11.png", false))
|
||||
setTooltip(new Tooltip("Both Node 1 and Node 2 are enabled"))
|
||||
setGraphic(directionImage)
|
||||
case ChannelInfo(_ , Some(true), Some(false)) =>
|
||||
case ChannelInfo(_, Some(true), Some(false)) =>
|
||||
directionImage.setImage(new Image("/gui/commons/images/in-out-10.png", false))
|
||||
setTooltip(new Tooltip("Node 1 is enabled, but not Node 2"))
|
||||
setGraphic(directionImage)
|
||||
case ChannelInfo(_ , Some(false), Some(true)) =>
|
||||
case ChannelInfo(_, Some(false), Some(true)) =>
|
||||
directionImage.setImage(new Image("/gui/commons/images/in-out-01.png", false))
|
||||
setTooltip(new Tooltip("Node 2 is enabled, but not Node 1"))
|
||||
setGraphic(directionImage)
|
||||
case ChannelInfo(_ , Some(false), Some(false)) =>
|
||||
case ChannelInfo(_, Some(false), Some(false)) =>
|
||||
directionImage.setImage(new Image("/gui/commons/images/in-out-00.png", false))
|
||||
setTooltip(new Tooltip("Neither Node 1 nor Node 2 is enabled"))
|
||||
setGraphic(directionImage)
|
||||
|
|
|
@ -20,6 +20,7 @@ class NotificationPaneController {
|
|||
@FXML def handleMouseEnter(event: MouseEvent) = {
|
||||
rootPane.setOpacity(1)
|
||||
}
|
||||
|
||||
@FXML def handleMouseExit(event: MouseEvent) = {
|
||||
rootPane.setOpacity(0.95)
|
||||
}
|
||||
|
|
|
@ -12,9 +12,13 @@ import javafx.util.Duration
|
|||
import grizzled.slf4j.Logging
|
||||
|
||||
sealed trait NotificationType
|
||||
|
||||
case object NOTIFICATION_NONE extends NotificationType
|
||||
|
||||
case object NOTIFICATION_SUCCESS extends NotificationType
|
||||
|
||||
case object NOTIFICATION_ERROR extends NotificationType
|
||||
|
||||
case object NOTIFICATION_INFO extends NotificationType
|
||||
|
||||
/**
|
||||
|
@ -30,11 +34,11 @@ class NotificationsController extends Logging {
|
|||
/**
|
||||
* Adds a notification panel to the notifications stage
|
||||
*
|
||||
* @param title Title of the notification, should not be too long
|
||||
* @param message Main message of the notification
|
||||
* @param title Title of the notification, should not be too long
|
||||
* @param message Main message of the notification
|
||||
* @param notificationType type of the notification (error, warning, success, info...)
|
||||
*/
|
||||
def addNotification (title: String, message: String, notificationType: NotificationType) = {
|
||||
def addNotification(title: String, message: String, notificationType: NotificationType) = {
|
||||
|
||||
val loader = new FXMLLoader(getClass.getResource("/gui/main/notificationPane.fxml"))
|
||||
val notifPaneController = new NotificationPaneController
|
||||
|
|
|
@ -8,7 +8,6 @@ import javafx.scene.control._
|
|||
import javafx.stage.Stage
|
||||
|
||||
import fr.acinq.bitcoin.{MilliSatoshi, Satoshi}
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.channel.ChannelFlags
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.utils.GUIValidators
|
||||
|
@ -71,7 +70,7 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage) extends Lo
|
|||
// pushMsat is optional, so we validate field only if it isn't empty
|
||||
if (GUIValidators.validate(pushMsat.getText, pushMsatError, "Push msat must be numeric", GUIValidators.amountRegex)
|
||||
&& GUIValidators.validate(pushMsatError, "Push msat must be 16 777 216 000 msat (~0.167 BTC) or less", pushMsat.getText.toLong <= maxPushMsat)) {
|
||||
val channelFlags = if(publicChannel.isSelected) ChannelFlags.AnnounceChannel else ChannelFlags.Empty
|
||||
val channelFlags = if (publicChannel.isSelected) ChannelFlags.AnnounceChannel else ChannelFlags.Empty
|
||||
handlers.open(host.getText, Some(NewChannel(smartFunding, MilliSatoshi(pushMsat.getText.toLong), Some(channelFlags))))
|
||||
stage.close
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import com.google.zxing.qrcode.QRCodeWriter
|
|||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
||||
import com.google.zxing.{BarcodeFormat, EncodeHintType}
|
||||
import fr.acinq.bitcoin.MilliSatoshi
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.utils.{ContextMenuUtils, GUIValidators}
|
||||
import fr.acinq.eclair.payment.PaymentRequest
|
||||
|
|
|
@ -8,9 +8,6 @@ import javafx.scene.input.KeyCode.{ENTER, TAB}
|
|||
import javafx.scene.input.KeyEvent
|
||||
import javafx.stage.Stage
|
||||
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.utils.GUIValidators
|
||||
import fr.acinq.eclair.payment.PaymentRequest
|
||||
|
|
|
@ -5,7 +5,7 @@ import javafx.application.HostServices
|
|||
import javafx.fxml.FXML
|
||||
import javafx.scene.control.{Button, Label}
|
||||
import javafx.scene.image.ImageView
|
||||
import javafx.scene.layout.{HBox, Pane, VBox}
|
||||
import javafx.scene.layout.{Pane, VBox}
|
||||
import javafx.util.Duration
|
||||
|
||||
import grizzled.slf4j.Logging
|
||||
|
@ -46,6 +46,7 @@ class SplashController(hostServices: HostServices) extends Logging {
|
|||
l.setWrapText(true)
|
||||
logBox.getChildren.add(l)
|
||||
}
|
||||
|
||||
def addError(message: String) = {
|
||||
val l = new Label
|
||||
l.setText(message)
|
||||
|
|
|
@ -5,7 +5,6 @@ import javafx.scene.image.Image
|
|||
import javafx.scene.{Parent, Scene}
|
||||
import javafx.stage.{Modality, Stage, StageStyle}
|
||||
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.controllers.OpenChannelController
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import javafx.scene.image.Image
|
|||
import javafx.scene.{Parent, Scene}
|
||||
import javafx.stage.{Modality, Stage, StageStyle}
|
||||
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.controllers.ReceivePaymentController
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue