mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Merge pull request #1156 from starius/lnd-21-improvements
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
Use new features of LND 0.21
This commit is contained in:
commit
375c02e0f6
29 changed files with 400 additions and 97 deletions
|
|
@ -55,14 +55,16 @@ linters:
|
||||||
- wsl_v5
|
- wsl_v5
|
||||||
- noinlineerr
|
- noinlineerr
|
||||||
settings:
|
settings:
|
||||||
|
staticcheck:
|
||||||
|
checks:
|
||||||
|
- all
|
||||||
|
- -QF*
|
||||||
|
- -ST*
|
||||||
gosec:
|
gosec:
|
||||||
excludes:
|
excludes:
|
||||||
- G402
|
- G402
|
||||||
- G306
|
- G306
|
||||||
- G115
|
- G115
|
||||||
staticcheck:
|
|
||||||
checks:
|
|
||||||
- -SA1019
|
|
||||||
tagliatelle:
|
tagliatelle:
|
||||||
case:
|
case:
|
||||||
rules:
|
rules:
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ func loopIn(ctx context.Context, cmd *cli.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Swap initiated\n")
|
fmt.Printf("Swap initiated\n")
|
||||||
fmt.Printf("ID: %v\n", resp.Id)
|
fmt.Printf("ID: %x\n", resp.IdBytes)
|
||||||
|
|
||||||
if resp.HtlcAddressP2Tr != "" {
|
if resp.HtlcAddressP2Tr != "" {
|
||||||
fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr)
|
fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -646,7 +645,7 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (daemonConn,
|
||||||
// gRPC dial options from it.
|
// gRPC dial options from it.
|
||||||
func readMacaroon(macPath string) (grpc.DialOption, error) {
|
func readMacaroon(macPath string) (grpc.DialOption, error) {
|
||||||
// Load the specified macaroon file.
|
// Load the specified macaroon file.
|
||||||
macBytes, err := ioutil.ReadFile(macPath)
|
macBytes, err := os.ReadFile(macPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to read macaroon path : %v", err)
|
return nil, fmt.Errorf("unable to read macaroon path : %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultUtxoMinConf = 1
|
defaultUtxoMinConf = 1
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
channelTypeTweakless = "tweakless"
|
channelTypeTweakless = "tweakless"
|
||||||
channelTypeAnchors = "anchors"
|
channelTypeAnchors = "anchors"
|
||||||
channelTypeSimpleTaproot = "taproot"
|
channelTypeSimpleTaproot = "simple-taproot"
|
||||||
|
channelTypeTaproot = "taproot"
|
||||||
)
|
)
|
||||||
|
|
||||||
var openChannelCommand = &cli.Command{
|
var openChannelCommand = &cli.Command{
|
||||||
|
|
@ -137,9 +135,9 @@ var openChannelCommand = &cli.Command{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "channel_type",
|
Name: "channel_type",
|
||||||
Usage: fmt.Sprintf("(optional) the type of channel to "+
|
Usage: fmt.Sprintf("(optional) the type of channel to "+
|
||||||
"propose to the remote peer (%q, %q, %q)",
|
"propose to the remote peer (%q, %q, %q, %q)",
|
||||||
channelTypeTweakless, channelTypeAnchors,
|
channelTypeTweakless, channelTypeAnchors,
|
||||||
channelTypeSimpleTaproot),
|
channelTypeSimpleTaproot, channelTypeTaproot),
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "zero_conf",
|
Name: "zero_conf",
|
||||||
|
|
@ -322,6 +320,7 @@ func openChannel(ctx context.Context, cmd *cli.Command) error {
|
||||||
switch channelType {
|
switch channelType {
|
||||||
case "":
|
case "":
|
||||||
break
|
break
|
||||||
|
|
||||||
case channelTypeTweakless:
|
case channelTypeTweakless:
|
||||||
req.CommitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
|
req.CommitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
|
||||||
|
|
||||||
|
|
@ -330,6 +329,10 @@ func openChannel(ctx context.Context, cmd *cli.Command) error {
|
||||||
|
|
||||||
case channelTypeSimpleTaproot:
|
case channelTypeSimpleTaproot:
|
||||||
req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
|
req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
|
||||||
|
|
||||||
|
case channelTypeTaproot:
|
||||||
|
req.CommitmentType = lnrpc.CommitmentType_TAPROOT
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported channel type %v", channelType)
|
return fmt.Errorf("unsupported channel type %v", channelType)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
" --max_local_csv uint (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close. (default: 0)\n",
|
" --max_local_csv uint (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close. (default: 0)\n",
|
||||||
" --close_address string (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address.\n",
|
" --close_address string (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address.\n",
|
||||||
" --remote_max_value_in_flight_msat uint (optional) the maximum value in msat that can be pending within the channel at any given time (default: 0)\n",
|
" --remote_max_value_in_flight_msat uint (optional) the maximum value in msat that can be pending within the channel at any given time (default: 0)\n",
|
||||||
" --channel_type string (optional) the type of channel to propose to the remote peer (\"tweakless\", \"anchors\", \"taproot\")\n",
|
" --channel_type string (optional) the type of channel to propose to the remote peer (\"tweakless\", \"anchors\", \"simple-taproot\", \"taproot\")\n",
|
||||||
" --zero_conf (optional) whether a zero-conf channel open should be attempted. (default: false)\n",
|
" --zero_conf (optional) whether a zero-conf channel open should be attempted. (default: false)\n",
|
||||||
" --scid_alias (optional) whether a scid-alias channel type should be negotiated. (default: false)\n",
|
" --scid_alias (optional) whether a scid-alias channel type should be negotiated. (default: false)\n",
|
||||||
" --remote_reserve_sats uint (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used. (default: 0)\n",
|
" --remote_reserve_sats uint (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used. (default: 0)\n",
|
||||||
|
|
|
||||||
104
cmd/loop/testdata/sessions/static-openchannel/07_loop-static-openchannel-taproot-success.json
vendored
Normal file
104
cmd/loop/testdata/sessions/static-openchannel/07_loop-static-openchannel-taproot-success.json
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"args": [
|
||||||
|
"/home/user/bin/loop",
|
||||||
|
"--rpcserver=localhost:11010",
|
||||||
|
"--loopdir=/redacted/loop",
|
||||||
|
"--tlscertpath=/redacted/loop/regtest/tls.cert",
|
||||||
|
"--macaroonpath=/redacted/loop/regtest/loop.macaroon",
|
||||||
|
"static",
|
||||||
|
"openchannel",
|
||||||
|
"--node_key",
|
||||||
|
"03465f68fd39358667678f8353a31e0d99475e3fd2fb4e58daf7dbfabe04c011f4",
|
||||||
|
"--fundmax",
|
||||||
|
"--utxo",
|
||||||
|
"89f6fd2ee96445c6e48278e7eaaca7de8e342904f20609ce72c0d27afb443e2d:1",
|
||||||
|
"--channel_type",
|
||||||
|
"taproot",
|
||||||
|
"--private",
|
||||||
|
"--network",
|
||||||
|
"regtest"
|
||||||
|
],
|
||||||
|
"env": {},
|
||||||
|
"version": "0.33.2-beta commit=v0.33.2-beta-bump-lnd-21-a-7-g21019e684ed06e2267382f473dfeaafb81a33310 commit_hash=21019e684ed06e2267382f473dfeaafb81a33310",
|
||||||
|
"duration": 295879956,
|
||||||
|
"clock_start_unix": 1782002722
|
||||||
|
},
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"time_ms": 2,
|
||||||
|
"kind": "grpc",
|
||||||
|
"data": {
|
||||||
|
"method": "/looprpc.SwapClient/StaticOpenChannel",
|
||||||
|
"event": "request",
|
||||||
|
"message_type": "looprpc.StaticOpenChannelRequest",
|
||||||
|
"payload": {
|
||||||
|
"open_channel_request": {
|
||||||
|
"sat_per_vbyte": "0",
|
||||||
|
"node_pubkey": "A0ZfaP05NYZnZ4+DU6MeDZlHXj/S+05Y2vfb+r4EwBH0",
|
||||||
|
"node_pubkey_string": "",
|
||||||
|
"local_funding_amount": "0",
|
||||||
|
"push_sat": "0",
|
||||||
|
"target_conf": 0,
|
||||||
|
"sat_per_byte": "0",
|
||||||
|
"private": true,
|
||||||
|
"min_htlc_msat": "0",
|
||||||
|
"remote_csv_delay": 0,
|
||||||
|
"min_confs": 1,
|
||||||
|
"spend_unconfirmed": false,
|
||||||
|
"close_address": "",
|
||||||
|
"funding_shim": null,
|
||||||
|
"remote_max_value_in_flight_msat": "0",
|
||||||
|
"remote_max_htlcs": 0,
|
||||||
|
"max_local_csv": 0,
|
||||||
|
"commitment_type": "TAPROOT",
|
||||||
|
"zero_conf": false,
|
||||||
|
"scid_alias": false,
|
||||||
|
"base_fee": "0",
|
||||||
|
"fee_rate": "0",
|
||||||
|
"use_base_fee": false,
|
||||||
|
"use_fee_rate": false,
|
||||||
|
"remote_chan_reserve_sat": "0",
|
||||||
|
"fund_max": true,
|
||||||
|
"memo": "",
|
||||||
|
"outpoints": [
|
||||||
|
{
|
||||||
|
"txid_bytes": "",
|
||||||
|
"txid_str": "89f6fd2ee96445c6e48278e7eaaca7de8e342904f20609ce72c0d27afb443e2d",
|
||||||
|
"output_index": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 295,
|
||||||
|
"kind": "grpc",
|
||||||
|
"data": {
|
||||||
|
"method": "/looprpc.SwapClient/StaticOpenChannel",
|
||||||
|
"event": "response",
|
||||||
|
"message_type": "looprpc.StaticOpenChannelResponse",
|
||||||
|
"payload": {
|
||||||
|
"channel_open_outpoint": "302a41b53946494306e415bdf4724e88b2cf2b37ad2f36dc075db00cc6499e9f:0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 295,
|
||||||
|
"kind": "stdout",
|
||||||
|
"data": {
|
||||||
|
"lines": [
|
||||||
|
"{\n",
|
||||||
|
" \"channel_open_outpoint\": \"302a41b53946494306e415bdf4724e88b2cf2b37ad2f36dc075db00cc6499e9f:0\"\n",
|
||||||
|
"}\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 295,
|
||||||
|
"kind": "exit",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"args": [
|
||||||
|
"/home/user/bin/loop",
|
||||||
|
"--rpcserver=localhost:11010",
|
||||||
|
"--loopdir=/redacted/loop",
|
||||||
|
"--tlscertpath=/redacted/loop/regtest/tls.cert",
|
||||||
|
"--macaroonpath=/redacted/loop/regtest/loop.macaroon",
|
||||||
|
"static",
|
||||||
|
"openchannel",
|
||||||
|
"--node_key",
|
||||||
|
"026eca9330cc3e589505c4a240ea1f7f551e5765b1aae9040c6667141da657eae6",
|
||||||
|
"--fundmax",
|
||||||
|
"--utxo",
|
||||||
|
"dc942b3252ded50abc30ef4e8614d392ab0f091acab75fdd09e18a07f6ac36e6:0",
|
||||||
|
"--channel_type",
|
||||||
|
"taproot",
|
||||||
|
"--private",
|
||||||
|
"--network",
|
||||||
|
"regtest"
|
||||||
|
],
|
||||||
|
"env": {},
|
||||||
|
"version": "0.33.3-beta commit= commit_hash=",
|
||||||
|
"run_error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7",
|
||||||
|
"duration": 39639744,
|
||||||
|
"clock_start_unix": 1782158339
|
||||||
|
},
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"time_ms": 7,
|
||||||
|
"kind": "grpc",
|
||||||
|
"data": {
|
||||||
|
"method": "/looprpc.SwapClient/StaticOpenChannel",
|
||||||
|
"event": "request",
|
||||||
|
"message_type": "looprpc.StaticOpenChannelRequest",
|
||||||
|
"payload": {
|
||||||
|
"open_channel_request": {
|
||||||
|
"sat_per_vbyte": "0",
|
||||||
|
"node_pubkey": "Am7KkzDMPliVBcSiQOoff1UeV2WxqukEDGZnFB2mV+rm",
|
||||||
|
"node_pubkey_string": "",
|
||||||
|
"local_funding_amount": "0",
|
||||||
|
"push_sat": "0",
|
||||||
|
"target_conf": 0,
|
||||||
|
"sat_per_byte": "0",
|
||||||
|
"private": true,
|
||||||
|
"min_htlc_msat": "0",
|
||||||
|
"remote_csv_delay": 0,
|
||||||
|
"min_confs": 1,
|
||||||
|
"spend_unconfirmed": false,
|
||||||
|
"close_address": "",
|
||||||
|
"funding_shim": null,
|
||||||
|
"remote_max_value_in_flight_msat": "0",
|
||||||
|
"remote_max_htlcs": 0,
|
||||||
|
"max_local_csv": 0,
|
||||||
|
"commitment_type": "TAPROOT",
|
||||||
|
"zero_conf": false,
|
||||||
|
"scid_alias": false,
|
||||||
|
"base_fee": "0",
|
||||||
|
"fee_rate": "0",
|
||||||
|
"use_base_fee": false,
|
||||||
|
"use_fee_rate": false,
|
||||||
|
"remote_chan_reserve_sat": "0",
|
||||||
|
"fund_max": true,
|
||||||
|
"memo": "",
|
||||||
|
"outpoints": [
|
||||||
|
{
|
||||||
|
"txid_bytes": "",
|
||||||
|
"txid_str": "dc942b3252ded50abc30ef4e8614d392ab0f091acab75fdd09e18a07f6ac36e6",
|
||||||
|
"output_index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 39,
|
||||||
|
"kind": "grpc",
|
||||||
|
"data": {
|
||||||
|
"method": "/looprpc.SwapClient/StaticOpenChannel",
|
||||||
|
"event": "error",
|
||||||
|
"error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7",
|
||||||
|
"status": {
|
||||||
|
"code": 2,
|
||||||
|
"message": "channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 39,
|
||||||
|
"kind": "stderr",
|
||||||
|
"data": {
|
||||||
|
"lines": [
|
||||||
|
"[loop] rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time_ms": 39,
|
||||||
|
"kind": "exit",
|
||||||
|
"data": {
|
||||||
|
"run_error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -142,6 +142,7 @@ func MigrateLoopOutCosts(ctx context.Context, lnd lndclient.LndServices,
|
||||||
ctx, lndclient.ListPaymentsRequest{
|
ctx, lndclient.ListPaymentsRequest{
|
||||||
Offset: offset,
|
Offset: offset,
|
||||||
MaxPayments: uint64(paymentBatchSize),
|
MaxPayments: uint64(paymentBatchSize),
|
||||||
|
OmitHops: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,11 @@ func TestCostMigration(t *testing.T) {
|
||||||
// Now we can run the migration.
|
// Now we can run the migration.
|
||||||
err = MigrateLoopOutCosts(context.Background(), lnd.LndServices, 1, store)
|
err = MigrateLoopOutCosts(context.Background(), lnd.LndServices, 1, store)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
listPaymentsRequests := lnd.ListPaymentsRequestsSnapshot()
|
||||||
|
require.NotEmpty(t, listPaymentsRequests)
|
||||||
|
for _, req := range listPaymentsRequests {
|
||||||
|
require.True(t, req.OmitHops)
|
||||||
|
}
|
||||||
|
|
||||||
// Finally check that the swap cost has been updated correctly.
|
// Finally check that the swap cost has been updated correctly.
|
||||||
swap, err := store.FetchLoopOutSwap(
|
swap, err := store.FetchLoopOutSwap(
|
||||||
|
|
|
||||||
|
|
@ -589,7 +589,7 @@ Open a channel to an existing peer.
|
||||||
\fB--base_fee_msat\fP="": the base fee in milli-satoshis that will be charged for each forwarded HTLC, regardless of payment size (default: 0)
|
\fB--base_fee_msat\fP="": the base fee in milli-satoshis that will be charged for each forwarded HTLC, regardless of payment size (default: 0)
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB--channel_type\fP="": (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "taproot")
|
\fB--channel_type\fP="": (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "simple-taproot", "taproot")
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB--close_address\fP="": (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will \fInot\fP be able to cooperatively close to a different address.
|
\fB--close_address\fP="": (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will \fInot\fP be able to cooperatively close to a different address.
|
||||||
|
|
|
||||||
|
|
@ -715,7 +715,7 @@ The following flags are supported:
|
||||||
| `--max_local_csv="…"` | (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close | uint | `0` |
|
| `--max_local_csv="…"` | (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close | uint | `0` |
|
||||||
| `--close_address="…"` | (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address | string |
|
| `--close_address="…"` | (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address | string |
|
||||||
| `--remote_max_value_in_flight_msat="…"` | (optional) the maximum value in msat that can be pending within the channel at any given time | uint | `0` |
|
| `--remote_max_value_in_flight_msat="…"` | (optional) the maximum value in msat that can be pending within the channel at any given time | uint | `0` |
|
||||||
| `--channel_type="…"` | (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "taproot") | string |
|
| `--channel_type="…"` | (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "simple-taproot", "taproot") | string |
|
||||||
| `--zero_conf` | (optional) whether a zero-conf channel open should be attempted | bool | `false` |
|
| `--zero_conf` | (optional) whether a zero-conf channel open should be attempted | bool | `false` |
|
||||||
| `--scid_alias` | (optional) whether a scid-alias channel type should be negotiated | bool | `false` |
|
| `--scid_alias` | (optional) whether a scid-alias channel type should be negotiated | bool | `false` |
|
||||||
| `--remote_reserve_sats="…"` | (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used | uint | `0` |
|
| `--remote_reserve_sats="…"` | (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used | uint | `0` |
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -20,7 +20,7 @@ require (
|
||||||
github.com/jessevdk/go-flags v1.6.1
|
github.com/jessevdk/go-flags v1.6.1
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/lightninglabs/aperture v0.4.0
|
github.com/lightninglabs/aperture v0.4.0
|
||||||
github.com/lightninglabs/lndclient v0.21.0-1
|
github.com/lightninglabs/lndclient v0.21.0-2
|
||||||
github.com/lightninglabs/loop/looprpc v1.0.7
|
github.com/lightninglabs/loop/looprpc v1.0.7
|
||||||
github.com/lightninglabs/loop/swapserverrpc v1.0.14
|
github.com/lightninglabs/loop/swapserverrpc v1.0.14
|
||||||
github.com/lightninglabs/taproot-assets v0.8.0
|
github.com/lightninglabs/taproot-assets v0.8.0
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -1116,8 +1116,8 @@ github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI
|
||||||
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
|
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
|
||||||
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.4-0.20250610182311-2f1d46ef18b7 h1:373o5lNr1udAdhcf5+zq/0dYpRtkvYLl8Lk6wG7I0DY=
|
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.4-0.20250610182311-2f1d46ef18b7 h1:373o5lNr1udAdhcf5+zq/0dYpRtkvYLl8Lk6wG7I0DY=
|
||||||
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.4-0.20250610182311-2f1d46ef18b7/go.mod h1:bDnEKRN1u13NFBuy/C+bFLhxA5bfd3clT25y76QY0AM=
|
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.4-0.20250610182311-2f1d46ef18b7/go.mod h1:bDnEKRN1u13NFBuy/C+bFLhxA5bfd3clT25y76QY0AM=
|
||||||
github.com/lightninglabs/lndclient v0.21.0-1 h1:NuyccCK7tbMaH7hhqtewcx+qeBel4/RLJrlnQ/lMkkY=
|
github.com/lightninglabs/lndclient v0.21.0-2 h1:gA1utFMoKV6OZfHpYAQ1TX0wVs5cAtgTORRVavHR/ls=
|
||||||
github.com/lightninglabs/lndclient v0.21.0-1/go.mod h1:RUIcfPr82HrvZr3pu9f8nbD5v6VFbm+KgExqNNp5bE4=
|
github.com/lightninglabs/lndclient v0.21.0-2/go.mod h1:RUIcfPr82HrvZr3pu9f8nbD5v6VFbm+KgExqNNp5bE4=
|
||||||
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2.0.20251211093704-71c1eef09789 h1:7kX7vUgHUazAHcCJ6uzBDa4/2MEGEbMEfa01GtfqmTQ=
|
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2.0.20251211093704-71c1eef09789 h1:7kX7vUgHUazAHcCJ6uzBDa4/2MEGEbMEfa01GtfqmTQ=
|
||||||
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2.0.20251211093704-71c1eef09789/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
|
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2.0.20251211093704-71c1eef09789/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
|
||||||
github.com/lightninglabs/neutrino v0.17.1 h1:lNhgq7ix/N81R6oATroP/kHMzH1qzVVF2dEGcTlN2t4=
|
github.com/lightninglabs/neutrino v0.17.1 h1:lNhgq7ix/N81R6oATroP/kHMzH1qzVVF2dEGcTlN2t4=
|
||||||
|
|
|
||||||
|
|
@ -559,8 +559,11 @@ func RpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
|
||||||
req.AutoloopBudgetSat != 0 {
|
req.AutoloopBudgetSat != 0 {
|
||||||
|
|
||||||
params.AutoFeeRefreshPeriod = InfiniteDuration
|
params.AutoFeeRefreshPeriod = InfiniteDuration
|
||||||
|
// Keep reading the legacy start field so old stored
|
||||||
|
// liquidity parameters migrate to the refresh-period model.
|
||||||
|
budgetStartSec := req.AutoloopBudgetStartSec //nolint:staticcheck
|
||||||
params.AutoloopBudgetLastRefresh = time.Unix(
|
params.AutoloopBudgetLastRefresh = time.Unix(
|
||||||
int64(req.AutoloopBudgetStartSec), 0)
|
int64(budgetStartSec), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range req.Rules {
|
for _, rule := range req.Rules {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/clock"
|
"github.com/lightningnetwork/lnd/clock"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
"go.etcd.io/bbolt"
|
bbolterrors "go.etcd.io/bbolt/errors"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||||
|
|
@ -161,7 +161,7 @@ func (d *Daemon) Start() error {
|
||||||
// and error handlers. If this fails, then nothing has been started yet,
|
// and error handlers. If this fails, then nothing has been started yet,
|
||||||
// and we can just return the error.
|
// and we can just return the error.
|
||||||
err = d.initialize(true)
|
err = d.initialize(true)
|
||||||
if errors.Is(err, bbolt.ErrTimeout) {
|
if errors.Is(err, bbolterrors.ErrTimeout) {
|
||||||
// We're trying to be started as a standalone Loop daemon, most
|
// We're trying to be started as a standalone Loop daemon, most
|
||||||
// likely LiT is already running and blocking the DB
|
// likely LiT is already running and blocking the DB
|
||||||
return fmt.Errorf("%v: make sure no other loop daemon process "+
|
return fmt.Errorf("%v: make sure no other loop daemon process "+
|
||||||
|
|
@ -211,7 +211,7 @@ func (d *Daemon) StartAsSubserver(lndGrpc *lndclient.GrpcLndServices,
|
||||||
// handlers. If this fails, then nothing has been started yet, and we
|
// handlers. If this fails, then nothing has been started yet, and we
|
||||||
// can just return the error.
|
// can just return the error.
|
||||||
err := d.initialize(withMacaroonService)
|
err := d.initialize(withMacaroonService)
|
||||||
if errors.Is(err, bbolt.ErrTimeout) {
|
if errors.Is(err, bbolterrors.ErrTimeout) {
|
||||||
// We're trying to be started inside LiT so there most likely is
|
// We're trying to be started inside LiT so there most likely is
|
||||||
// another standalone Loop process blocking the DB.
|
// another standalone Loop process blocking the DB.
|
||||||
return fmt.Errorf("%v: make sure no other loop daemon "+
|
return fmt.Errorf("%v: make sure no other loop daemon "+
|
||||||
|
|
@ -994,7 +994,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
|
||||||
d.wg.Go(func() {
|
d.wg.Go(func() {
|
||||||
infof("Starting static address open channel manager")
|
infof("Starting static address open channel manager")
|
||||||
err := openChannelManager.Run(d.mainCtx)
|
err := openChannelManager.Run(d.mainCtx)
|
||||||
if err != nil && !errors.Is(context.Canceled, err) {
|
if err != nil && !errors.Is(err, context.Canceled) {
|
||||||
d.internalErrChan <- err
|
d.internalErrChan <- err
|
||||||
}
|
}
|
||||||
infof("Static address open channel manager stopped")
|
infof("Static address open channel manager stopped")
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
|
||||||
req.AssetSwapRfqId = in.AssetRfqInfo.SwapRfqId
|
req.AssetSwapRfqId = in.AssetRfqInfo.SwapRfqId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep accepting the deprecated single-channel field for older clients.
|
||||||
switch {
|
switch {
|
||||||
case in.LoopOutChannel != 0 && len(in.OutgoingChanSet) > 0: // nolint:staticcheck
|
case in.LoopOutChannel != 0 && len(in.OutgoingChanSet) > 0: // nolint:staticcheck
|
||||||
return nil, errors.New("loop_out_channel and outgoing_" +
|
return nil, errors.New("loop_out_channel and outgoing_" +
|
||||||
|
|
@ -273,7 +274,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
|
||||||
resp := &looprpc.SwapResponse{
|
resp := &looprpc.SwapResponse{
|
||||||
Id: info.SwapHash.String(),
|
Id: info.SwapHash.String(),
|
||||||
IdBytes: info.SwapHash[:],
|
IdBytes: info.SwapHash[:],
|
||||||
HtlcAddress: htlcAddress,
|
HtlcAddress: htlcAddress, //nolint:staticcheck
|
||||||
ServerMessage: info.ServerMessage,
|
ServerMessage: info.ServerMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1182,11 +1183,11 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
|
||||||
|
|
||||||
if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 {
|
if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 {
|
||||||
p2wshAddr := swapInfo.HtlcAddressP2WSH.String()
|
p2wshAddr := swapInfo.HtlcAddressP2WSH.String()
|
||||||
response.HtlcAddress = p2wshAddr
|
response.HtlcAddress = p2wshAddr //nolint:staticcheck
|
||||||
response.HtlcAddressP2Wsh = p2wshAddr
|
response.HtlcAddressP2Wsh = p2wshAddr
|
||||||
} else {
|
} else {
|
||||||
p2trAddr := swapInfo.HtlcAddressP2TR.String()
|
p2trAddr := swapInfo.HtlcAddressP2TR.String()
|
||||||
response.HtlcAddress = p2trAddr
|
response.HtlcAddress = p2trAddr //nolint:staticcheck
|
||||||
response.HtlcAddressP2Tr = p2trAddr
|
response.HtlcAddressP2Tr = p2trAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ package loopdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -48,9 +46,7 @@ func TestMigrationUpdates(t *testing.T) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
// Restore a legacy database.
|
// Restore a legacy database.
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
tempPath := filepath.Join(tempDirName, dbFileName)
|
tempPath := filepath.Join(tempDirName, dbFileName)
|
||||||
db, err := bbolt.Open(tempPath, 0600, nil)
|
db, err := bbolt.Open(tempPath, 0600, nil)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
|
bbolterrors "go.etcd.io/bbolt/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -197,9 +198,9 @@ func NewBoltSwapStore(dbPath string, chainParams *chaincfg.Params) (
|
||||||
bdb, err := bboltOpen(path, 0600, &bbolt.Options{
|
bdb, err := bboltOpen(path, 0600, &bbolt.Options{
|
||||||
Timeout: DefaultLoopDBTimeout,
|
Timeout: DefaultLoopDBTimeout,
|
||||||
})
|
})
|
||||||
if errors.Is(err, bbolt.ErrTimeout) {
|
if errors.Is(err, bbolterrors.ErrTimeout) {
|
||||||
return nil, fmt.Errorf("%w: couldn't obtain exclusive lock on "+
|
return nil, fmt.Errorf("%w: couldn't obtain exclusive lock on "+
|
||||||
"%s, timed out after %v", bbolt.ErrTimeout, path,
|
"%s, timed out after %v", bbolterrors.ErrTimeout, path,
|
||||||
DefaultLoopDBTimeout)
|
DefaultLoopDBTimeout)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -18,6 +17,7 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
|
bbolterrors "go.etcd.io/bbolt/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -62,7 +62,7 @@ func TestNewBoltSwapStoreTimeout(t *testing.T) {
|
||||||
bboltOpen = origOpen
|
bboltOpen = origOpen
|
||||||
})
|
})
|
||||||
|
|
||||||
wrappedErr := fmt.Errorf("wrapped: %w", bbolt.ErrTimeout)
|
wrappedErr := fmt.Errorf("wrapped: %w", bbolterrors.ErrTimeout)
|
||||||
bboltOpen = func(path string, mode os.FileMode,
|
bboltOpen = func(path string, mode os.FileMode,
|
||||||
options *bbolt.Options) (*bbolt.DB, error) {
|
options *bbolt.Options) (*bbolt.DB, error) {
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ func TestNewBoltSwapStoreTimeout(t *testing.T) {
|
||||||
|
|
||||||
store, err := NewBoltSwapStore(tempDir, &chaincfg.MainNetParams)
|
store, err := NewBoltSwapStore(tempDir, &chaincfg.MainNetParams)
|
||||||
require.Nil(t, store)
|
require.Nil(t, store)
|
||||||
require.ErrorIs(t, err, bbolt.ErrTimeout)
|
require.ErrorIs(t, err, bbolterrors.ErrTimeout)
|
||||||
require.ErrorContains(t, err, "couldn't obtain exclusive lock")
|
require.ErrorContains(t, err, "couldn't obtain exclusive lock")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,10 +142,7 @@ func TestLoopOutStore(t *testing.T) {
|
||||||
// testLoopOutStore tests the basic functionality of the current bbolt
|
// testLoopOutStore tests the basic functionality of the current bbolt
|
||||||
// swap store for specific swap parameters.
|
// swap store for specific swap parameters.
|
||||||
func testLoopOutStore(t *testing.T, pendingSwap *LoopOutContract) {
|
func testLoopOutStore(t *testing.T, pendingSwap *LoopOutContract) {
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -284,9 +281,7 @@ func TestLoopInStore(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
|
func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -366,11 +361,7 @@ func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
|
||||||
// TestVersionNew tests that a new database is initialized with the current
|
// TestVersionNew tests that a new database is initialized with the current
|
||||||
// version.
|
// version.
|
||||||
func TestVersionNew(t *testing.T) {
|
func TestVersionNew(t *testing.T) {
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -390,11 +381,7 @@ func TestVersionNew(t *testing.T) {
|
||||||
// TestVersionMigrated tests that an existing version zero database is migrated
|
// TestVersionMigrated tests that an existing version zero database is migrated
|
||||||
// to the latest version.
|
// to the latest version.
|
||||||
func TestVersionMigrated(t *testing.T) {
|
func TestVersionMigrated(t *testing.T) {
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
createVersionZeroDb(t, tempDirName)
|
createVersionZeroDb(t, tempDirName)
|
||||||
|
|
||||||
|
|
@ -459,11 +446,7 @@ func TestLegacyOutgoingChannel(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore a legacy database.
|
// Restore a legacy database.
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
tempPath := filepath.Join(tempDirName, dbFileName)
|
tempPath := filepath.Join(tempDirName, dbFileName)
|
||||||
db, err := bbolt.Open(tempPath, 0600, nil)
|
db, err := bbolt.Open(tempPath, 0600, nil)
|
||||||
|
|
@ -498,9 +481,7 @@ func TestLegacyOutgoingChannel(t *testing.T) {
|
||||||
// TestLiquidityParams checks that reading and writing to liquidty bucket are
|
// TestLiquidityParams checks that reading and writing to liquidty bucket are
|
||||||
// as expected.
|
// as expected.
|
||||||
func TestLiquidityParams(t *testing.T) {
|
func TestLiquidityParams(t *testing.T) {
|
||||||
tempDirName, err := ioutil.TempDir("", "clientstore")
|
tempDirName := t.TempDir()
|
||||||
require.NoError(t, err, "failed to db")
|
|
||||||
defer os.RemoveAll(tempDirName)
|
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,10 @@ func (m *mockStaticAddressClient) PushStaticAddressHtlcSigs(ctx context.Context,
|
||||||
args.Error(1)
|
args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerWithdrawDeposits implements the deprecated RPC required by the
|
||||||
|
// generated client interface. Production code uses ServerPsbtWithdrawDeposits.
|
||||||
|
//
|
||||||
|
//nolint:staticcheck
|
||||||
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
|
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
|
||||||
in *swapserverrpc.ServerWithdrawRequest,
|
in *swapserverrpc.ServerWithdrawRequest,
|
||||||
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,
|
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,10 @@ func (m *mockStaticAddressClient) PushStaticAddressHtlcSigs(ctx context.Context,
|
||||||
args.Error(1)
|
args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerWithdrawDeposits implements the deprecated RPC required by the
|
||||||
|
// generated client interface. Production code uses ServerPsbtWithdrawDeposits.
|
||||||
|
//
|
||||||
|
//nolint:staticcheck
|
||||||
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
|
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
|
||||||
in *swapserverrpc.ServerWithdrawRequest,
|
in *swapserverrpc.ServerWithdrawRequest,
|
||||||
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,
|
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,8 @@ func (m *Manager) OpenChannel(ctx context.Context,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a local funding amount is set, coin-select deposits to
|
||||||
|
// cover it. Otherwise fundmax uses all available deposits.
|
||||||
if req.LocalFundingAmount != 0 {
|
if req.LocalFundingAmount != 0 {
|
||||||
deposits, err = staticutil.SelectDeposits(
|
deposits, err = staticutil.SelectDeposits(
|
||||||
deposits, req.LocalFundingAmount,
|
deposits, req.LocalFundingAmount,
|
||||||
|
|
@ -319,9 +321,6 @@ func (m *Manager) OpenChannel(ctx context.Context,
|
||||||
return nil, fmt.Errorf("error selecting "+
|
return nil, fmt.Errorf("error selecting "+
|
||||||
"deposits: %w", err)
|
"deposits: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// The fundmax flag is set, hence we select all deposits
|
|
||||||
// for funding the channel.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -369,6 +368,7 @@ func (m *Manager) OpenChannel(ctx context.Context,
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return chanOutpoint, nil
|
return chanOutpoint, nil
|
||||||
}
|
}
|
||||||
|
err = maybeWrapTaprootUnsupportedError(reqClone, err)
|
||||||
|
|
||||||
log.Infof("error opening channel: %v", err)
|
log.Infof("error opening channel: %v", err)
|
||||||
|
|
||||||
|
|
@ -773,6 +773,9 @@ func resolveCommitmentType(commitmentType lnrpc.CommitmentType) (
|
||||||
case lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
case lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
||||||
return lnrpc.CommitmentType_SIMPLE_TAPROOT, nil
|
return lnrpc.CommitmentType_SIMPLE_TAPROOT, nil
|
||||||
|
|
||||||
|
case lnrpc.CommitmentType_TAPROOT:
|
||||||
|
return lnrpc.CommitmentType_TAPROOT, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, fmt.Errorf(
|
return lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, fmt.Errorf(
|
||||||
"unsupported commitment type %v", commitmentType,
|
"unsupported commitment type %v", commitmentType,
|
||||||
|
|
@ -780,6 +783,30 @@ func resolveCommitmentType(commitmentType lnrpc.CommitmentType) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maybeWrapTaprootUnsupportedError turns lnd's generic unknown channel type
|
||||||
|
// error into a user-actionable message for Loop's production taproot channel
|
||||||
|
// type.
|
||||||
|
func maybeWrapTaprootUnsupportedError(req *lnrpc.OpenChannelRequest,
|
||||||
|
err error) error {
|
||||||
|
|
||||||
|
if err == nil || req.CommitmentType != lnrpc.CommitmentType_TAPROOT {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
errMsg := strings.ToLower(err.Error())
|
||||||
|
switch {
|
||||||
|
case strings.Contains(errMsg, "unhandled request channel type"),
|
||||||
|
strings.Contains(errMsg, "unknown channel type"),
|
||||||
|
strings.Contains(errMsg, "unsupported channel type"):
|
||||||
|
|
||||||
|
return fmt.Errorf("channel_type=taproot is not supported "+
|
||||||
|
"by the connected lnd; update LND to v0.21.0-beta "+
|
||||||
|
"or later to use this channel type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// checkPsbtFlags make sure a request to open a channel doesn't set any
|
// checkPsbtFlags make sure a request to open a channel doesn't set any
|
||||||
// parameters that are incompatible with the PSBT funding flow.
|
// parameters that are incompatible with the PSBT funding flow.
|
||||||
func checkPsbtFlags(req *lnrpc.OpenChannelRequest) error {
|
func checkPsbtFlags(req *lnrpc.OpenChannelRequest) error {
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,11 @@ func TestResolveCommitmentType(t *testing.T) {
|
||||||
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
expectedType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
expectedType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "production taproot supported",
|
||||||
|
commitmentType: lnrpc.CommitmentType_TAPROOT,
|
||||||
|
expectedType: lnrpc.CommitmentType_TAPROOT,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "legacy rejected",
|
name: "legacy rejected",
|
||||||
commitmentType: lnrpc.CommitmentType_LEGACY,
|
commitmentType: lnrpc.CommitmentType_LEGACY,
|
||||||
|
|
@ -596,6 +601,33 @@ func TestResolveCommitmentType(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMaybeWrapTaprootUnsupportedError verifies that generic old-lnd channel
|
||||||
|
// type rejections become actionable for Loop users selecting production
|
||||||
|
// taproot channels.
|
||||||
|
func TestMaybeWrapTaprootUnsupportedError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
baseErr := errors.New("got error from server: rpc error: " +
|
||||||
|
"code = Unknown desc = unhandled request channel type 7")
|
||||||
|
req := &lnrpc.OpenChannelRequest{
|
||||||
|
CommitmentType: lnrpc.CommitmentType_TAPROOT,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := maybeWrapTaprootUnsupportedError(req, baseErr)
|
||||||
|
require.ErrorContains(
|
||||||
|
t, err, "channel_type=taproot is not supported",
|
||||||
|
)
|
||||||
|
require.ErrorContains(
|
||||||
|
t, err, "update LND to v0.21.0-beta or later",
|
||||||
|
)
|
||||||
|
require.ErrorIs(t, err, baseErr)
|
||||||
|
|
||||||
|
req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
|
||||||
|
err = maybeWrapTaprootUnsupportedError(req, baseErr)
|
||||||
|
require.ErrorIs(t, err, baseErr)
|
||||||
|
require.NotContains(t, err.Error(), "update LND")
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Mock types for PSBT channel open flow tests.
|
// Mock types for PSBT channel open flow tests.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -232,8 +232,10 @@ func estimateFee(numInputs int, feeRate chainfee.SatPerKWeight,
|
||||||
|
|
||||||
// Add the funding output based on commitment type.
|
// Add the funding output based on commitment type.
|
||||||
switch commitmentType {
|
switch commitmentType {
|
||||||
case lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
case lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
|
lnrpc.CommitmentType_TAPROOT:
|
||||||
we.AddP2TROutput()
|
we.AddP2TROutput()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
we.AddP2WSHOutput()
|
we.AddP2WSHOutput()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -271,9 +271,6 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
// High fee rate: 100 sat/vbyte = 25000 sat/kw.
|
// High fee rate: 100 sat/vbyte = 25000 sat/kw.
|
||||||
highFeeRate := chainfee.SatPerKVByte(100_000).FeePerKWeight()
|
highFeeRate := chainfee.SatPerKVByte(100_000).FeePerKWeight()
|
||||||
|
|
||||||
anchors := lnrpc.CommitmentType_ANCHORS
|
|
||||||
taproot := lnrpc.CommitmentType_SIMPLE_TAPROOT
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
deposits []*deposit.Deposit
|
deposits []*deposit.Deposit
|
||||||
|
|
@ -290,7 +287,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(1_000, 2_000),
|
deposits: makeDeposits(1_000, 2_000),
|
||||||
amount: 1_000_000,
|
amount: 1_000_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantErr: "insufficient funds",
|
wantErr: "insufficient funds",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -298,7 +295,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(100_000),
|
deposits: makeDeposits(100_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantErr: "insufficient funds",
|
wantErr: "insufficient funds",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -310,7 +307,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(51_000),
|
deposits: makeDeposits(51_000),
|
||||||
amount: 50_000,
|
amount: 50_000,
|
||||||
feeRate: highFeeRate,
|
feeRate: highFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantErr: "insufficient funds",
|
wantErr: "insufficient funds",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -327,7 +324,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
),
|
),
|
||||||
amount: 400_000,
|
amount: 400_000,
|
||||||
feeRate: highFeeRate,
|
feeRate: highFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 2,
|
wantCount: 2,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
require.Equal(
|
require.Equal(
|
||||||
|
|
@ -345,7 +342,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(500_000),
|
deposits: makeDeposits(500_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 1,
|
wantCount: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -353,7 +350,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(60_000, 60_000),
|
deposits: makeDeposits(60_000, 60_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 2,
|
wantCount: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -361,7 +358,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(10_000, 200_000, 50_000),
|
deposits: makeDeposits(10_000, 200_000, 50_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 1,
|
wantCount: 1,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
// Should pick the 200k deposit.
|
// Should pick the 200k deposit.
|
||||||
|
|
@ -388,13 +385,13 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(35_500, 35_500, 10_000),
|
deposits: makeDeposits(35_500, 35_500, 10_000),
|
||||||
amount: 50_000,
|
amount: 50_000,
|
||||||
feeRate: highFeeRate,
|
feeRate: highFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 3,
|
wantCount: 3,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
total := depositSum(selected)
|
total := depositSum(selected)
|
||||||
fee := estimateFee(
|
fee := estimateFee(
|
||||||
len(selected), highFeeRate,
|
len(selected), highFeeRate,
|
||||||
anchors,
|
lnrpc.CommitmentType_ANCHORS,
|
||||||
)
|
)
|
||||||
require.GreaterOrEqual(
|
require.GreaterOrEqual(
|
||||||
t, total,
|
t, total,
|
||||||
|
|
@ -407,7 +404,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(40_000, 40_000, 40_000),
|
deposits: makeDeposits(40_000, 40_000, 40_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 3,
|
wantCount: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -415,7 +412,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(100_000, 50_000),
|
deposits: makeDeposits(100_000, 50_000),
|
||||||
amount: 99_000,
|
amount: 99_000,
|
||||||
feeRate: 0,
|
feeRate: 0,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 1,
|
wantCount: 1,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
// With zero fee, 100k covers 99k + 0 + dust.
|
// With zero fee, 100k covers 99k + 0 + dust.
|
||||||
|
|
@ -430,12 +427,12 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(200_000, 100_000, 50_000),
|
deposits: makeDeposits(200_000, 100_000, 50_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: highFeeRate,
|
feeRate: highFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
total := depositSum(selected)
|
total := depositSum(selected)
|
||||||
fee := estimateFee(
|
fee := estimateFee(
|
||||||
len(selected), highFeeRate,
|
len(selected), highFeeRate,
|
||||||
anchors,
|
lnrpc.CommitmentType_ANCHORS,
|
||||||
)
|
)
|
||||||
require.GreaterOrEqual(
|
require.GreaterOrEqual(
|
||||||
t, total,
|
t, total,
|
||||||
|
|
@ -448,7 +445,15 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(500_000),
|
deposits: makeDeposits(500_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: taproot,
|
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
|
wantCount: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "production taproot commitment type",
|
||||||
|
deposits: makeDeposits(500_000),
|
||||||
|
amount: 100_000,
|
||||||
|
feeRate: lowFeeRate,
|
||||||
|
commitmentType: lnrpc.CommitmentType_TAPROOT,
|
||||||
wantCount: 1,
|
wantCount: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -459,12 +464,12 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
),
|
),
|
||||||
amount: 50_000,
|
amount: 50_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
total := depositSum(selected)
|
total := depositSum(selected)
|
||||||
fee := estimateFee(
|
fee := estimateFee(
|
||||||
len(selected), lowFeeRate,
|
len(selected), lowFeeRate,
|
||||||
anchors,
|
lnrpc.CommitmentType_ANCHORS,
|
||||||
)
|
)
|
||||||
require.GreaterOrEqual(
|
require.GreaterOrEqual(
|
||||||
t, total,
|
t, total,
|
||||||
|
|
@ -484,12 +489,12 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
),
|
),
|
||||||
amount: 150_000,
|
amount: 150_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
total := depositSum(selected)
|
total := depositSum(selected)
|
||||||
fee := estimateFee(
|
fee := estimateFee(
|
||||||
len(selected), lowFeeRate,
|
len(selected), lowFeeRate,
|
||||||
anchors,
|
lnrpc.CommitmentType_ANCHORS,
|
||||||
)
|
)
|
||||||
// Core invariant: selected amount covers
|
// Core invariant: selected amount covers
|
||||||
// requested amount + fee + dust.
|
// requested amount + fee + dust.
|
||||||
|
|
@ -506,7 +511,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(10_000, 20_000, 300_000),
|
deposits: makeDeposits(10_000, 20_000, 300_000),
|
||||||
amount: 100_000,
|
amount: 100_000,
|
||||||
feeRate: lowFeeRate,
|
feeRate: lowFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 1,
|
wantCount: 1,
|
||||||
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
validate: func(t *testing.T, selected []*deposit.Deposit) {
|
||||||
require.Equal(
|
require.Equal(
|
||||||
|
|
@ -525,7 +530,7 @@ func TestSelectDeposits(t *testing.T) {
|
||||||
deposits: makeDeposits(60_000, 60_000),
|
deposits: makeDeposits(60_000, 60_000),
|
||||||
amount: 50_000,
|
amount: 50_000,
|
||||||
feeRate: highFeeRate,
|
feeRate: highFeeRate,
|
||||||
commitmentType: anchors,
|
commitmentType: lnrpc.CommitmentType_ANCHORS,
|
||||||
wantCount: 2,
|
wantCount: 2,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,11 @@ func TestCalculateWithdrawalTxValuesCommitmentTypeParity(t *testing.T) {
|
||||||
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
addr: taprootAddr,
|
addr: taprootAddr,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "production taproot and p2tr",
|
||||||
|
commitmentType: lnrpc.CommitmentType_TAPROOT,
|
||||||
|
addr: taprootAddr,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedAmounts := []btcutil.Amount{
|
selectedAmounts := []btcutil.Amount{
|
||||||
|
|
|
||||||
|
|
@ -1108,7 +1108,8 @@ func WithdrawalTxWeight(numInputs int, sweepAddress btcutil.Address,
|
||||||
|
|
||||||
if commitmentType != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE {
|
if commitmentType != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE {
|
||||||
switch commitmentType {
|
switch commitmentType {
|
||||||
case lnrpc.CommitmentType_SIMPLE_TAPROOT:
|
case lnrpc.CommitmentType_SIMPLE_TAPROOT,
|
||||||
|
lnrpc.CommitmentType_TAPROOT:
|
||||||
weightEstimator.AddP2TROutput()
|
weightEstimator.AddP2TROutput()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,11 @@ func (h *mockLightningClient) ListPayments(_ context.Context,
|
||||||
req lndclient.ListPaymentsRequest) (*lndclient.ListPaymentsResponse,
|
req lndclient.ListPaymentsRequest) (*lndclient.ListPaymentsResponse,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
|
h.lnd.lock.Lock()
|
||||||
|
defer h.lnd.lock.Unlock()
|
||||||
|
|
||||||
|
h.lnd.ListPaymentsRequests = append(h.lnd.ListPaymentsRequests, req)
|
||||||
|
|
||||||
if req.Offset >= uint64(len(h.lnd.Payments)) {
|
if req.Offset >= uint64(len(h.lnd.Payments)) {
|
||||||
return &lndclient.ListPaymentsResponse{}, nil
|
return &lndclient.ListPaymentsResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +278,8 @@ func (h *mockLightningClient) ListPayments(_ context.Context,
|
||||||
lastIndexOffset := req.Offset + req.MaxPayments
|
lastIndexOffset := req.Offset + req.MaxPayments
|
||||||
lastIndexOffset = min(lastIndexOffset, uint64(len(h.lnd.Payments)))
|
lastIndexOffset = min(lastIndexOffset, uint64(len(h.lnd.Payments)))
|
||||||
|
|
||||||
result := h.lnd.Payments[req.Offset:lastIndexOffset]
|
result := make([]lndclient.Payment, lastIndexOffset-req.Offset)
|
||||||
|
copy(result, h.lnd.Payments[req.Offset:lastIndexOffset])
|
||||||
|
|
||||||
return &lndclient.ListPaymentsResponse{
|
return &lndclient.ListPaymentsResponse{
|
||||||
Payments: result,
|
Payments: result,
|
||||||
|
|
|
||||||
|
|
@ -162,12 +162,13 @@ type LndMockServices struct {
|
||||||
// keyed by hash string.
|
// keyed by hash string.
|
||||||
Invoices map[lntypes.Hash]*lndclient.Invoice
|
Invoices map[lntypes.Hash]*lndclient.Invoice
|
||||||
|
|
||||||
Channels []lndclient.ChannelInfo
|
Channels []lndclient.ChannelInfo
|
||||||
ChannelEdges map[uint64]*lndclient.ChannelEdge
|
ChannelEdges map[uint64]*lndclient.ChannelEdge
|
||||||
ClosedChannels []lndclient.ClosedChannel
|
ClosedChannels []lndclient.ClosedChannel
|
||||||
ForwardingEvents []lndclient.ForwardingEvent
|
ForwardingEvents []lndclient.ForwardingEvent
|
||||||
Payments []lndclient.Payment
|
Payments []lndclient.Payment
|
||||||
MissionControlState []lndclient.MissionControlEntry
|
ListPaymentsRequests []lndclient.ListPaymentsRequest
|
||||||
|
MissionControlState []lndclient.MissionControlEntry
|
||||||
|
|
||||||
WaitForFinished func()
|
WaitForFinished func()
|
||||||
|
|
||||||
|
|
@ -185,6 +186,20 @@ func (s *LndMockServices) EpochSubscribers() int32 {
|
||||||
return int32(len(s.blockHeightListeners))
|
return int32(len(s.blockHeightListeners))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListPaymentsRequestsSnapshot returns a copy of all ListPayments requests
|
||||||
|
// recorded by the mock.
|
||||||
|
func (s *LndMockServices) ListPaymentsRequestsSnapshot() []lndclient.ListPaymentsRequest {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
requests := make(
|
||||||
|
[]lndclient.ListPaymentsRequest, len(s.ListPaymentsRequests),
|
||||||
|
)
|
||||||
|
copy(requests, s.ListPaymentsRequests)
|
||||||
|
|
||||||
|
return requests
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyHeight notifies a new block height.
|
// NotifyHeight notifies a new block height.
|
||||||
func (s *LndMockServices) NotifyHeight(height int32) error {
|
func (s *LndMockServices) NotifyHeight(height int32) error {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue