sync.go raw

   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