Skip to content

Commit

Permalink
Improve channel state tests (#1709)
Browse files Browse the repository at this point in the history
* add tests on funding mindepth

We verify that when using wumbo channels:
- if we are funder we keep our regular min_depth
- if we are fundee we use a greater min_depth

* use lenses to simplify tags handling

Co-authored-by: Bastien Teinturier <[email protected]>
  • Loading branch information
pm47 and t-bast authored Feb 26, 2021
1 parent 8065d0b commit 8d4da2f
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,29 +98,37 @@ trait StateTestsHelperMethods extends TestKitBase {
}

def reachNormal(setup: SetupFixture, tags: Set[String] = Set.empty): Unit = {
import com.softwaremill.quicklens._
import setup._
val channelVersion = List(
ChannelVersion.STANDARD,
if (tags.contains(StateTestsTags.AnchorOutputs)) ChannelVersion.ANCHOR_OUTPUTS else ChannelVersion.ZEROES,
if (tags.contains(StateTestsTags.StaticRemoteKey)) ChannelVersion.STATIC_REMOTEKEY else ChannelVersion.ZEROES,
).reduce(_ | _)

val channelFlags = if (tags.contains(StateTestsTags.ChannelsPublic)) ChannelFlags.AnnounceChannel else ChannelFlags.Empty
val pushMsat = if (tags.contains(StateTestsTags.NoPushMsat)) 0.msat else TestConstants.pushMsat
val (aliceParams, bobParams, channelVersion) = if (tags.contains(StateTestsTags.AnchorOutputs)) {
val features = Features(Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Mandatory), ActivatedFeature(Features.AnchorOutputs, FeatureSupport.Optional)))
(Alice.channelParams.copy(features = features), Bob.channelParams.copy(features = features), ChannelVersion.ANCHOR_OUTPUTS)
} else if (tags.contains(StateTestsTags.StaticRemoteKey)) {
val features = Features(Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Optional)))
val aliceParams = Alice.channelParams.copy(features = features, walletStaticPaymentBasepoint = Some(Helpers.getWalletPaymentBasepoint(wallet)))
val bobParams = Bob.channelParams.copy(features = features, walletStaticPaymentBasepoint = Some(Helpers.getWalletPaymentBasepoint(wallet)))
(aliceParams, bobParams, ChannelVersion.STATIC_REMOTEKEY)
} else {
(Alice.channelParams, Bob.channelParams, ChannelVersion.STANDARD)
}
val aliceParams = Alice.channelParams
.modify(_.features.activated).usingIf(channelVersion.hasStaticRemotekey)(_ ++ Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Optional)))
.modify(_.features.activated).usingIf(channelVersion.hasAnchorOutputs)(_ ++ Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Mandatory), ActivatedFeature(Features.AnchorOutputs, FeatureSupport.Optional)))
.modify(_.walletStaticPaymentBasepoint).setToIf(channelVersion.paysDirectlyToWallet)(Some(Helpers.getWalletPaymentBasepoint(wallet)))
val bobParams = Bob.channelParams
.modify(_.features.activated).usingIf(channelVersion.hasStaticRemotekey)(_ ++ Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Optional)))
.modify(_.features.activated).usingIf(channelVersion.hasAnchorOutputs)(_ ++ Set(ActivatedFeature(Features.StaticRemoteKey, FeatureSupport.Mandatory), ActivatedFeature(Features.AnchorOutputs, FeatureSupport.Optional)))
.modify(_.walletStaticPaymentBasepoint).setToIf(channelVersion.paysDirectlyToWallet)(Some(Helpers.getWalletPaymentBasepoint(wallet)))
val initialFeeratePerKw = if (tags.contains(StateTestsTags.AnchorOutputs)) {
FeeEstimator.AnchorOutputMaxCommitFeerate
} else {
TestConstants.feeratePerKw
}
val (fundingSatoshis, pushMsat) = if (tags.contains(StateTestsTags.NoPushMsat)) {
(TestConstants.fundingSatoshis, 0.msat)
} else {
(TestConstants.fundingSatoshis, TestConstants.pushMsat)
}

val aliceInit = Init(aliceParams.features)
val bobInit = Init(bobParams.features)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelVersion)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelVersion)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelVersion)
alice2bob.expectMsgType[OpenChannel]
alice2bob.forward(bob)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ package fr.acinq.eclair.channel.states.b

import akka.actor.ActorRef
import akka.testkit.{TestFSMRef, TestProbe}
import fr.acinq.bitcoin.{ByteVector32, SatoshiLong}
import fr.acinq.bitcoin.{Btc, ByteVector32, SatoshiLong}
import fr.acinq.eclair.FeatureSupport.Optional
import fr.acinq.eclair.Features.Wumbo
import fr.acinq.eclair.TestConstants.{Alice, Bob}
import fr.acinq.eclair.blockchain._
import fr.acinq.eclair.channel._
import fr.acinq.eclair.channel.states.StateTestsBase
import fr.acinq.eclair.transactions.Transactions
import fr.acinq.eclair.wire._
import fr.acinq.eclair.{TestConstants, TestKitBaseClass, ToMilliSatoshiConversion}
import fr.acinq.eclair.{ActivatedFeature, Features, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion}
import org.scalatest.funsuite.FixtureAnyFunSuiteLike
import org.scalatest.{Outcome, Tag}

Expand All @@ -40,18 +42,32 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun
case class FixtureParam(bob: TestFSMRef[State, Data, Channel], alice2bob: TestProbe, bob2alice: TestProbe, bob2blockchain: TestProbe)

override def withFixture(test: OneArgTest): Outcome = {
val setup = init()
import setup._
import com.softwaremill.quicklens._
val aliceNodeParams = Alice.nodeParams
.modify(_.maxFundingSatoshis).setToIf(test.tags.contains("wumbo"))(Btc(100))
val aliceParams = Alice.channelParams
.modify(_.features).setToIf(test.tags.contains("wumbo"))(Features(Set(ActivatedFeature(Wumbo, Optional))))
val bobNodeParams = Bob.nodeParams
.modify(_.maxFundingSatoshis).setToIf(test.tags.contains("wumbo"))(Btc(100))
val bobParams = Bob.channelParams
.modify(_.features).setToIf(test.tags.contains("wumbo"))(Features(Set(ActivatedFeature(Wumbo, Optional))))

val (fundingSatoshis, pushMsat) = if (test.tags.contains("funder_below_reserve")) {
(1000100 sat, (1000000 sat).toMilliSatoshi) // toLocal = 100 satoshis
} else if (test.tags.contains("wumbo")) {
(Btc(5).toSatoshi, TestConstants.pushMsat)
} else {
(TestConstants.fundingSatoshis, TestConstants.pushMsat)
}
val aliceInit = Init(Alice.channelParams.features)
val bobInit = Init(Bob.channelParams.features)

val setup = init(aliceNodeParams, bobNodeParams)

import setup._
val aliceInit = Init(aliceParams.features)
val bobInit = Init(bobParams.features)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, None, Alice.channelParams, alice2bob.ref, bobInit, ChannelFlags.Empty, ChannelVersion.STANDARD)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, bob2alice.ref, aliceInit, ChannelVersion.STANDARD)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, None, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, ChannelVersion.STANDARD)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, ChannelVersion.STANDARD)
alice2bob.expectMsgType[OpenChannel]
alice2bob.forward(bob)
bob2alice.expectMsgType[AcceptChannel]
Expand All @@ -68,7 +84,20 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun
awaitCond(bob.stateName == WAIT_FOR_FUNDING_CONFIRMED)
bob2alice.expectMsgType[FundingSigned]
bob2blockchain.expectMsgType[WatchSpent]
bob2blockchain.expectMsgType[WatchConfirmed]
val watchConfirmed = bob2blockchain.expectMsgType[WatchConfirmed]
assert(watchConfirmed.minDepth === Alice.nodeParams.minDepthBlocks)
}

test("recv FundingCreated (wumbo)", Tag("wumbo")) { f =>
import f._
alice2bob.expectMsgType[FundingCreated]
alice2bob.forward(bob)
awaitCond(bob.stateName == WAIT_FOR_FUNDING_CONFIRMED)
bob2alice.expectMsgType[FundingSigned]
bob2blockchain.expectMsgType[WatchSpent]
val watchConfirmed = bob2blockchain.expectMsgType[WatchConfirmed]
// when we are fundee, we use a higher min depth for wumbo channels
assert(watchConfirmed.minDepth > Bob.nodeParams.minDepthBlocks)
}

test("recv FundingCreated (funder can't pay fees)", Tag("funder_below_reserve")) { f =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@
package fr.acinq.eclair.channel.states.b

import akka.testkit.{TestFSMRef, TestProbe}
import fr.acinq.bitcoin.{ByteVector32, ByteVector64}
import fr.acinq.bitcoin.{Btc, ByteVector32, ByteVector64}
import fr.acinq.eclair.FeatureSupport.Optional
import fr.acinq.eclair.Features.Wumbo
import fr.acinq.eclair.TestConstants.{Alice, Bob}
import fr.acinq.eclair.blockchain._
import fr.acinq.eclair.channel.Channel.TickChannelOpenTimeout
import fr.acinq.eclair.channel._
import fr.acinq.eclair.channel.states.StateTestsBase
import fr.acinq.eclair.wire.{AcceptChannel, Error, FundingCreated, FundingSigned, Init, OpenChannel}
import fr.acinq.eclair.{TestConstants, TestKitBaseClass}
import org.scalatest.Outcome
import fr.acinq.eclair.{ActivatedFeature, Features, TestConstants, TestKitBaseClass}
import org.scalatest.{Outcome, Tag}
import org.scalatest.funsuite.FixtureAnyFunSuiteLike

import scala.concurrent.duration._
Expand All @@ -39,13 +41,30 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
case class FixtureParam(alice: TestFSMRef[State, Data, Channel], alice2bob: TestProbe, bob2alice: TestProbe, alice2blockchain: TestProbe)

override def withFixture(test: OneArgTest): Outcome = {
val setup = init()
import com.softwaremill.quicklens._
val aliceNodeParams = Alice.nodeParams
.modify(_.maxFundingSatoshis).setToIf(test.tags.contains("wumbo"))(Btc(100))
val aliceParams = Alice.channelParams
.modify(_.features).setToIf(test.tags.contains("wumbo"))(Features(Set(ActivatedFeature(Wumbo, Optional))))
val bobNodeParams = Bob.nodeParams
.modify(_.maxFundingSatoshis).setToIf(test.tags.contains("wumbo"))(Btc(100))
val bobParams = Bob.channelParams
.modify(_.features).setToIf(test.tags.contains("wumbo"))(Features(Set(ActivatedFeature(Wumbo, Optional))))

val (fundingSatoshis, pushMsat) = if (test.tags.contains("wumbo")) {
(Btc(5).toSatoshi, TestConstants.pushMsat)
} else {
(TestConstants.fundingSatoshis, TestConstants.pushMsat)
}

val setup = init(aliceNodeParams, bobNodeParams)

import setup._
val aliceInit = Init(Alice.channelParams.features)
val bobInit = Init(Bob.channelParams.features)
val aliceInit = Init(aliceParams.features)
val bobInit = Init(bobParams.features)
within(30 seconds) {
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, None, Alice.channelParams, alice2bob.ref, bobInit, ChannelFlags.Empty, ChannelVersion.STANDARD)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, bob2alice.ref, aliceInit, ChannelVersion.STANDARD)
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, None, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Empty, ChannelVersion.STANDARD)
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, ChannelVersion.STANDARD)
alice2bob.expectMsgType[OpenChannel]
alice2bob.forward(bob)
bob2alice.expectMsgType[AcceptChannel]
Expand All @@ -63,7 +82,20 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
bob2alice.forward(alice)
awaitCond(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED)
alice2blockchain.expectMsgType[WatchSpent]
alice2blockchain.expectMsgType[WatchConfirmed]
val watchConfirmed = alice2blockchain.expectMsgType[WatchConfirmed]
// when we are funder, we keep our regular min depth even for wumbo channels
assert(watchConfirmed.minDepth === Alice.nodeParams.minDepthBlocks)
}

test("recv FundingSigned with valid signature (wumbo)", Tag("wumbo")) { f =>
import f._
bob2alice.expectMsgType[FundingSigned]
bob2alice.forward(alice)
awaitCond(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED)
alice2blockchain.expectMsgType[WatchSpent]
val watchConfirmed = alice2blockchain.expectMsgType[WatchConfirmed]

assert(watchConfirmed.minDepth === Alice.nodeParams.minDepthBlocks)
}

test("recv FundingSigned with invalid signature") { f =>
Expand Down

0 comments on commit 8d4da2f

Please sign in to comment.