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
|
* 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)
|
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
|
## lncli Updates
|
||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|||||||
@@ -842,6 +842,9 @@ func init() {
|
|||||||
allTestCases = appendPrefixed(
|
allTestCases = appendPrefixed(
|
||||||
"wallet", allTestCases, walletTestCases,
|
"wallet", allTestCases, walletTestCases,
|
||||||
)
|
)
|
||||||
|
allTestCases = appendPrefixed(
|
||||||
|
"wallet sync", allTestCases, walletSyncTestCases,
|
||||||
|
)
|
||||||
allTestCases = appendPrefixed(
|
allTestCases = appendPrefixed(
|
||||||
"coop close with external delivery", allTestCases,
|
"coop close with external delivery", allTestCases,
|
||||||
coopCloseWithExternalTestCases,
|
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.
|
// Indicates whether final htlc resolutions are stored on disk.
|
||||||
bool store_final_htlc_resolutions = 22;
|
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 {
|
message GetDebugInfoRequest {
|
||||||
|
|||||||
@@ -5556,6 +5556,10 @@
|
|||||||
"store_final_htlc_resolutions": {
|
"store_final_htlc_resolutions": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Indicates whether final htlc resolutions are stored on disk."
|
"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,
|
Features: features,
|
||||||
RequireHtlcInterceptor: r.cfg.RequireInterceptor,
|
RequireHtlcInterceptor: r.cfg.RequireInterceptor,
|
||||||
StoreFinalHtlcResolutions: r.cfg.StoreFinalHtlcResolutions,
|
StoreFinalHtlcResolutions: r.cfg.StoreFinalHtlcResolutions,
|
||||||
|
WalletSynced: syncInfo.isWalletSynced,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9468,6 +9469,10 @@ type chainSyncInfo struct {
|
|||||||
// - blockbeat dispatcher.
|
// - blockbeat dispatcher.
|
||||||
isSynced bool
|
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 is the current height known to the chain backend.
|
||||||
bestHeight int32
|
bestHeight int32
|
||||||
|
|
||||||
@@ -9488,22 +9493,23 @@ func (r *rpcServer) getChainSyncInfo() (*chainSyncInfo, error) {
|
|||||||
return nil, fmt.Errorf("unable to get best block info: %w", err)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to sync PoV of the wallet "+
|
return nil, fmt.Errorf("unable to sync PoV of the wallet "+
|
||||||
"with current best block in the main chain: %v", err)
|
"with current best block in the main chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an info to be returned.
|
// Create info to be returned.
|
||||||
info := &chainSyncInfo{
|
info := &chainSyncInfo{
|
||||||
isSynced: isSynced,
|
isWalletSynced: isWalletSynced,
|
||||||
bestHeight: bestHeight,
|
bestHeight: bestHeight,
|
||||||
blockHash: *bestHash,
|
blockHash: *bestHash,
|
||||||
timestamp: bestHeaderTimestamp,
|
timestamp: bestHeaderTimestamp,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit early if the wallet is not synced.
|
// Exit early if the wallet is not synced.
|
||||||
if !isSynced {
|
if !isWalletSynced {
|
||||||
rpcsLog.Debugf("Wallet is not synced to height %v yet",
|
rpcsLog.Debugf("Wallet is not synced to height %v yet",
|
||||||
bestHeight)
|
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
|
// 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
|
// 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.
|
// to true once the router was also able to catch up.
|
||||||
|
isSynced := isWalletSynced
|
||||||
if !r.cfg.Routing.AssumeChannelValid {
|
if !r.cfg.Routing.AssumeChannelValid {
|
||||||
routerHeight := r.server.graphBuilder.SyncedHeight()
|
routerHeight := r.server.graphBuilder.SyncedHeight()
|
||||||
isSynced = uint32(bestHeight) == routerHeight
|
isSynced = uint32(bestHeight) == routerHeight
|
||||||
|
|||||||
Reference in new issue
Block a user