diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bdc8280..2cdfa2b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ defaults: shell: bash env: - GO_VERSION: 1.24.6 + GO_VERSION: 1.26 jobs: build: diff --git a/README.md b/README.md index 5f15da7..3fcfc03 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,11 @@ node-metrics-agent: - PeerAlias support for ChannelInfo ``` +| tag | `lnd` version in `go.mod` | minimum required `lnd` version | +|--------------|---------------------------|--------------------------------| +| `v0.18.5-13` | `v0.18.5-beta` | `v0.18.5-beta` | +| `v0.20.0-4` | `v0.20.0-beta` | `v0.19.0-beta` | + ## Building a new release Tag the commit and push the tag to remote. Then simply import the release in the target release. diff --git a/go.mod b/go.mod index 6fd550d..986ab1c 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/btcutil/psbt v1.1.8 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 - github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 - github.com/btcsuite/btcwallet v0.16.13 + github.com/btcsuite/btclog/v2 v2.0.1-0.20250728225537-6090e87c6c5b + github.com/btcsuite/btcwallet v0.16.17 github.com/btcsuite/btcwallet/wtxmgr v1.5.6 - github.com/lightningnetwork/lnd v0.19.0-beta + github.com/lightningnetwork/lnd v0.20.1-beta github.com/lightningnetwork/lnd/kvdb v1.4.16 github.com/stretchr/testify v1.10.0 google.golang.org/grpc v1.59.0 @@ -20,6 +20,7 @@ require ( require ( dario.cat/mergo v1.0.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect @@ -42,14 +43,12 @@ require ( github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/decred/dcrd/lru v1.1.2 // indirect - github.com/distribution/reference v0.6.0 // indirect - github.com/docker/cli v28.0.1+incompatible // indirect - github.com/docker/docker v28.0.1+incompatible // indirect + github.com/docker/cli v28.1.1+incompatible // indirect + github.com/docker/docker v28.1.1+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fergusstrange/embedded-postgres v1.25.0 // indirect - github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect @@ -57,7 +56,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-migrate/migrate/v4 v4.17.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -76,11 +75,11 @@ require ( github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.2 // indirect - github.com/jackc/pgx/v5 v5.5.4 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgtype v1.14.4 // indirect + github.com/jackc/pgx/v4 v4.18.3 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jessevdk/go-flags v1.4.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/jrick/logrotate v1.1.2 // indirect @@ -99,14 +98,14 @@ require ( github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect github.com/lightninglabs/neutrino v0.16.1 // indirect github.com/lightninglabs/neutrino/cache v1.1.2 // indirect - github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect + github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 // indirect github.com/lightningnetwork/lnd/clock v1.1.1 // indirect - github.com/lightningnetwork/lnd/fn/v2 v2.0.8 // indirect + github.com/lightningnetwork/lnd/fn/v2 v2.0.9 // indirect github.com/lightningnetwork/lnd/healthcheck v1.2.6 // indirect github.com/lightningnetwork/lnd/queue v1.1.1 // indirect - github.com/lightningnetwork/lnd/sqldb v1.0.9 // indirect + github.com/lightningnetwork/lnd/sqldb v1.0.12-0.20260113193010-8565d12e40b1 // indirect github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect - github.com/lightningnetwork/lnd/tlv v1.3.1 // indirect + github.com/lightningnetwork/lnd/tlv v1.3.2 // indirect github.com/lightningnetwork/lnd/tor v1.1.6 // indirect github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -120,7 +119,7 @@ require ( github.com/ncruces/go-strftime v0.1.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/opencontainers/runc v1.2.0 // indirect + github.com/opencontainers/runc v1.2.8 // indirect github.com/ory/dockertest/v3 v3.10.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -132,7 +131,7 @@ require ( github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect @@ -141,7 +140,7 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect - go.etcd.io/bbolt v1.3.11 // indirect + go.etcd.io/bbolt v1.4.3 // indirect go.etcd.io/etcd/api/v3 v3.5.12 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect go.etcd.io/etcd/client/v2 v2.305.12 // indirect @@ -151,7 +150,6 @@ require ( go.etcd.io/etcd/server/v3 v3.5.12 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect @@ -162,14 +160,14 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.17.0 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.37.0 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect @@ -195,4 +193,4 @@ require ( // allows us to specify that as an option. replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display -go 1.24.6 +go 1.25.5 diff --git a/go.sum b/go.sum index 9e16b35..45c3c7c 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,9 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -53,11 +54,11 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c h1:4HxD1lBUGUddhzgaNgrCPsFWd7cGYNpeFUgd9ZIgyM0= github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhwT3lmrS4H3b/D1XAXxvh+tbhUm8xeHN2y3TQ= -github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4= -github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= +github.com/btcsuite/btclog/v2 v2.0.1-0.20250728225537-6090e87c6c5b h1:MQ+Q6sDy37V1wP1Yu79A5KqJutolqUGwA99UZWQDWZM= +github.com/btcsuite/btclog/v2 v2.0.1-0.20250728225537-6090e87c6c5b/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.13 h1:JGu+wrihQ0I00ODb3w92JtBPbrHxZhbcvU01O+e+lKw= -github.com/btcsuite/btcwallet v0.16.13/go.mod h1:H6dfoZcWPonM2wbVsR2ZBY0PKNZKdQyLAmnX8vL9JFA= +github.com/btcsuite/btcwallet v0.16.17 h1:1N6lHznRdcjDopBvcofxaIHknArkJ/EcVKgLKfGL4Dg= +github.com/btcsuite/btcwallet v0.16.17/go.mod h1:YO+W745BAH8n/Rpgj68QsLR6eLlgM4W2do4RejT0buo= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk= @@ -121,10 +122,10 @@ github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs= -github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0= -github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k= +github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I= +github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -149,8 +150,6 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -189,8 +188,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -262,27 +261,31 @@ github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= -github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= +github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -351,26 +354,26 @@ github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3 github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo= github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display h1:Y2WiPkBS/00EiEg0qp0FhehxnQfk3vv8U6Xt3nN+rTY= github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY= -github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= -github.com/lightningnetwork/lnd v0.19.0-beta h1:/8i2UdARiEpI2iAmPoSDcwZSSEuWqXyfsMxz/mLGbdw= -github.com/lightningnetwork/lnd v0.19.0-beta/go.mod h1:hu6zo1zcznx7nViiFlJY8qGDwwGw5LNLdGJ7ICz5Ysc= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 h1:6D3LrdagJweLLdFm1JNodZsBk6iU4TTsBBFLQ4yiXfI= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9/go.mod h1:EDqJ3MuZIbMq0QI1czTIKDJ/GS8S14RXPwapHw8cw6w= +github.com/lightningnetwork/lnd v0.20.1-beta h1:wDMNgks5uST1CY+WwjIZ4+McPMMFpr2pIIGJp7ytDI4= +github.com/lightningnetwork/lnd v0.20.1-beta/go.mod h1:oIKh9EqE1sJJpQPq9ZCMFc4Ot287NrotZ1oZn0zUI+M= github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0= github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ= -github.com/lightningnetwork/lnd/fn/v2 v2.0.8 h1:r2SLz7gZYQPVc3IZhU82M66guz3Zk2oY+Rlj9QN5S3g= -github.com/lightningnetwork/lnd/fn/v2 v2.0.8/go.mod h1:TOzwrhjB/Azw1V7aa8t21ufcQmdsQOQMDtxVOQWNl8s= +github.com/lightningnetwork/lnd/fn/v2 v2.0.9 h1:ZytG4ltPac/sCyg1EJDn10RGzPIDJeyennUMRdOw7Y8= +github.com/lightningnetwork/lnd/fn/v2 v2.0.9/go.mod h1:aPUJHJ31S+Lgoo8I5SxDIjnmeCifqujaiTXKZqpav3w= github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI= github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ= github.com/lightningnetwork/lnd/kvdb v1.4.16 h1:9BZgWdDfjmHRHLS97cz39bVuBAqMc4/p3HX1xtUdbDI= github.com/lightningnetwork/lnd/kvdb v1.4.16/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM= github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI= github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4= -github.com/lightningnetwork/lnd/sqldb v1.0.9 h1:7OHi+Hui823mB/U9NzCdlZTAGSVdDCbjp33+6d/Q+G0= -github.com/lightningnetwork/lnd/sqldb v1.0.9/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4= +github.com/lightningnetwork/lnd/sqldb v1.0.12-0.20260113193010-8565d12e40b1 h1:PkEppKL17cZh0Dr9h/T9BEVJUbd/p2tjJ/x8ffG3R0M= +github.com/lightningnetwork/lnd/sqldb v1.0.12-0.20260113193010-8565d12e40b1/go.mod h1:tB2jlqu79TIOR9uhAZOmPxpVFUhB2s+oxKnqRRL1oc0= github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM= github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA= -github.com/lightningnetwork/lnd/tlv v1.3.1 h1:o7CZg06y+rJZfUMAo0WzBLr0pgBWCzrt0f9gpujYUzk= -github.com/lightningnetwork/lnd/tlv v1.3.1/go.mod h1:pJuiBj1ecr1WWLOtcZ+2+hu9Ey25aJWFIsjmAoPPnmc= +github.com/lightningnetwork/lnd/tlv v1.3.2 h1:MO4FCk7F4k5xPMqVZF6Nb/kOpxlwPrUQpYjmyKny5s0= +github.com/lightningnetwork/lnd/tlv v1.3.2/go.mod h1:pJuiBj1ecr1WWLOtcZ+2+hu9Ey25aJWFIsjmAoPPnmc= github.com/lightningnetwork/lnd/tor v1.1.6 h1:WHUumk7WgU6BUFsqHuqszI9P6nfhMeIG+rjJBlVE6OE= github.com/lightningnetwork/lnd/tor v1.1.6/go.mod h1:qSRB8llhAK+a6kaTPWOLLXSZc6Hg8ZC0mq1sUQ/8JfI= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= @@ -427,8 +430,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.2.0 h1:qke7ZVCmJcKrJVY2iHJVC+0kql9uYdkusOPsQOOeBw4= -github.com/opencontainers/runc v1.2.0/go.mod h1:/PXzF0h531HTMsYQnmxXkBD7YaGShm/2zcRB79dksUc= +github.com/opencontainers/runc v1.2.8 h1:RnEICeDReapbZ5lZEgHvj7E9Q3Eex9toYmaGBsbvU5Q= +github.com/opencontainers/runc v1.2.8/go.mod h1:cC0YkmZcuvr+rtBZ6T7NBoVbMGNAdLa/21vIElJDOzI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= @@ -479,11 +482,13 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -491,6 +496,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -512,9 +520,10 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= +go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= +go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= @@ -580,8 +589,11 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= @@ -593,6 +605,8 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -615,8 +629,12 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -630,8 +648,10 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -661,22 +681,35 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -693,6 +726,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/invoices_client.go b/invoices_client.go index a7ae58c..f8539f7 100644 --- a/invoices_client.go +++ b/invoices_client.go @@ -2,7 +2,6 @@ package lndclient import ( "context" - "errors" "fmt" "io" "sync" @@ -89,10 +88,20 @@ type InvoicesClient interface { handler InvoiceHtlcModifyHandler) error } -// InvoiceUpdate contains a state update for an invoice. +// InvoiceUpdate embeds an Invoice to expose the complete invoice view along +// with the legacy satoshis-paid field used by existing callers. type InvoiceUpdate struct { - State invpkg.ContractState - AmtPaid btcutil.Amount + // Invoice holds the current state of the invoice. + Invoice + + // AmtPaid is the amount that was accepted for this invoice, in sats. + // This will ONLY be set if this invoice has been settled or accepted. + // We provide this field as if the invoice was created with a zero + // value, then we need to record what amount was ultimately accepted. + // Additionally, it's possible that the sender paid MORE that was + // specified in the original invoice. So we'll record that here as well. + AmtPaid btcutil.Amount + AmtPaidMsat lnwire.MilliSatoshi } @@ -204,18 +213,20 @@ func (s *invoicesClient) SubscribeSingleInvoice(ctx context.Context, return } - state, err := fromRPCInvoiceState(invoice.State) + clientInvoice, err := unmarshalInvoice(invoice) if err != nil { errChan <- err return } - select { - case updateChan <- InvoiceUpdate{ - State: state, + invoiceUpdate := InvoiceUpdate{ + Invoice: *clientInvoice, AmtPaid: btcutil.Amount(invoice.AmtPaidSat), AmtPaidMsat: lnwire.MilliSatoshi(invoice.AmtPaidMsat), - }: + } + + select { + case updateChan <- invoiceUpdate: case <-ctx.Done(): return } @@ -231,6 +242,12 @@ func (s *invoicesClient) AddHoldInvoice(ctx context.Context, rpcCtx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() + if in.Amp || in.BlindedPathCfg != nil { + log.Warnf("invoicesClient.AddHoldInvoice ignores Amp/" + + "BlindedPathCfg; hold invoice RPC does not support " + + "those fields") + } + routeHints, err := marshallRouteHints(in.RouteHints) if err != nil { return "", fmt.Errorf("failed to marshal route hints: %v", err) @@ -256,26 +273,6 @@ func (s *invoicesClient) AddHoldInvoice(ctx context.Context, return resp.PaymentRequest, nil } -func fromRPCInvoiceState(state lnrpc.Invoice_InvoiceState) ( - invpkg.ContractState, error) { - - switch state { - case lnrpc.Invoice_OPEN: - return invpkg.ContractOpen, nil - - case lnrpc.Invoice_ACCEPTED: - return invpkg.ContractAccepted, nil - - case lnrpc.Invoice_SETTLED: - return invpkg.ContractSettled, nil - - case lnrpc.Invoice_CANCELED: - return invpkg.ContractCanceled, nil - } - - return 0, errors.New("unknown state") -} - // HtlcModifier is a bidirectional streaming RPC that allows a client to // intercept and modify the HTLCs that attempt to settle the given invoice. The // server will send HTLCs of invoices to the client and the client can modify diff --git a/invoices_client_test.go b/invoices_client_test.go new file mode 100644 index 0000000..ee5bef6 --- /dev/null +++ b/invoices_client_test.go @@ -0,0 +1,243 @@ +package lndclient + +import ( + "bytes" + "context" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/zpay32" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" +) + +// testInvoiceRouteHints returns deterministic route hints for invoice tests. +func testInvoiceRouteHints() [][]zpay32.HopHint { + _, pubKey1 := btcec.PrivKeyFromBytes(bytes.Repeat([]byte{1}, 32)) + _, pubKey2 := btcec.PrivKeyFromBytes(bytes.Repeat([]byte{2}, 32)) + _, pubKey3 := btcec.PrivKeyFromBytes(bytes.Repeat([]byte{3}, 32)) + + return [][]zpay32.HopHint{ + { + { + NodeID: pubKey1, + ChannelID: 101, + FeeBaseMSat: 1001, + FeeProportionalMillionths: 2001, + CLTVExpiryDelta: 40, + }, + { + NodeID: pubKey2, + ChannelID: 102, + FeeBaseMSat: 1002, + FeeProportionalMillionths: 2002, + CLTVExpiryDelta: 41, + }, + }, + { + { + NodeID: pubKey3, + ChannelID: 103, + FeeBaseMSat: 1003, + FeeProportionalMillionths: 2003, + CLTVExpiryDelta: 42, + }, + }, + } +} + +// fallbackAddr is just a Bitcoin address used for tests of FallbackAddr field. +const fallbackAddr = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080" + +// testRPCRouteHints returns the RPC form of the deterministic route hints. +func testRPCRouteHints(t *testing.T) []*lnrpc.RouteHint { + t.Helper() + + rpcRouteHints, err := marshallRouteHints(testInvoiceRouteHints()) + require.NoError(t, err) + + return rpcRouteHints +} + +// addHoldInvoiceArg records the args used in +// mockInvoicesRPCClient.AddHoldInvoice. +type addHoldInvoiceArg struct { + in *invoicesrpc.AddHoldInvoiceRequest + opts []grpc.CallOption +} + +// mockInvoicesRPCClient implements invoicesrpc.InvoicesClient with a dynamic +// AddHoldInvoice implementation and call spying. +type mockInvoicesRPCClient struct { + invoicesrpc.InvoicesClient + + addHoldInvoice func(in *invoicesrpc.AddHoldInvoiceRequest, + opts ...grpc.CallOption) (*invoicesrpc.AddHoldInvoiceResp, + error) + + addHoldInvoiceArgs []addHoldInvoiceArg +} + +// AddHoldInvoice records the call and forwards it to the test hook. +func (m *mockInvoicesRPCClient) AddHoldInvoice(ctx context.Context, + in *invoicesrpc.AddHoldInvoiceRequest, + opts ...grpc.CallOption) (*invoicesrpc.AddHoldInvoiceResp, error) { + + m.addHoldInvoiceArgs = append(m.addHoldInvoiceArgs, addHoldInvoiceArg{ + in: in, + opts: opts, + }) + + return m.addHoldInvoice(in, opts...) +} + +// assertInvoiceRequestParity verifies the shared fields that should be encoded +// identically by AddInvoice and AddHoldInvoice. +func assertInvoiceRequestParity(t *testing.T, add *lnrpc.Invoice, + hold *invoicesrpc.AddHoldInvoiceRequest) { + + t.Helper() + + require.Equal(t, add.Memo, hold.Memo) + require.Equal(t, add.ValueMsat, hold.ValueMsat) + require.Equal(t, add.DescriptionHash, hold.DescriptionHash) + require.Equal(t, add.Expiry, hold.Expiry) + require.Equal(t, add.FallbackAddr, hold.FallbackAddr) + require.Equal(t, add.CltvExpiry, hold.CltvExpiry) + require.Equal(t, add.Private, hold.Private) + require.Equal(t, add.RouteHints, hold.RouteHints) +} + +// TestInvoiceClientAddInvoiceParity ensures AddInvoice and AddHoldInvoice +// encode the same explicit invoice fields for the same invoice input. +func TestInvoiceClientAddInvoiceParity(t *testing.T) { + var validPreimage lntypes.Preimage + copy(validPreimage[:], "valid preimage") + + var validRHash lntypes.Hash + copy(validRHash[:], "valid hash") + + sharedInvoice := invoicesrpc.AddInvoiceData{ + Memo: "fake memo", + Value: lnwire.MilliSatoshi(500000), + DescriptionHash: []byte("fake 32 byte hash"), + Expiry: 123, + FallbackAddr: fallbackAddr, + CltvExpiry: 456, + Private: true, + RouteHints: testInvoiceRouteHints(), + } + + // The two wrappers use different invoice creation RPCs, so we provide + // path-specific fixtures for their mutually exclusive fields. + lightningInvoice := sharedInvoice + lightningInvoice.Preimage = &validPreimage + + holdInvoice := sharedInvoice + holdInvoice.Hash = &validRHash + + lightningRPC := &mockRPCClient{ + addInvoice: func(_ *lnrpc.Invoice, + _ ...grpc.CallOption) (*lnrpc.AddInvoiceResponse, + error) { + + return &lnrpc.AddInvoiceResponse{ + RHash: validRHash[:], + PaymentRequest: "swap invoice", + }, nil + }, + } + holdRPC := &mockInvoicesRPCClient{ + addHoldInvoice: func(_ *invoicesrpc.AddHoldInvoiceRequest, + _ ...grpc.CallOption) (*invoicesrpc.AddHoldInvoiceResp, + error) { + + return &invoicesrpc.AddHoldInvoiceResp{ + PaymentRequest: "probe invoice", + }, nil + }, + } + + lightning := &lightningClient{ + client: lightningRPC, + } + invoices := &invoicesClient{ + client: holdRPC, + } + + _, _, err := lightning.AddInvoice(t.Context(), &lightningInvoice) + require.NoError(t, err) + + _, err = invoices.AddHoldInvoice(t.Context(), &holdInvoice) + require.NoError(t, err) + + require.Len(t, lightningRPC.addInvoiceArgs, 1) + require.Len(t, holdRPC.addHoldInvoiceArgs, 1) + + assertInvoiceRequestParity( + t, lightningRPC.addInvoiceArgs[0].in, + holdRPC.addHoldInvoiceArgs[0].in, + ) +} + +// TestInvoicesClientAddHoldInvoiceIgnoresUnsupportedFields ensures the +// AddHoldInvoice wrapper still forwards the supported request fields when AMP +// or blinded-path-only inputs are provided. +func TestInvoicesClientAddHoldInvoiceIgnoresUnsupportedFields(t *testing.T) { + var validRHash lntypes.Hash + copy(validRHash[:], "valid hash") + + invoice := &invoicesrpc.AddInvoiceData{ + Memo: "fake memo", + Hash: &validRHash, + Value: lnwire.MilliSatoshi(500000), + DescriptionHash: []byte("fake 32 byte hash"), + Expiry: 123, + FallbackAddr: fallbackAddr, + CltvExpiry: 456, + Private: true, + Amp: true, + BlindedPathCfg: &invoicesrpc.BlindedPathConfig{ + MinNumPathHops: 5, + }, + RouteHints: testInvoiceRouteHints(), + } + + rpcRouteHints := testRPCRouteHints(t) + expectedRequest := &invoicesrpc.AddHoldInvoiceRequest{ + Memo: invoice.Memo, + Hash: invoice.Hash[:], + ValueMsat: int64(invoice.Value), + DescriptionHash: invoice.DescriptionHash, + Expiry: invoice.Expiry, + FallbackAddr: invoice.FallbackAddr, + CltvExpiry: invoice.CltvExpiry, + Private: invoice.Private, + RouteHints: rpcRouteHints, + } + + holdRPC := &mockInvoicesRPCClient{ + addHoldInvoice: func(_ *invoicesrpc.AddHoldInvoiceRequest, + _ ...grpc.CallOption) (*invoicesrpc.AddHoldInvoiceResp, + error) { + + return &invoicesrpc.AddHoldInvoiceResp{ + PaymentRequest: "probe invoice", + }, nil + }, + } + + invoices := &invoicesClient{ + client: holdRPC, + } + + _, err := invoices.AddHoldInvoice(t.Context(), invoice) + require.NoError(t, err) + + require.Len(t, holdRPC.addHoldInvoiceArgs, 1) + require.Equal(t, expectedRequest, holdRPC.addHoldInvoiceArgs[0].in) +} diff --git a/lightning_client.go b/lightning_client.go index f55a3c4..0dff555 100644 --- a/lightning_client.go +++ b/lightning_client.go @@ -15,7 +15,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightningnetwork/lnd/channeldb" invpkg "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" @@ -24,6 +23,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" + paymentsdb "github.com/lightningnetwork/lnd/payments/db" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/zpay32" "google.golang.org/grpc" @@ -97,13 +97,16 @@ type LightningClient interface { amt btcutil.Amount, confTarget int32) (btcutil.Amount, error) // NewAddress generates a new address for the lnd client. - NewAddress(ctx context.Context, addressType lnrpc.AddressType) (string, error) + NewAddress(ctx context.Context, addressType lnrpc.AddressType) ( + string, error) - // SendMany handles a request for a transaction that creates multiple specified outputs in parallel. - SendMany(ctx context.Context, txBatch map[string]int64, satPerVbyte uint64) (string, error) + // SendMany handles a request for a transaction that creates multiple + // specified outputs in parallel. + SendMany(ctx context.Context, txBatch map[string]int64, + satPerVbyte uint64) (string, error) - // EstimateFees estimates the total fees for a batch of transactions that pay the given - // amounts to the passed addresses. + // EstimateFees estimates the total fees for a batch of transactions + // that pay the given amounts to the passed addresses. EstimateFees(ctx context.Context, txBatch map[string]int64, targetConf int32, ) (*lnrpc.EstimateFeeResponse, error) @@ -132,7 +135,8 @@ type LightningClient interface { opts ...ListTransactionsOption) ([]Transaction, error) // ListChannels retrieves all channels of the backing lnd node. - ListChannels(ctx context.Context, input *lnrpc.ListChannelsRequest) ([]ChannelInfo, error) + ListChannels(ctx context.Context, + input *lnrpc.ListChannelsRequest) ([]ChannelInfo, error) // PendingChannels returns a list of lnd's pending channels. PendingChannels(ctx context.Context) (*PendingChannels, error) @@ -220,12 +224,12 @@ type LightningClient interface { // SendCoins sends the passed amount of (or all) coins to the passed // address. Either amount or sendAll must be specified, while - // confTarget, satsPerByte are optional and may be set to zero in which + // confTarget, satsPerVByte are optional and may be set to zero in which // case automatic conf target and fee will be used. Returns the tx id // upon success. SendCoins(ctx context.Context, addr btcutil.Address, amount btcutil.Amount, sendAll bool, confTarget int32, - satsPerByte int64, label string) (string, error) + satsPerVByte chainfee.SatPerVByte, label string) (string, error) // ChannelBalance returns a summary of our channel balances. ChannelBalance(ctx context.Context) (*ChannelBalance, error) @@ -473,6 +477,11 @@ type ChannelInfo struct { // may be used for this channel. This array can be empty. AliasScids []uint64 + // CustomChannelData is an optional field that can be used to store + // data for custom channels. + CustomChannelData []byte + + // PeerAlias is the alias of the peer node. PeerAlias string } @@ -515,9 +524,10 @@ func (s *lightningClient) newChannelInfo(channel *lnrpc.Channel) (*ChannelInfo, RemoteConstraints: newChannelConstraint( channel.RemoteConstraints, ), - ZeroConf: channel.ZeroConf, - ZeroConfScid: channel.ZeroConfConfirmedScid, - PeerAlias: channel.PeerAlias, + ZeroConf: channel.ZeroConf, + ZeroConfScid: channel.ZeroConfConfirmedScid, + CustomChannelData: channel.CustomChannelData, + PeerAlias: channel.PeerAlias, } chanInfo.AliasScids = make([]uint64, len(channel.AliasScids)) @@ -1284,8 +1294,9 @@ type QueryRoutesRequest struct { // FeeLimitMsat is the fee limit to use in millisatoshis. FeeLimitMsat lnwire.MilliSatoshi - // The time preference for this payment. Set to -1 to optimize for fees only, to 1 to optimize for reliability only - // or a value in between for a mix. + // The time preference for this payment. Set to -1 to optimize for + // fees only, to 1 to optimize for reliability only or a value in + // between for a mix. TimePref float64 } @@ -1357,12 +1368,12 @@ var ( // PaymentResultAlreadyPaid is the string result returned by SendPayment // when the payment was already completed in a previous SendPayment // call. - PaymentResultAlreadyPaid = channeldb.ErrAlreadyPaid.Error() + PaymentResultAlreadyPaid = paymentsdb.ErrAlreadyPaid.Error() // PaymentResultInFlight is the string result returned by SendPayment // when the payment was initiated in a previous SendPayment call and // still in flight. - PaymentResultInFlight = channeldb.ErrPaymentInFlight.Error() + PaymentResultInFlight = paymentsdb.ErrPaymentInFlight.Error() paymentPollInterval = 3 * time.Second ) @@ -1674,20 +1685,52 @@ func (s *lightningClient) AddInvoice(ctx context.Context, rpcCtx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() + if in.Hash != nil || in.HodlInvoice { + log.Warnf("lightningClient.AddInvoice ignores " + + "Hash/HodlInvoice; use InvoicesClient.AddHoldInvoice " + + "for hold invoices") + } + + routeHints, err := marshallRouteHints(in.RouteHints) + if err != nil { + return lntypes.Hash{}, "", fmt.Errorf( + "failed to marshal route hints: %v", err, + ) + } + rpcIn := &lnrpc.Invoice{ Memo: in.Memo, ValueMsat: int64(in.Value), DescriptionHash: in.DescriptionHash, Expiry: in.Expiry, + FallbackAddr: in.FallbackAddr, CltvExpiry: in.CltvExpiry, Private: in.Private, + IsAmp: in.Amp, + RouteHints: routeHints, } if in.Preimage != nil { rpcIn.RPreimage = in.Preimage[:] } - if in.Hash != nil { - rpcIn.RHash = in.Hash[:] + if in.BlindedPathCfg != nil { + rpcIn.IsBlinded = true + + if in.BlindedPathCfg.MinNumPathHops != 0 { + numHops := uint32(in.BlindedPathCfg.MinNumPathHops) + rpcIn.BlindedPathConfig = &lnrpc.BlindedPathConfig{ + NumHops: &numHops, + } + } + + if in.BlindedPathCfg.RoutePolicyIncrMultiplier != 0 || + in.BlindedPathCfg.RoutePolicyDecrMultiplier != 0 || + in.BlindedPathCfg.DefaultDummyHopPolicy != nil { + + log.Warnf("lightningClient.AddInvoice only forwards " + + "MinNumPathHops from BlindedPathCfg; other " + + "blinded path settings use lnd defaults") + } } rpcCtx = s.adminMac.WithMacaroonAuth(rpcCtx) @@ -3638,12 +3681,12 @@ func (s *lightningClient) Connect(ctx context.Context, peer route.Vertex, } // SendCoins sends the passed amount of (or all) coins to the passed address. -// Either amount or sendAll must be specified, while confTarget, satsPerByte are -// optional and may be set to zero in which case automatic conf target and fee -// will be used. Returns the tx id upon success. +// Either amount or sendAll must be specified, while confTarget, satsPerVByte +// are optional and may be set to zero in which case automatic conf target and +// fee will be used. Returns the tx id upon success. func (s *lightningClient) SendCoins(ctx context.Context, addr btcutil.Address, amount btcutil.Amount, sendAll bool, confTarget int32, - satsPerByte int64, label string) (string, error) { + satsPerVByte chainfee.SatPerVByte, label string) (string, error) { rpcCtx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() @@ -3651,12 +3694,12 @@ func (s *lightningClient) SendCoins(ctx context.Context, addr btcutil.Address, rpcCtx = s.adminMac.WithMacaroonAuth(rpcCtx) req := &lnrpc.SendCoinsRequest{ - Addr: addr.String(), - Amount: int64(amount), - TargetConf: confTarget, - SatPerByte: satsPerByte, - SendAll: sendAll, - Label: label, + Addr: addr.String(), + Amount: int64(amount), + TargetConf: confTarget, + SatPerVbyte: uint64(satsPerVByte), + SendAll: sendAll, + Label: label, } resp, err := s.client.SendCoins(rpcCtx, req) @@ -4576,8 +4619,8 @@ func (s *lightningClient) SubscribeTransactions( } // NewAddress generates a new address for the lnd client. -func (s *lightningClient) NewAddress(ctx context.Context, addressType lnrpc.AddressType) ( - string, error) { +func (s *lightningClient) NewAddress(ctx context.Context, + addressType lnrpc.AddressType) (string, error) { rpcCtx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() @@ -4597,9 +4640,10 @@ func (s *lightningClient) NewAddress(ctx context.Context, addressType lnrpc.Addr return resp.Address, nil } -// SendMany handles a request for a transaction that creates multiple specified outputs in parallel. -func (s *lightningClient) SendMany(ctx context.Context, txBatch map[string]int64, satPerVbyte uint64) ( - string, error) { +// SendMany handles a request for a transaction that creates multiple +// specified outputs in parallel. +func (s *lightningClient) SendMany(ctx context.Context, + txBatch map[string]int64, satPerVbyte uint64) (string, error) { rpcCtx, cancel := context.WithTimeout(ctx, s.timeout) defer cancel() @@ -4621,8 +4665,8 @@ func (s *lightningClient) SendMany(ctx context.Context, txBatch map[string]int64 return resp.Txid, nil } -// EstimateFees estimates the total fees for a batch of transactions that pay the given -// amounts to the passed addresses. +// EstimateFees estimates the total fees for a batch of transactions +// that pay the given amounts to the passed addresses. func (s *lightningClient) EstimateFees( ctx context.Context, txBatch map[string]int64, diff --git a/lightning_client_test.go b/lightning_client_test.go index 44ec327..b2451ef 100644 --- a/lightning_client_test.go +++ b/lightning_client_test.go @@ -40,6 +40,51 @@ func (m *mockRPCClient) AddInvoice(ctx context.Context, in *lnrpc.Invoice, return m.addInvoice(in, opts...) } +// assertAddInvoiceArgs verifies the recorded AddInvoice RPC calls. +func assertAddInvoiceArgs(t *testing.T, want, got []addInvoiceArg) { + t.Helper() + + require.Len(t, got, len(want)) + + for i := range want { + require.Equal(t, want[i].opts, got[i].opts) + require.Equal(t, want[i].in.Memo, got[i].in.Memo) + require.Equal(t, want[i].in.RPreimage, got[i].in.RPreimage) + require.Equal(t, want[i].in.RHash, got[i].in.RHash) + require.Equal(t, want[i].in.ValueMsat, got[i].in.ValueMsat) + require.Equal( + t, want[i].in.DescriptionHash, + got[i].in.DescriptionHash, + ) + require.Equal(t, want[i].in.Expiry, got[i].in.Expiry) + require.Equal( + t, want[i].in.FallbackAddr, got[i].in.FallbackAddr, + ) + require.Equal( + t, want[i].in.CltvExpiry, got[i].in.CltvExpiry, + ) + require.Equal(t, want[i].in.Private, got[i].in.Private) + require.Equal(t, want[i].in.IsAmp, got[i].in.IsAmp) + require.Equal(t, want[i].in.IsBlinded, got[i].in.IsBlinded) + + if want[i].in.BlindedPathConfig == nil { + require.Nil(t, got[i].in.BlindedPathConfig) + } else { + require.Equal( + t, want[i].in.BlindedPathConfig, + got[i].in.BlindedPathConfig, + ) + } + + if len(want[i].in.RouteHints) == 0 { + require.Empty(t, got[i].in.RouteHints) + continue + } + + require.Equal(t, want[i].in.RouteHints, got[i].in.RouteHints) + } +} + // TestLightningClientAddInvoice ensures that adding an invoice via // lightningClient is completed as expected. func TestLightningClientAddInvoice(t *testing.T) { @@ -48,10 +93,12 @@ func TestLightningClientAddInvoice(t *testing.T) { copy(validPreimage[:], "valid preimage") var validRHash lntypes.Hash copy(validRHash[:], "valid hash") + validRouteHints := testInvoiceRouteHints() + validRPCRouteHints := testRPCRouteHints(t) + validAddInvoiceData := &invoicesrpc.AddInvoiceData{ Memo: "fake memo", Preimage: &validPreimage, - Hash: &validRHash, Value: lnwire.MilliSatoshi(500000), DescriptionHash: []byte("fake 32 byte hash"), Expiry: 123, @@ -61,7 +108,6 @@ func TestLightningClientAddInvoice(t *testing.T) { validInvoice := &lnrpc.Invoice{ Memo: validAddInvoiceData.Memo, RPreimage: validAddInvoiceData.Preimage[:], - RHash: validAddInvoiceData.Hash[:], ValueMsat: int64(validAddInvoiceData.Value), DescriptionHash: validAddInvoiceData.DescriptionHash, Expiry: validAddInvoiceData.Expiry, @@ -89,7 +135,6 @@ func TestLightningClientAddInvoice(t *testing.T) { privateInvoice := &lnrpc.Invoice{ Memo: validAddInvoiceData.Memo, RPreimage: validAddInvoiceData.Preimage[:], - RHash: validAddInvoiceData.Hash[:], ValueMsat: int64(validAddInvoiceData.Value), DescriptionHash: validAddInvoiceData.DescriptionHash, Expiry: validAddInvoiceData.Expiry, @@ -100,6 +145,107 @@ func TestLightningClientAddInvoice(t *testing.T) { {in: privateInvoice}, } + fallbackAddrAddInvoiceData := *validAddInvoiceData + fallbackAddrAddInvoiceData.FallbackAddr = fallbackAddr + fallbackAddrInvoice := &lnrpc.Invoice{ + Memo: validAddInvoiceData.Memo, + RPreimage: validAddInvoiceData.Preimage[:], + ValueMsat: int64(validAddInvoiceData.Value), + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + FallbackAddr: fallbackAddrAddInvoiceData.FallbackAddr, + CltvExpiry: validAddInvoiceData.CltvExpiry, + } + fallbackAddrAddInvoiceArgs := []addInvoiceArg{ + {in: fallbackAddrInvoice}, + } + + ampAddInvoiceData := &invoicesrpc.AddInvoiceData{ + Memo: validAddInvoiceData.Memo, + Value: validAddInvoiceData.Value, + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + CltvExpiry: validAddInvoiceData.CltvExpiry, + Amp: true, + } + ampInvoice := &lnrpc.Invoice{ + Memo: ampAddInvoiceData.Memo, + ValueMsat: int64(ampAddInvoiceData.Value), + DescriptionHash: ampAddInvoiceData.DescriptionHash, + Expiry: ampAddInvoiceData.Expiry, + CltvExpiry: ampAddInvoiceData.CltvExpiry, + IsAmp: true, + } + ampAddInvoiceArgs := []addInvoiceArg{ + {in: ampInvoice}, + } + + hashAddInvoiceData := *validAddInvoiceData + hashAddInvoiceData.Preimage = nil + hashAddInvoiceData.Hash = &validRHash + hashAddInvoiceData.HodlInvoice = true + hashInvoice := &lnrpc.Invoice{ + Memo: validAddInvoiceData.Memo, + ValueMsat: int64(validAddInvoiceData.Value), + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + CltvExpiry: validAddInvoiceData.CltvExpiry, + } + hashAddInvoiceArgs := []addInvoiceArg{ + {in: hashInvoice}, + } + + blindedAddInvoiceData := *validAddInvoiceData + blindedAddInvoiceData.BlindedPathCfg = &invoicesrpc.BlindedPathConfig{ + MinNumPathHops: 5, + } + numHops := uint32(blindedAddInvoiceData.BlindedPathCfg.MinNumPathHops) + blindedInvoice := &lnrpc.Invoice{ + Memo: validAddInvoiceData.Memo, + RPreimage: validAddInvoiceData.Preimage[:], + ValueMsat: int64(validAddInvoiceData.Value), + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + CltvExpiry: validAddInvoiceData.CltvExpiry, + IsBlinded: true, + BlindedPathConfig: &lnrpc.BlindedPathConfig{ + NumHops: &numHops, + }, + } + blindedAddInvoiceArgs := []addInvoiceArg{ + {in: blindedInvoice}, + } + + blindedZeroHopAddInvoiceData := *validAddInvoiceData + blindedZeroHopAddInvoiceData.BlindedPathCfg = &invoicesrpc.BlindedPathConfig{} + blindedZeroHopInvoice := &lnrpc.Invoice{ + Memo: validAddInvoiceData.Memo, + RPreimage: validAddInvoiceData.Preimage[:], + ValueMsat: int64(validAddInvoiceData.Value), + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + CltvExpiry: validAddInvoiceData.CltvExpiry, + IsBlinded: true, + } + blindedZeroHopAddInvoiceArgs := []addInvoiceArg{ + {in: blindedZeroHopInvoice}, + } + + routeHintAddInvoiceData := *validAddInvoiceData + routeHintAddInvoiceData.RouteHints = validRouteHints + routeHintInvoice := &lnrpc.Invoice{ + Memo: validAddInvoiceData.Memo, + RPreimage: validAddInvoiceData.Preimage[:], + ValueMsat: int64(validAddInvoiceData.Value), + DescriptionHash: validAddInvoiceData.DescriptionHash, + Expiry: validAddInvoiceData.Expiry, + CltvExpiry: validAddInvoiceData.CltvExpiry, + RouteHints: validRPCRouteHints, + } + routeHintAddInvoiceArgs := []addInvoiceArg{ + {in: routeHintInvoice}, + } + errorAddInvoice := func(in *lnrpc.Invoice, opts ...grpc.CallOption) ( *lnrpc.AddInvoiceResponse, error) { @@ -147,6 +293,78 @@ func TestLightningClientAddInvoice(t *testing.T) { payRequest: validPayReq, }, }, + { + name: "invoice with fallback address", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: &fallbackAddrAddInvoiceData, + expect: expect{ + addInvoiceArgs: fallbackAddrAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, + { + name: "amp invoice", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: ampAddInvoiceData, + expect: expect{ + addInvoiceArgs: ampAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, + { + name: "invoice with hash uses standard invoice path", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: &hashAddInvoiceData, + expect: expect{ + addInvoiceArgs: hashAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, + { + name: "blinded invoice", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: &blindedAddInvoiceData, + expect: expect{ + addInvoiceArgs: blindedAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, + { + name: "blinded invoice with zero min path hops", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: &blindedZeroHopAddInvoiceData, + expect: expect{ + addInvoiceArgs: blindedZeroHopAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, + { + name: "invoice with route hints", + client: mockRPCClient{ + addInvoice: validAddInvoice, + }, + invoice: &routeHintAddInvoiceData, + expect: expect{ + addInvoiceArgs: routeHintAddInvoiceArgs, + hash: validRHash, + payRequest: validPayReq, + }, + }, { name: "rpc client error", client: mockRPCClient{ @@ -167,7 +385,7 @@ func TestLightningClientAddInvoice(t *testing.T) { } hash, payRequest, err := ln.AddInvoice( - context.Background(), test.invoice, + t.Context(), test.invoice, ) // Check if an error (or no error) was received as @@ -192,9 +410,9 @@ func TestLightningClientAddInvoice(t *testing.T) { // Check if the expected args were passed to the RPC // client call. - require.Equal(t, test.client.addInvoiceArgs, - test.expect.addInvoiceArgs, - "rpc client call was not made as expected", + assertAddInvoiceArgs( + t, test.expect.addInvoiceArgs, + test.client.addInvoiceArgs, ) }) } diff --git a/lnd_services.go b/lnd_services.go index 257068c..c8558fb 100644 --- a/lnd_services.go +++ b/lnd_services.go @@ -41,8 +41,8 @@ var ( // fallback version if none is specified in the configuration. minimalCompatibleVersion = &verrpc.Version{ AppMajor: 0, - AppMinor: 18, - AppPatch: 5, + AppMinor: 19, + AppPatch: 0, BuildTags: DefaultBuildTags, } @@ -143,6 +143,11 @@ type LndServicesConfig struct { // block download is still in progress. BlockUntilChainSynced bool + // BlockUntilChainNotifier indicates that the client should wait until + // the ChainNotifier RPC is accepting subscriptions. This requires lnd + // to be built with the "chainrpc" tag. + BlockUntilChainNotifier bool + // BlockUntilUnlocked denotes that the NewLndServices function should // block until lnd is unlocked. BlockUntilUnlocked bool @@ -327,7 +332,15 @@ func NewLndServices(cfg *LndServicesConfig) (*GrpcLndServices, error) { cleanupConn := func() { closeErr := conn.Close() - if closeErr != nil { + switch { + case closeErr == nil: + // No error. + + case errors.Is(closeErr, grpc.ErrClientConnClosing): + log.Debugf("LND connection is already closing: %v", + closeErr) + + default: log.Errorf("Error closing lnd connection: %v", closeErr) } } @@ -453,6 +466,25 @@ func NewLndServices(cfg *LndServicesConfig) (*GrpcLndServices, error) { log.Infof("lnd is now fully synced to its chain backend") } + // If requested, wait until the chain notifier RPC is ready before we + // return. This ensures sub-servers relying on the notifier don't fail + // during startup. + if cfg.BlockUntilChainNotifier { + log.Infof("Waiting for chain notifier RPC to be ready") + + err := services.waitForChainNotifier( + cfg.CallerCtx, timeout, cfg.ChainSyncPollInterval, + ) + if err != nil { + cleanup() + + return nil, fmt.Errorf("error waiting for chain "+ + "notifier readiness: %w", err) + } + + log.Infof("Chain notifier RPC is ready") + } + return services, nil } @@ -533,6 +565,77 @@ func (s *GrpcLndServices) waitForChainSync(ctx context.Context, return <-update } +// waitForChainNotifier blocks until the ChainNotifier RPC accepts block epoch +// subscriptions and delivers at least one block height. +func (s *GrpcLndServices) waitForChainNotifier(ctx context.Context, + timeout, pollInterval time.Duration) error { + + register := s.ChainNotifier.RegisterBlockEpochNtfn + + var errRetry = errors.New("retry RegisterBlockEpochNtfn") + + // attempt is a single attempt to make a RegisterBlockEpochNtfn call. + // It returns nil on success, errRetry if another retry is needed and + // other error in case of a final error. + attempt := func() error { + subCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + // Make new RegisterBlockEpochNtfn call. + blockChan, errChan, err := register(subCtx) + if err != nil { + return fmt.Errorf("register block epoch ntfn: %w", err) + } + + // Wait for block height notification, which indicates success. + select { + case <-subCtx.Done(): + return subCtx.Err() + + case err := <-errChan: + // If chainNotifier is not ready yet, retry. + if isChainNotifierStartingErr(err) { + select { + case <-time.After(pollInterval): + return errRetry + + case <-ctx.Done(): + return ctx.Err() + } + } + + return err + + // We got a block height. Success! + case <-blockChan: + return nil + } + } + + // Main retry loop. + for { + log.Info("Trying to make RegisterBlockEpochNtfn and receive " + + "the current height...") + err := attempt() + + if errors.Is(err, errRetry) { + log.Info("ChainNotifier is not ready yet. Will retry") + + continue + } else if err != nil { + log.Info("RegisterBlockEpochNtfn returned unexpected "+ + "error %v. LND client failed to start!", err) + + return err + } + + log.Info("RegisterBlockEpochNtfn returned a height. Success!") + break + } + + return nil +} + // getLndInfo queries lnd for information about the node it is connected to. // If the waitForUnlocked boolean is set, it will examine any errors returned // and back off if the failure is due to lnd currently being locked. Otherwise, @@ -676,6 +779,37 @@ func IsUnlockError(err error) bool { return false } +// chainNotifierStartupMessage matches the error string returned by lnd +// v0.20.0-rc3+ when a ChainNotifier RPC is invoked before the sub-server +// finishes initialization. +const chainNotifierStartupMessage = "chain notifier RPC is still in the " + + "process of starting" + +// isChainNotifierStartingErr reports whether err is due to the lnd +// ChainNotifier sub-server still starting up. Starting with lnd v0.20.0-rc3 +// the notifier is initialised later in the daemon lifecycle, and the RPC layer +// surfaces this as an Unknown gRPC status that contains the message defined in +// chainNotifierStartupMessage. There is a PR in LND to return code Unavailable +// instead of Unknown: https://github.com/lightningnetwork/lnd/pull/10352 +func isChainNotifierStartingErr(err error) bool { + if err == nil { + return false + } + + // gRPC code Unavailable means "the server can't handle this request + // now, retry later". LND's chain notifier returns this error when + // the server is starting. + // See https://github.com/lightningnetwork/lnd/pull/10352 + st, ok := status.FromError(err) + if ok && st.Code() == codes.Unavailable { + return true + } + + // TODO(ln-v0.20.0) remove the string fallback once lndclient depends on + // a version of lnd that returns codes.Unavailable for this condition. + return strings.Contains(err.Error(), chainNotifierStartupMessage) +} + // checkLndCompatibility makes sure the connected lnd instance is running on the // correct network, has the version RPC implemented, is the correct minimal // version and supports all required build tags/subservers. diff --git a/lnd_services_test.go b/lnd_services_test.go index 8bade98..4a23975 100644 --- a/lnd_services_test.go +++ b/lnd_services_test.go @@ -361,3 +361,27 @@ func TestCustomMacaroonHex(t *testing.T) { _, err = NewLndServices(testCfg) require.Error(t, err, "must set only one") } + +// TestIsChainNotifierStartingErr ensures we correctly detect the startup lag +// error returned by lnd v0.20.0-rc3+. +func TestIsChainNotifierStartingErr(t *testing.T) { + t.Parallel() + + require.True(t, isChainNotifierStartingErr( + status.Error(codes.Unavailable, chainNotifierStartupMessage), + )) + + require.True(t, isChainNotifierStartingErr( + status.Error(codes.Unknown, chainNotifierStartupMessage), + )) + + require.True(t, isChainNotifierStartingErr( + status.Error(codes.Unavailable, "some other error"), + )) + + require.False(t, isChainNotifierStartingErr(nil)) + + require.False(t, isChainNotifierStartingErr( + status.Error(codes.Unknown, "some other error"), + )) +} diff --git a/router_client.go b/router_client.go index b4f191e..5ecaa57 100644 --- a/router_client.go +++ b/router_client.go @@ -11,12 +11,12 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" - "github.com/lightningnetwork/lnd/channeldb" invpkg "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" + paymentsdb "github.com/lightningnetwork/lnd/payments/db" "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/zpay32" @@ -89,6 +89,11 @@ type RouterClient interface { // will not be communicated to the channel peer via any message. XDeleteLocalChanAlias(ctx context.Context, alias, baseScid lnwire.ShortChannelID) error + + // XFindBaseLocalChanAlias is an experimental API that looks up the base + // scid for a local chan alias that was registered. + XFindBaseLocalChanAlias(ctx context.Context, + alias lnwire.ShortChannelID) (lnwire.ShortChannelID, error) } // PaymentStatus describe the state of a payment. @@ -574,12 +579,12 @@ func (r *routerClient) trackPayment(ctx context.Context, // NotFound is only expected as a response to // TrackPayment. case codes.NotFound: - err = channeldb.ErrPaymentNotInitiated + err = paymentsdb.ErrPaymentNotInitiated // NotFound is only expected as a response to // SendPayment. case codes.AlreadyExists: - err = channeldb.ErrAlreadyPaid + err = paymentsdb.ErrAlreadyPaid } errorChan <- err @@ -1180,3 +1185,25 @@ func (r *routerClient) XDeleteLocalChanAlias(ctx context.Context, alias, ) return err } + +// XFindBaseLocalChanAlias is an experimental API that looks up the base scid +// for a local chan alias that was registered. +func (r *routerClient) XFindBaseLocalChanAlias(ctx context.Context, + alias lnwire.ShortChannelID) (lnwire.ShortChannelID, error) { + + rpcCtx, cancel := context.WithTimeout(ctx, r.timeout) + defer cancel() + + res, err := r.client.XFindBaseLocalChanAlias( + r.routerKitMac.WithMacaroonAuth(rpcCtx), + &routerrpc.FindBaseAliasRequest{ + Alias: alias.ToUint64(), + }, + ) + + if err != nil { + return lnwire.ShortChannelID{}, err + } + + return lnwire.NewShortChanIDFromInt(res.Base), nil +} diff --git a/testdata/permissions.json b/testdata/permissions.json index 0c99845..45bcc0c 100644 --- a/testdata/permissions.json +++ b/testdata/permissions.json @@ -928,6 +928,14 @@ } ] }, + "/routerrpc.Router/XFindBaseLocalChanAlias": { + "permissions": [ + { + "entity": "offchain", + "action": "read" + } + ] + }, "/signrpc.Signer/ComputeInputScript": { "permissions": [ { diff --git a/tools/Dockerfile b/tools/Dockerfile index 21d08d6..00d43d5 100644 --- a/tools/Dockerfile +++ b/tools/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6-bookworm +FROM golang:1.26.0-bookworm RUN apt-get update && apt-get install -y git ENV GOCACHE=/tmp/build/.cache diff --git a/tools/go.mod b/tools/go.mod index 02a0080..ed85df7 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,6 +1,6 @@ module github.com/lightninglabs/lndclient/tools -go 1.24.6 +go 1.25.5 require ( // Once golangci-lint v2.4.1 update it here.