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:
parent
21d90905a0
commit
9225d5a796
2 changed files with 61 additions and 47 deletions
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue