Merge pull request #1046 from starius/wait-for-height

loopd: fix premature block height receipt from LND
This commit is contained in:
Boris Nagaev 2025-11-16 15:15:15 -03:00 committed by GitHub
commit d9a633bc2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 103 additions and 44 deletions

View file

@ -20,7 +20,7 @@ env:
# If you change this value, please change it in the following files as well:
# /Dockerfile
GO_VERSION: 1.24.6
GO_VERSION: 1.24.10
jobs:
########################

View file

@ -1,4 +1,4 @@
FROM --platform=${BUILDPLATFORM} golang:1.24.6-alpine as builder
FROM --platform=${BUILDPLATFORM} golang:1.24.10-alpine as builder
# Copy in the local repository to build from.
COPY . /go/src/github.com/lightningnetwork/loop

View file

@ -67,14 +67,14 @@ for a release using the following commands:
```bash
$ go version
go version go1.25.0 linux/amd64
$ go install golang.org/dl/go1.24.6@latest
$ go1.24.6 download
Unpacking /home/user/sdk/go1.24.6/go1.24.6.linux-amd64.tar.gz ...
Success. You may now run 'go1.24.6'
$ go1.24.6 version
go version go1.24.6 linux/amd64
$ go install golang.org/dl/go1.24.10@latest
$ go1.24.10 download
Unpacking /home/user/sdk/go1.24.10/go1.24.10.linux-amd64.tar.gz ...
Success. You may now run 'go1.24.10'
$ go1.24.10 version
go version go1.24.10 linux/amd64
$ GO_CMD=/home/user/go/bin/go1.24.6 ./release.sh v0.31.5
$ GO_CMD=/home/user/go/bin/go1.24.10 ./release.sh v0.31.5
```
On MacOS, you will need to install GNU tar and GNU gzip, which can be done with

6
go.mod
View file

@ -20,7 +20,7 @@ require (
github.com/jessevdk/go-flags v1.4.0
github.com/lib/pq v1.10.9
github.com/lightninglabs/aperture v0.3.13-beta
github.com/lightninglabs/lndclient v0.20.0-4
github.com/lightninglabs/lndclient v0.20.0-6
github.com/lightninglabs/loop/looprpc v1.0.7
github.com/lightninglabs/loop/swapserverrpc v1.0.14
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20251014172227-e6ae082c0b4b
@ -124,7 +124,7 @@ require (
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.20240815225420-8b40adf04ab9 // 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/kvdb v1.4.16 // indirect
github.com/lightningnetwork/lnd/sqldb v1.0.11 // indirect
@ -225,4 +225,4 @@ replace gonum.org/v1/gonum => github.com/gonum/gonum v0.11.0
replace gonum.org/v1/plot => github.com/gonum/plot v0.10.1
go 1.24.6
go 1.24.10

8
go.sum
View file

@ -1107,8 +1107,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/lightning-node-connect/hashmailrpc v1.0.3 h1:NuDp6Z+QNMSzZ/+RzWsjgAgQSr/REDxTiHmTczZxlXA=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.3/go.mod h1:bDnEKRN1u13NFBuy/C+bFLhxA5bfd3clT25y76QY0AM=
github.com/lightninglabs/lndclient v0.20.0-4 h1:oSdoAtCcGJrlr6Pwi6jgzawBRpFFZKauyL+IzwV1iGc=
github.com/lightninglabs/lndclient v0.20.0-4/go.mod h1:VxIakyBmTIy4tmg2zqj45YrDkJi53PQLwW0lmFzRR6k=
github.com/lightninglabs/lndclient v0.20.0-6 h1:sh23eZkOpHxe39c4QRYwhsM7qbnJlS++dXVmcwr0BNk=
github.com/lightninglabs/lndclient v0.20.0-6/go.mod h1:gBtIFPGmC2xIspGIv/G5+HiPSGJsFD8uIow7Oke1HFI=
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2 h1:eFjp1dIB2BhhQp/THKrjLdlYuPugO9UU4kDqu91OX/Q=
github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
github.com/lightninglabs/neutrino v0.16.1 h1:5Kz4ToxncEVkpKC6fwUjXKtFKJhuxlG3sBB3MdJTJjs=
@ -1129,8 +1129,8 @@ github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
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=

View file

@ -451,6 +451,10 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
return fmt.Errorf("failed to get current block height: %w", err)
}
blockHeight := getInfo.BlockHeight
if blockHeight <= 0 {
return fmt.Errorf("invalid block height reported by lnd: %d",
blockHeight)
}
// If we're running an asset client, we'll log something here.
if d.assetClient != nil {
@ -586,7 +590,13 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
ChainParams: d.lnd.ChainParams,
ChainNotifier: d.lnd.ChainNotifier,
}
staticAddressManager = address.NewManager(addrCfg, int32(blockHeight))
staticAddressManager, err = address.NewManager(
addrCfg, int32(blockHeight),
)
if err != nil {
return fmt.Errorf("unable to create static address manager: %w",
err)
}
// Static address deposit manager setup.
depositStore := deposit.NewSqlStore(baseDb)
@ -617,7 +627,13 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
Signer: d.lnd.Signer,
Store: withdrawalStore,
}
withdrawalManager = withdraw.NewManager(withdrawalCfg, blockHeight)
withdrawalManager, err = withdraw.NewManager(
withdrawalCfg, blockHeight,
)
if err != nil {
return fmt.Errorf("unable to create withdrawal manager: %w",
err)
}
// Static address loop-in manager setup.
staticAddressLoopInStore := loopin.NewSqlStore(
@ -645,7 +661,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
return err
}
staticLoopInManager = loopin.NewManager(&loopin.Config{
staticLoopInManager, err = loopin.NewManager(&loopin.Config{
Server: staticAddressClient,
QuoteGetter: swapClient.Server,
LndClient: d.lnd.Client,
@ -663,6 +679,9 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
MaxStaticAddrHtlcFeePercentage: d.cfg.MaxStaticAddrHtlcFeePercentage,
MaxStaticAddrHtlcBackupFeePercentage: d.cfg.MaxStaticAddrHtlcBackupFeePercentage,
}, blockHeight)
if err != nil {
return fmt.Errorf("unable to create loop-in manager: %w", err)
}
var (
reservationManager *reservation.Manager

View file

@ -88,15 +88,17 @@ func NewListenerConfig(config *Config, rpcCfg RPCConfig) *ListenerCfg {
defer cancel()
svcCfg := &lndclient.LndServicesConfig{
LndAddress: cfg.Host,
Network: network,
CustomMacaroonPath: cfg.MacaroonPath,
TLSPath: cfg.TLSPath,
CheckVersion: LoopMinRequiredLndVersion,
BlockUntilChainSynced: true,
CallerCtx: callerCtx,
BlockUntilUnlocked: true,
RPCTimeout: cfg.RPCTimeout,
LndAddress: cfg.Host,
Network: network,
CustomMacaroonPath: cfg.MacaroonPath,
TLSPath: cfg.TLSPath,
CheckVersion: LoopMinRequiredLndVersion,
CallerCtx: callerCtx,
RPCTimeout: cfg.RPCTimeout,
BlockUntilChainSynced: true,
BlockUntilUnlocked: true,
BlockUntilChainNotifier: true,
}
// If a custom lnd connection is specified we use that

View file

@ -1006,12 +1006,13 @@ func TestListUnspentDeposits(t *testing.T) {
addrStore := &mockAddressStore{params: []*address.Parameters{addrParams}}
// Build an address manager using our mock lnd and fake address store.
addrMgr := address.NewManager(&address.ManagerConfig{
addrMgr, err := address.NewManager(&address.ManagerConfig{
Store: addrStore,
WalletKit: mock.WalletKit,
ChainParams: mock.ChainParams,
// ChainNotifier and AddressClient are not needed for this test.
}, 0)
}, 1)
require.NoError(t, err)
// Construct several UTXOs with different confirmation counts.
makeUtxo := func(idx uint32, confs int64) *lnwallet.Utxo {

View file

@ -1,6 +1,6 @@
module github.com/lightninglabs/loop/looprpc
go 1.24.6
go 1.24.10
require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3

View file

@ -1,4 +1,4 @@
FROM golang:1.24.6
FROM golang:1.24.10
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates zip gpg && rm -rf /var/lib/apt/lists/*

View file

@ -37,7 +37,7 @@ if ! command -v "$GO_CMD" >/dev/null 2>&1; then
fi
# Make sure we have the expected Go version installed.
EXPECTED_VERSION="go1.24.6"
EXPECTED_VERSION="go1.24.10"
INSTALLED_VERSION=$("$GO_CMD" version 2>/dev/null | awk '{print $3}')
if [ "$INSTALLED_VERSION" = "$EXPECTED_VERSION" ]; then
green "Go version matches expected: $INSTALLED_VERSION"

View file

@ -57,13 +57,18 @@ type Manager struct {
}
// NewManager creates a new address manager.
func NewManager(cfg *ManagerConfig, currentHeight int32) *Manager {
func NewManager(cfg *ManagerConfig, currentHeight int32) (*Manager, error) {
if currentHeight <= 0 {
return nil, fmt.Errorf("invalid current height %d",
currentHeight)
}
m := &Manager{
cfg: cfg,
}
m.currentHeight.Store(currentHeight)
return m
return m, nil
}
// Run runs the address manager.

View file

@ -195,7 +195,8 @@ func NewAddressManagerTestContext(t *testing.T) *ManagerTestContext {
getInfo, err := mockLnd.Client.GetInfo(ctxb)
require.NoError(t, err)
manager := NewManager(cfg, int32(getInfo.BlockHeight))
manager, err := NewManager(cfg, int32(getInfo.BlockHeight))
require.NoError(t, err)
return &ManagerTestContext{
manager: manager,

View file

@ -143,7 +143,12 @@ type Manager struct {
}
// NewManager creates a new deposit withdrawal manager.
func NewManager(cfg *Config, currentHeight uint32) *Manager {
func NewManager(cfg *Config, currentHeight uint32) (*Manager, error) {
if currentHeight == 0 {
return nil, fmt.Errorf("invalid current height %d",
currentHeight)
}
m := &Manager{
cfg: cfg,
newLoopInChan: make(chan *newSwapRequest),
@ -153,7 +158,7 @@ func NewManager(cfg *Config, currentHeight uint32) *Manager {
}
m.currentHeight.Store(currentHeight)
return m
return m, nil
}
// Run runs the static address loop-in manager.

View file

@ -138,7 +138,12 @@ type Manager struct {
}
// NewManager creates a new deposit withdrawal manager.
func NewManager(cfg *ManagerConfig, currentHeight uint32) *Manager {
func NewManager(cfg *ManagerConfig, currentHeight uint32) (*Manager, error) {
if currentHeight == 0 {
return nil, fmt.Errorf("invalid current height %d",
currentHeight)
}
m := &Manager{
cfg: cfg,
finalizedWithdrawalTxns: make(map[chainhash.Hash]*wire.MsgTx),
@ -148,7 +153,7 @@ func NewManager(cfg *ManagerConfig, currentHeight uint32) *Manager {
}
m.initiationHeight.Store(currentHeight)
return m
return m, nil
}
// Run runs the deposit withdrawal manager.
@ -696,7 +701,7 @@ func (m *Manager) handleWithdrawal(ctx context.Context,
}
case err := <-errChan:
log.Errorf("Error waiting for confirmation: %v", err)
log.Errorf("Error waiting for spending: %v", err)
case <-ctx.Done():
log.Errorf("Withdrawal tx confirmation wait canceled")

View file

@ -0,0 +1,21 @@
package withdraw
import (
"testing"
"github.com/stretchr/testify/require"
)
// TestNewManagerHeightValidation ensures the constructor rejects zero heights.
func TestNewManagerHeightValidation(t *testing.T) {
t.Parallel()
cfg := &ManagerConfig{}
_, err := NewManager(cfg, 0)
require.ErrorContains(t, err, "invalid current height 0")
manager, err := NewManager(cfg, 1)
require.NoError(t, err)
require.NotNil(t, manager)
}

View file

@ -13,4 +13,4 @@ require (
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
)
go 1.24.6
go 1.24.10

View file

@ -1,4 +1,4 @@
FROM golang:1.24.6
FROM golang:1.24.10
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
&& rm -rf /var/lib/apt/lists/*

View file

@ -1,6 +1,6 @@
module github.com/lightninglabs/loop/tools
go 1.24.6
go 1.24.10
require (
// Once golangci-lint v2.4.1 update it here.