Skip to content

Commit

Permalink
allow Wallet impls provide tip change tracking where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
itswisdomagain committed Oct 20, 2021
1 parent 67663b4 commit e5815dd
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 9 deletions.
29 changes: 20 additions & 9 deletions client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,11 +537,17 @@ func (dcr *ExchangeWallet) Connect(ctx context.Context) (*sync.WaitGroup, error)

success = true // All good, don't disconnect the wallet when this method returns.

// NotifyOnTipChange will return false if the wallet does not support
// tip change notification. We'll use dcr.monitorBlocks below if so.
monitoringBlocks := dcr.wallet.NotifyOnTipChange(ctx, dcr.handleTipChange)

var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
dcr.monitorBlocks(ctx)
if !monitoringBlocks {
dcr.monitorBlocks(ctx)
}
dcr.shutdown()
}()
return &wg, nil
Expand Down Expand Up @@ -2691,25 +2697,30 @@ func (dcr *ExchangeWallet) checkForNewBlocks() {
defer cancel()
newTip, err := dcr.getBestBlock(ctx)
if err != nil {
go dcr.tipChange(fmt.Errorf("failed to get best block: %w", err))
dcr.handleTipChange(nil, 0, fmt.Errorf("failed to get best block: %w", err))
return
}

// This method is called frequently. Don't hold write lock
// unless tip has changed.
dcr.tipMtx.RLock()
sameTip := dcr.currentTip.hash.IsEqual(newTip.hash)
dcr.tipMtx.RUnlock()
if sameTip {
if !sameTip {
dcr.handleTipChange(newTip.hash, newTip.height, nil)
}
}

func (dcr *ExchangeWallet) handleTipChange(newTipHash *chainhash.Hash, newTipHeight int64, err error) {
if err != nil {
go dcr.tipChange(err)
return
}

dcr.tipMtx.Lock()
defer dcr.tipMtx.Unlock()

prevTip := dcr.currentTip
dcr.currentTip = newTip
dcr.log.Debugf("tip change: %d (%s) => %d (%s)", prevTip.height, prevTip.hash, newTip.height, newTip.hash)
dcr.currentTip = &block{newTipHeight, newTipHash}
dcr.log.Debugf("tip change: %d (%s) => %d (%s)", prevTip.height, prevTip.hash, newTipHeight, newTipHash)
go dcr.tipChange(nil)

// Search for contract redemption in new blocks if there
Expand Down Expand Up @@ -2765,7 +2776,7 @@ func (dcr *ExchangeWallet) checkForNewBlocks() {
if aBlock.Confirmations > -1 {
// Found the mainchain ancestor of previous tip.
startHeight = int64(aBlock.Height)
dcr.log.Debugf("reorg detected from height %d to %d", aBlock.Height, newTip.height)
dcr.log.Debugf("reorg detected from height %d to %d", aBlock.Height, newTipHeight)
break
}
if aBlock.Height == 0 {
Expand All @@ -2785,7 +2796,7 @@ func (dcr *ExchangeWallet) checkForNewBlocks() {

// Run the redemption search from the startHeight determined above up
// till the current tip height.
go dcr.findRedemptionsInBlockRange(startHeight, newTip.height, contractOutpoints)
go dcr.findRedemptionsInBlockRange(startHeight, newTipHeight, contractOutpoints)
}

func (dcr *ExchangeWallet) getBestBlock(ctx context.Context) (*block, error) {
Expand Down
12 changes: 12 additions & 0 deletions client/asset/dcr/rpcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ func (w *rpcWallet) Network(ctx context.Context) (wire.CurrencyNet, error) {
return net, translateRPCCancelErr(err)
}

// NotifyOnTipChange registers a callback function that the should be invoked
// when the wallet sees new mainchain blocks. The return value indicates if this
// notification can be provided.
// Part of the Wallet interface.
func (w *rpcWallet) NotifyOnTipChange(ctx context.Context, cb TipChangeCallback) bool {
// TODO: Could use the ctx provided to poll getbestblock and detect tip changes
// in order to invoke the provided callback. This is currently already being handled
// by the dcr ExchangeWallet to accomodate other implementations that may also not
// have an out-of-the-box provision for block change notifications.
return false
}

// AccountOwnsAddress uses the validateaddress rpc to check if the provided
// address belongs to the specified account.
// Part of the Wallet interface.
Expand Down
8 changes: 8 additions & 0 deletions client/asset/dcr/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ func RegisterCustomWallet(constructor WalletConstructor, info *asset.WalletInfo)
chaincfg.TestNet3Params()
}

type TipChangeCallback func(*chainhash.Hash, int64, error)

type Wallet interface {
// Connect establishes a connection to the wallet.
Connect(ctx context.Context) error
Expand All @@ -51,6 +53,12 @@ type Wallet interface {
Disconnected() bool
// Network returns the network of the connected wallet.
Network(ctx context.Context) (wire.CurrencyNet, error)
// NotifyOnTipChange registers a callback function that the should be
// invoked when the wallet sees new mainchain blocks. The return value
// indicates if this notification can be provided. Where this tip change
// notification is unimplemented, monitorBlocks should be used to track
// tip changes.
NotifyOnTipChange(ctx context.Context, cb TipChangeCallback) bool
// AccountOwnsAddress checks if the provided address belongs to the
// specified account.
AccountOwnsAddress(ctx context.Context, account, address string) (bool, error)
Expand Down

0 comments on commit e5815dd

Please sign in to comment.