1
0
Fork 0
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:
Pierre-Marie Padiou 2017-11-21 20:08:15 +01:00 committed by Dominique
parent df67157119
commit bfa3e1c2ca
107 changed files with 589 additions and 452 deletions

View file

@ -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

View file

@ -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"
}
}

View file

@ -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"
}
}

View file

@ -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

View file

@ -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

View file

@ -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
/**

View file

@ -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,

View file

@ -31,4 +31,5 @@ object UInt64 {
implicit def longToUint64(l: Long) = UInt64(l)
}
}

View file

@ -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

View file

@ -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]

View file

@ -30,6 +30,7 @@ trait EclairWallet {
/**
* Cancels this transaction: this probably translates to "release locks on utxos".
*
* @param tx
* @return
*/

View file

@ -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
*/

View file

@ -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)

View file

@ -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 {
}
}

View file

@ -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

View file

@ -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
*/

View file

@ -1,4 +1,5 @@
package fr.acinq.eclair.blockchain.fee
import scala.concurrent.Future
/**

View file

@ -28,6 +28,7 @@ object FeeratesPerKw {
/**
* Used in tests
*
* @param feeratePerKw
* @return
*/

View file

@ -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}

View file

@ -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

View file

@ -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._

View file

@ -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.

View file

@ -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
*/

View file

@ -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)

View file

@ -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 = {

View file

@ -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

View file

@ -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))
)

View file

@ -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)))

View file

@ -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

View file

@ -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
*/

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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)
}
}
}
}

View file

@ -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
}

View file

@ -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
/**

View file

@ -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 }

View file

@ -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)

View file

@ -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

View file

@ -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")

View file

@ -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")

View file

@ -1,6 +1,5 @@
package fr.acinq.eclair.transactions
import fr.acinq.bitcoin.BinaryData
import fr.acinq.eclair.wire._
/**

View file

@ -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.

View file

@ -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._

View file

@ -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)"
}
}

View file

@ -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}

View file

@ -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,

View file

@ -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.

View file

@ -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

View file

@ -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
/**

View file

@ -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)),

View file

@ -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)))
}
}

View file

@ -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 {

View file

@ -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)
}

View file

@ -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()

View file

@ -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 {
}
}

View file

@ -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}

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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._

View file

@ -10,6 +10,7 @@ import org.spongycastle.util.encoders.Hex
*/
@RunWith(classOf[JUnitRunner])
class BitStreamSpec extends FunSuite {
import BitStream._
test("add bits") {

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -364,6 +364,7 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
/**
* We currently use p2pkh script Helpers.getFinalScriptPubKey
*
* @param scriptPubKey
* @return
*/

View file

@ -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}

View file

@ -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

View file

@ -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.

View file

@ -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._

View file

@ -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]

View file

@ -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

View file

@ -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._
/**

View file

@ -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

View file

@ -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

View file

@ -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"/>

View file

@ -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>

View file

@ -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"/>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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"/>

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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))
}
}

View file

@ -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")
}

View file

@ -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)"))
}
}

View file

@ -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)

View file

@ -20,6 +20,7 @@ class NotificationPaneController {
@FXML def handleMouseEnter(event: MouseEvent) = {
rootPane.setOpacity(1)
}
@FXML def handleMouseExit(event: MouseEvent) = {
rootPane.setOpacity(0.95)
}

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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