mirror of
https://github.com/ACINQ/eclair.git
synced 2025-02-22 14:22:39 +01:00
now checking final scriptpubkey validity
This commit is contained in:
parent
2badd3d7c2
commit
ef586fe4ad
3 changed files with 40 additions and 6 deletions
|
@ -447,22 +447,25 @@ class Channel(val them: ActorRef, val blockchain: ActorRef, paymentHandler: Acto
|
|||
|
||||
case Event(CMD_CLOSE(ourScriptPubKey_opt), d: DATA_NORMAL) if d.localShutdown.isDefined =>
|
||||
handleCommandError(sender, new RuntimeException("closing already in progress"))
|
||||
stay
|
||||
|
||||
case Event(c@CMD_CLOSE(ourScriptPubKey_opt), d: DATA_NORMAL) if Commitments.localHasChanges(d.commitments) =>
|
||||
// TODO: simplistic behavior, we could maybe sign+close
|
||||
handleCommandError(sender, new RuntimeException("cannot close when there are pending changes"))
|
||||
stay
|
||||
|
||||
case Event(CMD_CLOSE(ourScriptPubKey_opt), d: DATA_NORMAL) =>
|
||||
val localShutdown = Shutdown(d.channelId, Script.write(d.params.localParams.defaultFinalScriptPubKey))
|
||||
handleCommandSuccess(sender, localShutdown, d.copy(localShutdown = Some(localShutdown)))
|
||||
ourScriptPubKey_opt.getOrElse(Script.write(d.params.localParams.defaultFinalScriptPubKey)) match {
|
||||
case finalScriptPubKey if Closing.isValidFinalScriptPubkey(finalScriptPubKey) =>
|
||||
val localShutdown = Shutdown(d.channelId, finalScriptPubKey)
|
||||
handleCommandSuccess(sender, localShutdown, d.copy(localShutdown = Some(localShutdown)))
|
||||
case _ => handleCommandError(sender, new RuntimeException("invalid final script"))
|
||||
}
|
||||
|
||||
case Event(remoteShutdown@Shutdown(_, remoteScriptPubKey), d@DATA_NORMAL(channelId, params, commitments, ourShutdownOpt, downstreams)) if commitments.remoteChanges.proposed.size > 0 =>
|
||||
handleLocalError(new RuntimeException("it is illegal to send a shutdown while having unsigned changes"), d)
|
||||
|
||||
case Event(remoteShutdown@Shutdown(_, remoteScriptPubKey), d@DATA_NORMAL(channelId, params, commitments, ourShutdownOpt, downstreams)) =>
|
||||
Try(ourShutdownOpt.map(s => (s, commitments)).getOrElse {
|
||||
require(Closing.isValidFinalScriptPubkey(remoteScriptPubKey), "invalid final script")
|
||||
// first if we have pending changes, we need to commit them
|
||||
val commitments2 = if (Commitments.localHasChanges(commitments)) {
|
||||
val (commitments1, commit) = Commitments.sendCommit(d.commitments)
|
||||
|
|
|
@ -9,7 +9,7 @@ import fr.acinq.eclair.transactions.Transactions._
|
|||
import fr.acinq.eclair.transactions._
|
||||
import fr.acinq.eclair.wire.{ClosingSigned, UpdateAddHtlc, UpdateFulfillHtlc}
|
||||
|
||||
import scala.util.Try
|
||||
import scala.util.{Success, Try}
|
||||
|
||||
/**
|
||||
* Created by PM on 20/05/2016.
|
||||
|
@ -55,6 +55,16 @@ object Helpers {
|
|||
|
||||
object Closing {
|
||||
|
||||
def isValidFinalScriptPubkey(scriptPubKey: BinaryData): Boolean = {
|
||||
Try(Script.parse(scriptPubKey)) match {
|
||||
case Success(OP_DUP :: OP_HASH160 :: OP_PUSHDATA(pubkeyHash, _) :: OP_EQUALVERIFY :: OP_CHECKSIG :: Nil) if pubkeyHash.size == 20 => true
|
||||
case Success(OP_HASH160 :: OP_PUSHDATA(scriptHash, _) :: OP_EQUAL :: Nil) if scriptHash.size == 20 => true
|
||||
case Success(OP_0 :: OP_PUSHDATA(pubkeyHash, _) :: Nil) if pubkeyHash.size == 20 => true
|
||||
case Success(OP_0 :: OP_PUSHDATA(scriptHash, _) :: Nil) if scriptHash.size == 32 => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def makeFirstClosingTx(params: ChannelParams, commitments: Commitments, localScriptPubkey: BinaryData, remoteScriptPubkey: BinaryData): ClosingSigned = {
|
||||
import commitments._
|
||||
val closingFee = {
|
||||
|
@ -69,6 +79,8 @@ object Helpers {
|
|||
|
||||
def makeClosingTx(params: ChannelParams, commitments: Commitments, localScriptPubkey: BinaryData, remoteScriptPubkey: BinaryData, closingFee: Satoshi): (ClosingTx, ClosingSigned) = {
|
||||
import commitments._
|
||||
require(isValidFinalScriptPubkey(localScriptPubkey), "invalid localScriptPubkey")
|
||||
require(isValidFinalScriptPubkey(remoteScriptPubkey), "invalid remoteScriptPubkey")
|
||||
// TODO: check that
|
||||
val dustLimitSatoshis = Satoshi(Math.max(localParams.dustLimitSatoshis, remoteParams.dustLimitSatoshis))
|
||||
val closingTx = Transactions.makeClosingTx(commitInput, localScriptPubkey, remoteScriptPubkey, localParams.isFunder, dustLimitSatoshis, closingFee, localCommit.spec)
|
||||
|
|
|
@ -648,6 +648,14 @@ class NormalStateSpec extends StateSpecBaseClass with StateTestsHelperMethods {
|
|||
}
|
||||
}
|
||||
|
||||
test("recv CMD_CLOSE (with invalid final script)") { case (alice, bob, alice2bob, bob2alice, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
sender.send(alice, CMD_CLOSE(Some(BinaryData("00112233445566778899"))))
|
||||
sender.expectMsg("invalid final script")
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CMD_CLOSE (with signed sent htlcs)") { case (alice, bob, alice2bob, bob2alice, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
|
@ -693,7 +701,7 @@ class NormalStateSpec extends StateSpecBaseClass with StateTestsHelperMethods {
|
|||
test("recv Shutdown (no pending htlcs)") { case (alice, _, alice2bob, _, alice2blockchain, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
sender.send(alice, Shutdown(0, "00" * 25))
|
||||
sender.send(alice, Shutdown(0, Script.write(Bob.channelParams.defaultFinalScriptPubKey)))
|
||||
alice2bob.expectMsgType[Shutdown]
|
||||
alice2bob.expectMsgType[ClosingSigned]
|
||||
awaitCond(alice.stateName == NEGOTIATING)
|
||||
|
@ -727,6 +735,17 @@ class NormalStateSpec extends StateSpecBaseClass with StateTestsHelperMethods {
|
|||
}
|
||||
}
|
||||
|
||||
test("recv Shutdown (with invalid final script)") { case (alice, bob, alice2bob, bob2alice, _, bob2blockchain) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
sender.send(bob, Shutdown(0, BinaryData("00112233445566778899")))
|
||||
bob2alice.expectMsgType[Error]
|
||||
bob2blockchain.expectMsgType[PublishAsap]
|
||||
bob2blockchain.expectMsgType[WatchConfirmed]
|
||||
awaitCond(bob.stateName == CLOSING)
|
||||
}
|
||||
}
|
||||
|
||||
test("recv Shutdown (with signed htlcs)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
|
|
Loading…
Add table
Reference in a new issue