From ad3b01051e61a5018002c9c0b3306098bd5d8ac0 Mon Sep 17 00:00:00 2001 From: JoeGruff Date: Wed, 19 Jun 2024 16:20:52 +0900 Subject: [PATCH] birthday: Set correctly for existing wallets. --- chain/sync.go | 4 +++ spv/sync.go | 5 +++ wallet/rescan.go | 9 +++-- wallet/udb/txmined.go | 6 ++-- wallet/wallet.go | 81 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 4 deletions(-) diff --git a/chain/sync.go b/chain/sync.go index ca2996f51..869eeca30 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -642,6 +642,10 @@ func (s *Syncer) Run(ctx context.Context) (err error) { log.Infof("Transactions synced through block %v height %d", &tipHash, tipHeight) } + if err := s.wallet.CheckBirthState(ctx, rescanPoint); err != nil { + return err + } + err = s.waitRPCSync(ctx, int64(tipHeight)) if err != nil { return err diff --git a/spv/sync.go b/spv/sync.go index 1cf9a57c3..2007d27c7 100644 --- a/spv/sync.go +++ b/spv/sync.go @@ -1774,6 +1774,11 @@ func (s *Syncer) initialSyncRescan(ctx context.Context) error { if err != nil { return err } + + if err := s.wallet.CheckBirthState(ctx, rescanPoint); err != nil { + return err + } + if rescanPoint == nil { // The wallet is already up to date with transactions in all // blocks. Load the data filters to check for transactions in diff --git a/wallet/rescan.go b/wallet/rescan.go index 36e97bb9c..d2213d35e 100644 --- a/wallet/rescan.go +++ b/wallet/rescan.go @@ -497,9 +497,13 @@ func (w *Wallet) rescanPoint(dbtx walletdb.ReadTx) (*chainhash.Hash, error) { return &rescanPoint, nil } -// SetBirthState sets the birthday state in the database. +// SetBirthState sets the birthday state in the database. This should be called +// before syncing is started. func (w *Wallet) SetBirthState(ctx context.Context, bs *udb.BirthdayState) error { const op errors.Op = "wallet.SetBirthState" + if bs == nil { + return errors.E(op, errors.Invalid, "nil birthday state") + } err := walletdb.Update(ctx, w.db, func(dbtx walletdb.ReadWriteTx) error { return udb.SetBirthState(dbtx, bs) }) @@ -509,7 +513,8 @@ func (w *Wallet) SetBirthState(ctx context.Context, bs *udb.BirthdayState) error return nil } -// BirthState returns the birthday state. +// BirthState returns the birthday state. Will return a nil state if none has +// been set. func (w *Wallet) BirthState(ctx context.Context) (bs *udb.BirthdayState, err error) { const op errors.Op = "wallet.BirthState" err = walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error { diff --git a/wallet/udb/txmined.go b/wallet/udb/txmined.go index efaf23196..06a42d755 100644 --- a/wallet/udb/txmined.go +++ b/wallet/udb/txmined.go @@ -331,7 +331,8 @@ type BirthdayState struct { SetFromHeight, SetFromTime bool } -// SetBirthState sets the birthday state in the database. +// SetBirthState sets the birthday state in the database. *BirthdayState must +// not be nil. // // [0:1] Options (1 byte) // [1:33] Birthblock block header hash (32 bytes) @@ -361,7 +362,8 @@ func SetBirthState(dbtx walletdb.ReadWriteTx, bs *BirthdayState) error { return ns.Put(rootBirthState, v) } -// BirthState returns the current birthday state. +// BirthState returns the current birthday state. Will return nil if none has +// been set. func BirthState(dbtx walletdb.ReadTx) *BirthdayState { ns := dbtx.ReadBucket(wtxmgrBucketKey) const ( diff --git a/wallet/wallet.go b/wallet/wallet.go index 2fd9bde22..519f0bf3b 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -5813,3 +5813,84 @@ func (w *Wallet) ProcessedTickets(ctx context.Context) ([]*VSPTicket, error) { return managedTickets, nil } + +// CheckBirthState sets the wallet birthstate if required and if we already have +// enough info to do so. +func (w *Wallet) CheckBirthState(ctx context.Context, rescanPoint *chainhash.Hash) error { + birthState, err := w.BirthState(ctx) + if err != nil { + return err + } + + if birthState != nil && (birthState.SetFromTime || birthState.SetFromHeight) { + var syncedHeader *wire.BlockHeader + if rescanPoint != nil { + syncedHeader, err = w.BlockHeader(ctx, rescanPoint) + if err != nil { + return err + } + } else { + tipHash, _ := w.MainChainTip(ctx) + syncedHeader, err = w.BlockHeader(ctx, &tipHash) + if err != nil { + return err + } + } + if birthState.SetFromTime { + if syncedHeader.Timestamp.After(birthState.Time) { + h := syncedHeader + for { + if h.Height == 0 { + bh := h.BlockHash() + birthState.Hash = bh + birthState.Height = 0 + birthState.SetFromTime = false + if err := w.SetBirthState(ctx, birthState); err != nil { + return err + } + log.Infof("Set wallet birthday to block 0 (%v).", bh) + break + } + h, err = w.BlockHeader(ctx, &h.PrevBlock) + if err != nil { + return err + } + if h.Timestamp.Before(birthState.Time) { + bh := h.PrevBlock + height := h.Height - 1 + birthState.Hash = bh + birthState.Height = height + birthState.SetFromTime = false + if err := w.SetBirthState(ctx, birthState); err != nil { + return err + } + log.Infof("Set wallet birthday to block %d (%v).", height, bh) + break + } + } + } + } + if birthState.SetFromHeight { + if syncedHeader.Height >= birthState.Height { + h := syncedHeader + for { + if h.Height == birthState.Height { + bh := h.BlockHash() + birthState.Hash = bh + birthState.SetFromHeight = false + if err := w.SetBirthState(ctx, birthState); err != nil { + return err + } + log.Infof("Set wallet birthday to block %d (%v).", h.Height, bh) + break + } + h, err = w.BlockHeader(ctx, &h.PrevBlock) + if err != nil { + return err + } + } + } + } + } + return nil +}