Skip to content
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/core: Refactor Login #1903

Merged
merged 1 commit into from
Dec 2, 2022
Merged

client/core: Refactor Login #1903

merged 1 commit into from
Dec 2, 2022

Conversation

martonp
Copy link
Contributor

@martonp martonp commented Oct 15, 2022

client/core:

  • Login is updated not return a LoginResult. It only returns an error if the password is incorrect. On the first login after startup or after a logout, the wallets are connected, active trades are resolved, and the dex connections are authed. On subsequent logins, only the password is checked.
  • Two new functions, GetNotifications and AuthDEXConnections are added.
  • loadDBTrades now adds all trades for which a walletSet is able to be generated to the dexConnection's trades map. A field readyToTick is added to trackedTrade, and tick returns early for trades where it is set to false. resumeTrades will set readyToTick to true for all trades where both wallets can be unlocked. resumeTrades is also called whenever a wallet is unlocked or connected in order to possibly resume trades that were previously unable to have both wallets unlocked.

client/webserver:

  • /api/getnotes and /api/authdexconns are added.

app:

  • /api/getnotes is called after login to retrieve existing notifications since this is now removed from login.
  • /api/authdexconns is called instead of /api/login after a dex account is imported.
  • Active trades that have readyToTick will have their header displayed in red on the market's page. Also a message asking the user to unlock their wallets is displayed.

Screen Shot 2022-11-22 at 9 28 04 AM

Closes #1762

@martonp martonp force-pushed the refactorLogin branch 2 times, most recently from 1c1e301 to 17a5e71 Compare November 1, 2022 23:16
@martonp martonp marked this pull request as ready for review November 1, 2022 23:16
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some quick thoughts about the webserver/middleware/frontend bits. Moving to backend...

client/core/core.go Outdated Show resolved Hide resolved
client/webserver/api.go Outdated Show resolved Hide resolved
client/webserver/api.go Outdated Show resolved Hide resolved
client/webserver/site/src/js/forms.ts Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Show resolved Hide resolved
client/core/core.go Show resolved Hide resolved
}

tracker.wallets = walletSet
dc.trades[tracker.ID()] = tracker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is dc.tradeMtx locked when doing this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I've locked it now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't digested the logic yet as it pertains to the resumeTrades bool, but we should be sure never to overwrite an existing map entry. If there are two trackedTrade instances for the same orders, bad things can and will happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think an overwrite could happen because this function is only called at login, but I've added a check to make sure.

The resumeTrades bool arguments have anything to do with adding trades to the map. It's only to avoid recursive calls back to resumeTrades when wallets are being unlocked in resumeTrade.

Copy link
Member

@chappjc chappjc Nov 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In (*Core).resumeTrade, there is a large amount of work being done even for trades that don't need to be resumed i.e. are already running fine. We should really leave alone trades that are fine. Calling FundingCoins repeatedly, re-auditing contracts, messing with account-based wallet reserves, etc. Need to avoid all that somehow. It looks to me like all orders that would (re)load fine are going to go through all this, return true from resumeTrade, and emit an order note.

We talked about having the lame trades in the trades map for reasons, but that doesn't mean we can't add a tracking structure as a field to dexConnections to assist.

That's potentially separate, but I also think we should reconsider at the need for the bool because it does hint that something is amiss in the design.

A related thing that stands out is when wallet A is unlocked, we try to resume all trades even if they have nothing to do with wallet A.

Copy link
Member

@chappjc chappjc Nov 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh, readyToTick blocks calling these again? OK. Seems like resumeTrade could check this too and return true.

Please consider the other points though.

Copy link
Contributor Author

@martonp martonp Nov 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like resumeTrade could check this too and return true.

Good call, I'll add a check.

That's potentially separate, but I also think we should reconsider at the need for the bool because it does hint that something is amiss in the design.

I was considering putting the lame trades into a separate map, and then having cancelOrder search through those as well, but it seemed cleaner to do it with the bool. Why is this a bad design? The trades map has all of the active trades for a dex, but some of them could not yet complete pre-processing, so we mark this with a flag. It seems decently straightforward.

A related thing that stands out is when wallet A is unlocked, we try to resume all trades even if they have nothing to do with wallet A.

I considered this also.. we could pass an assetID filter to resumeTrades, but the max cost of not doing it is one failed call to per wallet that has active trades.
Maybe it's far fetched, but there could be a case where the user has an active trade with asset A-B, and one with A-C. Both A and B initially failed to connect. Then they start both the A and B RPC wallets, unlock the B wallet, and A is able to automatically unlock. If we only resume trades involving wallet B, then the A-C trade will not be resumed. Unless we allow recursive calls back to resumeTrades.

I just think it's such a minimal cost, and better to attempt and fail, than not attempt and miss a chance to resume a trade.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seemed cleaner to do it with the bool. Why is this a bad design? The trades map has all of the active trades for a dex, but some of them could not yet complete pre-processing, so we mark this with a flag. It seems decently straightforward.

OK, I think it works well.
It's just a bit error prone (see last review for instance) and takes some more investigation to follow when it's used correctly.

@martonp martonp force-pushed the refactorLogin branch 2 times, most recently from 2d6ce52 to 66bca3e Compare November 23, 2022 14:05
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/rpcserver/handlers.go Show resolved Hide resolved
@@ -1252,6 +1258,7 @@ export default class MarketsPage extends BasePage {
})
app().bindTooltips(div)
}
Doc.setVis(unreadyOrders, page.unreadyOrdersMsg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we'll want a way to indicate a problem even if the user is on a different market. Don't have to do it now. Could be a db.ErrorLevel notification maybe. Or maybe just well-placed messaging. Either way, I'd hate it if my orders on one market were not processing but I'm unaware because I'm looking at a different market.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking to do a popup that shows up on the markets page after login in another PR.

// status, emitting WalletStateNotes on each progress update. If resumeTrades
// is set to true, an attempt to resume and trades that were unable to be
// resumed at startup will be made.
func (c *Core) connectAndUnlockResumeTrades(crypter encrypt.Crypter, wallet *xcWallet, resumeTrades bool) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing that smells is the resumeTrades bool arguments being passed around. My intuition is that this hides an underlying deficiency where we should be doing a more sophisticated form of resolution once new wallets come online, i.e. we should be able to tell if trades need to be resumed without the caller's input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for passing it around is to avoid recursive calls from happening when connectAndUnlockWallet is called from resumeTrade. I guess it's not completely necessary..

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking pretty good to me!

client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
}

tracker.wallets = walletSet
dc.trades[tracker.ID()] = tracker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seemed cleaner to do it with the bool. Why is this a bad design? The trades map has all of the active trades for a dex, but some of them could not yet complete pre-processing, so we mark this with a flag. It seems decently straightforward.

OK, I think it works well.
It's just a bit error prone (see last review for instance) and takes some more investigation to follow when it's used correctly.

client/core/core.go Show resolved Hide resolved
client/core/core.go Outdated Show resolved Hide resolved
client/webserver/locales/en-us.go Outdated Show resolved Hide resolved
client/webserver/site/src/js/settings.ts Show resolved Hide resolved
Comment on lines +1903 to +1905
// - If an OrderLoaded notification is recieved, it means an order that was
// previously not "ready to tick" (due to its wallets not being connected
// and unlocked) has now become ready to tick. The active orders section
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this also happen when the user just logs in with active orders? Won't it emit one of these OrderLoaded topic notes for each active order on initial login, causing it to refresh active orders multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but those will be before login is complete, so the market page will not yet be loaded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but those will be before login is complete, so the market page will not yet be loaded.

Ah, OK, perfect.

@chappjc
Copy link
Member

chappjc commented Nov 30, 2022

I noticed a nil context panic in btc.externalFeeEstimator, but I'll get to that in #1967 right after this goes in. Saw a duplicate log statement too, but otherwise working as expected.

I had forgotten that "unfunded" orders get automatically canceled in authDEX. Since these failed-to-resume orders never get tracker.coinsLocked = true in resumeTrade, booked orders that don't have a connected or unlockable wallet get canceled. I think that's good, I just forgot. Yeah, very good... previously these orders wouldn't have even been loaded into the trades map. 😬

@chappjc
Copy link
Member

chappjc commented Dec 1, 2022

The wild goroutine (go c.resumeTrades(nil)) is causing issues, particularly with tests where data races are caused with rapid repeated calls like in TestReconfigureWallet.

client/core:
- Login is updated not return a LoginResult. It only returns an error if
  the password is incorrect. On the first login after startup or after a
  logout, the wallets are connected, active trades are resolved, and the
  dex connections are authed. On subsequent logins, only the password is
  checked.
- The new Core method, Notifications is are added.
- resolveActiveTrades is now called not only from login, but also after
  a wallet is unlocked. Trades that failed to resume on the initial call
  to resolveActiveTrades are cached on the dexConnection and when wallets
  are later unlocked, resolveActiveTrades is called again in order to
  attempt to resume those trades.

client/webserver:
- /api/getnotes is added.

ui:
- /api/getnotes is called after login to retrieve existing notifications
  since this is now removed from login.
@chappjc chappjc merged commit 13758c0 into decred:master Dec 2, 2022
@martonp martonp deleted the refactorLogin branch December 20, 2022 22:07
@chappjc chappjc added this to the 0.6 milestone Dec 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

client/core: rethink scope of Login, expand API, separate concerns
3 participants