-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
client: monitor wallet peers #1445
Conversation
0b49f8d
to
e231a12
Compare
timeDiff := time.Now().Unix() - int64(bh.Time) | ||
if timeDiff > dexeth.MaxBlockInterval && eth.net != dex.Simnet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JoeGruffins I noticed this was dividing now in seconds by a thousand before comparing with the header time in seconds, so in practice this check was almost impossible to fail. I'm pretty sure 180 seconds since last block in our simnet workflows is gonna be too tight so I'm excluding simnet here. Note that the unit tests leave net as 0 (mainnet), so we're still testing the conditions.
e231a12
to
9a4db97
Compare
9a4db97
to
07f1858
Compare
07f1858
to
5aefc72
Compare
select { | ||
case <-ticker.C: | ||
if c.walletCheckAndNotify(wallet) { | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not new behavior (see the old connectWallet
method), but in this case the canceler goroutine above is stuck on Wait
until the wallet shuts down even though the sync status loop is done. Arguably a minor goroutine leak, but really just excessive lifetime. No issue IMO, but worth noting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Iffy about the pattern used in loadWallet
, but otherwise g2g.
@@ -1871,7 +1860,7 @@ func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) { | |||
|
|||
// Construct the unconnected xcWallet. | |||
contractLockedAmt, orderLockedAmt := c.lockedAmounts(assetID) | |||
return &xcWallet{ | |||
wallet = &xcWallet{ // captured by the PeersChange closure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// captured by the PeersChange closure
Assumption is that a wallet will never call its PeersChange
callback in the constructor itself, otherwise we'd panic in (*Core).peerChange
.
client/asset/interface.go
Outdated
// PeersChange is a function that will be called when the number of | ||
// wallet/node peers changes, or the wallet fails to get the count. | ||
PeersChange func(uint32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per other comment, it's important that PeersChange
is not called in the constructor (actually a little fuzzier than that). It's presumably not an issue since we wouldn't have a peer change until Connect
, but we're relying on the wallet to get this right.
If you wanna roll as-is, please comment here on the importance of not calling this method during initialization.
go func() { | ||
if wallet.connector.On() { | ||
wallet.connector.Wait() | ||
} | ||
cancel() | ||
}() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me want a Done() <-chan struct{}
on the ConnectionMaster
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing a Done()
method in #1474
client/core/core.go
Outdated
@@ -1860,6 +1846,9 @@ func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) { | |||
// of deadlocking a Core method that calls Wallet.Disconnect. | |||
go c.tipChange(assetID, err) | |||
}, | |||
PeersChange: func(numPeers uint32) { | |||
go c.peerChange(wallet, numPeers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@buck54321 I can put a wallet != nil
check in here.
If the check is hit that would mean there's a data race though..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you just pass an assetID
and pull the wallet from the map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had actually started that way. Will see why I veered away. Might be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, because it's not in the wallets
map until after successful connect and a variety of other operations depending on whos calling loadWallet
. :(
I recall now being mystified why peerChanges sometimes didn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
potentially:
diff --git a/client/core/core.go b/client/core/core.go
index f81f9895..45ca809d 100644
--- a/client/core/core.go
+++ b/client/core/core.go
@@ -1834,6 +1834,7 @@ func (c *Core) assetDataDirectory(assetID uint32) string {
// wallet. The returned wallet is running but not connected.
func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) {
var wallet *xcWallet
+ var ready uint32 // in case asset.Open tries to call PeersChange before actually starting
// Create the client/asset.Wallet.
assetID := dbWallet.AssetID
walletCfg := &asset.WalletConfig{
@@ -1847,6 +1848,9 @@ func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) {
go c.tipChange(assetID, err)
},
PeersChange: func(numPeers uint32) {
+ if atomic.LoadUint32(&ready) == 0 {
+ return
+ }
go c.peerChange(wallet, numPeers)
},
DataDir: c.assetDataDirectory(assetID),
@@ -1875,6 +1879,7 @@ func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) {
walletType: dbWallet.Type,
traits: asset.DetermineWalletTraits(w),
}
+ atomic.StoreUint32(&ready, 1)
return wallet, nil
}
but... 🤮
5aefc72
to
ea72e3d
Compare
ea72e3d
to
0ca5b52
Compare
This adds a
PeersChange
callback toclient/asset.WalletConfig
, similar toTipChange
, for backends to report changes to the network peer count. The backends now implement amonitorPeers
goroutine similar tomonitorBlocks
but checking and reporting on peer count changes. Any changes in peer count result in a wallet state note. Change in peer count from 0 to >0 also start a sync status monitoring goroutine, which runs until sync is restored.This also updates each backend's
SyncStatus
method to ensure that thesynced bool
will never be true if there are peer count is 0.Killing the "beta" node with the SPV beta wallet:
Starting up beta dcrd makes the signal-! icon change to a syncing arrow circle icon, which then goes away when it catches up with the network.
Killing "alpha" bitcoind with native btcwallet:
That also returns to normal after restarting alpha bitcoind.
Now the full-node wallets (still simnet):
wallet-peer-state-icons.mp4