99 "fmt"
1010 "sync"
1111 "sync/atomic"
12+ "time"
1213
1314 "github.com/btcsuite/btcd/btcutil"
1415 "github.com/btcsuite/btcd/btcutil/gcs/builder"
@@ -32,6 +33,19 @@ type RescanManager struct {
3233 // rescanInProgress tracks the number of active rescans (atomic).
3334 // Non-zero means a rescan goroutine is running.
3435 rescanInProgress atomic.Int32
36+
37+ statusMu sync.RWMutex
38+ status RescanStatus
39+ }
40+
41+ // RescanStatus exposes rescan lifecycle details for API consumers.
42+ type RescanStatus struct {
43+ InProgress bool `json:"in_progress"`
44+ LastStarted int64 `json:"last_started"`
45+ LastFinished int64 `json:"last_finished"`
46+ LastStartHeight int32 `json:"last_start_height"`
47+ LastScannedTip int32 `json:"last_scanned_tip"`
48+ LastError string `json:"last_error,omitempty"`
3549}
3650
3751// NewRescanManager creates a new rescan manager.
@@ -104,6 +118,16 @@ func (r *RescanManager) IsRescanInProgress() bool {
104118 return r .rescanInProgress .Load () > 0
105119}
106120
121+ // GetRescanStatus returns the current detailed rescan status.
122+ func (r * RescanManager ) GetRescanStatus () RescanStatus {
123+ r .statusMu .RLock ()
124+ defer r .statusMu .RUnlock ()
125+
126+ status := r .status
127+ status .InProgress = r .IsRescanInProgress ()
128+ return status
129+ }
130+
107131// Rescan triggers a rescan from the given height for specified addresses.
108132// This uses neutrino's block filter-based scanning.
109133func (r * RescanManager ) Rescan (startHeight int32 , addresses []string ) error {
@@ -129,6 +153,11 @@ func (r *RescanManager) Rescan(startHeight int32, addresses []string) error {
129153 }
130154
131155 r .logger .Infof ("Starting rescan from height %d for %d addresses" , startHeight , len (addrs ))
156+ r .statusMu .Lock ()
157+ r .status .LastStarted = time .Now ().Unix ()
158+ r .status .LastStartHeight = startHeight
159+ r .status .LastError = ""
160+ r .statusMu .Unlock ()
132161
133162 // Mark rescan as in-progress so callers can poll /v1/rescan/status.
134163 r .rescanInProgress .Add (1 )
@@ -141,7 +170,15 @@ func (r *RescanManager) Rescan(startHeight int32, addresses []string) error {
141170 }
142171
143172 // Scan blocks from startHeight to bestBlock.Height
144- return r .scanBlocks (startHeight , bestBlock .Height , addrs )
173+ err = r .scanBlocks (startHeight , bestBlock .Height , addrs )
174+ r .statusMu .Lock ()
175+ r .status .LastFinished = time .Now ().Unix ()
176+ r .status .LastScannedTip = bestBlock .Height
177+ if err != nil {
178+ r .status .LastError = err .Error ()
179+ }
180+ r .statusMu .Unlock ()
181+ return err
145182}
146183
147184// scanBlocks scans blocks in the given range for transactions matching the addresses.
0 commit comments