1 package waddrmgr
2 3 import (
4 "time"
5 6 "github.com/p9c/p9/pkg/chainhash"
7 "github.com/p9c/p9/pkg/walletdb"
8 )
9 10 // BlockStamp defines a block (by height and a unique hash) and is used to mark
11 // a point in the blockchain that an address manager element is synced to.
12 type BlockStamp struct {
13 Height int32
14 Hash chainhash.Hash
15 Timestamp time.Time
16 }
17 18 // syncState houses the sync state of the manager. It consists of the recently
19 // seen blocks as height, as well as the start and current sync block stamps.
20 type syncState struct {
21 // startBlock is the first block that can be safely used to start a rescan. It
22 // is either the block the manager was created with, or the earliest block
23 // provided with imported addresses or scripts.
24 startBlock BlockStamp
25 // syncedTo is the current block the addresses in the manager are known to be
26 // synced against.
27 syncedTo BlockStamp
28 }
29 30 // newSyncState returns a new sync state with the provided parameters.
31 func newSyncState(startBlock, syncedTo *BlockStamp) *syncState {
32 return &syncState{
33 startBlock: *startBlock,
34 syncedTo: *syncedTo,
35 }
36 }
37 38 // SetSyncedTo marks the address manager to be in sync with the recently-seen
39 // block described by the blockstamp. When the provided blockstamp is nil, the
40 // oldest blockstamp of the block the manager was created at and of all imported
41 // addresses will be used. This effectively allows the manager to be marked as
42 // unsynced back to the oldest known point any of the addresses have appeared in
43 // the block chain.
44 func (m *Manager) SetSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) (e error) {
45 m.mtx.Lock()
46 defer m.mtx.Unlock()
47 // Use the stored start blockstamp and reset recent hashes and height when the
48 // provided blockstamp is nil.
49 if bs == nil {
50 bs = &m.syncState.startBlock
51 }
52 // Update the database.
53 if e = putSyncedTo(ns, bs); E.Chk(e) {
54 return e
55 }
56 // Update memory now that the database is updated.
57 m.syncState.syncedTo = *bs
58 return nil
59 }
60 61 // SyncedTo returns details about the block height and hash that the address
62 // manager is synced through at the very least. The intention is that callers
63 // can use this information for intelligently initiating rescans to sync back to
64 // the best chain from the last known good block.
65 func (m *Manager) SyncedTo() BlockStamp {
66 m.mtx.Lock()
67 defer m.mtx.Unlock()
68 return m.syncState.syncedTo
69 }
70 71 // BlockHash returns the block hash at a particular block height. This
72 // information is useful for comparing against the chain back-end to see if a
73 // reorg is taking place and how far back it goes.
74 func (m *Manager) BlockHash(ns walletdb.ReadBucket, height int32) (
75 *chainhash.Hash, error,
76 ) {
77 m.mtx.Lock()
78 defer m.mtx.Unlock()
79 return fetchBlockHash(ns, height)
80 }
81 82 // Birthday returns the birthday, or earliest time a key could have been used,
83 // for the manager.
84 func (m *Manager) Birthday() time.Time {
85 m.mtx.Lock()
86 defer m.mtx.Unlock()
87 return m.birthday
88 }
89 90 // SetBirthday sets the birthday, or earliest time a key could have been used,
91 // for the manager.
92 func (m *Manager) SetBirthday(ns walletdb.ReadWriteBucket,
93 birthday time.Time,
94 ) (e error) {
95 m.mtx.Lock()
96 defer m.mtx.Unlock()
97 m.birthday = birthday
98 return putBirthday(ns, birthday)
99 }
100