1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-20 02:27:32 +01:00

dummy impl non-functional, compiles and run

This commit is contained in:
pm47 2015-08-24 18:06:04 +02:00
parent 2899aff02d
commit d5640fdd07
5 changed files with 206 additions and 81 deletions

View File

@ -50,5 +50,11 @@
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<!--conditional logging -->
<groupId>janino</groupId>
<artifactId>janino</artifactId>
<version>2.5.10</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" debug="false">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<withJansi>false</withJansi>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return logger.contains("Node");</expression>
</evaluator>
<OnMatch>DENY</OnMatch>
<OnMismatch>ACCEPT</OnMismatch>
</filter>
<encoder>
<pattern>%yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %msg%ex{12}%n</pattern>
</encoder>
</appender>
<appender name="ALICE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<withJansi>false</withJansi>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return ((String) mdc.get("akkaSource")).contains("alice");</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<encoder>
<pattern>%yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %blue(%msg) %ex{12}%n</pattern>
</encoder>
</appender>
<appender name="BOB" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<withJansi>false</withJansi>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return ((String) mdc.get("akkaSource")).contains("bob");</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<encoder>
<pattern>%yellow(${HOSTNAME} %d) %highlight(%-5level) %logger{36} %X{akkaSource} - %red(%msg) %ex{12}%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="ALICE"/>
<appender-ref ref="BOB"/>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

View File

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

View File

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

View File

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