From d5640fdd070d2d1a1a6acd29b30ce4a9ce53f13a Mon Sep 17 00:00:00 2001 From: pm47 Date: Mon, 24 Aug 2015 18:06:04 +0200 Subject: [PATCH] dummy impl non-functional, compiles and run --- eclair-demo/pom.xml | 6 + eclair-demo/src/main/resources/logback.xml | 56 +++++++ .../src/main/scala/fr/acinq/eclair/Boot.scala | 54 ++----- .../src/main/scala/fr/acinq/eclair/Node.scala | 148 ++++++++++++++---- .../scala/fr/acinq/lightning/package.scala | 23 ++- 5 files changed, 206 insertions(+), 81 deletions(-) create mode 100644 eclair-demo/src/main/resources/logback.xml diff --git a/eclair-demo/pom.xml b/eclair-demo/pom.xml index 08ec52b11..5e0846282 100644 --- a/eclair-demo/pom.xml +++ b/eclair-demo/pom.xml @@ -50,5 +50,11 @@ logback-classic 1.1.3 + + + janino + janino + 2.5.10 + diff --git a/eclair-demo/src/main/resources/logback.xml b/eclair-demo/src/main/resources/logback.xml new file mode 100644 index 000000000..9a9e8409f --- /dev/null +++ b/eclair-demo/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + System.out + false + + + return logger.contains("Node"); + + DENY + ACCEPT + + + %yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %msg%ex{12}%n + + + + + System.out + false + + + return ((String) mdc.get("akkaSource")).contains("alice"); + + DENY + ACCEPT + + + %yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %blue(%msg) %ex{12}%n + + + + + System.out + false + + + return ((String) mdc.get("akkaSource")).contains("bob"); + + DENY + ACCEPT + + + %yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %red(%msg) %ex{12}%n + + + + + + + + + + + \ No newline at end of file diff --git a/eclair-demo/src/main/scala/fr/acinq/eclair/Boot.scala b/eclair-demo/src/main/scala/fr/acinq/eclair/Boot.scala index f34ab6a69..966c145f0 100644 --- a/eclair-demo/src/main/scala/fr/acinq/eclair/Boot.scala +++ b/eclair-demo/src/main/scala/fr/acinq/eclair/Boot.scala @@ -1,10 +1,8 @@ package fr.acinq.eclair import akka.actor.{Props, ActorSystem} -import com.google.protobuf.ByteString -import lightning._ -import lightning.locktime.Locktime._ -import lightning.open_channel.anchor_offer.WILL_CREATE_ANCHOR +import lightning.sha256_hash +import org.bouncycastle.util.encoders.Hex /** * Created by PM on 20/08/2015. @@ -13,46 +11,18 @@ object Boot extends App { val system = ActorSystem() - val node = system.actorOf(Props(classOf[Node])) + val alice = system.actorOf(Props(new Node(Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), Hex.decode("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), INIT_WITHANCHOR)), name = "alice") + val bob = system.actorOf(Props(new Node(Hex.decode("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"), Hex.decode("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), INIT_NOANCHOR)), name = "bob") - node ! open_channel( - delay = locktime(Blocks(1)), - revocationHash = sha256_hash(1, 1, 1, 1), - commitKey = bitcoin_pubkey(ByteString.copyFromUtf8("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")), - finalKey = bitcoin_pubkey(ByteString.copyFromUtf8("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")), - anch = WILL_CREATE_ANCHOR, - minDepth = Some(2), - commitmentFee = 100) + bob.tell(INPUT_NONE, alice) + alice.tell(INPUT_NONE, bob) - node ! open_anchor( - txid = sha256_hash(1, 1, 1, 1), - outputIndex = 1, - amount = 100000000L, - commitSig = signature(1, 1, 1, 1, 0, 0, 0, 0)) + Thread.sleep(3000) + alice ! TxConfirmed(sha256_hash(1, 2, 3, 4), 1) + bob ! TxConfirmed(sha256_hash(1, 2, 3, 4), 1) - node ! TxConfirmed(1) - node ! TxConfirmed(2) + Thread.sleep(2000) + alice ! TxConfirmed(sha256_hash(1, 2, 3, 4), 2) + bob ! TxConfirmed(sha256_hash(1, 2, 3, 4), 2) - node ! open_complete( - blockid = Some(sha256_hash(1, 1, 1, 1)) - ) - - node ! update_add_htlc( - revocationHash = sha256_hash(1, 1, 1, 1), - amount = 1000, - rHash = sha256_hash(1, 1, 1, 1), - expiry = locktime(Blocks(4))) - - node ! update_signature( - sig = signature(1, 1, 1, 1, 0, 0, 0, 0), - revocationPreimage = sha256_hash(1, 1, 1, 1)) - - // this is sent by the next node - node ! update_complete_htlc( - revocationHash = sha256_hash(1, 1, 1, 1), - r = sha256_hash(1, 1, 1, 1)) - - node ! update_signature( - sig = signature(1, 1, 1, 1, 0, 0, 0, 0), - revocationPreimage = sha256_hash(1, 1, 1, 1)) } diff --git a/eclair-demo/src/main/scala/fr/acinq/eclair/Node.scala b/eclair-demo/src/main/scala/fr/acinq/eclair/Node.scala index aee4b1319..b821d8926 100644 --- a/eclair-demo/src/main/scala/fr/acinq/eclair/Node.scala +++ b/eclair-demo/src/main/scala/fr/acinq/eclair/Node.scala @@ -1,11 +1,16 @@ package fr.acinq.eclair -import akka.actor.{LoggingFSM, FSM} +import akka.actor.{ActorRef, LoggingFSM} import com.google.protobuf.ByteString -import fr.acinq.bitcoin.Transaction +import fr.acinq.bitcoin.Crypto._ +import fr.acinq.bitcoin._ +import fr.acinq.lightning._ import lightning._ import lightning.locktime.Locktime.Blocks -import lightning.open_channel.anchor_offer.WILL_CREATE_ANCHOR +import lightning.open_channel.anchor_offer.{WILL_CREATE_ANCHOR, WONT_CREATE_ANCHOR} +import org.bouncycastle.util.encoders.Hex + +import scala.util.Try /** * Created by PM on 20/08/2015. @@ -15,9 +20,13 @@ import lightning.open_channel.anchor_offer.WILL_CREATE_ANCHOR sealed trait State case object INIT_NOANCHOR extends State +case object INIT_WITHANCHOR extends State case object OPEN_WAIT_FOR_OPEN_NOANCHOR extends State +case object OPEN_WAIT_FOR_OPEN_WITHANCHOR extends State case object OPEN_WAIT_FOR_ANCHOR extends State -case object OPEN_WAITING extends State +case object OPEN_WAIT_FOR_COMMIT_SIG extends State +case object OPEN_WAITING_THEIRANCHOR extends State +case object OPEN_WAITING_OURANCHOR extends State case object OPEN_WAIT_FOR_COMPLETE extends State case object NORMAL extends State case object WAIT_FOR_HTLC_ACCEPT extends State @@ -30,7 +39,7 @@ case object CLOSED extends State case object INPUT_NONE sealed trait BlockchainEvent -final case class TxConfirmed(confirmations: Int) +final case class TxConfirmed(blockId: sha256_hash, confirmations: Int) sealed trait Commands final case class SendHtlcUpdate(amount: Long, finalPayee: String, rHash: sha256_hash) @@ -40,68 +49,143 @@ final case class SendHtlcUpdate(amount: Long, finalPayee: String, rHash: sha256_ sealed trait Data case object Uninitialized extends Data final case class ChannelParams(delay: locktime, commitKey: bitcoin_pubkey, finalKey: bitcoin_pubkey, minDepth: Int, commitmentFee: Long) -final case class Anchor(txid: sha256_hash, outputIndex: Int, amount: Long) -final case class CommitmentTx(tx: Transaction, theirSig: signature, ourRevocationPreimage: sha256_hash) +final case class Anchor(txid: sha256_hash, outputIndex: Int, amount: Long, pubKeyScript: Seq[ScriptElt]) +final case class CommitmentTx(tx: Transaction, ourRevocationPreimage: sha256_hash) final case class DATA_OPEN_WAIT_FOR_OPEN_NOANCHOR(ourParams: ChannelParams, ourRevocationPreimage: sha256_hash) extends Data +final case class DATA_OPEN_WAIT_FOR_OPEN_WITHANCHOR(ourParams: ChannelParams, ourRevocationPreimage: sha256_hash) extends Data final case class DATA_OPEN_WAIT_FOR_ANCHOR(ourParams: ChannelParams, theirParams: ChannelParams, ourRevocationPreimage: sha256_hash, theirRevocationHash: sha256_hash) extends Data +final case class DATA_OPEN_WAIT_FOR_COMMIT_SIG(ourParams: ChannelParams, theirParams: ChannelParams, anchor: Anchor, ourRevocationPreimage: sha256_hash, theirRevocationHash: sha256_hash) extends Data final case class DATA_OPEN_WAITING(ourParams: ChannelParams, theirParams: ChannelParams, anchor: Anchor, commitmentTx: CommitmentTx, otherPartyOpen: Boolean = false) extends Data final case class DATA_NORMAL(ourParams: ChannelParams, theirParams: ChannelParams, anchor: Anchor, commitmentTx: CommitmentTx) extends Data // -class Node extends LoggingFSM[State, Data] { +class Node(val commitPrivKey: BinaryData, val finalPrivKey: BinaryData, val initialState: State = INIT_NOANCHOR) extends LoggingFSM[State, Data] { val DEFAULT_delay = locktime(Blocks(1)) - val DEFAULT_commitKey = bitcoin_pubkey(ByteString.copyFromUtf8("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) - val DEFAULT_finalKey = bitcoin_pubkey(ByteString.copyFromUtf8("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")) val DEFAULT_minDepth = 2 val DEFAULT_commitmentFee = 100 - startWith(INIT_NOANCHOR, Uninitialized) + val commitPubKey = bitcoin_pubkey(ByteString.copyFrom(Crypto.publicKeyFromPrivateKey(commitPrivKey.key.toByteArray))) + val finalPubKey = bitcoin_pubkey(ByteString.copyFrom(Crypto.publicKeyFromPrivateKey(finalPrivKey.key.toByteArray))) + + // TODO + var them: ActorRef = null + + startWith(initialState, Uninitialized) when(INIT_NOANCHOR) { case Event(INPUT_NONE, _) => - val ourParams = ChannelParams(DEFAULT_delay, DEFAULT_commitKey, DEFAULT_finalKey, DEFAULT_minDepth, DEFAULT_commitmentFee) - val ourRevocationHashPreimage = sha256_hash(1, 1, 1, 1) - val ourRevocationHash = sha256_hash(1, 1, 1, 1) - // TODO : send open_channel(delay, ourRevocationHash, commitKey, finalKey, WONT_CREATE_ANCHOR, minDepth, commitmentFee) + them = sender + val ourParams = ChannelParams(DEFAULT_delay, commitPubKey, finalPubKey, DEFAULT_minDepth, DEFAULT_commitmentFee) + val ourRevocationHashPreimage = sha256_hash(1, 2, 3, 4) //TODO : should be random + val ourRevocationHash = Crypto.sha256(ourRevocationHashPreimage) + sender ! open_channel(ourParams.delay, ourRevocationHash, ourParams.commitKey, ourParams.finalKey, WONT_CREATE_ANCHOR, Some(ourParams.minDepth), ourParams.commitmentFee) goto(OPEN_WAIT_FOR_OPEN_NOANCHOR) using DATA_OPEN_WAIT_FOR_OPEN_NOANCHOR(ourParams, ourRevocationHashPreimage) } + when(INIT_WITHANCHOR) { + case Event(INPUT_NONE, _) => + them = sender + val ourParams = ChannelParams(DEFAULT_delay, commitPubKey, finalPubKey, DEFAULT_minDepth, DEFAULT_commitmentFee) + val ourRevocationHashPreimage = sha256_hash(1, 2, 3, 4) //TODO : should be random + val ourRevocationHash = Crypto.sha256(ourRevocationHashPreimage) + sender ! open_channel(ourParams.delay, ourRevocationHash, ourParams.commitKey, ourParams.finalKey, WILL_CREATE_ANCHOR, Some(ourParams.minDepth), ourParams.commitmentFee) + goto(OPEN_WAIT_FOR_OPEN_WITHANCHOR) using DATA_OPEN_WAIT_FOR_OPEN_WITHANCHOR(ourParams, ourRevocationHashPreimage) + } + when(OPEN_WAIT_FOR_OPEN_NOANCHOR) { case Event(open_channel(delay, revocationHash, commitKey, finalKey, WILL_CREATE_ANCHOR, minDepth, commitmentFee), DATA_OPEN_WAIT_FOR_OPEN_NOANCHOR(ourParams, ourRevocationPreimage)) => val theirParams = ChannelParams(delay, commitKey, finalKey, minDepth.get, commitmentFee) goto(OPEN_WAIT_FOR_ANCHOR) using DATA_OPEN_WAIT_FOR_ANCHOR(ourParams, theirParams, ourRevocationPreimage, revocationHash) } - when(OPEN_WAIT_FOR_ANCHOR) { - case Event(open_anchor(txid, outputIndex, amount, commitSig), DATA_OPEN_WAIT_FOR_ANCHOR(ourParams, theirParams, ourRevocationPreimage, theirRevocationHash)) => - val anchor = Anchor(txid, outputIndex, amount) - // TODO : build our commitment tx and check counterparty's sig - // TODO : build counterparty's commitment tx and sign it - val ourSig = signature(1, 1, 1, 1, 0, 0, 0, 0) - // TODO : reply with open_commit_sig(sig) - // TODO : register for confirmations of anchor tx on the bitcoin network - goto(OPEN_WAITING) using DATA_OPEN_WAITING(ourParams, theirParams, anchor, null, false) + when(OPEN_WAIT_FOR_OPEN_WITHANCHOR) { + case Event(open_channel(delay, revocationHash, commitKey, finalKey, WONT_CREATE_ANCHOR, minDepth, commitmentFee), DATA_OPEN_WAIT_FOR_OPEN_WITHANCHOR(ourParams, ourRevocationHashPreimage)) => + val theirParams = ChannelParams(delay, commitKey, finalKey, minDepth.get, commitmentFee) + // TODO create the anchor + val anchor = Anchor(sha256_hash(1, 2, 3, 4), 0, 100000, OP_HASH160 :: OP_PUSHDATA(hash160(Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))))) :: OP_EQUAL :: Nil) + // then we build their commitment tx and sign it + val state = ChannelState(ChannelOneSide(anchor.amount, 0, Seq()), ChannelOneSide(0, 0, Seq())) + val theirCommitTx = makeCommitTx(theirParams.finalKey, ourParams.finalKey, ourParams.delay, anchor.txid, anchor.outputIndex, Crypto.sha256(ourRevocationHashPreimage), state.copy(a = state.b, b = state.a)) + val ourSig = bin2signature(Transaction.signInput(theirCommitTx, 0, Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))), SIGHASH_ALL, pubkey2bin(commitPrivKey))) + sender ! open_anchor(anchor.txid, anchor.outputIndex, anchor.amount, ourSig) + goto(OPEN_WAIT_FOR_COMMIT_SIG) using DATA_OPEN_WAIT_FOR_COMMIT_SIG(ourParams, theirParams, anchor, ourRevocationHashPreimage, revocationHash) } - when(OPEN_WAITING) { - case Event(TxConfirmed(confirmations), DATA_OPEN_WAITING(ourParams, _, _, _, _)) if confirmations < ourParams.minDepth => + when(OPEN_WAIT_FOR_ANCHOR) { + case Event(open_anchor(txid, outputIndex, amount, commitSig), DATA_OPEN_WAIT_FOR_ANCHOR(ourParams, theirParams, ourRevocationHashPreimage, theirRevocationHash)) => + val anchor = Anchor(txid, outputIndex, amount, OP_HASH160 :: OP_PUSHDATA(hash160(Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))))) :: OP_EQUAL :: Nil) + val state = ChannelState(ChannelOneSide(amount, 0, Seq()), ChannelOneSide(0, 0, Seq())) + // we build our commitment tx, sign it and check that it is spendable using the counterparty's sig + val ourCommitTx = makeCommitTx(ourParams.finalKey, theirParams.finalKey, theirParams.delay, anchor.txid, anchor.outputIndex, theirRevocationHash, state) + val sigB = Transaction.signInput(ourCommitTx, 0, Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))), SIGHASH_ALL, pubkey2bin(commitPrivKey)) + val scriptSig = Script.write(OP_0 :: OP_PUSHDATA(commitSig) :: OP_PUSHDATA(sigB) :: OP_PUSHDATA(Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey)))) :: Nil) + val signedCommitTx = ourCommitTx.updateSigScript(0, scriptSig) + val ok = Try(Transaction.correctlySpends(signedCommitTx, Map(OutPoint(txid, outputIndex) -> BinaryData(Script.write(anchor.pubKeyScript))), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)).isSuccess + // TODO : return Error and close channel if !ok + // then we build their commitment tx and sign it + val theirCommitTx = makeCommitTx(theirParams.finalKey, ourParams.finalKey, ourParams.delay, anchor.txid, anchor.outputIndex, Crypto.sha256(ourRevocationHashPreimage), state.copy(a = state.b, b = state.a)) + val ourSig = bin2signature(Transaction.signInput(theirCommitTx, 0, Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))), SIGHASH_ALL, pubkey2bin(commitPrivKey))) + sender ! open_commit_sig(ourSig) + // TODO : register for confirmations of anchor tx on the bitcoin network + goto(OPEN_WAITING_THEIRANCHOR) using DATA_OPEN_WAITING(ourParams, theirParams, anchor, CommitmentTx(ourCommitTx, ourRevocationHashPreimage), false) + } + + when(OPEN_WAIT_FOR_COMMIT_SIG) { + case Event(open_commit_sig(theirSig), DATA_OPEN_WAIT_FOR_COMMIT_SIG(ourParams, theirParams, anchor, ourRevocationHashPreimage, theirRevocationHash)) => + val state = ChannelState(ChannelOneSide(anchor.amount, 0, Seq()), ChannelOneSide(0, 0, Seq())) + // we build our commitment tx, sign it and check that it is spendable using the counterparty's sig + val ourCommitTx = makeCommitTx(ourParams.finalKey, theirParams.finalKey, theirParams.delay, anchor.txid, anchor.outputIndex, theirRevocationHash, state) + val sigB = Transaction.signInput(ourCommitTx, 0, Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey))), SIGHASH_ALL, pubkey2bin(commitPrivKey)) + val scriptSig = Script.write(OP_0 :: OP_PUSHDATA(theirSig) :: OP_PUSHDATA(sigB) :: OP_PUSHDATA(Script.createMultiSigMofN(2, Seq(pubkey2bin(theirParams.commitKey), pubkey2bin(ourParams.commitKey)))) :: Nil) + val signedCommitTx = ourCommitTx.updateSigScript(0, scriptSig) + val ok = Try(Transaction.correctlySpends(signedCommitTx, Map(OutPoint(anchor.txid, anchor.outputIndex) -> BinaryData(Script.write(anchor.pubKeyScript))), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)).isSuccess + // TODO : return Error and close channel if !ok + goto(OPEN_WAITING_OURANCHOR) using DATA_OPEN_WAITING(ourParams, theirParams, anchor, CommitmentTx(ourCommitTx, ourRevocationHashPreimage), false) + } + + when(OPEN_WAITING_THEIRANCHOR) { + case Event(TxConfirmed(blockId, confirmations), DATA_OPEN_WAITING(ourParams, _, _, _, _)) if confirmations < ourParams.minDepth => + // TODO : check anchor pub key script log.info(s"got $confirmations confirmation(s) for anchor tx") stay - case Event(TxConfirmed(confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, false)) if confirmations >= ourParams.minDepth => + case Event(TxConfirmed(blockId, confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, false)) if confirmations >= ourParams.minDepth => + // TODO : check anchor pub key script log.info(s"got $confirmations confirmation(s) for anchor tx, minDepth reached") - // TODO : send open_complete(blockid) + them ! open_complete(Some(blockId)) goto(OPEN_WAIT_FOR_COMPLETE) using DATA_NORMAL(d.ourParams, d.theirParams, d.anchor, d.commitmentTx) - case Event(TxConfirmed(confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, true)) if confirmations >= ourParams.minDepth => + case Event(TxConfirmed(blockId, confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, true)) if confirmations >= ourParams.minDepth => log.info(s"got $confirmations confirmation(s) for anchor tx, minDepth reached, and already received their open_complete") - // TODO : send open_complete(blockid) + them ! open_complete(Some(blockId)) goto(NORMAL) using DATA_NORMAL(d.ourParams, d.theirParams, d.anchor, d.commitmentTx) - case Event(open_complete(blockid_opt), d@DATA_OPEN_WAITING(ourParams, _, _, _, _)) => - log.info(s"received their open_complete") + case Event(open_complete(blockId_opt), d@DATA_OPEN_WAITING(ourParams, _, _, _, _)) => + log.info(s"received their open_complete, blockId=${blockId_opt.map(x => Hex.toHexString(sha2562bin(x))).getOrElse("unknown")}") + stay using d.copy(otherPartyOpen = true) + } + + when(OPEN_WAITING_OURANCHOR) { + case Event(TxConfirmed(blockId, confirmations), DATA_OPEN_WAITING(ourParams, _, _, _, _)) if confirmations < ourParams.minDepth => + // TODO : check anchor pub key script + log.info(s"got $confirmations confirmation(s) for anchor tx") + stay + + case Event(TxConfirmed(blockId, confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, false)) if confirmations >= ourParams.minDepth => + // TODO : check anchor pub key script + log.info(s"got $confirmations confirmation(s) for anchor tx, minDepth reached") + them ! open_complete(Some(blockId)) + goto(OPEN_WAIT_FOR_COMPLETE) using DATA_NORMAL(d.ourParams, d.theirParams, d.anchor, d.commitmentTx) + + case Event(TxConfirmed(blockId, confirmations), d@DATA_OPEN_WAITING(ourParams, _, _, _, true)) if confirmations >= ourParams.minDepth => + log.info(s"got $confirmations confirmation(s) for anchor tx, minDepth reached, and already received their open_complete") + them ! open_complete(Some(blockId)) + goto(NORMAL) using DATA_NORMAL(d.ourParams, d.theirParams, d.anchor, d.commitmentTx) + + case Event(open_complete(blockId_opt), d@DATA_OPEN_WAITING(ourParams, _, _, _, _)) => + log.info(s"received their open_complete, blockId=${blockId_opt.map(x => Hex.toHexString(sha2562bin(x))).getOrElse("unknown")}") stay using d.copy(otherPartyOpen = true) } diff --git a/eclair-demo/src/main/scala/fr/acinq/lightning/package.scala b/eclair-demo/src/main/scala/fr/acinq/lightning/package.scala index e738dc242..198515be0 100644 --- a/eclair-demo/src/main/scala/fr/acinq/lightning/package.scala +++ b/eclair-demo/src/main/scala/fr/acinq/lightning/package.scala @@ -35,6 +35,9 @@ package object lightning { bos.toByteArray } + // TODO : redundant with above, needed for seamless Crypto.sha256(sha256_hash) + implicit def sha2562seq(in: sha256_hash): Seq[Byte] = sha2562bin(in) + implicit def bin2pubkey(in: BinaryData) = bitcoin_pubkey(ByteString.copyFrom(in)) implicit def array2pubkey(in: Array[Byte]) = bin2pubkey(in) @@ -132,24 +135,28 @@ package object lightning { // @formatter:on } - def makeCommitTx(ours: open_channel, theirs: open_channel, anchor: open_anchor, rhash: BinaryData, channelState: ChannelState): Transaction = { - val txIn = TxIn(OutPoint(sha2562bin(anchor.txid), anchor.outputIndex), Array.emptyByteArray, 0xffffffffL) - val redeemScript = redeemSecretOrDelay(ours.finalKey, theirs.delay, theirs.finalKey, rhash) + //TODO : do we really need this ? + def makeCommitTx(ours: open_channel, theirs: open_channel, anchor: open_anchor, rhash: BinaryData, channelState: ChannelState): Transaction = + makeCommitTx(ours.finalKey, theirs.finalKey, theirs.delay, anchor.txid, anchor.outputIndex, rhash, channelState) + + def makeCommitTx(ourFinalKey: BinaryData, theirFinalKey: BinaryData, theirDelay: Long, anchorTxId: BinaryData, anchorOutputIndex: Int, rhash: BinaryData, channelState: ChannelState): Transaction = { + val txIn = TxIn(OutPoint(anchorTxId, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) + val redeemScript = redeemSecretOrDelay(ourFinalKey, theirDelay, theirFinalKey, rhash) val tx = Transaction( version = 1, - txIn = TxIn(OutPoint(sha2562bin(anchor.txid), anchor.outputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, + txIn = TxIn(OutPoint(anchorTxId, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, txOut = Seq( TxOut(amount = channelState.a.pay, publicKeyScript = pay2sh(redeemScript)), - TxOut(amount = channelState.b.pay, publicKeyScript = pay2sh(OP_PUSHDATA(theirs.finalKey) :: OP_CHECKSIG :: Nil)) + TxOut(amount = channelState.b.pay, publicKeyScript = pay2sh(OP_PUSHDATA(theirFinalKey) :: OP_CHECKSIG :: Nil)) ), lockTime = 0) val sendOuts = channelState.a.htlcs.map(htlc => { - TxOut(htlc.amount, pay2sh(scriptPubKeyHtlcSend(ours.finalKey, theirs.finalKey, htlc.amount, htlc.expiry, theirs.delay, rhash, htlc.revocationHash))) + TxOut(htlc.amount, pay2sh(scriptPubKeyHtlcSend(ourFinalKey, theirFinalKey, htlc.amount, htlc.expiry, theirDelay, rhash, htlc.revocationHash))) }) val receiveOuts = channelState.b.htlcs.map(htlc => { - TxOut(htlc.amount, pay2sh(scriptPubKeyHtlcReceive(ours.finalKey, theirs.finalKey, htlc.amount, htlc.expiry, theirs.delay, rhash, htlc.revocationHash))) + TxOut(htlc.amount, pay2sh(scriptPubKeyHtlcReceive(ourFinalKey, theirFinalKey, htlc.amount, htlc.expiry, theirDelay, rhash, htlc.revocationHash))) }) val tx1 = tx.copy(txOut = tx.txOut ++ sendOuts ++ receiveOuts) tx1 @@ -163,3 +170,5 @@ package object lightning { if (isFunder(a)) ChannelState(c1, c2) else ChannelState(c2, c1) } } + +