1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-23 14:40:34 +01:00

Wip bolt2 nakamoto (#9)

* use lightning.proto from lightning-c v0.3-2016-05-26 "Nakamoto's Genesis Coins"

* check that preimage size is 32 bytes (see 1245ffaae3 and
https://lists.linuxfoundation.org/pipermail/lightning-dev/2016-May/000529.html)
This commit is contained in:
Fabrice Drouin 2016-05-27 18:30:22 +02:00 committed by Pierre-Marie Padiou
parent 0396b5589d
commit b055df5338
5 changed files with 20 additions and 36 deletions

View file

@ -64,18 +64,16 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, val params: OurChann
log.info(s"anchor txid=${anchorTx.txid}")
val amount = anchorTx.txOut(anchorOutputIndex).amount.toLong
val theirSpec = CommitmentSpec(Set.empty[Htlc], feeRate = theirParams.initialFeeRate, initial_amount_us_msat = 0, initial_amount_them_msat = amount * 1000, amount_us_msat = 0, amount_them_msat = amount * 1000)
val theirTx = makeTheirTx(ourParams, theirParams, TxIn(OutPoint(anchorTx.hash, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, theirRevocationHash, theirSpec)
val ourSig = sign(ourParams, theirParams, amount, theirTx)
them ! open_anchor(anchorTx.hash, anchorOutputIndex, amount, ourSig)
them ! open_anchor(anchorTx.hash, anchorOutputIndex, amount)
goto(OPEN_WAIT_FOR_COMMIT_SIG) using DATA_OPEN_WAIT_FOR_COMMIT_SIG(ourParams, theirParams, anchorTx, anchorOutputIndex, TheirCommit(0, theirSpec, theirRevocationHash), theirNextRevocationHash)
case Event(CMD_CLOSE(_), _) => goto(CLOSED)
}
when(OPEN_WAIT_FOR_ANCHOR) {
case Event(open_anchor(anchorTxHash, anchorOutputIndex, anchorAmount, theirSig), DATA_OPEN_WAIT_FOR_ANCHOR(ourParams, theirParams, theirRevocationHash, theirNextRevocationHash)) =>
case Event(open_anchor(anchorTxHash, anchorOutputIndex, anchorAmount), DATA_OPEN_WAIT_FOR_ANCHOR(ourParams, theirParams, theirRevocationHash, theirNextRevocationHash)) =>
val anchorTxid = anchorTxHash.reverse //see https://github.com/ElementsProject/lightning/issues/17
val anchorOutput = TxOut(Satoshi(anchorAmount), publicKeyScript = Scripts.anchorPubkeyScript(ourParams.commitPubKey, theirParams.commitPubKey))
val anchorOutput = TxOut(Satoshi(anchorAmount), publicKeyScript = Scripts.anchorPubkeyScript(ourParams.commitPubKey, theirParams.commitPubKey))
// they fund the channel with their anchor tx, so the money is theirs
val ourSpec = CommitmentSpec(Set.empty[Htlc], feeRate = ourParams.initialFeeRate, initial_amount_them_msat = anchorAmount * 1000, initial_amount_us_msat = 0, amount_them_msat = anchorAmount * 1000, amount_us_msat = 0)
@ -84,21 +82,14 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, val params: OurChann
// we build our commitment tx, sign it and check that it is spendable using the counterparty's sig
val ourRevocationHash = Crypto.sha256(ShaChain.shaChainFromSeed(ourParams.shaSeed, 0))
val ourTx = makeOurTx(ourParams, theirParams, TxIn(OutPoint(anchorTxHash, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, ourRevocationHash, ourSpec)
val ourSig = sign(ourParams, theirParams, anchorAmount, ourTx)
val signedTx = addSigs(ourParams, theirParams, anchorAmount, ourTx, ourSig, theirSig)
checksig(ourParams, theirParams, anchorOutput, signedTx) match {
case false =>
them ! error(Some("Bad signature"))
goto(CLOSED)
case true =>
val theirTx = makeTheirTx(ourParams, theirParams, TxIn(OutPoint(anchorTxHash, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, theirRevocationHash, theirSpec)
log.info(s"signing their tx: $theirTx")
val ourSigForThem = sign(ourParams, theirParams, anchorAmount, theirTx)
them ! open_commit_sig(ourSigForThem)
blockchain ! WatchConfirmed(self, anchorTxid, ourParams.minDepth, BITCOIN_ANCHOR_DEPTHOK)
blockchain ! WatchSpent(self, anchorTxid, anchorOutputIndex, 0, BITCOIN_ANCHOR_SPENT)
goto(OPEN_WAITING_THEIRANCHOR) using DATA_OPEN_WAITING(ourParams, theirParams, ShaChain.init, OurCommit(0, ourSpec, signedTx), TheirCommit(0, theirSpec, theirRevocationHash), theirNextRevocationHash, None, anchorOutput)
}
val theirTx = makeTheirTx(ourParams, theirParams, TxIn(OutPoint(anchorTxHash, anchorOutputIndex), Array.emptyByteArray, 0xffffffffL) :: Nil, theirRevocationHash, theirSpec)
log.info(s"signing their tx: $theirTx")
val ourSigForThem = sign(ourParams, theirParams, anchorAmount, theirTx)
them ! open_commit_sig(ourSigForThem)
blockchain ! WatchConfirmed(self, anchorTxid, ourParams.minDepth, BITCOIN_ANCHOR_DEPTHOK)
blockchain ! WatchSpent(self, anchorTxid, anchorOutputIndex, 0, BITCOIN_ANCHOR_SPENT)
// FIXME: ourTx is not signed by them and cannot be published
goto(OPEN_WAITING_THEIRANCHOR) using DATA_OPEN_WAITING(ourParams, theirParams, ShaChain.init, OurCommit(0, ourSpec, ourTx), TheirCommit(0, theirSpec, theirRevocationHash), theirNextRevocationHash, None, anchorOutput)
case Event(CMD_CLOSE(_), _) => goto(CLOSED)
}

View file

@ -116,6 +116,7 @@ object Scripts {
def scriptPubKeyHtlcSend(ourkey: BinaryData, theirkey: BinaryData, abstimeout: Long, reltimeout: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
// @formatter:off
OP_SIZE :: OP_PUSHDATA(Script.encodeNumber(32)) :: OP_EQUALVERIFY ::
OP_HASH160 :: OP_DUP ::
OP_PUSHDATA(ripemd160(rhash)) :: OP_EQUAL ::
OP_SWAP :: OP_PUSHDATA(ripemd160(commit_revoke)) :: OP_EQUAL :: OP_ADD ::
@ -130,6 +131,7 @@ object Scripts {
def scriptPubKeyHtlcReceive(ourkey: BinaryData, theirkey: BinaryData, abstimeout: Long, reltimeout: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
// @formatter:off
OP_SIZE :: OP_PUSHDATA(Script.encodeNumber(32)) :: OP_EQUALVERIFY ::
OP_HASH160 :: OP_DUP ::
OP_PUSHDATA(ripemd160(rhash)) :: OP_EQUAL ::
OP_IF ::

View file

@ -14,7 +14,7 @@ class ClaimReceivedHtlcSpec extends FunSuite {
val (_, finalKey) = Base58Check.decode("cRUfvpbRtMSqCFD1ADdvgPn5HfRLYuHCFYAr2noWnaRDNger2AoA")
val commitPubKey = Crypto.publicKeyFromPrivateKey(commitKey)
val finalPubKey = Crypto.publicKeyFromPrivateKey(finalKey)
val R = "this is Alice's R".getBytes("UTF-8")
val R = Crypto.sha256("this is Alice's R".getBytes("UTF-8"))
val Rhash = Crypto.sha256(R)
val H = Crypto.hash160(R)
val revokeCommit = "Alice foo".getBytes("UTF-8")
@ -26,7 +26,7 @@ class ClaimReceivedHtlcSpec extends FunSuite {
val (_, finalKey) = Base58Check.decode("cQLk5fMydgVwJjygt9ta8GcUU4GXLumNiXJCQviibs2LE5vyMXey")
val commitPubKey = Crypto.publicKeyFromPrivateKey(commitKey)
val finalPubKey = Crypto.publicKeyFromPrivateKey(finalKey)
val R: BinaryData = "this is Bob's R".getBytes("UTF-8")
val R: BinaryData = Crypto.sha256("this is Bob's R".getBytes("UTF-8"))
val Rhash: BinaryData = Crypto.sha256(R)
val H: BinaryData = Crypto.hash160(R)
val revokeCommit: BinaryData = Crypto.sha256("Alice revocation R".getBytes("UTF-8"))

View file

@ -81,24 +81,18 @@ class ProtocolSpec extends FunSuite {
initialFeeRate = 1)
// we assume that Alice knows Bob's H
val openAnchor = open_anchor(anchor.hash, anchorOutputIndex, 1000*1000, signature.defaultInstance) // commit sig will be computed later
val openAnchor = open_anchor(anchor.hash, anchorOutputIndex, 1000*1000)
val spec = CommitmentSpec(Set(), ours.initialFeeRate, 1000 *1000, 0, 1000 *1000, 0)
val tx = makeCommitTx(ours.finalKey, theirs.finalKey, theirs.delay, openAnchor.txid, openAnchor.outputIndex, Bob.H, spec)
val redeemScript = multiSig2of2(Alice.commitPubKey, Bob.commitPubKey)
val sigA: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, anchor.txOut(anchorOutputIndex).amount.toLong, 1, Alice.commitKey)
//val sigA: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, Alice.commitKey)
val openAnchor1 = openAnchor.copy(commitSig = sigA)
// now Bob receives open anchor and wants to check that Alice's commit sig is valid
// Bob can sign too and check that he can spend the anchox tx
// now Bob receives open anchor, creates Alice's commit tx and sends backs its signature.
// this first commit tx sends all the funds to Alice and nothing to Bob
val sigB: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, anchor.txOut(anchorOutputIndex).amount.toLong, 1, Bob.commitKey)
//val sigB = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, Bob.commitKey)
val witness = witness2of2(openAnchor1.commitSig, sigB, Alice.commitPubKey, Bob.commitPubKey)
val witness = witness2of2(sigA, sigB, Alice.commitPubKey, Bob.commitPubKey)
val commitTx = tx.copy(witness = Seq(witness))
Transaction.correctlySpends(commitTx, Seq(anchor), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
// or Bob can just check that Alice's sig is valid
val hash = Transaction.hashForSigning(commitTx, 0, redeemScript, SIGHASH_ALL, anchor.txOut(anchorOutputIndex).amount.toLong, signatureVersion = 1)
assert(Crypto.verifySignature(hash, Crypto.decodeSignature(sigA.dropRight(1)), Alice.commitPubKey))
// how do we spend our commit tx ?

View file

@ -97,9 +97,6 @@ message open_anchor {
required uint32 output_index = 2;
// Amount of anchor output.
required uint64 amount = 3;
// Signature for your initial commitment tx.
required signature commit_sig = 4;
}
// Reply: signature for your initial commitment tx
@ -153,7 +150,7 @@ message update_fail_htlc {
required fail_reason reason = 2;
}
// Commit all the staged HTLCs.
// Commit all the staged changes.
message update_commit {
// Signature for your new commitment tx.
required signature sig = 1;