1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-23 06:35:11 +01:00

upgrade CSV handling

This commit is contained in:
sstone 2016-02-24 17:32:47 +01:00
parent b530a15cf7
commit b3f5ce4e38
4 changed files with 82 additions and 41 deletions

View file

@ -59,19 +59,19 @@ object Scripts {
def anchorPubkeyScript(pubkey1: BinaryData, pubkey2: BinaryData): BinaryData = Script.write(pay2sh(multiSig2of2(pubkey1, pubkey2)))
def redeemSecretOrDelay(delayedKey: BinaryData, lockTime: Long, keyIfSecretKnown: BinaryData, hashOfSecret: BinaryData): Seq[ScriptElt] = {
def redeemSecretOrDelay(delayedKey: BinaryData, reltimeout: Long, keyIfSecretKnown: BinaryData, hashOfSecret: BinaryData): Seq[ScriptElt] = {
// @formatter:off
OP_HASH160 :: OP_PUSHDATA(ripemd160(hashOfSecret)) :: OP_EQUAL ::
OP_IF ::
OP_PUSHDATA(keyIfSecretKnown) ::
OP_ELSE ::
OP_PUSHDATA(Script.encodeNumber(lockTime)) :: OP_CHECKSEQUENCEVERIFY :: OP_DROP :: OP_PUSHDATA(delayedKey) ::
OP_PUSHDATA(Script.encodeNumber(reltimeout)) :: OP_CHECKSEQUENCEVERIFY :: OP_DROP :: OP_PUSHDATA(delayedKey) ::
OP_ENDIF ::
OP_CHECKSIG :: Nil
// @formatter:on
}
def scriptPubKeyHtlcSend(ourkey: BinaryData, theirkey: BinaryData, htlc_abstimeout: Long, locktime: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
def scriptPubKeyHtlcSend(ourkey: BinaryData, theirkey: BinaryData, abstimeout: Long, reltimeout: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
// @formatter:off
OP_HASH160 :: OP_DUP ::
OP_PUSHDATA(ripemd160(rhash)) :: OP_EQUAL ::
@ -79,22 +79,22 @@ object Scripts {
OP_IF ::
OP_PUSHDATA(theirkey) ::
OP_ELSE ::
OP_PUSHDATA(Script.encodeNumber(htlc_abstimeout)) :: OP_CHECKLOCKTIMEVERIFY :: OP_PUSHDATA(Script.encodeNumber(locktime)) :: OP_CHECKSEQUENCEVERIFY :: OP_2DROP :: OP_PUSHDATA(ourkey) ::
OP_PUSHDATA(Script.encodeNumber(abstimeout)) :: OP_CHECKLOCKTIMEVERIFY :: OP_PUSHDATA(Script.encodeNumber(reltimeout)) :: OP_CHECKSEQUENCEVERIFY :: OP_2DROP :: OP_PUSHDATA(ourkey) ::
OP_ENDIF ::
OP_CHECKSIG :: Nil
// @formatter:on
}
def scriptPubKeyHtlcReceive(ourkey: BinaryData, theirkey: BinaryData, htlc_abstimeout: Long, locktime: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
def scriptPubKeyHtlcReceive(ourkey: BinaryData, theirkey: BinaryData, abstimeout: Long, reltimeout: Long, rhash: BinaryData, commit_revoke: BinaryData): Seq[ScriptElt] = {
// @formatter:off
OP_HASH160 :: OP_DUP ::
OP_PUSHDATA(ripemd160(rhash)) :: OP_EQUAL ::
OP_IF ::
OP_PUSHDATA(Script.encodeNumber(locktime)) :: OP_CHECKSEQUENCEVERIFY :: OP_2DROP :: OP_PUSHDATA(ourkey) ::
OP_PUSHDATA(Script.encodeNumber(reltimeout)) :: OP_CHECKSEQUENCEVERIFY :: OP_2DROP :: OP_PUSHDATA(ourkey) ::
OP_ELSE ::
OP_PUSHDATA(ripemd160(commit_revoke)) :: OP_EQUAL ::
OP_NOTIF ::
OP_PUSHDATA(Script.encodeNumber(htlc_abstimeout)) :: OP_CHECKLOCKTIMEVERIFY :: OP_DROP ::
OP_PUSHDATA(Script.encodeNumber(abstimeout)) :: OP_CHECKLOCKTIMEVERIFY :: OP_DROP ::
OP_ENDIF ::
OP_PUSHDATA(theirkey) ::
OP_ENDIF ::

View file

@ -33,7 +33,9 @@ class ClaimReceivedHtlcSpec extends FunSuite {
val revokeCommitHash = Crypto.sha256(revokeCommit)
}
val htlcScript = scriptPubKeyHtlcReceive(Alice.finalPubKey, Bob.finalPubKey, 1000, 2000, Bob.Rhash, Bob.revokeCommitHash)
val abstimeout = 3000
val reltimeout = 2000
val htlcScript = scriptPubKeyHtlcReceive(Alice.finalPubKey, Bob.finalPubKey, abstimeout, reltimeout, Bob.Rhash, Bob.revokeCommitHash)
// this tx sends money to our HTLC
val tx = Transaction(
@ -44,24 +46,24 @@ class ClaimReceivedHtlcSpec extends FunSuite {
// this tx tries to spend the previous tx
val tx1 = Transaction(
version = 1,
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, 0xffffffff) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = 0)
test("Alice can spend this HTLC after a delay if she knows the payment hash") {
val tx1 = Transaction(
version = 1,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, 0xffffffff - 2000) :: Nil,
val tx2 = Transaction(
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, reltimeout + 1) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = 2000)
lockTime = abstimeout + 1)
val sig = Transaction.signInput(tx1, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Bob.R) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx2 = tx1.updateSigScript(0, Script.write(sigScript))
val tx3 = tx2.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(
new Script.Context(tx2, 0),
new Script.Context(tx3, 0),
ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
@ -69,18 +71,18 @@ class ClaimReceivedHtlcSpec extends FunSuite {
}
test("Blob can spend this HTLC after a delay") {
val tx1 = Transaction(
version = 1,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, 0xffffffff - 2000) :: Nil,
val tx2 = Transaction(
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, reltimeout + 1) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = 2000)
lockTime = abstimeout + 1)
val sig = Transaction.signInput(tx1, 0, Script.write(htlcScript), SIGHASH_ALL, Bob.finalKey)
val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, Bob.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Array.emptyByteArray) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx2 = tx1.updateSigScript(0, Script.write(sigScript))
val tx3 = tx2.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(new Script.Context(tx2, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val runner = new Script.Runner(new Script.Context(tx3, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
assert(result)
}

View file

@ -8,6 +8,7 @@ import org.scalatest.junit.JUnitRunner
@RunWith(classOf[JUnitRunner])
class ClaimSentHtlcSpec extends FunSuite {
object Alice {
val (_, commitKey) = Base58Check.decode("cVuzKWCszfvjkoJyUasvsrRdECriz8hSd1BDinRNzytwnXmX7m1g")
val (_, finalKey) = Base58Check.decode("cRUfvpbRtMSqCFD1ADdvgPn5HfRLYuHCFYAr2noWnaRDNger2AoA")
@ -31,7 +32,9 @@ class ClaimSentHtlcSpec extends FunSuite {
val revokeCommitHash = Crypto.sha256(revokeCommit)
}
val htlcScript = scriptPubKeyHtlcSend(Alice.finalPubKey, Bob.finalPubKey, 1000, 2000, Alice.revokeCommitHash, Alice.Rhash)
val abstimeout = 3000
val reltimeout = 2000
val htlcScript = scriptPubKeyHtlcSend(Alice.finalPubKey, Bob.finalPubKey, abstimeout, reltimeout, Alice.revokeCommitHash, Alice.Rhash)
// this tx sends money to our HTLC
val tx = Transaction(
@ -48,29 +51,65 @@ class ClaimSentHtlcSpec extends FunSuite {
lockTime = 0)
test("Alice can spend this HTLC after a delay") {
val tx1 = Transaction(
version = 1,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, sequence = 0xffffffff - 2000) :: Nil,
val tx2 = Transaction(
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, sequence = reltimeout + 1) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = 2000)
lockTime = abstimeout + 1)
val sig = Transaction.signInput(tx1, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Array.emptyByteArray) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx2 = tx1.updateSigScript(0, Script.write(sigScript))
val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Array.emptyByteArray) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx3 = tx2.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(new Script.Context(tx2, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
assert(result)
val runner = new Script.Runner(new Script.Context(tx3, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
assert(result)
}
test("Alice cannot spend this HTLC before its absolute timeout") {
val tx2 = Transaction(
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, sequence = reltimeout + 1) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = abstimeout -1)
val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Array.emptyByteArray) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx3 = tx2.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(new Script.Context(tx3, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val e = intercept[RuntimeException] {
runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
}
assert(e.getMessage === "unsatisfied CLTV lock time")
}
test("Alice cannot spend this HTLC before its relative timeout") {
val tx2 = Transaction(
version = 2,
txIn = TxIn(OutPoint(tx, 0), Array.emptyByteArray, sequence = reltimeout - 1) :: Nil,
txOut = TxOut(10, OP_DUP :: OP_HASH160 :: OP_PUSHDATA(Crypto.hash160(Alice.finalPubKey)) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) :: Nil,
lockTime = abstimeout +1)
val sig = Transaction.signInput(tx2, 0, Script.write(htlcScript), SIGHASH_ALL, Alice.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Array.emptyByteArray) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx3 = tx2.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(new Script.Context(tx3, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val e = intercept[RuntimeException] {
runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
}
assert(e.getMessage === "unsatisfied CSV lock time")
}
test("Blob can spend this HTLC if he knows the payment hash") {
val sig = Transaction.signInput(tx1, 0, Script.write(htlcScript), SIGHASH_ALL, Bob.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Alice.R) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx2 = tx1.updateSigScript(0, Script.write(sigScript))
val sig = Transaction.signInput(tx1, 0, Script.write(htlcScript), SIGHASH_ALL, Bob.finalKey)
val sigScript = OP_PUSHDATA(sig) :: OP_PUSHDATA(Alice.R) :: OP_PUSHDATA(Script.write(htlcScript)) :: Nil
val tx2 = tx1.updateSigScript(0, Script.write(sigScript))
val runner = new Script.Runner(new Script.Context(tx2, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
assert(result)
val runner = new Script.Runner(new Script.Context(tx2, 0), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS | ScriptFlags.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | ScriptFlags.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
val result = runner.verifyScripts(Script.write(sigScript), Script.write(pay2sh(htlcScript)))
assert(result)
}
test("Blob can spend this HTLC if he knows the revocation hash") {

View file

@ -45,7 +45,7 @@
<scala.version.short>2.11</scala.version.short>
<akka.version>2.4.1</akka.version>
<spray.version>1.3.3</spray.version>
<bitcoinlib.version>0.9.4</bitcoinlib.version>
<bitcoinlib.version>0.9.5</bitcoinlib.version>
<acinqtools.version>1.2</acinqtools.version>
</properties>