mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 10:39:19 +01:00
Added pushMsat param when connecting to a channel
* pushMsat is an optional field in millisatoshi, default is 0 * In channel creation, `amount` parameter has been renamed to fundingSatoshis to make code more readable * Added pushMsat field in open channel modal GUI * Added description label in open channel modal to improve user experience
This commit is contained in:
parent
2d2ecdabf2
commit
de99fdb566
@ -76,4 +76,9 @@
|
||||
}
|
||||
.text-error.text-error-upward {
|
||||
-fx-translate-y: -6px;
|
||||
}
|
||||
|
||||
.label-description {
|
||||
-fx-text-fill: rgb(156,159,161);
|
||||
-fx-font-size: 10px;
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="528.0"
|
||||
styleClass="grid" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||
@ -23,11 +24,13 @@
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="1.0" prefHeight="3.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="1.0" prefHeight="3.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="50.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<TextField fx:id="host" prefWidth="313.0" promptText="pubkey@host:port1" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1" />
|
||||
<TextField fx:id="amount" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<TextField fx:id="fundingSatoshis" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<ComboBox fx:id="unit" prefWidth="150.0" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
@ -37,12 +40,30 @@
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ComboBox>
|
||||
<Button fx:id="button" defaultButton="true" mnemonicParsing="false" onAction="#handleOpen" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4" GridPane.valignment="BOTTOM" />
|
||||
<Label text="Target Node URI" GridPane.rowIndex="1" />
|
||||
<Label text="Amount" GridPane.rowIndex="3" />
|
||||
<TextField fx:id="pushMsat" layoutX="193.0" layoutY="112.0" prefWidth="313.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
<Button fx:id="button" defaultButton="true" mnemonicParsing="false" onAction="#handleOpen" text="Connect" 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" />
|
||||
<VBox alignment="CENTER_RIGHT" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Capacity *" />
|
||||
<Label styleClass="label-description" text="Funding capacity of the channel." textAlignment="RIGHT" wrapText="true" />
|
||||
</children>
|
||||
</VBox>
|
||||
<Label fx:id="hostError" opacity="0.0" styleClass="text-error" text="Please use a valid url (pubkey@host:port)" GridPane.columnIndex="1" GridPane.columnSpan="2" />
|
||||
<Label fx:id="amountError" opacity="0.0" styleClass="text-error" text="Please use a valid amount" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="2" />
|
||||
<Button cancelButton="true" mnemonicParsing="false" onAction="#handleClose" styleClass="cancel" text="Cancel" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="4" GridPane.valignment="BOTTOM" />
|
||||
<Label fx:id="fundingSatoshisError" opacity="0.0" styleClass="text-error" text="Please use a valid amount" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="2" />
|
||||
<Label fx:id="pushMsatError" layoutX="193.0" layoutY="89.0" opacity="0.0" styleClass="text-error" text="Please use a valid Push Amount" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<VBox alignment="CENTER_RIGHT" layoutX="24.0" layoutY="112.0" GridPane.rowIndex="5">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Push Amount" />
|
||||
<Label styleClass="label-description" text="Optional amount in millisatoshi. Sent when opening channel" textAlignment="RIGHT" wrapText="true" />
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox alignment="CENTER_RIGHT" layoutX="24.0" layoutY="112.0" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Label styleClass="text-strong" text="Target Node URI *" />
|
||||
<Label styleClass="label-description" text="Address of the node" textAlignment="RIGHT" wrapText="true" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@modals.css" />
|
||||
|
@ -8,7 +8,7 @@ import akka.http.scaladsl.Http
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.util.Timeout
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import fr.acinq.bitcoin.{Base58Check, BinaryData, OP_CHECKSIG, OP_DUP, OP_EQUALVERIFY, OP_HASH160, OP_PUSHDATA, Satoshi}
|
||||
import fr.acinq.bitcoin.{Base58Check, BinaryData, MilliSatoshi, OP_CHECKSIG, OP_DUP, OP_EQUALVERIFY, OP_HASH160, OP_PUSHDATA, Satoshi}
|
||||
import fr.acinq.eclair.api.Service
|
||||
import fr.acinq.eclair.blockchain.peer.PeerClient
|
||||
import fr.acinq.eclair.blockchain.rpc.BitcoinJsonRPCClient
|
||||
@ -98,7 +98,7 @@ class Setup() extends Logging {
|
||||
override val paymentHandler: ActorRef = _setup.paymentHandler
|
||||
override val paymentInitiator: ActorRef = _setup.paymentInitiator
|
||||
|
||||
override def connect(host: String, port: Int, pubkey: BinaryData, amount: Satoshi): Unit = system.actorOf(Client.props(host, port, pubkey, amount, register))
|
||||
override def connect(host: String, port: Int, pubkey: BinaryData, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi): Unit = system.actorOf(Client.props(host, port, pubkey, fundingSatoshis, pushMsat, register))
|
||||
}
|
||||
Http().bindAndHandle(api.route, config.getString("eclair.api.host"), config.getInt("eclair.api.port")) onFailure {
|
||||
case t: Throwable => system.eventStream.publish(HTTPBindError)
|
||||
|
@ -11,7 +11,7 @@ import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport.ShouldWritePretty
|
||||
import fr.acinq.bitcoin.{BinaryData, Satoshi}
|
||||
import fr.acinq.bitcoin.{BinaryData, MilliSatoshi, Satoshi}
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.channel.Register.{ListChannels, SendCommand}
|
||||
import fr.acinq.eclair.channel._
|
||||
@ -47,7 +47,7 @@ trait Service extends Logging {
|
||||
|
||||
import Json4sSupport.{json4sMarshaller, json4sUnmarshaller}
|
||||
|
||||
def connect(host: String, port: Int, pubkey: BinaryData, amount: Satoshi): Unit
|
||||
def connect(host: String, port: Int, pubkey: BinaryData, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi): Unit
|
||||
|
||||
def register: ActorRef
|
||||
|
||||
@ -71,7 +71,7 @@ trait Service extends Logging {
|
||||
req =>
|
||||
val f_res: Future[AnyRef] = req match {
|
||||
case JsonRPCBody(_, _, "connect", JString(host) :: JInt(port) :: JString(pubkey) :: JInt(anchor_amount) :: Nil) =>
|
||||
connect(host, port.toInt, BinaryData(pubkey), Satoshi(anchor_amount.toLong))
|
||||
connect(host, port.toInt, BinaryData(pubkey), Satoshi(anchor_amount.toLong), MilliSatoshi(0))
|
||||
Future.successful("ok")
|
||||
case JsonRPCBody(_, _, "info", _) =>
|
||||
Future.successful(Status(Globals.Node.id))
|
||||
|
@ -3,7 +3,7 @@ package fr.acinq.eclair.channel
|
||||
import akka.actor.{Props, _}
|
||||
import akka.util.Timeout
|
||||
import fr.acinq.bitcoin.Crypto.PrivateKey
|
||||
import fr.acinq.bitcoin.{BinaryData, DeterministicWallet, Satoshi, ScriptElt}
|
||||
import fr.acinq.bitcoin.{BinaryData, DeterministicWallet, MilliSatoshi, Satoshi, ScriptElt}
|
||||
import fr.acinq.eclair.Globals
|
||||
import fr.acinq.eclair.crypto.Noise.KeyPair
|
||||
import fr.acinq.eclair.crypto.TransportHandler
|
||||
@ -39,7 +39,7 @@ class Register(watcher: ActorRef, router: ActorRef, paymentHandler: ActorRef, de
|
||||
def receive: Receive = main(0L)
|
||||
|
||||
def main(counter: Long): Receive = {
|
||||
case CreateChannel(connection, pubkey, amount_opt) =>
|
||||
case CreateChannel(connection, pubkey, funding_opt, pushmsat_opt) =>
|
||||
def generateKey(index: Long): PrivateKey = DeterministicWallet.derivePrivateKey(Globals.Node.extendedPrivateKey, index :: counter :: Nil).privateKey
|
||||
|
||||
val localParams = LocalParams(
|
||||
@ -56,14 +56,17 @@ class Register(watcher: ActorRef, router: ActorRef, paymentHandler: ActorRef, de
|
||||
delayedPaymentKey = generateKey(3),
|
||||
defaultFinalScriptPubKey = defaultFinalScriptPubKey,
|
||||
shaSeed = Globals.Node.seed,
|
||||
isFunder = amount_opt.isDefined
|
||||
isFunder = funding_opt.isDefined
|
||||
)
|
||||
|
||||
def makeChannel(conn: ActorRef, publicKey: BinaryData, ctx: ActorContext): ActorRef = {
|
||||
// note that we use transport's context and not register's context
|
||||
val channel = ctx.actorOf(Channel.props(conn, watcher, router, paymentHandler, localParams, publicKey.toString(), Some(Globals.autosign_interval)), s"channel-$counter")
|
||||
amount_opt match {
|
||||
case Some(amount) => channel ! INPUT_INIT_FUNDER(amount.amount, 0)
|
||||
funding_opt match {
|
||||
case Some(funding) => pushmsat_opt match {
|
||||
case Some(pushmsat) => channel ! INPUT_INIT_FUNDER(funding.amount, pushmsat.amount)
|
||||
case None => channel ! INPUT_INIT_FUNDER(funding.amount, 0)
|
||||
}
|
||||
case None => channel ! INPUT_INIT_FUNDEE()
|
||||
}
|
||||
channel
|
||||
@ -73,7 +76,7 @@ class Register(watcher: ActorRef, router: ActorRef, paymentHandler: ActorRef, de
|
||||
new TransportHandler[LightningMessage](
|
||||
KeyPair(Globals.Node.publicKey.toBin, Globals.Node.privateKey.toBin),
|
||||
pubkey,
|
||||
isWriter = amount_opt.isDefined,
|
||||
isWriter = funding_opt.isDefined,
|
||||
them = connection,
|
||||
listenerFactory = makeChannel,
|
||||
serializer = LightningMessageSerializer)),
|
||||
@ -99,7 +102,7 @@ object Register {
|
||||
def props(blockchain: ActorRef, router: ActorRef, paymentHandler: ActorRef, defaultFinalScriptPubKey: Seq[ScriptElt]) = Props(classOf[Register], blockchain, router, paymentHandler, defaultFinalScriptPubKey)
|
||||
|
||||
// @formatter:off
|
||||
case class CreateChannel(connection: ActorRef, pubkey: Option[BinaryData], anchorAmount: Option[Satoshi])
|
||||
case class CreateChannel(connection: ActorRef, pubkey: Option[BinaryData], fundingSatoshis: Option[Satoshi], pushMsat: Option[MilliSatoshi])
|
||||
|
||||
case class ListChannels()
|
||||
|
||||
|
@ -4,7 +4,7 @@ package fr.acinq.eclair.gui
|
||||
import javafx.application.Platform
|
||||
import javafx.scene.control.{TextArea, TextField}
|
||||
|
||||
import fr.acinq.bitcoin.{BinaryData, Satoshi}
|
||||
import fr.acinq.bitcoin.{BinaryData, MilliSatoshi, Satoshi}
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.io.Client
|
||||
import fr.acinq.eclair.payment.CreatePayment
|
||||
@ -17,12 +17,12 @@ class Handlers(setup: Setup) extends Logging {
|
||||
|
||||
import setup._
|
||||
|
||||
def open(hostPort: String, amount: Satoshi) = {
|
||||
def open(hostPort: String, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi) = {
|
||||
val regex = "([a-fA-F0-9]+)@([a-zA-Z0-9\\.\\-_]+):([0-9]+)".r
|
||||
hostPort match {
|
||||
case regex(pubkey, host, port) =>
|
||||
logger.info(s"connecting to $host:$port")
|
||||
system.actorOf(Client.props(host, port.toInt, pubkey, amount, register))
|
||||
system.actorOf(Client.props(host, port.toInt, pubkey, fundingSatoshis, pushMsat, register))
|
||||
case _ => {}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import javafx.fxml.FXML
|
||||
import javafx.scene.control.{Button, ComboBox, Label, TextField}
|
||||
import javafx.stage.Stage
|
||||
|
||||
import fr.acinq.bitcoin.Satoshi
|
||||
import fr.acinq.bitcoin.{MilliSatoshi, Satoshi}
|
||||
import fr.acinq.eclair.Setup
|
||||
import fr.acinq.eclair.gui.Handlers
|
||||
import fr.acinq.eclair.gui.utils.GUIValidators
|
||||
@ -18,8 +18,10 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage, val setup:
|
||||
|
||||
@FXML var host: TextField = _
|
||||
@FXML var hostError: Label = _
|
||||
@FXML var amount: TextField = _
|
||||
@FXML var amountError: Label = _
|
||||
@FXML var fundingSatoshis: TextField = _
|
||||
@FXML var fundingSatoshisError: Label = _
|
||||
@FXML var pushMsat: TextField = _
|
||||
@FXML var pushMsatError: Label = _
|
||||
@FXML var unit: ComboBox[String] = _
|
||||
@FXML var button: Button = _
|
||||
|
||||
@ -29,15 +31,23 @@ class OpenChannelController(val handlers: Handlers, val stage: Stage, val setup:
|
||||
|
||||
@FXML def handleOpen(event: ActionEvent): Unit = {
|
||||
if (GUIValidators.validate(host.getText, hostError, GUIValidators.hostRegex)
|
||||
&& GUIValidators.validate(amount.getText, amountError, GUIValidators.amountRegex)) {
|
||||
val raw = amount.getText.toLong
|
||||
val smartAmount = unit.getValue match {
|
||||
case "milliBTC" => Satoshi(raw * 100000L)
|
||||
case "Satoshi" => Satoshi(raw)
|
||||
case "milliSatoshi" => Satoshi(raw / 1000L)
|
||||
&& GUIValidators.validate(fundingSatoshis.getText, fundingSatoshisError, GUIValidators.amountRegex)) {
|
||||
val rawFunding = fundingSatoshis.getText.toLong
|
||||
val smartFunding = unit.getValue match {
|
||||
case "milliBTC" => Satoshi(rawFunding * 100000L)
|
||||
case "Satoshi" => Satoshi(rawFunding)
|
||||
case "milliSatoshi" => Satoshi(rawFunding / 1000L)
|
||||
}
|
||||
if (!pushMsat.getText.isEmpty) {
|
||||
// pushMsat is optional, so we validate field only if it isn't empty
|
||||
if (GUIValidators.validate(pushMsat.getText, pushMsatError, GUIValidators.amountRegex)) {
|
||||
handlers.open(host.getText, smartFunding, MilliSatoshi(pushMsat.getText.toLong))
|
||||
stage.close()
|
||||
}
|
||||
} else {
|
||||
handlers.open(host.getText, smartFunding, Satoshi(0))
|
||||
stage.close()
|
||||
}
|
||||
handlers.open(host.getText, smartAmount)
|
||||
stage.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ class OpenChannelStage(handlers: Handlers, setup: Setup) extends Stage() {
|
||||
initStyle(StageStyle.DECORATED)
|
||||
getIcons().add(new Image("/gui/commons/images/eclair02.png", false))
|
||||
setTitle("Open a new channel")
|
||||
setWidth(500)
|
||||
setHeight(250)
|
||||
setWidth(550)
|
||||
setHeight(350)
|
||||
setResizable(false)
|
||||
|
||||
// get fxml/controller
|
||||
|
@ -4,13 +4,13 @@ import java.net.InetSocketAddress
|
||||
|
||||
import akka.actor._
|
||||
import akka.io.{IO, Tcp}
|
||||
import fr.acinq.bitcoin.{BinaryData, Satoshi}
|
||||
import fr.acinq.bitcoin.{BinaryData, MilliSatoshi, Satoshi}
|
||||
import fr.acinq.eclair.channel.Register.CreateChannel
|
||||
|
||||
/**
|
||||
* Created by PM on 27/10/2015.
|
||||
*/
|
||||
class Client(remote: InetSocketAddress, pubkey: BinaryData, amount: Satoshi, register: ActorRef) extends Actor with ActorLogging {
|
||||
class Client(remote: InetSocketAddress, pubkey: BinaryData, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, register: ActorRef) extends Actor with ActorLogging {
|
||||
|
||||
import Tcp._
|
||||
import context.system
|
||||
@ -23,15 +23,15 @@ class Client(remote: InetSocketAddress, pubkey: BinaryData, amount: Satoshi, reg
|
||||
case c@Connected(remote, local) =>
|
||||
log.info(s"connected to $remote")
|
||||
val connection = sender()
|
||||
register ! CreateChannel(connection, Some(pubkey), Some(amount))
|
||||
register ! CreateChannel(connection, Some(pubkey), Some(fundingSatoshis), Some(pushMsat))
|
||||
// TODO: kill this actor ?
|
||||
}
|
||||
}
|
||||
|
||||
object Client extends App {
|
||||
|
||||
def props(address: InetSocketAddress, pubkey: BinaryData, amount: Satoshi, register: ActorRef): Props = Props(classOf[Client], address, pubkey, amount, register)
|
||||
def props(address: InetSocketAddress, pubkey: BinaryData, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, register: ActorRef): Props = Props(classOf[Client], address, pubkey, fundingSatoshis, pushMsat, register)
|
||||
|
||||
def props(host: String, port: Int, pubkey: BinaryData, amount: Satoshi, register: ActorRef): Props = Props(classOf[Client], new InetSocketAddress(host, port), pubkey, amount, register)
|
||||
def props(host: String, port: Int, pubkey: BinaryData, fundingSatoshis: Satoshi, pushMsat: MilliSatoshi, register: ActorRef): Props = Props(classOf[Client], new InetSocketAddress(host, port), pubkey, fundingSatoshis, pushMsat, register)
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class Server(address: InetSocketAddress, register: ActorRef) extends Actor with
|
||||
case c@Connected(remote, local) =>
|
||||
log.info(s"connected to $remote")
|
||||
val connection = sender()
|
||||
register ! CreateChannel(connection, None, None)
|
||||
register ! CreateChannel(connection, None, None, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user