lightwalletd: adaptive reorg-lag tip + non-blocking startup coinsupply

Adaptive-lag: advertise a tip that trails the real tip by a reorg-rate-driven
lag (GetLatestBlock/GetLightdInfo) so wallets anchor shielded spends at a
settled height during reorg churn. Configurable via
-adaptive-lag/-lag-min/-lag-max/-lag-window; monitor_lwd.sh runs
-lag-min 4 -lag-max 12 -lag-window 30.

Startup coinsupply: the informational startup coinsupply RPC (result used only
for a log line) blocked the gRPC bind for minutes on a node whose supply index
is cold, keeping the lite endpoint down on every restart while it also starved
the block-cache ingestor. Run it in a goroutine so the bind is never blocked;
clients still get coinsupply on demand via the GetCoinsupply RPC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 01:05:10 -05:00
parent b1b0d4559b
commit 2bab58c6d2
5 changed files with 192 additions and 23 deletions

View File

@@ -41,9 +41,12 @@ func (s *SqlStreamer) GetCache() *common.BlockCache {
}
func (s *SqlStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) {
latestBlock := s.cache.GetLatestBlock()
// Advertise a tip that trails the real tip by the adaptive confirmation lag,
// so wallets anchor shielded spends at a settled height during reorg churn.
latestBlock := s.cache.AdvertisedLatestBlock()
s.log.WithFields(logrus.Fields{
"latestBlock": latestBlock,
"adaptiveLag": s.cache.CurrentLag(),
}).Info("GetLatestBlock called")
if latestBlock == -1 {
@@ -321,6 +324,13 @@ func (s *SqlStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*
return nil, err
}
// Report the advertised (lag-adjusted) tip so wallets consider themselves
// synced at the height they are actually served, not perpetually N behind.
advHeight := s.cache.AdvertisedLatestBlock()
if advHeight < 0 {
advHeight = blockHeight
}
// TODO these are called Error but they aren't at the moment.
// A success will return code 0 and message txhash.
return &walletrpc.LightdInfo{
@@ -330,7 +340,7 @@ func (s *SqlStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*
ChainName: chainName,
SaplingActivationHeight: uint64(saplingHeight),
ConsensusBranchId: consensusBranchId,
BlockHeight: uint64(blockHeight),
BlockHeight: uint64(advHeight),
Difficulty: uint64(difficulty),
Longestchain: uint64(longestchain),
Notarized: uint64(notarized),