mirror of
https://github.com/ACINQ/eclair.git
synced 2025-02-23 22:46:44 +01:00
Add localChannelReserve
and remoteChannelReserve
(#2237)
This is easier to use than having to decide which params we should look into (local or remote). It will also be easier to integrate with dual funding. Rename initialFeeratePerKw: this name was very confusing. This feerate only applies to the commit tx, so we make that explicit.
This commit is contained in:
parent
bb7703aa5d
commit
03097b0d42
25 changed files with 157 additions and 100 deletions
|
@ -18,7 +18,7 @@ package fr.acinq.eclair.channel
|
|||
|
||||
import akka.actor.{ActorRef, PossiblyHarmful}
|
||||
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
|
||||
import fr.acinq.bitcoin.scalacompat.{ByteVector32, DeterministicWallet, OutPoint, Satoshi, Transaction}
|
||||
import fr.acinq.bitcoin.scalacompat.{ByteVector32, DeterministicWallet, OutPoint, Satoshi, SatoshiLong, Transaction}
|
||||
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
|
||||
import fr.acinq.eclair.payment.OutgoingPaymentPacket.Upstream
|
||||
import fr.acinq.eclair.transactions.CommitmentSpec
|
||||
|
@ -78,8 +78,8 @@ case object ERR_INFORMATION_LEAK extends ChannelState
|
|||
case class INPUT_INIT_FUNDER(temporaryChannelId: ByteVector32,
|
||||
fundingAmount: Satoshi,
|
||||
pushAmount: MilliSatoshi,
|
||||
initialFeeratePerKw: FeeratePerKw,
|
||||
fundingTxFeeratePerKw: FeeratePerKw,
|
||||
commitTxFeerate: FeeratePerKw,
|
||||
fundingTxFeerate: FeeratePerKw,
|
||||
localParams: LocalParams,
|
||||
remote: ActorRef,
|
||||
remoteInit: Init,
|
||||
|
@ -196,7 +196,7 @@ final case class CMD_GET_CHANNEL_INFO(replyTo: ActorRef)extends HasReplyToComman
|
|||
/** response to [[Command]] requests */
|
||||
sealed trait CommandResponse[+C <: Command]
|
||||
sealed trait CommandSuccess[+C <: Command] extends CommandResponse[C]
|
||||
sealed trait CommandFailure[+C <: Command, +T <: Throwable] extends CommandResponse[C] { def t: Throwable }
|
||||
sealed trait CommandFailure[+C <: Command, +T <: Throwable] extends CommandResponse[C] { def t: T }
|
||||
|
||||
/** generic responses */
|
||||
final case class RES_SUCCESS[+C <: Command](cmd: C, channelId: ByteVector32) extends CommandSuccess[C]
|
||||
|
@ -387,7 +387,7 @@ final case class DATA_WAIT_FOR_FUNDING_INTERNAL(temporaryChannelId: ByteVector32
|
|||
remoteParams: RemoteParams,
|
||||
fundingAmount: Satoshi,
|
||||
pushAmount: MilliSatoshi,
|
||||
initialFeeratePerKw: FeeratePerKw,
|
||||
commitTxFeerate: FeeratePerKw,
|
||||
remoteFirstPerCommitmentPoint: PublicKey,
|
||||
channelConfig: ChannelConfig,
|
||||
channelFeatures: ChannelFeatures,
|
||||
|
@ -399,7 +399,7 @@ final case class DATA_WAIT_FOR_FUNDING_CREATED(temporaryChannelId: ByteVector32,
|
|||
remoteParams: RemoteParams,
|
||||
fundingAmount: Satoshi,
|
||||
pushAmount: MilliSatoshi,
|
||||
initialFeeratePerKw: FeeratePerKw,
|
||||
commitTxFeerate: FeeratePerKw,
|
||||
remoteFirstPerCommitmentPoint: PublicKey,
|
||||
channelFlags: ChannelFlags,
|
||||
channelConfig: ChannelConfig,
|
||||
|
@ -466,7 +466,7 @@ case class LocalParams(nodeId: PublicKey,
|
|||
fundingKeyPath: DeterministicWallet.KeyPath,
|
||||
dustLimit: Satoshi,
|
||||
maxHtlcValueInFlightMsat: UInt64, // this is not MilliSatoshi because it can exceed the total amount of MilliSatoshi
|
||||
channelReserve: Satoshi,
|
||||
requestedChannelReserve_opt: Option[Satoshi],
|
||||
htlcMinimum: MilliSatoshi,
|
||||
toSelfDelay: CltvExpiryDelta,
|
||||
maxAcceptedHtlcs: Int,
|
||||
|
@ -481,7 +481,7 @@ case class LocalParams(nodeId: PublicKey,
|
|||
case class RemoteParams(nodeId: PublicKey,
|
||||
dustLimit: Satoshi,
|
||||
maxHtlcValueInFlightMsat: UInt64, // this is not MilliSatoshi because it can exceed the total amount of MilliSatoshi
|
||||
channelReserve: Satoshi,
|
||||
requestedChannelReserve_opt: Option[Satoshi],
|
||||
htlcMinimum: MilliSatoshi,
|
||||
toSelfDelay: CltvExpiryDelta,
|
||||
maxAcceptedHtlcs: Int,
|
||||
|
|
|
@ -30,7 +30,7 @@ import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelUpdate}
|
|||
|
||||
trait ChannelEvent
|
||||
|
||||
case class ChannelCreated(channel: ActorRef, peer: ActorRef, remoteNodeId: PublicKey, isInitiator: Boolean, temporaryChannelId: ByteVector32, initialFeeratePerKw: FeeratePerKw, fundingTxFeeratePerKw: Option[FeeratePerKw]) extends ChannelEvent
|
||||
case class ChannelCreated(channel: ActorRef, peer: ActorRef, remoteNodeId: PublicKey, isInitiator: Boolean, temporaryChannelId: ByteVector32, commitTxFeerate: FeeratePerKw, fundingTxFeerate: Option[FeeratePerKw]) extends ChannelEvent
|
||||
|
||||
// This trait can be used by non-standard channels to inject themselves into Register actor and thus make them usable for routing
|
||||
trait AbstractChannelRestored extends ChannelEvent {
|
||||
|
|
|
@ -211,6 +211,12 @@ case class Commitments(channelId: ByteVector32,
|
|||
|
||||
val capacity: Satoshi = commitInput.txOut.amount
|
||||
|
||||
/** Channel reserve that applies to our funds. */
|
||||
val localChannelReserve: Satoshi = remoteParams.requestedChannelReserve_opt.getOrElse(0 sat)
|
||||
|
||||
/** Channel reserve that applies to our peer's funds. */
|
||||
val remoteChannelReserve: Satoshi = localParams.requestedChannelReserve_opt.getOrElse(0 sat)
|
||||
|
||||
// NB: when computing availableBalanceForSend and availableBalanceForReceive, the initiator keeps an extra buffer on
|
||||
// top of its usual channel reserve to avoid getting channels stuck in case the on-chain feerate increases (see
|
||||
// https://github.com/lightningnetwork/lightning-rfc/issues/728 for details).
|
||||
|
@ -241,7 +247,7 @@ case class Commitments(channelId: ByteVector32,
|
|||
// we need to base the next current commitment on the last sig we sent, even if we didn't yet receive their revocation
|
||||
val remoteCommit1 = remoteNextCommitInfo.left.toOption.map(_.nextRemoteCommit).getOrElse(remoteCommit)
|
||||
val reduced = CommitmentSpec.reduce(remoteCommit1.spec, remoteChanges.acked, localChanges.proposed)
|
||||
val balanceNoFees = (reduced.toRemote - remoteParams.channelReserve).max(0 msat)
|
||||
val balanceNoFees = (reduced.toRemote - localChannelReserve).max(0 msat)
|
||||
if (localParams.isInitiator) {
|
||||
// The initiator always pays the on-chain fees, so we must subtract that from the amount we can send.
|
||||
val commitFees = commitTxTotalCostMsat(remoteParams.dustLimit, reduced, commitmentFormat)
|
||||
|
@ -267,7 +273,7 @@ case class Commitments(channelId: ByteVector32,
|
|||
|
||||
lazy val availableBalanceForReceive: MilliSatoshi = {
|
||||
val reduced = CommitmentSpec.reduce(localCommit.spec, localChanges.acked, remoteChanges.proposed)
|
||||
val balanceNoFees = (reduced.toRemote - localParams.channelReserve).max(0 msat)
|
||||
val balanceNoFees = (reduced.toRemote - remoteChannelReserve).max(0 msat)
|
||||
if (localParams.isInitiator) {
|
||||
// The non-initiator doesn't pay on-chain fees so we don't take those into account when receiving.
|
||||
balanceNoFees
|
||||
|
@ -372,15 +378,15 @@ object Commitments {
|
|||
val funderFeeBuffer = commitTxTotalCostMsat(commitments1.remoteParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), commitments.commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, commitments.commitmentFormat)
|
||||
// NB: increasing the feerate can actually remove htlcs from the commit tx (if they fall below the trim threshold)
|
||||
// which may result in a lower commit tx fee; this is why we take the max of the two.
|
||||
val missingForSender = reduced.toRemote - commitments1.remoteParams.channelReserve - (if (commitments1.localParams.isInitiator) fees.max(funderFeeBuffer.truncateToSatoshi) else 0.sat)
|
||||
val missingForReceiver = reduced.toLocal - commitments1.localParams.channelReserve - (if (commitments1.localParams.isInitiator) 0.sat else fees)
|
||||
val missingForSender = reduced.toRemote - commitments1.localChannelReserve - (if (commitments1.localParams.isInitiator) fees.max(funderFeeBuffer.truncateToSatoshi) else 0.sat)
|
||||
val missingForReceiver = reduced.toLocal - commitments1.remoteChannelReserve - (if (commitments1.localParams.isInitiator) 0.sat else fees)
|
||||
if (missingForSender < 0.msat) {
|
||||
return Left(InsufficientFunds(commitments.channelId, amount = cmd.amount, missing = -missingForSender.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = if (commitments1.localParams.isInitiator) fees else 0.sat))
|
||||
return Left(InsufficientFunds(commitments.channelId, amount = cmd.amount, missing = -missingForSender.truncateToSatoshi, reserve = commitments1.localChannelReserve, fees = if (commitments1.localParams.isInitiator) fees else 0.sat))
|
||||
} else if (missingForReceiver < 0.msat) {
|
||||
if (commitments.localParams.isInitiator) {
|
||||
// receiver is not the channel initiator; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment
|
||||
} else {
|
||||
return Left(RemoteCannotAffordFeesForNewHtlc(commitments.channelId, amount = cmd.amount, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = fees))
|
||||
return Left(RemoteCannotAffordFeesForNewHtlc(commitments.channelId, amount = cmd.amount, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteChannelReserve, fees = fees))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,13 +447,13 @@ object Commitments {
|
|||
val fees = commitTxTotalCost(commitments1.remoteParams.dustLimit, reduced, commitments.commitmentFormat)
|
||||
// NB: we don't enforce the funderFeeReserve (see sendAdd) because it would confuse a remote initiator that doesn't have this mitigation in place
|
||||
// We could enforce it once we're confident a large portion of the network implements it.
|
||||
val missingForSender = reduced.toRemote - commitments1.localParams.channelReserve - (if (commitments1.localParams.isInitiator) 0.sat else fees)
|
||||
val missingForReceiver = reduced.toLocal - commitments1.remoteParams.channelReserve - (if (commitments1.localParams.isInitiator) fees else 0.sat)
|
||||
val missingForSender = reduced.toRemote - commitments1.remoteChannelReserve - (if (commitments1.localParams.isInitiator) 0.sat else fees)
|
||||
val missingForReceiver = reduced.toLocal - commitments1.localChannelReserve - (if (commitments1.localParams.isInitiator) fees else 0.sat)
|
||||
if (missingForSender < 0.sat) {
|
||||
return Left(InsufficientFunds(commitments.channelId, amount = add.amountMsat, missing = -missingForSender.truncateToSatoshi, reserve = commitments1.localParams.channelReserve, fees = if (commitments1.localParams.isInitiator) 0.sat else fees))
|
||||
return Left(InsufficientFunds(commitments.channelId, amount = add.amountMsat, missing = -missingForSender.truncateToSatoshi, reserve = commitments1.remoteChannelReserve, fees = if (commitments1.localParams.isInitiator) 0.sat else fees))
|
||||
} else if (missingForReceiver < 0.sat) {
|
||||
if (commitments.localParams.isInitiator) {
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = fees))
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.localChannelReserve, fees = fees))
|
||||
} else {
|
||||
// receiver is not the channel initiator; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment
|
||||
}
|
||||
|
@ -558,9 +564,9 @@ object Commitments {
|
|||
// a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee
|
||||
// we look from remote's point of view, so if local is initiator remote doesn't pay the fees
|
||||
val fees = commitTxTotalCost(commitments1.remoteParams.dustLimit, reduced, commitments.commitmentFormat)
|
||||
val missing = reduced.toRemote.truncateToSatoshi - commitments1.remoteParams.channelReserve - fees
|
||||
val missing = reduced.toRemote.truncateToSatoshi - commitments1.localChannelReserve - fees
|
||||
if (missing < 0.sat) {
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.remoteParams.channelReserve, fees = fees))
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.localChannelReserve, fees = fees))
|
||||
}
|
||||
|
||||
// if we would overflow our dust exposure with the new feerate, we avoid sending this fee update
|
||||
|
@ -608,9 +614,9 @@ object Commitments {
|
|||
|
||||
// a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee
|
||||
val fees = commitTxTotalCost(commitments1.localParams.dustLimit, reduced, commitments.commitmentFormat)
|
||||
val missing = reduced.toRemote.truncateToSatoshi - commitments1.localParams.channelReserve - fees
|
||||
val missing = reduced.toRemote.truncateToSatoshi - commitments1.remoteChannelReserve - fees
|
||||
if (missing < 0.sat) {
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.localParams.channelReserve, fees = fees))
|
||||
return Left(CannotAffordFees(commitments.channelId, missing = -missing, reserve = commitments1.remoteChannelReserve, fees = fees))
|
||||
}
|
||||
|
||||
// if we would overflow our dust exposure with the new feerate, we reject this fee update
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
package fr.acinq.eclair.channel
|
||||
|
||||
import akka.event.{DiagnosticLoggingAdapter, LoggingAdapter}
|
||||
import fr.acinq.bitcoin.ScriptFlags
|
||||
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, sha256}
|
||||
import fr.acinq.bitcoin.scalacompat.Script._
|
||||
import fr.acinq.bitcoin.scalacompat._
|
||||
import fr.acinq.bitcoin.ScriptFlags
|
||||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.blockchain.OnChainAddressGenerator
|
||||
import fr.acinq.eclair.blockchain.fee.{FeeEstimator, FeeTargets, FeeratePerKw}
|
||||
|
@ -254,8 +254,8 @@ object Helpers {
|
|||
}
|
||||
val toRemoteSatoshis = remoteCommit.spec.toRemote.truncateToSatoshi
|
||||
// NB: this is an approximation (we don't take network fees into account)
|
||||
val result = toRemoteSatoshis > commitments.remoteParams.channelReserve
|
||||
log.debug(s"toRemoteSatoshis=$toRemoteSatoshis reserve=${commitments.remoteParams.channelReserve} aboveReserve=$result for remoteCommitNumber=${remoteCommit.index}")
|
||||
val result = toRemoteSatoshis > commitments.localChannelReserve
|
||||
log.debug(s"toRemoteSatoshis=$toRemoteSatoshis reserve=${commitments.localChannelReserve} aboveReserve=$result for remoteCommitNumber=${remoteCommit.index}")
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -289,20 +289,21 @@ object Helpers {
|
|||
*
|
||||
* @return (localSpec, localTx, remoteSpec, remoteTx, fundingTxOutput)
|
||||
*/
|
||||
def makeFirstCommitTxs(keyManager: ChannelKeyManager, channelConfig: ChannelConfig, channelFeatures: ChannelFeatures, temporaryChannelId: ByteVector32, localParams: LocalParams, remoteParams: RemoteParams, fundingAmount: Satoshi, pushMsat: MilliSatoshi, initialFeeratePerKw: FeeratePerKw, fundingTxHash: ByteVector32, fundingTxOutputIndex: Int, remoteFirstPerCommitmentPoint: PublicKey): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx)] = {
|
||||
def makeFirstCommitTxs(keyManager: ChannelKeyManager, channelConfig: ChannelConfig, channelFeatures: ChannelFeatures, temporaryChannelId: ByteVector32, localParams: LocalParams, remoteParams: RemoteParams, fundingAmount: Satoshi, pushMsat: MilliSatoshi, commitTxFeerate: FeeratePerKw, fundingTxHash: ByteVector32, fundingTxOutputIndex: Int, remoteFirstPerCommitmentPoint: PublicKey): Either[ChannelException, (CommitmentSpec, CommitTx, CommitmentSpec, CommitTx)] = {
|
||||
val toLocalMsat = if (localParams.isInitiator) fundingAmount.toMilliSatoshi - pushMsat else pushMsat
|
||||
val toRemoteMsat = if (localParams.isInitiator) pushMsat else fundingAmount.toMilliSatoshi - pushMsat
|
||||
|
||||
val localSpec = CommitmentSpec(Set.empty[DirectedHtlc], initialFeeratePerKw, toLocal = toLocalMsat, toRemote = toRemoteMsat)
|
||||
val remoteSpec = CommitmentSpec(Set.empty[DirectedHtlc], initialFeeratePerKw, toLocal = toRemoteMsat, toRemote = toLocalMsat)
|
||||
val localSpec = CommitmentSpec(Set.empty[DirectedHtlc], commitTxFeerate, toLocal = toLocalMsat, toRemote = toRemoteMsat)
|
||||
val remoteSpec = CommitmentSpec(Set.empty[DirectedHtlc], commitTxFeerate, toLocal = toRemoteMsat, toRemote = toLocalMsat)
|
||||
|
||||
if (!localParams.isInitiator) {
|
||||
// they initiated the channel open, therefore they pay the fee: we need to make sure they can afford it!
|
||||
val toRemoteMsat = remoteSpec.toLocal
|
||||
val fees = commitTxTotalCost(remoteParams.dustLimit, remoteSpec, channelFeatures.commitmentFormat)
|
||||
val missing = toRemoteMsat.truncateToSatoshi - localParams.channelReserve - fees
|
||||
val reserve = localParams.requestedChannelReserve_opt.getOrElse(0 sat)
|
||||
val missing = toRemoteMsat.truncateToSatoshi - reserve - fees
|
||||
if (missing < Satoshi(0)) {
|
||||
return Left(CannotAffordFees(temporaryChannelId, missing = -missing, reserve = localParams.channelReserve, fees = fees))
|
||||
return Left(CannotAffordFees(temporaryChannelId, missing = -missing, reserve = reserve, fees = fees))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -208,8 +208,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder, val
|
|||
startWith(WAIT_FOR_INIT_INTERNAL, Nothing)
|
||||
|
||||
when(WAIT_FOR_INIT_INTERNAL)(handleExceptions {
|
||||
case Event(initFunder@INPUT_INIT_FUNDER(temporaryChannelId, fundingSatoshis, pushMsat, initialFeeratePerKw, fundingTxFeeratePerKw, localParams, remote, remoteInit, channelFlags, channelConfig, channelType), Nothing) =>
|
||||
context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isInitiator = true, temporaryChannelId, initialFeeratePerKw, Some(fundingTxFeeratePerKw)))
|
||||
case Event(initFunder@INPUT_INIT_FUNDER(temporaryChannelId, fundingSatoshis, pushMsat, commitTxFeerate, fundingTxFeerate, localParams, remote, remoteInit, channelFlags, channelConfig, channelType), Nothing) =>
|
||||
context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isInitiator = true, temporaryChannelId, commitTxFeerate, Some(fundingTxFeerate)))
|
||||
activeConnection = remote
|
||||
txPublisher ! SetChannelId(remoteNodeId, temporaryChannelId)
|
||||
val fundingPubKey = keyManager.fundingPublicKey(localParams.fundingKeyPath).publicKey
|
||||
|
@ -223,9 +223,9 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder, val
|
|||
pushMsat = pushMsat,
|
||||
dustLimitSatoshis = localParams.dustLimit,
|
||||
maxHtlcValueInFlightMsat = localParams.maxHtlcValueInFlightMsat,
|
||||
channelReserveSatoshis = localParams.channelReserve,
|
||||
channelReserveSatoshis = localParams.requestedChannelReserve_opt.getOrElse(0 sat),
|
||||
htlcMinimumMsat = localParams.htlcMinimum,
|
||||
feeratePerKw = initialFeeratePerKw,
|
||||
feeratePerKw = commitTxFeerate,
|
||||
toSelfDelay = localParams.toSelfDelay,
|
||||
maxAcceptedHtlcs = localParams.maxAcceptedHtlcs,
|
||||
fundingPubkey = fundingPubKey,
|
||||
|
|
|
@ -87,7 +87,7 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
val accept = AcceptChannel(temporaryChannelId = open.temporaryChannelId,
|
||||
dustLimitSatoshis = localParams.dustLimit,
|
||||
maxHtlcValueInFlightMsat = localParams.maxHtlcValueInFlightMsat,
|
||||
channelReserveSatoshis = localParams.channelReserve,
|
||||
channelReserveSatoshis = localParams.requestedChannelReserve_opt.getOrElse(0 sat),
|
||||
minimumDepth = minimumDepth,
|
||||
htlcMinimumMsat = localParams.htlcMinimum,
|
||||
toSelfDelay = localParams.toSelfDelay,
|
||||
|
@ -106,7 +106,7 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
nodeId = remoteNodeId,
|
||||
dustLimit = open.dustLimitSatoshis,
|
||||
maxHtlcValueInFlightMsat = open.maxHtlcValueInFlightMsat,
|
||||
channelReserve = open.channelReserveSatoshis, // remote requires local to keep this much satoshis as direct payment
|
||||
requestedChannelReserve_opt = Some(open.channelReserveSatoshis), // our peer requires us to always have at least that much satoshis in our balance
|
||||
htlcMinimum = open.htlcMinimumMsat,
|
||||
toSelfDelay = open.toSelfDelay,
|
||||
maxAcceptedHtlcs = open.maxAcceptedHtlcs,
|
||||
|
@ -129,7 +129,7 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
})
|
||||
|
||||
when(WAIT_FOR_ACCEPT_CHANNEL)(handleExceptions {
|
||||
case Event(accept: AcceptChannel, d@DATA_WAIT_FOR_ACCEPT_CHANNEL(INPUT_INIT_FUNDER(temporaryChannelId, fundingSatoshis, pushMsat, initialFeeratePerKw, fundingTxFeeratePerKw, localParams, _, remoteInit, _, channelConfig, channelType), open)) =>
|
||||
case Event(accept: AcceptChannel, d@DATA_WAIT_FOR_ACCEPT_CHANNEL(INPUT_INIT_FUNDER(temporaryChannelId, fundingSatoshis, pushMsat, commitTxFeerate, fundingTxFeerate, localParams, _, remoteInit, _, channelConfig, channelType), open)) =>
|
||||
Helpers.validateParamsFunder(nodeParams, channelType, localParams.initFeatures, remoteInit.features, open, accept) match {
|
||||
case Left(t) =>
|
||||
channelOpenReplyToUser(Left(LocalError(t)))
|
||||
|
@ -139,7 +139,7 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
nodeId = remoteNodeId,
|
||||
dustLimit = accept.dustLimitSatoshis,
|
||||
maxHtlcValueInFlightMsat = accept.maxHtlcValueInFlightMsat,
|
||||
channelReserve = accept.channelReserveSatoshis, // remote requires local to keep this much satoshis as direct payment
|
||||
requestedChannelReserve_opt = Some(accept.channelReserveSatoshis), // our peer requires us to always have at least that much satoshis in our balance
|
||||
htlcMinimum = accept.htlcMinimumMsat,
|
||||
toSelfDelay = accept.toSelfDelay,
|
||||
maxAcceptedHtlcs = accept.maxAcceptedHtlcs,
|
||||
|
@ -153,8 +153,8 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
log.debug("remote params: {}", remoteParams)
|
||||
val localFundingPubkey = keyManager.fundingPublicKey(localParams.fundingKeyPath)
|
||||
val fundingPubkeyScript = Script.write(Script.pay2wsh(Scripts.multiSig2of2(localFundingPubkey.publicKey, remoteParams.fundingPubKey)))
|
||||
wallet.makeFundingTx(fundingPubkeyScript, fundingSatoshis, fundingTxFeeratePerKw).pipeTo(self)
|
||||
goto(WAIT_FOR_FUNDING_INTERNAL) using DATA_WAIT_FOR_FUNDING_INTERNAL(temporaryChannelId, localParams, remoteParams, fundingSatoshis, pushMsat, initialFeeratePerKw, accept.firstPerCommitmentPoint, channelConfig, channelFeatures, open)
|
||||
wallet.makeFundingTx(fundingPubkeyScript, fundingSatoshis, fundingTxFeerate).pipeTo(self)
|
||||
goto(WAIT_FOR_FUNDING_INTERNAL) using DATA_WAIT_FOR_FUNDING_INTERNAL(temporaryChannelId, localParams, remoteParams, fundingSatoshis, pushMsat, commitTxFeerate, accept.firstPerCommitmentPoint, channelConfig, channelFeatures, open)
|
||||
}
|
||||
|
||||
case Event(c: CloseCommand, d: DATA_WAIT_FOR_ACCEPT_CHANNEL) =>
|
||||
|
@ -175,9 +175,9 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
})
|
||||
|
||||
when(WAIT_FOR_FUNDING_INTERNAL)(handleExceptions {
|
||||
case Event(MakeFundingTxResponse(fundingTx, fundingTxOutputIndex, fundingTxFee), d@DATA_WAIT_FOR_FUNDING_INTERNAL(temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, initialFeeratePerKw, remoteFirstPerCommitmentPoint, channelConfig, channelFeatures, open)) =>
|
||||
case Event(MakeFundingTxResponse(fundingTx, fundingTxOutputIndex, fundingTxFee), d@DATA_WAIT_FOR_FUNDING_INTERNAL(temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, commitTxFeerate, remoteFirstPerCommitmentPoint, channelConfig, channelFeatures, open)) =>
|
||||
// let's create the first commitment tx that spends the yet uncommitted funding tx
|
||||
Funding.makeFirstCommitTxs(keyManager, channelConfig, channelFeatures, temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, initialFeeratePerKw, fundingTx.hash, fundingTxOutputIndex, remoteFirstPerCommitmentPoint) match {
|
||||
Funding.makeFirstCommitTxs(keyManager, channelConfig, channelFeatures, temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, commitTxFeerate, fundingTx.hash, fundingTxOutputIndex, remoteFirstPerCommitmentPoint) match {
|
||||
case Left(ex) => handleLocalError(ex, d, None)
|
||||
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) =>
|
||||
require(fundingTx.txOut(fundingTxOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, s"pubkey script mismatch!")
|
||||
|
@ -220,9 +220,9 @@ trait ChannelOpenSingleFunder extends FundingHandlers with ErrorHandlers {
|
|||
})
|
||||
|
||||
when(WAIT_FOR_FUNDING_CREATED)(handleExceptions {
|
||||
case Event(FundingCreated(_, fundingTxHash, fundingTxOutputIndex, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_CREATED(temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, initialFeeratePerKw, remoteFirstPerCommitmentPoint, channelFlags, channelConfig, channelFeatures, _)) =>
|
||||
case Event(FundingCreated(_, fundingTxHash, fundingTxOutputIndex, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_CREATED(temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, commitTxFeerate, remoteFirstPerCommitmentPoint, channelFlags, channelConfig, channelFeatures, _)) =>
|
||||
// they fund the channel with their funding tx, so the money is theirs (but we are paid pushMsat)
|
||||
Funding.makeFirstCommitTxs(keyManager, channelConfig, channelFeatures, temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, initialFeeratePerKw, fundingTxHash, fundingTxOutputIndex, remoteFirstPerCommitmentPoint) match {
|
||||
Funding.makeFirstCommitTxs(keyManager, channelConfig, channelFeatures, temporaryChannelId, localParams, remoteParams, fundingAmount, pushMsat, commitTxFeerate, fundingTxHash, fundingTxOutputIndex, remoteFirstPerCommitmentPoint) match {
|
||||
case Left(ex) => handleLocalError(ex, d, None)
|
||||
case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) =>
|
||||
// check remote signature validity
|
||||
|
|
|
@ -506,7 +506,7 @@ object Peer {
|
|||
nodeParams.channelKeyManager.newFundingKeyPath(isInitiator), // we make sure that initiator and non-initiator key paths end differently
|
||||
dustLimit = nodeParams.channelConf.dustLimit,
|
||||
maxHtlcValueInFlightMsat = nodeParams.channelConf.maxHtlcValueInFlightMsat,
|
||||
channelReserve = (fundingAmount * nodeParams.channelConf.reserveToFundingRatio).max(nodeParams.channelConf.dustLimit), // BOLT #2: make sure that our reserve is above our dust limit
|
||||
requestedChannelReserve_opt = Some((fundingAmount * nodeParams.channelConf.reserveToFundingRatio).max(nodeParams.channelConf.dustLimit)), // BOLT #2: make sure that our reserve is above our dust limit
|
||||
htlcMinimum = nodeParams.channelConf.htlcMinimum,
|
||||
toSelfDelay = nodeParams.channelConf.toRemoteDelay, // we choose their delay
|
||||
maxAcceptedHtlcs = nodeParams.channelConf.maxAcceptedHtlcs,
|
||||
|
|
|
@ -401,8 +401,8 @@ object ChannelEventSerializer extends MinimalSerializer({
|
|||
JField("remoteNodeId", JString(e.remoteNodeId.toString())),
|
||||
JField("isInitiator", JBool(e.isInitiator)),
|
||||
JField("temporaryChannelId", JString(e.temporaryChannelId.toHex)),
|
||||
JField("initialFeeratePerKw", JLong(e.initialFeeratePerKw.toLong)),
|
||||
JField("fundingTxFeeratePerKw", e.fundingTxFeeratePerKw.map(f => JLong(f.toLong)).getOrElse(JNothing))
|
||||
JField("commitTxFeeratePerKw", JLong(e.commitTxFeerate.toLong)),
|
||||
JField("fundingTxFeeratePerKw", e.fundingTxFeerate.map(f => JLong(f.toLong)).getOrElse(JNothing))
|
||||
)
|
||||
case e: ChannelStateChanged => JObject(
|
||||
JField("type", JString("channel-state-changed")),
|
||||
|
|
|
@ -18,7 +18,7 @@ package fr.acinq.eclair.wire.internal.channel.version0
|
|||
|
||||
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath}
|
||||
import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, Transaction, TxOut}
|
||||
import fr.acinq.eclair.TimestampSecond
|
||||
import fr.acinq.eclair.{BlockHeight, TimestampSecond}
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.transactions.Transactions._
|
||||
|
@ -27,7 +27,6 @@ import fr.acinq.eclair.wire.internal.channel.version0.ChannelTypes0.{HtlcTxAndSi
|
|||
import fr.acinq.eclair.wire.protocol.CommonCodecs._
|
||||
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs.{channelAnnouncementCodec, channelUpdateCodec, combinedFeaturesCodec}
|
||||
import fr.acinq.eclair.wire.protocol._
|
||||
import fr.acinq.eclair.{BlockHeight, Features, InitFeature, TimestampSecond}
|
||||
import scodec.Codec
|
||||
import scodec.bits.{BitVector, ByteVector}
|
||||
import scodec.codecs._
|
||||
|
@ -69,7 +68,7 @@ private[channel] object ChannelCodecs0 {
|
|||
("channelPath" | keyPathCodec) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
@ -82,7 +81,7 @@ private[channel] object ChannelCodecs0 {
|
|||
("nodeId" | publicKey) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
|
|
@ -18,6 +18,7 @@ package fr.acinq.eclair.wire.internal.channel.version1
|
|||
|
||||
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath}
|
||||
import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Transaction, TxOut}
|
||||
import fr.acinq.eclair.BlockHeight
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.transactions.Transactions._
|
||||
|
@ -27,7 +28,6 @@ import fr.acinq.eclair.wire.internal.channel.version0.ChannelTypes0.{HtlcTxAndSi
|
|||
import fr.acinq.eclair.wire.protocol.CommonCodecs._
|
||||
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._
|
||||
import fr.acinq.eclair.wire.protocol._
|
||||
import fr.acinq.eclair.{BlockHeight, Features, InitFeature}
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.codecs._
|
||||
import scodec.{Attempt, Codec}
|
||||
|
@ -55,7 +55,7 @@ private[channel] object ChannelCodecs1 {
|
|||
("channelPath" | keyPathCodec) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
@ -68,7 +68,7 @@ private[channel] object ChannelCodecs1 {
|
|||
("nodeId" | publicKey) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
|
|
@ -18,6 +18,7 @@ package fr.acinq.eclair.wire.internal.channel.version2
|
|||
|
||||
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath}
|
||||
import fr.acinq.bitcoin.scalacompat.{OutPoint, Transaction, TxOut}
|
||||
import fr.acinq.eclair.BlockHeight
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.transactions.Transactions._
|
||||
|
@ -27,7 +28,6 @@ import fr.acinq.eclair.wire.internal.channel.version0.ChannelTypes0.{HtlcTxAndSi
|
|||
import fr.acinq.eclair.wire.protocol.CommonCodecs._
|
||||
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._
|
||||
import fr.acinq.eclair.wire.protocol._
|
||||
import fr.acinq.eclair.{BlockHeight, Features, InitFeature}
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.codecs._
|
||||
import scodec.{Attempt, Codec}
|
||||
|
@ -55,7 +55,7 @@ private[channel] object ChannelCodecs2 {
|
|||
("channelPath" | keyPathCodec) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
@ -68,7 +68,7 @@ private[channel] object ChannelCodecs2 {
|
|||
("nodeId" | publicKey) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(included = true, satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package fr.acinq.eclair.wire.internal.channel.version3
|
||||
|
||||
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.{ExtendedPrivateKey, KeyPath}
|
||||
import fr.acinq.bitcoin.scalacompat.{ByteVector32, OutPoint, Transaction, TxOut}
|
||||
import fr.acinq.bitcoin.scalacompat.{OutPoint, Satoshi, Transaction, TxOut}
|
||||
import fr.acinq.eclair.channel._
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.transactions.Transactions._
|
||||
|
@ -25,7 +25,7 @@ import fr.acinq.eclair.transactions.{CommitmentSpec, DirectedHtlc, IncomingHtlc,
|
|||
import fr.acinq.eclair.wire.protocol.CommonCodecs._
|
||||
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs._
|
||||
import fr.acinq.eclair.wire.protocol.UpdateMessage
|
||||
import fr.acinq.eclair.{BlockHeight, FeatureSupport, Features, InitFeature}
|
||||
import fr.acinq.eclair.{BlockHeight, FeatureSupport, Features}
|
||||
import scodec.bits.{BitVector, ByteVector}
|
||||
import scodec.codecs._
|
||||
import scodec.{Attempt, Codec}
|
||||
|
@ -75,7 +75,7 @@ private[channel] object ChannelCodecs3 {
|
|||
("channelPath" | keyPathCodec) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(!channelFeatures.hasFeature(Features.DualFunding), satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
@ -84,11 +84,11 @@ private[channel] object ChannelCodecs3 {
|
|||
("walletStaticPaymentBasepoint" | optional(provide(channelFeatures.paysDirectlyToWallet), publicKey)) ::
|
||||
("features" | combinedFeaturesCodec)).as[LocalParams]
|
||||
|
||||
val remoteParamsCodec: Codec[RemoteParams] = (
|
||||
def remoteParamsCodec(channelFeatures: ChannelFeatures): Codec[RemoteParams] = (
|
||||
("nodeId" | publicKey) ::
|
||||
("dustLimit" | satoshi) ::
|
||||
("maxHtlcValueInFlightMsat" | uint64) ::
|
||||
("channelReserve" | satoshi) ::
|
||||
("channelReserve" | conditional(!channelFeatures.hasFeature(Features.DualFunding), satoshi)) ::
|
||||
("htlcMinimum" | millisatoshi) ::
|
||||
("toSelfDelay" | cltvExpiryDelta) ::
|
||||
("maxAcceptedHtlcs" | uint16) ::
|
||||
|
@ -269,7 +269,7 @@ private[channel] object ChannelCodecs3 {
|
|||
("channelConfig" | channelConfigCodec) ::
|
||||
(("channelFeatures" | channelFeaturesCodec) >>:~ { channelFeatures =>
|
||||
("localParams" | localParamsCodec(channelFeatures)) ::
|
||||
("remoteParams" | remoteParamsCodec) ::
|
||||
("remoteParams" | remoteParamsCodec(channelFeatures)) ::
|
||||
("channelFlags" | channelflags) ::
|
||||
("localCommit" | localCommitCodec) ::
|
||||
("remoteCommit" | remoteCommitCodec) ::
|
||||
|
|
|
@ -208,7 +208,7 @@ object TestConstants {
|
|||
isInitiator = true,
|
||||
fundingSatoshis
|
||||
).copy(
|
||||
channelReserve = 10000 sat // Bob will need to keep that much satoshis as direct payment
|
||||
requestedChannelReserve_opt = Some(10_000 sat) // Bob will need to keep that much satoshis in his balance
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ object TestConstants {
|
|||
isInitiator = false,
|
||||
fundingSatoshis
|
||||
).copy(
|
||||
channelReserve = 20000 sat // Alice will need to keep that much satoshis as direct payment
|
||||
requestedChannelReserve_opt = Some(20_000 sat) // Alice will need to keep that much satoshis in her balance
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -480,8 +480,8 @@ class CommitmentsSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
|||
object CommitmentsSpec {
|
||||
|
||||
def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, feeRatePerKw: FeeratePerKw = FeeratePerKw(0 sat), dustLimit: Satoshi = 0 sat, isInitiator: Boolean = true, announceChannel: Boolean = true): Commitments = {
|
||||
val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, UInt64.MaxValue, 0 sat, 1 msat, CltvExpiryDelta(144), 50, isInitiator, ByteVector.empty, None, Features.empty)
|
||||
val remoteParams = RemoteParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, 0 sat, 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
|
||||
val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, UInt64.MaxValue, None, 1 msat, CltvExpiryDelta(144), 50, isInitiator, ByteVector.empty, None, Features.empty)
|
||||
val remoteParams = RemoteParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, None, 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
|
||||
val commitmentInput = Funding.makeFundingInputInfo(randomBytes32(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteParams.fundingPubKey)
|
||||
Commitments(
|
||||
channelId = randomBytes32(),
|
||||
|
@ -503,8 +503,8 @@ object CommitmentsSpec {
|
|||
}
|
||||
|
||||
def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, localNodeId: PublicKey, remoteNodeId: PublicKey, announceChannel: Boolean): Commitments = {
|
||||
val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, UInt64.MaxValue, 0 sat, 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, ByteVector.empty, None, Features.empty)
|
||||
val remoteParams = RemoteParams(remoteNodeId, 0 sat, UInt64.MaxValue, 0 sat, 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
|
||||
val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, UInt64.MaxValue, None, 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, ByteVector.empty, None, Features.empty)
|
||||
val remoteParams = RemoteParams(remoteNodeId, 0 sat, UInt64.MaxValue, None, 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
|
||||
val commitmentInput = Funding.makeFundingInputInfo(randomBytes32(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteParams.fundingPubKey)
|
||||
Commitments(
|
||||
channelId = randomBytes32(),
|
||||
|
|
|
@ -200,7 +200,7 @@ trait ChannelStateTestsHelperMethods extends TestKitBase {
|
|||
val channelConfig = ChannelConfig.standard
|
||||
val (aliceParams, bobParams, channelType) = computeFeatures(setup, tags)
|
||||
val channelFlags = ChannelFlags(announceChannel = tags.contains(ChannelStateTestsTags.ChannelsPublic))
|
||||
val initialFeeratePerKw = if (tags.contains(ChannelStateTestsTags.AnchorOutputs) || tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val commitTxFeerate = if (tags.contains(ChannelStateTestsTags.AnchorOutputs) || tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val (fundingSatoshis, pushMsat) = if (tags.contains(ChannelStateTestsTags.NoPushMsat)) {
|
||||
(TestConstants.fundingSatoshis, 0.msat)
|
||||
} else {
|
||||
|
@ -209,7 +209,7 @@ trait ChannelStateTestsHelperMethods extends TestKitBase {
|
|||
|
||||
val aliceInit = Init(aliceParams.initFeatures)
|
||||
val bobInit = Init(bobParams.initFeatures)
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType)
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingSatoshis, pushMsat, commitTxFeerate, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType)
|
||||
assert(alice2blockchain.expectMsgType[TxPublisher.SetChannelId].channelId === ByteVector32.Zeroes)
|
||||
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
|
||||
assert(bob2blockchain.expectMsgType[TxPublisher.SetChannelId].channelId === ByteVector32.Zeroes)
|
||||
|
@ -241,7 +241,7 @@ trait ChannelStateTestsHelperMethods extends TestKitBase {
|
|||
bob2blockchain.expectMsgType[WatchFundingDeeplyBuried]
|
||||
awaitCond(alice.stateName == NORMAL)
|
||||
awaitCond(bob.stateName == NORMAL)
|
||||
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == (pushMsat - aliceParams.channelReserve).max(0 msat))
|
||||
assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.availableBalanceForSend == (pushMsat - aliceParams.requestedChannelReserve_opt.getOrElse(0 sat)).max(0 msat))
|
||||
// x2 because alice and bob share the same relayer
|
||||
channelUpdateListener.expectMsgType[LocalChannelUpdate]
|
||||
channelUpdateListener.expectMsgType[LocalChannelUpdate]
|
||||
|
|
|
@ -58,12 +58,12 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS
|
|||
val channelConfig = ChannelConfig.standard
|
||||
val (aliceParams, bobParams, defaultChannelType) = computeFeatures(setup, test.tags)
|
||||
val channelType = if (test.tags.contains("standard-channel-type")) ChannelTypes.Standard else defaultChannelType
|
||||
val initialFeeratePerKw = if (channelType == ChannelTypes.AnchorOutputs || channelType == ChannelTypes.AnchorOutputsZeroFeeHtlcTx) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val commitTxFeerate = if (channelType == ChannelTypes.AnchorOutputs || channelType == ChannelTypes.AnchorOutputsZeroFeeHtlcTx) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val aliceInit = Init(aliceParams.initFeatures)
|
||||
val bobInit = Init(bobParams.initFeatures)
|
||||
within(30 seconds) {
|
||||
val fundingAmount = if (test.tags.contains(ChannelStateTestsTags.Wumbo)) Btc(5).toSatoshi else TestConstants.fundingSatoshis
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingAmount, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, fundingAmount, TestConstants.pushMsat, commitTxFeerate, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
|
||||
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
|
||||
alice2bob.expectMsgType[OpenChannel]
|
||||
alice2bob.forward(bob)
|
||||
|
|
|
@ -52,11 +52,11 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui
|
|||
val channelConfig = ChannelConfig.standard
|
||||
val (aliceParams, bobParams, defaultChannelType) = computeFeatures(setup, test.tags)
|
||||
val channelType = if (test.tags.contains("standard-channel-type")) ChannelTypes.Standard else defaultChannelType
|
||||
val initialFeeratePerKw = if (channelType == ChannelTypes.AnchorOutputs || channelType == ChannelTypes.AnchorOutputsZeroFeeHtlcTx) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val commitTxFeerate = if (channelType == ChannelTypes.AnchorOutputs || channelType == ChannelTypes.AnchorOutputsZeroFeeHtlcTx) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw
|
||||
val aliceInit = Init(aliceParams.initFeatures)
|
||||
val bobInit = Init(bobParams.initFeatures)
|
||||
within(30 seconds) {
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, initialFeeratePerKw, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
|
||||
alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, commitTxFeerate, TestConstants.feeratePerKw, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType)
|
||||
bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType)
|
||||
awaitCond(bob.stateName == WAIT_FOR_OPEN_CHANNEL)
|
||||
withFixture(test.toNoArgTest(FixtureParam(alice, bob, alice2bob, bob2alice, bob2blockchain)))
|
||||
|
|
|
@ -106,7 +106,7 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun
|
|||
import f._
|
||||
val fees = Transactions.weight2fee(TestConstants.feeratePerKw, Transactions.DefaultCommitmentFormat.commitWeight)
|
||||
val bobParams = bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].localParams
|
||||
val reserve = bobParams.channelReserve
|
||||
val reserve = bobParams.requestedChannelReserve_opt.get
|
||||
val missing = 100.sat - fees - reserve
|
||||
val fundingCreated = alice2bob.expectMsgType[FundingCreated]
|
||||
alice2bob.forward(bob)
|
||||
|
|
|
@ -257,7 +257,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
|
|||
// but this one will dip alice below her reserve: we must wait for the previous HTLCs to settle before sending any more
|
||||
val failedAdd = CMD_ADD_HTLC(sender.ref, 11000000 msat, randomBytes32(), CltvExpiry(400144), TestConstants.emptyOnionPacket, localOrigin(sender.ref))
|
||||
bob ! failedAdd
|
||||
val error = RemoteCannotAffordFeesForNewHtlc(channelId(bob), failedAdd.amount, missing = 1360 sat, 10000 sat, 22720 sat)
|
||||
val error = RemoteCannotAffordFeesForNewHtlc(channelId(bob), failedAdd.amount, missing = 1360 sat, 20000 sat, 22720 sat)
|
||||
sender.expectMsg(RES_ADD_FAILED(failedAdd, error, Some(bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate)))
|
||||
}
|
||||
|
||||
|
|
|
@ -416,8 +416,8 @@ class PeerSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Paralle
|
|||
val init = channel.expectMsgType[INPUT_INIT_FUNDER]
|
||||
assert(init.channelType === ChannelTypes.AnchorOutputs)
|
||||
assert(init.fundingAmount === 15000.sat)
|
||||
assert(init.initialFeeratePerKw === TestConstants.anchorOutputsFeeratePerKw)
|
||||
assert(init.fundingTxFeeratePerKw === feeEstimator.getFeeratePerKw(nodeParams.onChainFeeConf.feeTargets.fundingBlockTarget))
|
||||
assert(init.commitTxFeerate === TestConstants.anchorOutputsFeeratePerKw)
|
||||
assert(init.fundingTxFeerate === feeEstimator.getFeeratePerKw(nodeParams.onChainFeeConf.feeTargets.fundingBlockTarget))
|
||||
}
|
||||
|
||||
test("use correct on-chain fee rates when spawning a channel (anchor outputs zero fee htlc)", Tag("anchor_outputs_zero_fee_htlc_tx")) { f =>
|
||||
|
@ -434,8 +434,8 @@ class PeerSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Paralle
|
|||
val init = channel.expectMsgType[INPUT_INIT_FUNDER]
|
||||
assert(init.channelType === ChannelTypes.AnchorOutputsZeroFeeHtlcTx)
|
||||
assert(init.fundingAmount === 15000.sat)
|
||||
assert(init.initialFeeratePerKw === TestConstants.anchorOutputsFeeratePerKw)
|
||||
assert(init.fundingTxFeeratePerKw === feeEstimator.getFeeratePerKw(nodeParams.onChainFeeConf.feeTargets.fundingBlockTarget))
|
||||
assert(init.commitTxFeerate === TestConstants.anchorOutputsFeeratePerKw)
|
||||
assert(init.fundingTxFeerate === feeEstimator.getFeeratePerKw(nodeParams.onChainFeeConf.feeTargets.fundingBlockTarget))
|
||||
}
|
||||
|
||||
test("use correct final script if option_static_remotekey is negotiated", Tag("static_remotekey")) { f =>
|
||||
|
|
|
@ -369,8 +369,8 @@ object PaymentPacketSpec {
|
|||
}
|
||||
|
||||
def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = 50000000 msat, testAvailableBalanceForReceive: MilliSatoshi = 50000000 msat, testCapacity: Satoshi = 100000 sat): Commitments = {
|
||||
val params = LocalParams(null, null, null, null, null, null, null, 0, isInitiator = true, null, None, null)
|
||||
val remoteParams = RemoteParams(randomKey().publicKey, null, null, null, null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, null, None)
|
||||
val params = LocalParams(null, null, null, null, None, null, null, 0, isInitiator = true, null, None, null)
|
||||
val remoteParams = RemoteParams(randomKey().publicKey, null, null, None, null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, null, None)
|
||||
val commitInput = InputInfo(OutPoint(randomBytes32(), 1), TxOut(testCapacity, Nil), Nil)
|
||||
val channelFlags = ChannelFlags.Private
|
||||
new Commitments(channelId, ChannelConfig.standard, ChannelFeatures(), params, remoteParams, channelFlags, null, null, null, null, 0, 0, Map.empty, null, commitInput, null) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -51,7 +51,7 @@ class ChannelCodecs1Spec extends AnyFunSuite {
|
|||
assert(channelVersionCodec.encode(ChannelVersion.ANCHOR_OUTPUTS) === Attempt.successful(hex"00000007".bits))
|
||||
}
|
||||
|
||||
test("encode/decode localparams") {
|
||||
test("encode/decode local params") {
|
||||
def roundtrip(localParams: LocalParams, codec: Codec[LocalParams]) = {
|
||||
val encoded = codec.encode(localParams).require
|
||||
val decoded = codec.decode(encoded).require
|
||||
|
@ -63,7 +63,7 @@ class ChannelCodecs1Spec extends AnyFunSuite {
|
|||
fundingKeyPath = DeterministicWallet.KeyPath(Seq(42L)),
|
||||
dustLimit = Satoshi(Random.nextInt(Int.MaxValue)),
|
||||
maxHtlcValueInFlightMsat = UInt64(Random.nextInt(Int.MaxValue)),
|
||||
channelReserve = Satoshi(Random.nextInt(Int.MaxValue)),
|
||||
requestedChannelReserve_opt = Some(Satoshi(Random.nextInt(Int.MaxValue))),
|
||||
htlcMinimum = MilliSatoshi(Random.nextInt(Int.MaxValue)),
|
||||
toSelfDelay = CltvExpiryDelta(Random.nextInt(Short.MaxValue)),
|
||||
maxAcceptedHtlcs = Random.nextInt(Short.MaxValue),
|
||||
|
@ -78,12 +78,12 @@ class ChannelCodecs1Spec extends AnyFunSuite {
|
|||
roundtrip(o, localParamsCodec(ChannelVersion.ANCHOR_OUTPUTS))
|
||||
}
|
||||
|
||||
test("encode/decode remoteparams") {
|
||||
test("encode/decode remote params") {
|
||||
val o = RemoteParams(
|
||||
nodeId = randomKey().publicKey,
|
||||
dustLimit = Satoshi(Random.nextInt(Int.MaxValue)),
|
||||
maxHtlcValueInFlightMsat = UInt64(Random.nextInt(Int.MaxValue)),
|
||||
channelReserve = Satoshi(Random.nextInt(Int.MaxValue)),
|
||||
requestedChannelReserve_opt = Some(Satoshi(Random.nextInt(Int.MaxValue))),
|
||||
htlcMinimum = MilliSatoshi(Random.nextInt(Int.MaxValue)),
|
||||
toSelfDelay = CltvExpiryDelta(Random.nextInt(Short.MaxValue)),
|
||||
maxAcceptedHtlcs = Random.nextInt(Short.MaxValue),
|
||||
|
@ -98,7 +98,7 @@ class ChannelCodecs1Spec extends AnyFunSuite {
|
|||
val decoded = remoteParamsCodec.decodeValue(encoded).require
|
||||
assert(o === decoded)
|
||||
|
||||
// Backwards-compatibility: decode remoteparams with global features.
|
||||
// Backwards-compatibility: decode remote params with global features.
|
||||
val withGlobalFeatures = hex"03c70c3b813815a8b79f41622b6f2c343fa24d94fb35fa7110bbb3d4d59cd9612e0000000059844cbc000000001b1524ea000000001503cbac000000006b75d3272e38777e029fa4e94066163024177311de7ba1befec2e48b473c387bbcee1484bf276a54460215e3dfb8e6f262222c5f343f5e38c5c9a43d2594c7f06dd7ac1a4326c665dd050347aba4d56d7007a7dcf03594423dccba9ed700d11e665d261594e1154203df31020d457ee336ba6eeb328d00f1b8bd8bfefb8a4dcd5af6db4c438b7ec5106c7edc0380df17e1beb0f238e51a39122ac4c6fb57f3c4f5b7bc9432f991b1ef4a8af3570002020000018a"
|
||||
val withGlobalFeaturesDecoded = remoteParamsCodec.decode(withGlobalFeatures.bits).require.value
|
||||
assert(withGlobalFeaturesDecoded.initFeatures.toByteVector === hex"028a")
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1156,7 +1156,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM
|
|||
wsClient.expectMessage(expectedSerializedPset)
|
||||
|
||||
val chcr = ChannelCreated(system.deadLetters, system.deadLetters, bobNodeId, isInitiator = true, ByteVector32.One, FeeratePerKw(25 sat), Some(FeeratePerKw(20 sat)))
|
||||
val expectedSerializedChcr = """{"type":"channel-opened","remoteNodeId":"039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a3585","isInitiator":true,"temporaryChannelId":"0100000000000000000000000000000000000000000000000000000000000000","initialFeeratePerKw":25,"fundingTxFeeratePerKw":20}"""
|
||||
val expectedSerializedChcr = """{"type":"channel-opened","remoteNodeId":"039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a3585","isInitiator":true,"temporaryChannelId":"0100000000000000000000000000000000000000000000000000000000000000","commitTxFeeratePerKw":25,"fundingTxFeeratePerKw":20}"""
|
||||
assert(serialization.write(chcr) === expectedSerializedChcr)
|
||||
system.eventStream.publish(chcr)
|
||||
wsClient.expectMessage(expectedSerializedChcr)
|
||||
|
|
Loading…
Add table
Reference in a new issue