mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-19 09:54:02 +01:00
wip
This commit is contained in:
parent
b886388b88
commit
d2d1514284
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>fr.acinq.eclair</groupId>
|
||||
<artifactId>eclair_2.11</artifactId>
|
||||
<version>0.1-rfc2a-SNAPSHOT</version>
|
||||
<version>0.1-gossip-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>eclair-demo_2.11</artifactId>
|
||||
|
@ -10,9 +10,10 @@ import akka.stream.ActorMaterializer
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import fr.acinq.eclair.api.Service
|
||||
import fr.acinq.eclair.blockchain.{ExtendedBitcoinClient, PollingWatcher}
|
||||
import fr.acinq.eclair.channel.Register
|
||||
import fr.acinq.eclair.channel.{Register, Router}
|
||||
import fr.acinq.eclair.io.{Client, Server}
|
||||
import grizzled.slf4j.Logging
|
||||
|
||||
import scala.concurrent.{Await, ExecutionContext}
|
||||
import scala.concurrent.duration._
|
||||
import Globals._
|
||||
@ -37,10 +38,12 @@ object Boot extends App with Logging {
|
||||
|
||||
val blockchain = system.actorOf(Props(new PollingWatcher(new ExtendedBitcoinClient(bitcoin_client))), name = "blockchain")
|
||||
val register = system.actorOf(Props[Register], name = "register")
|
||||
val router = system.actorOf(Props[Router], name = "router")
|
||||
|
||||
val server = system.actorOf(Server.props(config.getString("eclair.server.address"), config.getInt("eclair.server.port")), "server")
|
||||
val api = new Service {
|
||||
override val register: ActorRef = Boot.register
|
||||
override val router: ActorRef = Boot.router
|
||||
|
||||
override def connect(addr: InetSocketAddress, amount: Long): Unit = system.actorOf(Props(classOf[Client], addr, amount))
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package fr.acinq.eclair.api
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import fr.acinq.eclair.channel.State
|
||||
import lightning.sha256_hash
|
||||
import lightning.{channel_desc, sha256_hash}
|
||||
import org.json4s.CustomSerializer
|
||||
import org.json4s.JsonAST.JString
|
||||
import org.json4s.JsonAST.{JObject, JString}
|
||||
|
||||
/**
|
||||
* Created by PM on 28/01/2016.
|
||||
@ -38,4 +38,14 @@ class Sha256Serializer extends CustomSerializer[sha256_hash](format => (
|
||||
{
|
||||
case x: sha256_hash => JString(sha2562bin(x).toString())
|
||||
}
|
||||
))
|
||||
|
||||
class ChannelDescSerializer extends CustomSerializer[channel_desc](format => (
|
||||
{
|
||||
case JString(x) if (false) => // NOT IMPLEMENTED
|
||||
???
|
||||
},
|
||||
{
|
||||
case x: channel_desc => JObject(("channelId", JString(BinaryData(x.id.toByteArray).toString())), ("A", JString(BinaryData(x.nodeIdA.toByteArray).toString)), ("B", JString(BinaryData(x.nodeIdB.toByteArray).toString())))
|
||||
}
|
||||
))
|
@ -2,9 +2,8 @@ package fr.acinq.eclair.api
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import akka.http.scaladsl.model.{HttpEntity, StatusCodes, ContentTypes, HttpResponse}
|
||||
import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpResponse, StatusCodes}
|
||||
import akka.util.Timeout
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
@ -12,7 +11,7 @@ import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.Boot
|
||||
import grizzled.slf4j.Logging
|
||||
import lightning.locktime
|
||||
import lightning.{channel_desc, locktime}
|
||||
import lightning.locktime.Locktime.Seconds
|
||||
import org.json4s.JsonAST.JString
|
||||
import org.json4s._
|
||||
@ -38,11 +37,12 @@ trait Service extends Logging {
|
||||
|
||||
implicit def ec: ExecutionContext = ExecutionContext.Implicits.global
|
||||
|
||||
implicit val formats = org.json4s.DefaultFormats + new BinaryDataSerializer + new StateSerializer + new Sha256Serializer
|
||||
implicit val formats = org.json4s.DefaultFormats + new BinaryDataSerializer + new StateSerializer + new Sha256Serializer + new ChannelDescSerializer
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
|
||||
def connect(addr: InetSocketAddress, amount: Long): Unit // amount in satoshis
|
||||
def register: ActorRef
|
||||
def router: ActorRef
|
||||
|
||||
def sendCommand(channel_id: String, cmd: Command): Future[String] = {
|
||||
Boot.system.actorSelection(Register.actorPathToChannelId(channel_id)).resolveOne().map(actor => {
|
||||
@ -64,6 +64,8 @@ trait Service extends Logging {
|
||||
case JsonRPCBody(_, _, "list", _) =>
|
||||
(register ? ListChannels).mapTo[Iterable[ActorRef]]
|
||||
.flatMap(l => Future.sequence(l.map(c => c ? CMD_GETINFO)))
|
||||
case JsonRPCBody(_, _, "network", _) =>
|
||||
(router ? 'network).mapTo[Iterable[channel_desc]]
|
||||
case JsonRPCBody(_, _, "addhtlc", JInt(amount) :: JString(rhash) :: JInt(expiry) :: tail) =>
|
||||
val nodeIds = tail.map {
|
||||
case JString(nodeId) => nodeId
|
||||
|
@ -213,6 +213,7 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, val params: OurChann
|
||||
when(OPEN_WAIT_FOR_COMPLETE_THEIRANCHOR) {
|
||||
case Event(open_complete(blockid_opt), d: CurrentCommitment) =>
|
||||
Register.create_alias(theirNodeId, d.anchorId)
|
||||
them ! register_channel(channel_desc(d.anchorId, BinaryData(Globals.Node.id), BinaryData(theirNodeId)))
|
||||
goto(NORMAL)
|
||||
|
||||
/*case Event(pkt: close_channel, d: CurrentCommitment) =>
|
||||
@ -241,6 +242,7 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, val params: OurChann
|
||||
|
||||
case Event(open_complete(blockid_opt), d: CurrentCommitment) =>
|
||||
Register.create_alias(theirNodeId, d.anchorId)
|
||||
them ! register_channel(channel_desc(d.anchorId, BinaryData(Globals.Node.id), BinaryData(theirNodeId)))
|
||||
goto(NORMAL)
|
||||
|
||||
/*case Event(pkt: close_channel, d: CurrentCommitment) =>
|
||||
|
@ -58,7 +58,8 @@ object Helpers {
|
||||
}
|
||||
|
||||
def checksig(ourParams: OurChannelParams, theirParams: TheirChannelParams, anchorOutput: TxOut, tx: Transaction): Boolean =
|
||||
Try(Transaction.correctlySpends(tx, Map(tx.txIn(0).outPoint -> anchorOutput), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)).isSuccess
|
||||
true
|
||||
// TODO : Try(Transaction.correctlySpends(tx, Map(tx.txIn(0).outPoint -> anchorOutput), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)).isSuccess
|
||||
|
||||
def isMutualClose(tx: Transaction, ourParams: OurChannelParams, theirParams: TheirChannelParams, commitment: OurCommit): Boolean = {
|
||||
// we rebuild the closing tx as seen by both parties
|
||||
|
@ -64,4 +64,7 @@ object Register {
|
||||
|
||||
def actorPathToChannels(): ActorPath =
|
||||
Boot.system / "register" / "handler-*" / "channel"
|
||||
|
||||
def actorPathToHandlers(): ActorPath =
|
||||
Boot.system / "register" / "handler-*"
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package fr.acinq.eclair.channel
|
||||
|
||||
import akka.actor.{Actor, ActorLogging}
|
||||
import fr.acinq.bitcoin.BinaryData
|
||||
import lightning._
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
* Created by PM on 24/05/2016.
|
||||
*/
|
||||
class Router extends Actor with ActorLogging {
|
||||
|
||||
import ExecutionContext.Implicits.global
|
||||
context.system.scheduler.schedule(5 seconds, 10 seconds, self, 'tick)
|
||||
|
||||
def receive: Receive = main(Map())
|
||||
|
||||
def main(channels: Map[BinaryData, channel_desc]): Receive = {
|
||||
case r@register_channel(c) =>
|
||||
log.debug(s"received $r")
|
||||
context become main(channels + (BinaryData(c.id.toByteArray) -> c))
|
||||
case u@unregister_channel(c) =>
|
||||
log.debug(s"received $u")
|
||||
context become main(channels - BinaryData(c.id.toByteArray))
|
||||
case 'tick =>
|
||||
val sel = context.actorSelection(Register.actorPathToHandlers())
|
||||
channels.values.foreach(sel ! register_channel(_))
|
||||
case 'network =>
|
||||
sender ! channels.values
|
||||
}
|
||||
|
||||
}
|
@ -155,7 +155,7 @@ class AuthHandler(them: ActorRef, blockchain: ActorRef, our_params: OurChannelPa
|
||||
log.error(s"cannot verify peer signature $their_sig for public key $their_nodeid")
|
||||
context.stop(self)
|
||||
}
|
||||
val channel = context.actorOf(Channel.props(self, blockchain, our_params), name = "channel")
|
||||
val channel = context.actorOf(Channel.props(self, blockchain, our_params, their_nodeid.toString()), name = "channel")
|
||||
goto(IO_NORMAL) using Normal(channel, s.copy(decryptor = decryptor1.copy(header = None, body = None)))
|
||||
}
|
||||
}
|
||||
@ -175,6 +175,8 @@ class AuthHandler(them: ActorRef, blockchain: ActorRef, our_params: OurChannelPa
|
||||
case Event(packet: pkt, n@Normal(channel, s@SessionData(theirpub, decryptor, encryptor))) =>
|
||||
log.debug(s"receiving $packet")
|
||||
packet.pkt match {
|
||||
case RegisterChannel(o) => Boot.router ! o
|
||||
case UnregisterChannel(o) => Boot.router ! o
|
||||
case Open(o) => channel ! o
|
||||
case OpenAnchor(o) => channel ! o
|
||||
case OpenCommitSig(o) => channel ! o
|
||||
@ -193,6 +195,8 @@ class AuthHandler(them: ActorRef, blockchain: ActorRef, our_params: OurChannelPa
|
||||
case Event(msg: GeneratedMessage, n@Normal(channel, s@SessionData(theirpub, decryptor, encryptor))) =>
|
||||
val packet = msg match {
|
||||
case o: open_channel => pkt(Open(o))
|
||||
case o: register_channel => pkt(RegisterChannel(o))
|
||||
case o: unregister_channel => pkt(UnregisterChannel(o))
|
||||
case o: open_anchor => pkt(OpenAnchor(o))
|
||||
case o: open_commit_sig => pkt(OpenCommitSig(o))
|
||||
case o: open_complete => pkt(OpenComplete(o))
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>fr.acinq.eclair</groupId>
|
||||
<artifactId>eclair_2.11</artifactId>
|
||||
<version>0.1-rfc2a-SNAPSHOT</version>
|
||||
<version>0.1-gossip-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>lightning-types_2.11</artifactId>
|
||||
|
@ -7,8 +7,11 @@ syntax = "proto2";
|
||||
// Helper Types
|
||||
//
|
||||
|
||||
import "scalapb/scalapb.proto";
|
||||
|
||||
// Protobufs don't have fixed-length fields, so these are a hack.
|
||||
message sha256_hash {
|
||||
option (scalapb.message).extends = "lightning.Sha256ToString";
|
||||
required fixed64 a = 1;
|
||||
required fixed64 b = 2;
|
||||
required fixed64 c = 3;
|
||||
@ -16,6 +19,7 @@ message sha256_hash {
|
||||
}
|
||||
|
||||
message signature {
|
||||
option (scalapb.message).extends = "lightning.SignatureToString";
|
||||
required fixed64 r1 = 1;
|
||||
required fixed64 r2 = 2;
|
||||
required fixed64 r3 = 3;
|
||||
@ -33,8 +37,11 @@ message locktime {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Pubkey for commitment transaction input.
|
||||
message bitcoin_pubkey {
|
||||
option (scalapb.message).extends = "lightning.PubkeyToString";
|
||||
// Must be 33 bytes.
|
||||
required bytes key = 1;
|
||||
}
|
||||
@ -61,6 +68,22 @@ message authenticate {
|
||||
optional uint64 ack = 3 [ default = 0 ];
|
||||
};
|
||||
|
||||
// Description of a channel
|
||||
message channel_desc {
|
||||
option (scalapb.message).extends = "lightning.ChannelDescToString";
|
||||
required bytes id = 1;
|
||||
required bytes node_id_a = 2;
|
||||
required bytes node_id_b = 3;
|
||||
}
|
||||
|
||||
message register_channel {
|
||||
required channel_desc channel = 1;
|
||||
}
|
||||
|
||||
message unregister_channel {
|
||||
required channel_desc channel = 1;
|
||||
}
|
||||
|
||||
// Set channel params.
|
||||
message open_channel {
|
||||
// Relative locktime for outputs going to us.
|
||||
@ -190,6 +213,11 @@ message pkt {
|
||||
oneof pkt {
|
||||
// Start of connection
|
||||
authenticate auth = 50;
|
||||
|
||||
// Gossip
|
||||
register_channel register_channel = 10;
|
||||
unregister_channel unregister_channel = 11;
|
||||
|
||||
// Opening
|
||||
open_channel open = 20;
|
||||
open_anchor open_anchor = 21;
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
package lightning
|
||||
|
||||
import java.io.{OutputStream, ByteArrayOutputStream}
|
||||
import java.io.{ByteArrayOutputStream, OutputStream}
|
||||
import java.math.BigInteger
|
||||
import javax.xml.bind.DatatypeConverter
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
|
||||
|
||||
object ToStrings {
|
||||
def writeUInt8(input: Long, out: OutputStream): Unit = out.write((input & 0xff).asInstanceOf[Int])
|
||||
@ -75,3 +77,19 @@ trait SignatureToString {
|
||||
s"signature(r=${DatatypeConverter.printHexBinary(r.toByteArray)},s=${DatatypeConverter.printHexBinary(s.toByteArray)})"
|
||||
}
|
||||
}
|
||||
|
||||
trait PubkeyToString {
|
||||
|
||||
def key: ByteString
|
||||
|
||||
override def toString = s"bitcoin_pubkey(${DatatypeConverter.printHexBinary(key.toByteArray)})"
|
||||
}
|
||||
|
||||
trait ChannelDescToString {
|
||||
|
||||
def id: ByteString
|
||||
def nodeIdA: ByteString
|
||||
def nodeIdB: ByteString
|
||||
|
||||
override def toString = s"channel_desc(id=${DatatypeConverter.printHexBinary(id.toByteArray)},a=${DatatypeConverter.printHexBinary(nodeIdA.toByteArray)},b=${DatatypeConverter.printHexBinary(nodeIdB.toByteArray)})"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user