Merge pull request #10507 from hieblmi/wallet-tip
rpcserver: add `wallet_synced` to `GetInfoResponse`
This commit is contained in:
7 files changed
+2573
-2465
No files matched your search
@@ -116,6 +116,13 @@
|
||||
* routerrpc HTLC event subscribers now receive specific failure details for
|
||||
invoice-level validation failures, avoiding ambiguous `UNKNOWN` results. [#10520](https://github.com/lightningnetwork/lnd/pull/10520)
|
||||
|
||||
* [A new `wallet_synced` field has been
|
||||
added](https://github.com/lightningnetwork/lnd/pull/10507) to the `GetInfo`
|
||||
RPC response. This field indicates whether the wallet is fully synced to the
|
||||
best chain, providing the wallet's internal sync state independently from the
|
||||
composite `synced_to_chain` field which also considers router and blockbeat
|
||||
dispatcher states.
|
||||
|
||||
## lncli Updates
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
@@ -842,6 +842,9 @@ func init() {
|
||||
allTestCases = appendPrefixed(
|
||||
"wallet", allTestCases, walletTestCases,
|
||||
)
|
||||
allTestCases = appendPrefixed(
|
||||
"wallet sync", allTestCases, walletSyncTestCases,
|
||||
)
|
||||
allTestCases = appendPrefixed(
|
||||
"coop close with external delivery", allTestCases,
|
||||
coopCloseWithExternalTestCases,
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package itest
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// walletSyncTestCases defines a set of tests for the wallet_synced field
|
||||
// in GetInfoResponse.
|
||||
var walletSyncTestCases = []*lntest.TestCase{
|
||||
{
|
||||
Name: "wallet synced",
|
||||
TestFunc: runTestWalletSynced,
|
||||
},
|
||||
}
|
||||
|
||||
// runTestWalletSynced tests that the wallet_synced field in GetInfoResponse
|
||||
// correctly reflects the wallet's sync state. It verifies that wallet_synced
|
||||
// is false while the wallet is catching up to new blocks, and becomes true
|
||||
// once fully synced.
|
||||
func runTestWalletSynced(ht *lntest.HarnessTest) {
|
||||
// Create a test node.
|
||||
alice := ht.NewNodeWithCoins("Alice", nil)
|
||||
|
||||
// Verify wallet starts synced.
|
||||
resp := alice.RPC.GetInfo()
|
||||
require.True(ht, resp.WalletSynced)
|
||||
ht.Logf("Alice wallet_synced=%v", resp.WalletSynced)
|
||||
|
||||
// Stop Alice to create a clear sync gap while we mine blocks.
|
||||
require.NoError(ht, alice.Stop(), "failed to stop Alice")
|
||||
|
||||
// Mine blocks while Alice is offline.
|
||||
const numBlocks = 40
|
||||
ht.Miner().MineBlocks(numBlocks)
|
||||
_, minerHeight := ht.Miner().GetBestBlock()
|
||||
|
||||
// Restart Alice without waiting for full chain sync.
|
||||
require.NoError(
|
||||
ht, alice.Start(ht.Context()), "failed to restart Alice",
|
||||
)
|
||||
|
||||
// While Alice is behind the miner height, wallet_synced must be false.
|
||||
deadline := time.Now().Add(lntest.DefaultTimeout)
|
||||
for {
|
||||
resp := alice.RPC.GetInfo()
|
||||
if int32(resp.BlockHeight) >= minerHeight {
|
||||
break
|
||||
}
|
||||
|
||||
require.Falsef(ht, resp.WalletSynced,
|
||||
"wallet_synced=true while behind "+
|
||||
"(nodeHeight=%v, minerHeight=%v)",
|
||||
resp.BlockHeight, minerHeight)
|
||||
|
||||
if time.Now().After(deadline) {
|
||||
require.Fail(ht, "timed out waiting for "+
|
||||
"node to catch up")
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Final verification that wallet_synced is true.
|
||||
require.Eventually(ht, func() bool {
|
||||
return alice.RPC.GetInfo().WalletSynced
|
||||
}, lntest.DefaultTimeout, 200*time.Millisecond,
|
||||
"wallet should be synced after waiting")
|
||||
}
|
||||
+2470
-2458
File diff suppressed because it is too large.
Load diff
@@ -2118,6 +2118,10 @@ message GetInfoResponse {
|
||||
|
||||
// Indicates whether final htlc resolutions are stored on disk.
|
||||
bool store_final_htlc_resolutions = 22;
|
||||
|
||||
// Whether the wallet is fully synced to the best chain. This indicates the
|
||||
// wallet's internal sync state with the backing chain source.
|
||||
bool wallet_synced = 23;
|
||||
}
|
||||
|
||||
message GetDebugInfoRequest {
|
||||
|
||||
@@ -5556,6 +5556,10 @@
|
||||
"store_final_htlc_resolutions": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates whether final htlc resolutions are stored on disk."
|
||||
},
|
||||
"wallet_synced": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the wallet is fully synced to the best chain. This indicates the\nwallet's internal sync state with the backing chain source."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+14
-7
@@ -3450,6 +3450,7 @@ func (r *rpcServer) GetInfo(_ context.Context,
|
||||
Features: features,
|
||||
RequireHtlcInterceptor: r.cfg.RequireInterceptor,
|
||||
StoreFinalHtlcResolutions: r.cfg.StoreFinalHtlcResolutions,
|
||||
WalletSynced: syncInfo.isWalletSynced,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -9468,6 +9469,10 @@ type chainSyncInfo struct {
|
||||
// - blockbeat dispatcher.
|
||||
isSynced bool
|
||||
|
||||
// isWalletSynced specifies whether the wallet is synced to
|
||||
// our chain view.
|
||||
isWalletSynced bool
|
||||
|
||||
// bestHeight is the current height known to the chain backend.
|
||||
bestHeight int32
|
||||
|
||||
@@ -9488,22 +9493,23 @@ func (r *rpcServer) getChainSyncInfo() (*chainSyncInfo, error) {
|
||||
return nil, fmt.Errorf("unable to get best block info: %w", err)
|
||||
}
|
||||
|
||||
isSynced, bestHeaderTimestamp, err := r.server.cc.Wallet.IsSynced()
|
||||
isWalletSynced, bestHeaderTimestamp, err :=
|
||||
r.server.cc.Wallet.IsSynced()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to sync PoV of the wallet "+
|
||||
"with current best block in the main chain: %v", err)
|
||||
}
|
||||
|
||||
// Create an info to be returned.
|
||||
// Create info to be returned.
|
||||
info := &chainSyncInfo{
|
||||
isSynced: isSynced,
|
||||
bestHeight: bestHeight,
|
||||
blockHash: *bestHash,
|
||||
timestamp: bestHeaderTimestamp,
|
||||
isWalletSynced: isWalletSynced,
|
||||
bestHeight: bestHeight,
|
||||
blockHash: *bestHash,
|
||||
timestamp: bestHeaderTimestamp,
|
||||
}
|
||||
|
||||
// Exit early if the wallet is not synced.
|
||||
if !isSynced {
|
||||
if !isWalletSynced {
|
||||
rpcsLog.Debugf("Wallet is not synced to height %v yet",
|
||||
bestHeight)
|
||||
|
||||
@@ -9518,6 +9524,7 @@ func (r *rpcServer) getChainSyncInfo() (*chainSyncInfo, error) {
|
||||
// by many wallets (and also our itests) to make sure everything's up to
|
||||
// date, we add the router's state to it. So the flag will only toggle
|
||||
// to true once the router was also able to catch up.
|
||||
isSynced := isWalletSynced
|
||||
if !r.cfg.Routing.AssumeChannelValid {
|
||||
routerHeight := r.server.graphBuilder.SyncedHeight()
|
||||
isSynced = uint32(bestHeight) == routerHeight
|
||||
|
||||
Reference in new issue
Block a user