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:
@@ -85,6 +85,11 @@ type Options struct {
|
||||
logPath string `json:"log_file,omitempty"`
|
||||
confPath string `json:"conf_file,omitempty"`
|
||||
cacheSize int `json:"cache_size,omitempty"`
|
||||
|
||||
adaptiveLag bool `json:"adaptive_lag,omitempty"`
|
||||
lagMin int `json:"lag_min,omitempty"`
|
||||
lagMax int `json:"lag_max,omitempty"`
|
||||
lagWindowMin int `json:"lag_window_min,omitempty"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -99,6 +104,10 @@ func main() {
|
||||
flag.StringVar(&opts.logPath, "log-file", "", "log file to write to")
|
||||
flag.StringVar(&opts.confPath, "conf-file", "", "conf file to pull RPC creds from")
|
||||
flag.IntVar(&opts.cacheSize, "cache-size", 400000, "number of blocks to hold in the cache")
|
||||
flag.BoolVar(&opts.adaptiveLag, "adaptive-lag", true, "advertise a tip that trails the real tip by a reorg-rate-driven lag, so wallets anchor shielded spends at a settled height")
|
||||
flag.IntVar(&opts.lagMin, "lag-min", 1, "minimum confirmation lag in blocks (applied when the chain is stable)")
|
||||
flag.IntVar(&opts.lagMax, "lag-max", 12, "maximum confirmation lag in blocks (cap during heavy reorgs)")
|
||||
flag.IntVar(&opts.lagWindowMin, "lag-window", 30, "minutes of recent reorg history used to size the adaptive lag")
|
||||
|
||||
// creating --version as a requirement of help2man
|
||||
if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-v") {
|
||||
@@ -188,18 +197,25 @@ func main() {
|
||||
|
||||
log.Info("Got sapling height ", saplingHeight, " chain ", chainName, " branchID ", branchID, " difficulty ", difficulty, longestchain, " longestchain ", notarized, " notarized ")
|
||||
|
||||
// Get the Coinsupply from the RPC
|
||||
result, coin, height, supply, zfunds, total, err := common.GetCoinsupply(rpcClient)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Warn("Unable to get coinsupply")
|
||||
}
|
||||
|
||||
log.Info(" result ", result, " coin ", coin, " height", height, "supply", supply, "zfunds", zfunds, "total", total)
|
||||
// Fetch coinsupply for an informational startup log line only (the result is not
|
||||
// used elsewhere). On a node whose supply index is cold this RPC can take minutes,
|
||||
// so run it in the background rather than blocking the gRPC bind on it — otherwise
|
||||
// the lite endpoint stays down for the entire duration on every restart. Clients
|
||||
// still get coinsupply on demand via the GetCoinsupply RPC.
|
||||
go func() {
|
||||
result, coin, height, supply, zfunds, total, err := common.GetCoinsupply(rpcClient)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Warn("Unable to get coinsupply")
|
||||
return
|
||||
}
|
||||
log.Info(" result ", result, " coin ", coin, " height", height, "supply", supply, "zfunds", zfunds, "total", total)
|
||||
}()
|
||||
|
||||
// Initialize the cache
|
||||
cache := common.NewBlockCache(opts.cacheSize)
|
||||
cache.ConfigureLag(opts.adaptiveLag, opts.lagWindowMin, opts.lagMin, opts.lagMax)
|
||||
|
||||
stopChan := make(chan bool, 1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user