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

use bip69 ordering for tx inputs/outputs

This commit is contained in:
sstone 2016-11-30 17:21:50 +01:00
parent 21d90905a0
commit 9225d5a796
2 changed files with 61 additions and 47 deletions

View file

@ -79,7 +79,7 @@
<dependency>
<groupId>fr.acinq</groupId>
<artifactId>bitcoin-lib_${scala.version.short}</artifactId>
<version>${bitcoinlib.version}</version>
<version>0.9.8-SNAPSHOT</version>
</dependency>
<!-- SERIALIZATION -->
<dependency>

View file

@ -26,7 +26,7 @@ class Bolt3Spec extends FunSuite {
val (Base58.Prefix.SecretKeyTestnet, revocationPrivKey) = Base58Check.decode("cSupnaiBh6jgTcQf9QANCB5fZtXojxkJQczq5kwfSBeULjNd5Ypo")
val revocationPubKey = Crypto.publicKeyFromPrivateKey(revocationPrivKey)
val amount = 92000 satoshi
val amount = 40000 + 30000 + 20000 + 15000 satoshi
val config = ConfigFactory.load()
@ -50,12 +50,12 @@ class Bolt3Spec extends FunSuite {
def hex(tx: Transaction) = toHexString(Transaction.write(tx))
println(s"funding tx (use output $fundingPos): ${hex(fundingTx)}")
val paymentPreimage = Hash.Zeroes
val paymentHash = Crypto.hash256(paymentPreimage)
val localDelayedKey = localPubKey
val paymentPreimage1 = Hash.Zeroes
val paymentPreimage2 = Hash.One
val paymentHash1 = Crypto.hash160(paymentPreimage1)
val paymentHash2 = Crypto.hash160(paymentPreimage2)
// this is an absolute timeout (i.e. a block height or UNIX timestamp) that will be used with OP_CLTV
val htlcTimeout = 10000
@ -67,16 +67,19 @@ class Bolt3Spec extends FunSuite {
// create our local commit tx, with an HTLC that we've offered and a HTLC that we've received
val commitTx = {
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(fundingTx, fundingPos), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = Seq(
TxOut((amount - fee) / 4, Script.pay2wsh(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))),
TxOut((amount - fee) / 4, Script.pay2wpkh(remotePubKey)),
TxOut((amount - fee) / 4, Script.pay2wsh(Bolt3.htlcOffered(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage1)))),
TxOut((amount - fee) / 4, Script.pay2wsh(Bolt3.htlcReceived(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage2), htlcTimeout)))
),
lockTime = 0)
val tx = LexicographicalOrdering.sort(
Transaction(
version = 2,
txIn = TxIn(OutPoint(fundingTx, fundingPos), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = Seq(
TxOut(40000.satoshi - fee / 4, Script.pay2wsh(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))),
TxOut(30000.satoshi - fee / 4, Script.pay2wpkh(remotePubKey)),
TxOut(20000.satoshi - fee / 4, Script.pay2wsh(Bolt3.htlcOffered(localPubKey, remotePubKey, paymentHash1))),
TxOut(15000.satoshi - fee / 4, Script.pay2wsh(Bolt3.htlcReceived(localPubKey, remotePubKey, paymentHash2, htlcTimeout)))
),
lockTime = 0)
)
val redeemScript: BinaryData = Bolt3.fundingScript(localPubKey, remotePubKey)
println(s"size of funding script: ${redeemScript.length}")
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, fundingTx.txOut(fundingPos).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
@ -94,20 +97,25 @@ class Bolt3Spec extends FunSuite {
}
println(s"commit tx: ${hex(commitTx)}")
def findPubKeyScriptIndex(tx: Transaction, script: BinaryData): Int = tx.txOut.indexWhere(_.publicKeyScript == script)
def findPubKeyScriptIndex(tx: Transaction, script: Seq[ScriptElt]): Int = findPubKeyScriptIndex(tx, Script.write(script))
// create our local HTLC timeout tx for the HTLC that we've offered
// it is signed by both parties
val htlcTimeoutTx = {
val redeemScript: BinaryData = Script.write(Bolt3.htlcOffered(localPubKey, remotePubKey, paymentHash1))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 2), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(2).amount - fee, Script.pay2wsh(Bolt3.htlcSuccessOrTimeout(revocationPubKey, selfDelay, localDelayedKey))) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wsh(Bolt3.htlcSuccessOrTimeout(revocationPubKey, selfDelay, localDelayedKey))) :: Nil,
lockTime = 0)
// both parties sign the unsigned tx
val redeemScript: BinaryData = Script.write(Bolt3.htlcOffered(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage1)))
println(s"size of htlcOffered script: ${redeemScript.length}")
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(2).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
println(s"local sig size: ${localSig.length}")
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(2).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
println(s"remote sig size: ${remoteSig.length}")
val witness = ScriptWitness(BinaryData.empty :: remoteSig :: localSig :: BinaryData.empty :: redeemScript :: Nil)
println(s"witness size: ${ScriptWitness.write(witness).length}")
@ -120,17 +128,18 @@ class Bolt3Spec extends FunSuite {
// create our local HTLC success tx for the HTLC that we've received
// it is signed by both parties and its witness contains the HTLC payment preimage
val htlcSuccessTx = {
val redeemScript: BinaryData = Script.write(Bolt3.htlcReceived(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage2), htlcTimeout))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 3), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(3).amount - fee, Script.pay2wsh(Bolt3.htlcSuccessOrTimeout(revocationPubKey, selfDelay, localDelayedKey))) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wsh(Bolt3.htlcSuccessOrTimeout(revocationPubKey, selfDelay, localDelayedKey))) :: Nil,
lockTime = 0)
// both parties sign the unsigned tx
val redeemScript: BinaryData = Script.write(Bolt3.htlcReceived(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage2), htlcTimeout))
println(s"size of htlcReceived script: ${redeemScript.length}")
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(3).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
println(s"local sig size: ${localSig.length}")
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(3).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
println(s"remote sig size: ${remoteSig.length}")
val witness = ScriptWitness(BinaryData.empty :: remoteSig :: localSig :: paymentPreimage2 :: redeemScript :: Nil)
println(s"witness size: ${ScriptWitness.write(witness).length}")
@ -154,14 +163,15 @@ class Bolt3Spec extends FunSuite {
test("we can spend our commit tx output after a delay") {
val spendOurOutput = {
val redeemScript: BinaryData = Script.write(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 0), signatureScript = Nil, sequence = selfDelay + 1) :: Nil,
txOut = TxOut(commitTx.txOut(0).amount - fee, Script.pay2wpkh(localPubKey)) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = selfDelay + 1) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wpkh(localPubKey)) :: Nil,
lockTime = 0)
val redeemScript: BinaryData = Script.write(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))
println(s"size of toLocal script: ${redeemScript.length}")
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(0).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
val localSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, localPrivKey)
println(s"local sig size: ${localSig.length}")
val witness = ScriptWitness(localSig :: BinaryData.empty :: redeemScript :: Nil)
tx.updateWitness(0, witness)
@ -172,31 +182,33 @@ class Bolt3Spec extends FunSuite {
}
test("they can spend their commit tx immediately") {
val index = findPubKeyScriptIndex(commitTx, Script.pay2wpkh(remotePubKey))
val spendTheirOutput = {
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 1), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(1).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
lockTime = 0)
val redeemScript: BinaryData = Script.write(Script.pay2pkh(remotePubKey))
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(1).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val witness = ScriptWitness(remoteSig :: remotePubKey :: Nil)
tx.updateWitness(0, witness)
}
Transaction.correctlySpends(spendTheirOutput, commitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
println(s"spend-their-output tx: ${hex(spendTheirOutput)}")
println(s"they-spend-their-output tx: ${hex(spendTheirOutput)}")
}
test("they can spend our commit tx output immediately if they have the revocation key") {
val redeemScript: BinaryData = Script.write(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val penaltyTx = {
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 0), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(0).amount - fee, Script.pay2wpkh(localPubKey)) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wpkh(localPubKey)) :: Nil,
lockTime = 0)
val redeemScript: BinaryData = Script.write(Bolt3.toLocal(revocationPubKey, selfDelay, localDelayedKey))
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(0).amount, SigVersion.SIGVERSION_WITNESS_V0, revocationPrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, revocationPrivKey)
println(s"remote sig size: ${remoteSig.length}")
val witness = ScriptWitness(remoteSig :: BinaryData("01") :: redeemScript :: Nil)
tx.updateWitness(0, witness)
@ -220,7 +232,7 @@ class Bolt3Spec extends FunSuite {
tx.updateWitness(0, witness)
}
Transaction.correctlySpends(spendHtlcTimeout, htlcTimeoutTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
println(s"spend-offered-htlc-timeout tx: ${hex(spendHtlcTimeout)}")
println(s"we-spend-offered-htlc-timeout tx: ${hex(spendHtlcTimeout)}")
println(s"you need to publish the htlc timeout tx and generate ${selfDelay} blocks before you can publish this tx")
}
@ -238,36 +250,38 @@ class Bolt3Spec extends FunSuite {
tx.updateWitness(0, witness)
}
Transaction.correctlySpends(spendHtlcSuccess, htlcSuccessTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
println(s"spend-received-htlc tx: ${hex(spendHtlcSuccess)}")
println(s"we-spend-received-htlc tx: ${hex(spendHtlcSuccess)}")
println(s"you need to publish the htlc success tx and generate ${selfDelay} blocks before you can publish this tx")
}
test("they can spend the offered HTLC with the payment preimage") {
val spendOfferedHtlc = {
val redeemScript: BinaryData = Script.write(Bolt3.htlcOffered(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage1)))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 2), signatureScript = Nil, sequence = selfDelay + 1) :: Nil,
txOut = TxOut(commitTx.txOut(2).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = selfDelay + 1) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
lockTime = 0)
val redeemScript: BinaryData = Script.write(Bolt3.htlcOffered(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage1)))
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(2).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
println(s"remote sig size: ${remoteSig.length}")
val witness = ScriptWitness(remoteSig :: paymentPreimage1 :: redeemScript :: Nil)
tx.updateWitness(0, witness)
}
Transaction.correctlySpends(spendOfferedHtlc, commitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
println(s"spend-offered-htlc tx: ${hex(spendOfferedHtlc)}")
println(s"they-spend-offered-htlc tx: ${hex(spendOfferedHtlc)}")
}
test("they can timeout the received HTLC after a delay") {
val redeemScript: BinaryData = Script.write(Bolt3.htlcReceived(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage2), htlcTimeout))
val index = findPubKeyScriptIndex(commitTx, Script.pay2wsh(redeemScript))
val timeoutReceivedHtlc = {
val tx = Transaction(
version = 2,
txIn = TxIn(OutPoint(commitTx, 3), signatureScript = Nil, sequence = 0) :: Nil,
txOut = TxOut(commitTx.txOut(3).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
txIn = TxIn(OutPoint(commitTx, index), signatureScript = Nil, sequence = 0) :: Nil,
txOut = TxOut(commitTx.txOut(index).amount - fee, Script.pay2wpkh(remotePubKey)) :: Nil,
lockTime = htlcTimeout + 1)
val redeemScript: BinaryData = Script.write(Bolt3.htlcReceived(localPubKey, remotePubKey, Crypto.hash160(paymentPreimage2), htlcTimeout))
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(3).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
val remoteSig: BinaryData = Transaction.signInput(tx, 0, redeemScript, SIGHASH_ALL, commitTx.txOut(index).amount, SigVersion.SIGVERSION_WITNESS_V0, remotePrivKey)
println(s"remote sig size: ${remoteSig.length}")
val witness = ScriptWitness(remoteSig :: BinaryData.empty :: redeemScript :: Nil)
tx.updateWitness(0, witness)