Skip to content

Commit

Permalink
Backend(LN),End2End,Frontend.Console(L2): support for anchor channels
Browse files Browse the repository at this point in the history
Anchor channels add the possiblity for both parties (funder&fundee)
to use CPFP for speeding up the confirmation in the case of force-closing
a channel (previously CPFP support only was allowed with mutual-close).

NOTE: the change in ChainWatcher.fs is to only broadcast penalty if/when
the spending tx is confirmed (because after this commit, Geewallet's penalty
tx tries to spend to_remote output as well and that output is time-locked by
1 block, so we need to wait for at least 1 confirmation before broadcasting
the penalty tx; otherwise, "no-BIP68-final" error would be thrown when
broadcasting the penalty tx before the 1 block confirmation).
  • Loading branch information
aarani authored and knocte committed Aug 11, 2022
1 parent c697b0b commit 931fb42
Show file tree
Hide file tree
Showing 19 changed files with 417 additions and 142 deletions.
2 changes: 1 addition & 1 deletion GWallet.Backend.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>geewallet is a minimalistic and pragmatist crossplatform lightweight opensource brainwallet for people that want to hold the most important cryptocurrencies in the same application with ease and peace of mind.</description>
<dependencies>
<dependency id="DotNetLightning.Kiss" version="1.1.2-date20220204-0457-git-9c7a03c" />
<dependency id="DotNetLightning.Kiss" version="1.1.2-date20220322-1031-git-5379324" />
<dependency id="FSharp.Core" version="4.7.2" />
<dependency id="FSharp.Data" version="3.0.0" />
<dependency id="HtmlAgilityPack" version="1.11.24" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@
<HintPath>..\..\packages\BTCPayServer.Lightning.Ptarmigan.1.2.2\lib\netstandard2.0\BTCPayServer.Lightning.Ptarmigan.dll</HintPath>
</Reference>
<Reference Include="DotNetLightning.Core">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
</Reference>
<Reference Include="InternalBech32Encoder">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
</Reference>
<Reference Include="ResultUtils">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\ResultUtils.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\ResultUtils.dll</HintPath>
</Reference>
<Reference Include="System.Memory">
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
Expand Down
70 changes: 24 additions & 46 deletions src/GWallet.Backend.Tests.End2End/LN.fs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,6 @@ type LN() =
(Node.Server serverWallet.NodeServer).CreateRecoveryTxForRemoteForceClose
channelId
closingTx
false
| _ ->
do! Async.Sleep 2000
return! waitForRemoteForceClose()
Expand Down Expand Up @@ -899,7 +898,6 @@ type LN() =
(Node.Client clientWallet.NodeClient).CreateRecoveryTxForRemoteForceClose
channelId
forceCloseTx
false
let recoveryTx = UnwrapResult recoveryTxOpt "no funds could be recovered"
let! _recoveryTxId =
ChannelManager.BroadcastRecoveryTxAndCloseChannel recoveryTx clientWallet.ChannelStore
Expand Down Expand Up @@ -1294,6 +1292,30 @@ type LN() =
FeeRatePerKw.FromFeeAndVSize(commitmentTxFee, uint64 (commitmentTx.GetVirtualSize()))
assert FeesHelper.FeeRatesApproxEqual commitmentTxFeeRate oldFeeRate

let! anchorTxRes =
(Node.Client clientWallet.NodeClient).CreateAnchorFeeBumpForForceClose
channelId
(commitmentTx.ToHex())
clientWallet.Password
let anchorTxString =
UnwrapResult
anchorTxRes
"force close failed to recover funds from the commitment tx"
let anchorTx = Transaction.Parse(anchorTxString.Tx.ToString(), Network.RegTest)
let! anchorTxFee = FeesHelper.GetFeeFromTransaction anchorTx
let anchorTxFeeRate =
FeeRatePerKw.FromFeeAndVSize(anchorTxFee, uint64 (anchorTx.GetVirtualSize()))
assert (not <| FeesHelper.FeeRatesApproxEqual anchorTxFeeRate oldFeeRate)
assert (not <| FeesHelper.FeeRatesApproxEqual anchorTxFeeRate newFeeRate)
let combinedFeeRate =
FeeRatePerKw.FromFeeAndVSize(
anchorTxFee + commitmentTxFee,
uint64 (anchorTx.GetVirtualSize() + commitmentTx.GetVirtualSize())
)
assert FeesHelper.FeeRatesApproxEqual combinedFeeRate newFeeRate

let! _anchorTxIdString = Account.BroadcastRawTransaction Currency.BTC (anchorTxString.Tx.ToString())

// Give the fundee time to see the force-close tx
do! Async.Sleep 5000

Expand Down Expand Up @@ -1350,50 +1372,6 @@ type LN() =
FeeRatePerKw.FromFeeAndVSize(forceCloseTxFee, uint64 (forceCloseTx.GetVirtualSize()))
assert FeesHelper.FeeRatesApproxEqual forceCloseTxFeeRate oldFeeRate

let! recoveryTxStringNoCpfpRes =
(Node.Server serverWallet.NodeServer).CreateRecoveryTxForRemoteForceClose
channelId
wrappedForceCloseTx
false
let recoveryTxStringNoCpfp =
UnwrapResult
recoveryTxStringNoCpfpRes
"force close failed to recover funds from the commitment tx"
let recoveryTxNoCpfp = Transaction.Parse(recoveryTxStringNoCpfp.Tx.ToString(), Network.RegTest)
let! recoveryTxFeeNoCpfp = FeesHelper.GetFeeFromTransaction recoveryTxNoCpfp
let recoveryTxFeeRateNoCpfp =
FeeRatePerKw.FromFeeAndVSize(recoveryTxFeeNoCpfp, uint64 (recoveryTxNoCpfp.GetVirtualSize()))
assert FeesHelper.FeeRatesApproxEqual recoveryTxFeeRateNoCpfp newFeeRate
let combinedFeeRateNoCpfp =
FeeRatePerKw.FromFeeAndVSize(
recoveryTxFeeNoCpfp + forceCloseTxFee,
uint64 (recoveryTxNoCpfp.GetVirtualSize() + forceCloseTx.GetVirtualSize())
)
assert (not <| FeesHelper.FeeRatesApproxEqual combinedFeeRateNoCpfp oldFeeRate)
assert (not <| FeesHelper.FeeRatesApproxEqual combinedFeeRateNoCpfp newFeeRate)

let! recoveryTxStringWithCpfpRes =
(Node.Server serverWallet.NodeServer).CreateRecoveryTxForRemoteForceClose
channelId
wrappedForceCloseTx
true
let recoveryTxStringWithCpfp =
UnwrapResult
recoveryTxStringWithCpfpRes
"force close failed to recover funds from the commitment tx"
let recoveryTxWithCpfp = Transaction.Parse(recoveryTxStringWithCpfp.Tx.ToString(), Network.RegTest)
let! recoveryTxFeeWithCpfp = FeesHelper.GetFeeFromTransaction recoveryTxWithCpfp
let recoveryTxFeeRateWithCpfp =
FeeRatePerKw.FromFeeAndVSize(recoveryTxFeeWithCpfp, uint64 (recoveryTxWithCpfp.GetVirtualSize()))
assert (not <| FeesHelper.FeeRatesApproxEqual recoveryTxFeeRateWithCpfp oldFeeRate)
assert (not <| FeesHelper.FeeRatesApproxEqual recoveryTxFeeRateWithCpfp newFeeRate)
let combinedFeeRateWithCpfp =
FeeRatePerKw.FromFeeAndVSize(
recoveryTxFeeWithCpfp + forceCloseTxFee,
uint64 (recoveryTxWithCpfp.GetVirtualSize() + forceCloseTx.GetVirtualSize())
)
assert FeesHelper.FeeRatesApproxEqual combinedFeeRateWithCpfp newFeeRate

(serverWallet :> IDisposable).Dispose()
}

Expand Down
2 changes: 1 addition & 1 deletion src/GWallet.Backend.Tests.End2End/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<package id="BTCPayServer.Lightning.Eclair" version="1.2.2" targetFramework="net472" />
<package id="BTCPayServer.Lightning.LND" version="1.2.4" targetFramework="net472" />
<package id="BTCPayServer.Lightning.Ptarmigan" version="1.2.2" targetFramework="net472" />
<package id="DotNetLightning.Kiss" version="1.1.2-date20220204-0457-git-9c7a03c" targetFramework="net472" />
<package id="DotNetLightning.Kiss" version="1.1.2-date20220322-1031-git-5379324" targetFramework="net472" />
<package id="FSharp.Core" version="4.7.2" targetFramework="net472" />
<package id="FSharpx.Collections" version="3.0.1" targetFramework="net472" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net472" />
Expand Down
3 changes: 3 additions & 0 deletions src/GWallet.Backend.Tests.Unit/ChannelMarshalling.fs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ type ChannelMarshalling () =
"024172921dc95fd529d4e5418e2d59c8037c1d7ff03c10d9c432bbefdff49bb741"
]
}
},
"type": {
"case": "StaticRemoteKey"
}
},
"remotePerCommitmentSecrets": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="DotNetLightning.Core">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
</Reference>
<Reference Include="InternalBech32Encoder">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
</Reference>
<Reference Include="ResultUtils">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\ResultUtils.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\ResultUtils.dll</HintPath>
</Reference>
<Reference Include="BouncyCastle.Crypto">
<HintPath>..\..\packages\Portable.BouncyCastle.1.8.10\lib\net40\BouncyCastle.Crypto.dll</HintPath>
Expand Down
2 changes: 1 addition & 1 deletion src/GWallet.Backend.Tests.Unit/packages.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DotNetLightning.Kiss" version="1.1.2-date20220204-0457-git-9c7a03c" targetFramework="net472" />
<package id="DotNetLightning.Kiss" version="1.1.2-date20220322-1031-git-5379324" targetFramework="net472" />
<package id="FSharp.Core" version="4.7.2" targetFramework="net472" />
<package id="FSharpx.Collections" version="3.0.1" targetFramework="net472" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net472" />
Expand Down
7 changes: 4 additions & 3 deletions src/GWallet.Backend/GWallet.Backend.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<Compile Include="UtxoCoin\TorOperations.fs" />
<Compile Include="UtxoCoin\UtxoCoinAccount.fs" />
<Compile Include="UtxoCoin\Lightning\FeeEstimator.fs" />
<Compile Include="UtxoCoin\Lightning\Validation.fs" />
<Compile Include="UtxoCoin\Lightning\Settings.fs" />
<Compile Include="UtxoCoin\Lightning\ScriptManagement.fs" />
<Compile Include="UtxoCoin\Lightning\Wrappers.fs" />
Expand Down Expand Up @@ -333,13 +334,13 @@
<HintPath>..\..\packages\HtmlAgilityPack.1.11.24\lib\Net45\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="DotNetLightning.Core">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\DotNetLightning.Core.dll</HintPath>
</Reference>
<Reference Include="InternalBech32Encoder">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\InternalBech32Encoder.dll</HintPath>
</Reference>
<Reference Include="ResultUtils">
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220204-0457-git-9c7a03c\lib\netstandard2.0\ResultUtils.dll</HintPath>
<HintPath>..\..\packages\DotNetLightning.Kiss.1.1.2-date20220322-1031-git-5379324\lib\netstandard2.0\ResultUtils.dll</HintPath>
</Reference>
<Reference Include="FSharpx.Collections">
<HintPath>..\..\packages\FSharpx.Collections.3.0.1\lib\netstandard2.0\FSharpx.Collections.dll</HintPath>
Expand Down
12 changes: 11 additions & 1 deletion src/GWallet.Backend/UtxoCoin/Lightning/ChainWatcher.fs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,17 @@ module public ChainWatcher =
}


return! ListAsyncTryPick historyList checkIfRevokedCommitment
return!
ListAsyncTryPick
historyList
(fun txInfo ->
// Only check spending txs with at least 1 conf, cause we need at least 1 conf to broadcast our
// penalty tx (because it tries to spend to_remote output as well, which is time-locked for one block)
if txInfo.Height > 0u then
checkIfRevokedCommitment txInfo
else
async { return None })

}

let CheckForChannelFraudsAndSendRevocationTx (accounts: seq<UtxoCoin.NormalUtxoAccount>)
Expand Down
2 changes: 2 additions & 0 deletions src/GWallet.Backend/UtxoCoin/Lightning/ChannelManagement.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type LocallyForceClosedData =
Currency: Currency
ToSelfDelay: uint16
ForceCloseTxId: TransactionIdentifier
ClosingTimestampUtc: DateTime
}
member self.GetRemainingConfirmations (): Async<uint16> =
async {
Expand Down Expand Up @@ -97,6 +98,7 @@ type ChannelInfo =
Currency = currency
ToSelfDelay = serializedChannel.SavedChannelState.StaticChannelConfig.LocalParams.ToSelfDelay.Value
ForceCloseTxId = forceCloseTxId
ClosingTimestampUtc = UnwrapOption serializedChannel.ClosingTimestampUtc "BUG: closing date is empty after local force close"
}
| None ->
if serializedChannel.NegotiatingState.HasEnteredShutdown() then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ module public ForceCloseTransaction =
(Commitments.RemoteCommitAmount
savedChannelState.StaticChannelConfig.IsFunder
savedChannelState.StaticChannelConfig.RemoteParams
savedChannelState.RemoteCommit)
savedChannelState.RemoteCommit
savedChannelState.StaticChannelConfig.Type.CommitmentFormat)
.ToLocal
.ToDecimal(MoneyUnit.Satoshi)

let toRemote =
(Commitments.RemoteCommitAmount
savedChannelState.StaticChannelConfig.IsFunder
savedChannelState.StaticChannelConfig.RemoteParams
savedChannelState.RemoteCommit)
savedChannelState.RemoteCommit
savedChannelState.StaticChannelConfig.Type.CommitmentFormat)
.ToRemote
.ToDecimal(MoneyUnit.Satoshi)

Expand Down
Loading

0 comments on commit 931fb42

Please sign in to comment.