mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-13 11:35:47 +01:00
merged from master, set version to 0.2-android-alpha13
This commit is contained in:
commit
99df38db8d
15 changed files with 109 additions and 43 deletions
|
@ -154,6 +154,7 @@ java -Declair.datadir=/tmp/node1 -jar eclair-node-gui-<version>-<commit_id>.jar
|
|||
checkpayment | paymentRequest | returns true if the payment has been received, false otherwise
|
||||
close | channelId | close a channel
|
||||
close | channelId, scriptPubKey | close a channel and send the funds to the given scriptPubKey
|
||||
forceclose | channelId | force-close a channel by publishing the local commitment tx (careful: this is more expensive than a regular close and will incur a delay before funds are spendable)"
|
||||
help | | display available methods
|
||||
|
||||
## Docker
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>fr.acinq.eclair</groupId>
|
||||
<artifactId>eclair_2.11</artifactId>
|
||||
<version>0.2-android-SNAPSHOT</version>
|
||||
<version>0.2-android-alpha13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>eclair-core_2.11</artifactId>
|
||||
|
|
|
@ -175,6 +175,8 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
blockchain ! WatchLost(self, data.commitments.commitInput.outPoint.txid, nodeParams.minDepthBlocks, BITCOIN_FUNDING_LOST)
|
||||
goto(OFFLINE) using data
|
||||
}
|
||||
|
||||
case Event(CMD_CLOSE(_), _) => goto(CLOSED) replying "ok"
|
||||
})
|
||||
|
||||
when(WAIT_FOR_OPEN_CHANNEL)(handleExceptions {
|
||||
|
@ -221,7 +223,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
goto(WAIT_FOR_FUNDING_CREATED) using DATA_WAIT_FOR_FUNDING_CREATED(open.temporaryChannelId, localParams, remoteParams, open.fundingSatoshis, open.pushMsat, open.feeratePerKw, open.firstPerCommitmentPoint, open.channelFlags, accept) sending accept
|
||||
}
|
||||
|
||||
case Event(CMD_CLOSE(_), _) => goto(CLOSED)
|
||||
case Event(CMD_CLOSE(_), _) => goto(CLOSED) replying "ok"
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_OPEN_CHANNEL) => handleRemoteError(e, d)
|
||||
|
||||
|
@ -262,7 +264,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
case Event(CMD_CLOSE(_), _) =>
|
||||
replyToUser(Right("closed"))
|
||||
goto(CLOSED)
|
||||
goto(CLOSED) replying "ok"
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_ACCEPT_CHANNEL) =>
|
||||
replyToUser(Left(Right(e)))
|
||||
|
@ -301,7 +303,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
case Event(CMD_CLOSE(_), _) =>
|
||||
replyToUser(Right("closed"))
|
||||
goto(CLOSED)
|
||||
goto(CLOSED) replying "ok"
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_INTERNAL) =>
|
||||
replyToUser(Left(Right(e)))
|
||||
|
@ -353,7 +355,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
goto(WAIT_FOR_FUNDING_CONFIRMED) using store(DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, None, Right(fundingSigned))) sending fundingSigned
|
||||
}
|
||||
|
||||
case Event(CMD_CLOSE(_), _) => goto(CLOSED)
|
||||
case Event(CMD_CLOSE(_), _) => goto(CLOSED) replying "ok"
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_CREATED) => handleRemoteError(e, d)
|
||||
|
||||
|
@ -404,11 +406,11 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
goto(WAIT_FOR_FUNDING_CONFIRMED) using nextState
|
||||
}
|
||||
|
||||
case Event(CMD_CLOSE(_), d: DATA_WAIT_FOR_FUNDING_SIGNED) =>
|
||||
case Event(CMD_CLOSE(_) | CMD_FORCECLOSE, d: DATA_WAIT_FOR_FUNDING_SIGNED) =>
|
||||
// we rollback the funding tx, it will never be published
|
||||
wallet.rollback(d.fundingTx)
|
||||
replyToUser(Right("closed"))
|
||||
goto(CLOSED)
|
||||
goto(CLOSED) replying "ok"
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_SIGNED) =>
|
||||
// we rollback the funding tx, it will never be published
|
||||
|
@ -457,8 +459,6 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
case Event(WatchEventSpent(BITCOIN_FUNDING_SPENT, tx), d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => handleInformationLeak(tx, d)
|
||||
|
||||
case Event(CMD_CLOSE(_), d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => spendLocalCurrent(d)
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => handleRemoteError(e, d)
|
||||
})
|
||||
|
||||
|
@ -481,8 +481,6 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
case Event(WatchEventSpent(BITCOIN_FUNDING_SPENT, tx), d: DATA_WAIT_FOR_FUNDING_LOCKED) => handleInformationLeak(tx, d)
|
||||
|
||||
case Event(CMD_CLOSE(_), d: DATA_WAIT_FOR_FUNDING_LOCKED) => spendLocalCurrent(d)
|
||||
|
||||
case Event(e: Error, d: DATA_WAIT_FOR_FUNDING_LOCKED) => handleRemoteError(e, d)
|
||||
})
|
||||
|
||||
|
@ -1077,6 +1075,9 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
if (d.mutualCloseProposed.map(_.txid).contains(tx.txid)) {
|
||||
// at any time they can publish a closing tx with any sig we sent them
|
||||
handleMutualClose(tx, Right(d))
|
||||
} else if (d.mutualClosePublished.map(_.txid).contains(tx.txid)) {
|
||||
// we have published a closing tx which isn't one that we proposed, and used it instead of our last commitment when an error happened
|
||||
handleMutualClose(tx, Right(d))
|
||||
} else if (Some(tx.txid) == d.localCommitPublished.map(_.commitTx.txid)) {
|
||||
// this is because WatchSpent watches never expire and we are notified multiple times
|
||||
stay
|
||||
|
@ -1224,8 +1225,6 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
goto(SYNCING) sending channelReestablish
|
||||
|
||||
case Event(c: CMD_CLOSE, d: HasCommitments) => handleLocalError(ForcedLocalCommit(d.channelId, "can't do a mutual close while disconnected"), d, Some(c)) replying "ok"
|
||||
|
||||
case Event(c@CurrentBlockCount(count), d: HasCommitments) if d.commitments.hasTimedoutOutgoingHtlcs(count) =>
|
||||
// note: this can only happen if state is NORMAL or SHUTDOWN
|
||||
// -> in NEGOTIATING there are no more htlcs
|
||||
|
@ -1334,8 +1333,6 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
goto(NEGOTIATING) using d.copy(closingTxProposed = closingTxProposed1) sending d.localShutdown
|
||||
}
|
||||
|
||||
case Event(c: CMD_CLOSE, d: HasCommitments) => handleLocalError(ForcedLocalCommit(d.channelId, "can't do a mutual close while syncing"), d, Some(c))
|
||||
|
||||
case Event(c@CurrentBlockCount(count), d: HasCommitments) if d.commitments.hasTimedoutOutgoingHtlcs(count) => handleLocalError(HtlcTimedout(d.channelId), d, Some(c))
|
||||
|
||||
case Event(WatchEventSpent(BITCOIN_FUNDING_SPENT, tx), d: DATA_NEGOTIATING) if d.closingTxProposed.flatten.map(_.unsignedTx.txid).contains(tx.txid) => handleMutualClose(tx, Left(d))
|
||||
|
@ -1367,8 +1364,6 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
whenUnhandled {
|
||||
|
||||
case Event(c@INPUT_PUBLISH_LOCALCOMMIT, d: HasCommitments) => handleLocalError(ForcedLocalCommit(d.channelId, "manual unilateral close"), d, Some(c))
|
||||
|
||||
case Event(INPUT_DISCONNECTED, _) => goto(OFFLINE)
|
||||
|
||||
case Event(WatchEventLost(BITCOIN_FUNDING_LOST), _) => goto(ERR_FUNDING_LOST)
|
||||
|
@ -1394,6 +1389,14 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
case _ => handleCommandError(AddHtlcFailed(d.channelId, c.paymentHash, error, origin(c), None), c) // we don't provide a channel_update: this will be a permanent channel failure
|
||||
}
|
||||
|
||||
case Event(c: CMD_CLOSE, d) => handleCommandError(CannotCloseInThisState(Helpers.getChannelId(d), stateName), c)
|
||||
|
||||
case Event(c@CMD_FORCECLOSE, d) =>
|
||||
d match {
|
||||
case data: HasCommitments => handleLocalError(ForcedLocalCommit(data.channelId, "forced local commit"), data, Some(c)) replying "ok"
|
||||
case _ => handleCommandError(CannotCloseInThisState(Helpers.getChannelId(d), stateName), c)
|
||||
}
|
||||
|
||||
// we only care about this event in NORMAL and SHUTDOWN state, and we never unregister to the event stream
|
||||
case Event(CurrentBlockCount(_), _) => stay
|
||||
|
||||
|
@ -1490,7 +1493,10 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
}
|
||||
|
||||
def handleLocalError(cause: Throwable, d: HasCommitments, msg: Option[Any]) = {
|
||||
log.error(s"${cause.getMessage} while processing msg=${msg.getOrElse("n/a").getClass.getSimpleName} in state=$stateName")
|
||||
cause match {
|
||||
case _: ForcedLocalCommit => log.warning(s"force-closing channel at user request")
|
||||
case _ => log.error(s"${cause.getMessage} while processing msg=${msg.getOrElse("n/a").getClass.getSimpleName} in state=$stateName")
|
||||
}
|
||||
cause match {
|
||||
case _: ChannelException => ()
|
||||
case _ => log.error(cause, s"msg=${msg.getOrElse("n/a")} stateData=$stateData ")
|
||||
|
@ -1499,6 +1505,7 @@ class Channel(val nodeParams: NodeParams, wallet: EclairWallet, remoteNodeId: Pu
|
|||
|
||||
d match {
|
||||
case negotiating@DATA_NEGOTIATING(_, _, _, _, Some(bestUnpublishedClosingTx)) =>
|
||||
log.info(s"we have a valid closing tx, publishing it instead of our commitment: closingTxId=${bestUnpublishedClosingTx.txid}")
|
||||
// if we were in the process of closing and already received a closing sig from the counterparty, it's always better to use that
|
||||
handleMutualClose(bestUnpublishedClosingTx, Left(negotiating))
|
||||
case _ =>
|
||||
|
|
|
@ -22,6 +22,7 @@ case class ChannelReserveTooHigh (override val channelId: BinaryDa
|
|||
case class ChannelFundingError (override val channelId: BinaryData) extends ChannelException(channelId, "channel funding error")
|
||||
case class NoMoreHtlcsClosingInProgress (override val channelId: BinaryData) extends ChannelException(channelId, "cannot send new htlcs, closing in progress")
|
||||
case class ClosingAlreadyInProgress (override val channelId: BinaryData) extends ChannelException(channelId, "closing already in progress")
|
||||
case class CannotCloseInThisState (override val channelId: BinaryData, state: State) extends ChannelException(channelId, s"cannot close in state=$state")
|
||||
case class CannotCloseWithUnsignedOutgoingHtlcs(override val channelId: BinaryData) extends ChannelException(channelId, "cannot close when there are unsigned outgoing htlcs")
|
||||
case class ChannelUnavailable (override val channelId: BinaryData) extends ChannelException(channelId, "channel is unavailable (offline or closing)")
|
||||
case class InvalidFinalScript (override val channelId: BinaryData) extends ChannelException(channelId, "invalid final script")
|
||||
|
|
|
@ -33,7 +33,6 @@ case object WAIT_FOR_ACCEPT_CHANNEL extends State
|
|||
case object WAIT_FOR_FUNDING_INTERNAL extends State
|
||||
case object WAIT_FOR_FUNDING_CREATED extends State
|
||||
case object WAIT_FOR_FUNDING_SIGNED extends State
|
||||
case object WAIT_FOR_FUNDING_PUBLISHED extends State
|
||||
case object WAIT_FOR_FUNDING_CONFIRMED extends State
|
||||
case object WAIT_FOR_FUNDING_LOCKED extends State
|
||||
case object NORMAL extends State
|
||||
|
@ -63,7 +62,6 @@ case object ERR_INFORMATION_LEAK extends State
|
|||
case class INPUT_INIT_FUNDER(temporaryChannelId: BinaryData, fundingSatoshis: Long, pushMsat: Long, initialFeeratePerKw: Long, fundingTxFeeratePerKw: Long, localParams: LocalParams, remote: ActorRef, remoteInit: Init, channelFlags: Byte)
|
||||
case class INPUT_INIT_FUNDEE(temporaryChannelId: BinaryData, localParams: LocalParams, remote: ActorRef, remoteInit: Init)
|
||||
case object INPUT_CLOSE_COMPLETE_TIMEOUT // when requesting a mutual close, we wait for as much as this timeout, then unilateral close
|
||||
case object INPUT_PUBLISH_LOCALCOMMIT // used in tests
|
||||
case object INPUT_DISCONNECTED
|
||||
case class INPUT_RECONNECTED(remote: ActorRef)
|
||||
case class INPUT_RESTORED(data: HasCommitments)
|
||||
|
@ -97,11 +95,12 @@ final case class CMD_FULFILL_HTLC(id: Long, r: BinaryData, commit: Boolean = fal
|
|||
final case class CMD_FAIL_HTLC(id: Long, reason: Either[BinaryData, FailureMessage], commit: Boolean = false) extends Command
|
||||
final case class CMD_FAIL_MALFORMED_HTLC(id: Long, onionHash: BinaryData, failureCode: Int, commit: Boolean = false) extends Command
|
||||
final case class CMD_UPDATE_FEE(feeratePerKw: Long, commit: Boolean = false) extends Command
|
||||
case object CMD_SIGN extends Command
|
||||
final case object CMD_SIGN extends Command
|
||||
final case class CMD_CLOSE(scriptPubKey: Option[BinaryData]) extends Command
|
||||
case object CMD_GETSTATE extends Command
|
||||
case object CMD_GETSTATEDATA extends Command
|
||||
case object CMD_GETINFO extends Command
|
||||
final case object CMD_FORCECLOSE extends Command
|
||||
final case object CMD_GETSTATE extends Command
|
||||
final case object CMD_GETSTATEDATA extends Command
|
||||
final case object CMD_GETINFO extends Command
|
||||
final case class RES_GETINFO(nodeId: BinaryData, channelId: BinaryData, state: State, data: Data)
|
||||
|
||||
/*
|
||||
|
|
|
@ -40,7 +40,7 @@ class WaitForFundingSignedStateSpec extends TestkitBaseClass with StateTestsHelp
|
|||
test((alice, alice2bob, bob2alice, alice2blockchain))
|
||||
}
|
||||
|
||||
test("recv FundingSigned with valid signature") { case (alice, alice2bob, bob2alice, alice2blockchain) =>
|
||||
test("recv FundingSigned with valid signature") { case (alice, _, bob2alice, alice2blockchain) =>
|
||||
within(30 seconds) {
|
||||
bob2alice.expectMsgType[FundingSigned]
|
||||
bob2alice.forward(alice)
|
||||
|
@ -50,7 +50,7 @@ class WaitForFundingSignedStateSpec extends TestkitBaseClass with StateTestsHelp
|
|||
}
|
||||
}
|
||||
|
||||
test("recv FundingSigned with invalid signature") { case (alice, alice2bob, bob2alice, alice2blockchain) =>
|
||||
test("recv FundingSigned with invalid signature") { case (alice, alice2bob, _, _) =>
|
||||
within(30 seconds) {
|
||||
// sending an invalid sig
|
||||
alice ! FundingSigned("00" * 32, BinaryData("00" * 64))
|
||||
|
@ -59,11 +59,18 @@ class WaitForFundingSignedStateSpec extends TestkitBaseClass with StateTestsHelp
|
|||
}
|
||||
}
|
||||
|
||||
test("recv CMD_CLOSE") { case (alice, alice2bob, bob2alice, _) =>
|
||||
test("recv CMD_CLOSE") { case (alice, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
alice ! CMD_CLOSE(None)
|
||||
awaitCond(alice.stateName == CLOSED)
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CMD_FORCECLOSE") { case (alice, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
alice ! CMD_FORCECLOSE
|
||||
awaitCond(alice.stateName == CLOSED)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package fr.acinq.eclair.channel.states.c
|
||||
|
||||
import akka.actor.Status.Failure
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.Transaction
|
||||
import fr.acinq.eclair.TestConstants.{Alice, Bob}
|
||||
|
@ -104,10 +105,18 @@ class WaitForFundingConfirmedStateSpec extends TestkitBaseClass with StateTestsH
|
|||
}
|
||||
}
|
||||
|
||||
test("recv CMD_CLOSE") { case (alice, _, _, _, alice2blockchain) =>
|
||||
test("recv CMD_CLOSE") { case (alice, _, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
sender.send(alice, CMD_CLOSE(None))
|
||||
sender.expectMsg(Failure(CannotCloseInThisState(channelId(alice), WAIT_FOR_FUNDING_CONFIRMED)))
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CMD_FORCECLOSE") { case (alice, _, _, _, alice2blockchain) =>
|
||||
within(30 seconds) {
|
||||
val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CONFIRMED].commitments.localCommit.publishableTxs.commitTx.tx
|
||||
alice ! CMD_CLOSE(None)
|
||||
alice ! CMD_FORCECLOSE
|
||||
awaitCond(alice.stateName == CLOSING)
|
||||
alice2blockchain.expectMsg(PublishAsap(tx))
|
||||
alice2blockchain.expectMsgType[PublishAsap] // claim-main-delayed
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package fr.acinq.eclair.channel.states.c
|
||||
|
||||
import akka.actor.Status
|
||||
import akka.actor.Status.Failure
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.Transaction
|
||||
import fr.acinq.eclair.TestConstants.{Alice, Bob}
|
||||
|
@ -94,10 +96,18 @@ class WaitForFundingLockedStateSpec extends TestkitBaseClass with StateTestsHelp
|
|||
}
|
||||
}
|
||||
|
||||
test("recv CMD_CLOSE") { case (alice, _, alice2bob, bob2alice, alice2blockchain, router) =>
|
||||
test("recv CMD_CLOSE") { case (alice, _, _, _, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
sender.send(alice, CMD_CLOSE(None))
|
||||
sender.expectMsg(Failure(CannotCloseInThisState(channelId(alice), WAIT_FOR_FUNDING_LOCKED)))
|
||||
}
|
||||
}
|
||||
|
||||
test("recv CMD_FORCECLOSE") { case (alice, _, _, _, alice2blockchain, _) =>
|
||||
within(30 seconds) {
|
||||
val tx = alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_LOCKED].commitments.localCommit.publishableTxs.commitTx.tx
|
||||
alice ! CMD_CLOSE(None)
|
||||
alice ! CMD_FORCECLOSE
|
||||
awaitCond(alice.stateName == CLOSING)
|
||||
alice2blockchain.expectMsg(PublishAsap(tx))
|
||||
alice2blockchain.expectMsgType[PublishAsap]
|
||||
|
|
|
@ -1863,11 +1863,9 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
|||
within(30 seconds) {
|
||||
val initialState = alice.stateData.asInstanceOf[DATA_NORMAL]
|
||||
val sender = TestProbe()
|
||||
sender.send(alice, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 42, 10))
|
||||
assert(relayer.expectMsgType[LocalChannelUpdate].channelAnnouncement_opt === None)
|
||||
sender.send(alice, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 400000, 42))
|
||||
val annSigsA = alice2bob.expectMsgType[AnnouncementSignatures]
|
||||
sender.send(bob, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 42, 10))
|
||||
assert(relayer.expectMsgType[LocalChannelUpdate].channelAnnouncement_opt === None)
|
||||
sender.send(bob, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 400000, 42))
|
||||
val annSigsB = bob2alice.expectMsgType[AnnouncementSignatures]
|
||||
import initialState.commitments.localParams
|
||||
import initialState.commitments.remoteParams
|
||||
|
|
|
@ -3,8 +3,9 @@ package fr.acinq.eclair.channel.states.h
|
|||
import akka.actor.Status.Failure
|
||||
import akka.testkit.{TestFSMRef, TestProbe}
|
||||
import fr.acinq.bitcoin.{OutPoint, ScriptFlags, Transaction, TxIn}
|
||||
import fr.acinq.eclair.TestkitBaseClass
|
||||
import fr.acinq.eclair.{Globals, TestkitBaseClass}
|
||||
import fr.acinq.eclair.blockchain._
|
||||
import fr.acinq.eclair.blockchain.fee.FeeratesPerKw
|
||||
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
|
||||
import fr.acinq.eclair.channel.{Data, State, _}
|
||||
import fr.acinq.eclair.payment.{CommandBuffer, ForwardAdd, ForwardFulfill, Local}
|
||||
|
@ -101,7 +102,6 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
test("recv CMD_FULFILL_HTLC (unexisting htlc)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _, _) =>
|
||||
within(30 seconds) {
|
||||
mutualClose(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain)
|
||||
|
@ -115,6 +115,36 @@ class ClosingStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
|
|||
}
|
||||
}
|
||||
|
||||
test("recv BITCOIN_FUNDING_SPENT (mutual close before converging)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _, _) =>
|
||||
within(30 seconds) {
|
||||
val sender = TestProbe()
|
||||
// alice initiates a closing
|
||||
sender.send(alice, CMD_CLOSE(None))
|
||||
alice2bob.expectMsgType[Shutdown]
|
||||
alice2bob.forward(bob)
|
||||
bob2alice.expectMsgType[Shutdown]
|
||||
bob2alice.forward(alice)
|
||||
// agreeing on a closing fee
|
||||
val aliceCloseFee = alice2bob.expectMsgType[ClosingSigned].feeSatoshis
|
||||
Globals.feeratesPerKw.set(FeeratesPerKw.single(100))
|
||||
alice2bob.forward(bob)
|
||||
val bobCloseFee = bob2alice.expectMsgType[ClosingSigned].feeSatoshis
|
||||
bob2alice.forward(alice)
|
||||
// they don't converge yet, but alice has a publishable commit tx now
|
||||
assert(aliceCloseFee != bobCloseFee)
|
||||
val Some(mutualCloseTx) = alice.stateData.asInstanceOf[DATA_NEGOTIATING].bestUnpublishedClosingTx_opt
|
||||
// let's make alice publish this closing tx
|
||||
alice ! Error("00" * 32, "")
|
||||
awaitCond(alice.stateName == CLOSING)
|
||||
assert(mutualCloseTx === alice.stateData.asInstanceOf[DATA_CLOSING].mutualClosePublished.last)
|
||||
|
||||
// actual test starts here
|
||||
alice ! WatchEventSpent(BITCOIN_FUNDING_SPENT, mutualCloseTx)
|
||||
alice ! WatchEventConfirmed(BITCOIN_TX_CONFIRMED(mutualCloseTx), 0, 0)
|
||||
awaitCond(alice.stateName == CLOSED)
|
||||
}
|
||||
}
|
||||
|
||||
test("recv BITCOIN_TX_CONFIRMED (mutual close)") { case (alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain, _, _) =>
|
||||
within(30 seconds) {
|
||||
mutualClose(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain)
|
||||
|
|
|
@ -405,7 +405,8 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
|||
sender.expectMsgType[State] == OFFLINE
|
||||
}, max = 20 seconds, interval = 1 second)
|
||||
// we then have C unilateral close the channel (which will make F redeem the htlc onchain)
|
||||
sender.send(nodes("C").register, Forward(htlc.channelId, INPUT_PUBLISH_LOCALCOMMIT))
|
||||
sender.send(nodes("C").register, Forward(htlc.channelId, CMD_FORCECLOSE))
|
||||
sender.expectMsg("ok")
|
||||
// we then wait for F to detect the unilateral close and go to CLOSING state
|
||||
awaitCond({
|
||||
sender.send(nodes("F1").register, Forward(htlc.channelId, CMD_GETSTATE))
|
||||
|
@ -474,7 +475,8 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
|||
sender.expectMsgType[State] == OFFLINE
|
||||
}, max = 20 seconds, interval = 1 second)
|
||||
// then we have F unilateral close the channel
|
||||
sender.send(nodes("F2").register, Forward(htlc.channelId, INPUT_PUBLISH_LOCALCOMMIT))
|
||||
sender.send(nodes("F2").register, Forward(htlc.channelId, CMD_FORCECLOSE))
|
||||
sender.expectMsg("ok")
|
||||
// we then fulfill the htlc (it won't be sent to C, and will be used to pull funds on-chain)
|
||||
sender.send(nodes("F2").register, Forward(htlc.channelId, CMD_FULFILL_HTLC(htlc.id, preimage)))
|
||||
// we then generate one block so that the htlc success tx gets written to the blockchain
|
||||
|
@ -580,7 +582,8 @@ class IntegrationSpec extends TestKit(ActorSystem("test")) with FunSuiteLike wit
|
|||
val res = sender.expectMsgType[JValue](10 seconds)
|
||||
val previouslyReceivedByC = res.filter(_ \ "address" == JString(finalAddressC)).flatMap(_ \ "txids" \\ classOf[JString])
|
||||
// then we ask F to unilaterally close the channel
|
||||
sender.send(nodes("F4").register, Forward(htlc.channelId, INPUT_PUBLISH_LOCALCOMMIT))
|
||||
sender.send(nodes("F4").register, Forward(htlc.channelId, CMD_FORCECLOSE))
|
||||
sender.expectMsg("ok")
|
||||
// we then generate enough blocks to make the htlc timeout
|
||||
sender.send(bitcoincli, BitcoinReq("generate", 11))
|
||||
sender.expectMsgType[JValue](10 seconds)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>fr.acinq.eclair</groupId>
|
||||
<artifactId>eclair_2.11</artifactId>
|
||||
<version>0.2-android-SNAPSHOT</version>
|
||||
<version>0.2-android-alpha13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>eclair-node_2.11</artifactId>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
akka {
|
||||
|
||||
loggers = ["akka.event.slf4j.Slf4jLogger"]
|
||||
loglevel = "INFO"
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<appender-ref ref="CYAN"/>
|
||||
</logger>
|
||||
|
||||
<logger name="fr.acinq.eclair.gui" level="WARN" additivity="false">
|
||||
<logger name="fr.acinq.eclair.gui" level="INFO" additivity="false">
|
||||
<appender-ref ref="MAGENTA"/>
|
||||
</logger>
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -4,7 +4,7 @@
|
|||
|
||||
<groupId>fr.acinq.eclair</groupId>
|
||||
<artifactId>eclair_2.11</artifactId>
|
||||
<version>0.2-android-SNAPSHOT</version>
|
||||
<version>0.2-android-alpha13</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
|
|
Loading…
Add table
Reference in a new issue