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

remove creating all clients at startup #1662

Merged
merged 2 commits into from
Nov 23, 2023

Conversation

zkokelj
Copy link
Contributor

@zkokelj zkokelj commented Nov 23, 2023

Why this change is needed

This change is needed to fix recently found issue with large number connections to the host.
This is temporary hotfix and the way we do and maintain connection needs to be changed.

What changes were made as part of this PR

Previously we were creating clients for all existing users in the database at startup.
To avoid problems with that we now create all the clients for existing users and only when they are requested with: GetUserAccountManager

PR checks pre-merging

Please indicate below by ticking the checkbox that you have read and performed the required
PR checks

  • PR checks reviewed and performed

@zkokelj zkokelj marked this pull request as ready for review November 23, 2023 10:33
Copy link

coderabbitai bot commented Nov 23, 2023

Walkthrough

The changes across various files in the wallet extension toolset involve the introduction of new functions and parameters to enhance the management of user accounts and their associated clients. The AccountManager now includes a function to retrieve addresses with clients, while the UserAccountManager has been updated to check for and create missing clients from the database. Additionally, the initialization of these managers has been adjusted to accommodate new parameters, and redundant code has been removed to streamline the process of saving user data and creating clients.

Changes

File Path Change Summary
.../accountmanager/account_manager.go Added GetAllAddressesWithClients function to return addresses with clients.
.../container/walletextension_container.go Modified NewWalletExtensionContainerFromConfig function to initialize userAccountManager with new parameters and streamlined client addition. Removed redundant imports.
.../useraccountmanager/user_account_manager.go Updated NewUserAccountManager to accept new parameters and added addressAlreadyExists helper function. Modified GetUserAccountManager to create missing clients.
.../useraccountmanager/user_account_manager_test.go Adjusted tests to reflect new parameters in NewUserAccountManager.
.../wallet_extension.go Updated SubmitViewingKey function to save user data before creating an encrypted RPC client and removed duplicate saving code.

Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • If you reply to a review comment from CodeRabbit, the bot will automatically respond.
  • To engage with CodeRabbit bot directly around the specific lines of code in the PR, mention @coderabbitai in your review comment
  • Note: Review comments are made on code diffs or files, not on the PR overview.
  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Note: For conversation with the bot, please use the review comments on code diffs or files.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 7

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 1248086 and 7dd2351.
Files selected for processing (4)
  • tools/walletextension/accountmanager/account_manager.go (1 hunks)
  • tools/walletextension/container/walletextension_container.go (3 hunks)
  • tools/walletextension/useraccountmanager/user_account_manager.go (3 hunks)
  • tools/walletextension/useraccountmanager/user_account_manager_test.go (3 hunks)
Additional comments: 4
tools/walletextension/useraccountmanager/user_account_manager.go (2)
  • 23-30:
    The constructor has been updated to accept new parameters for lazy initialization.

  • 113-121:
    The new helper function addressAlreadyExists is correctly implemented.

tools/walletextension/container/walletextension_container.go (1)
  • 61-65:
    Consider adding error handling for the AddAndReturnAccountManager method to ensure account managers are added successfully.
tools/walletextension/accountmanager/account_manager.go (1)
  • 54-64:
    The implementation of GetAllAddressesWithClients correctly acquires a read lock and defers its release, ensuring thread-safe access to the accountClients map. The function iterates over the map keys and collects the hexadecimal representations of the addresses.

Comment on lines 10 to 17
func TestAddingAndGettingUserAccountManagers(t *testing.T) {
unauthedClient, _ := rpc.NewNetworkClient("ws://test")
userAccountManager := NewUserAccountManager(unauthedClient, log.New())
userID1 := "user1"
userID2 := "user2"
userAccountManager := NewUserAccountManager(unauthedClient, log.New(), nil, "ws://test")
userID1 := "4A6F686E20446F65"
userID2 := "7A65746F65A2676F"

// Test adding and getting account manager for userID1
userAccountManager.AddAndReturnAccountManager(userID1)
Copy link

@coderabbitai coderabbitai bot Nov 23, 2023

Choose a reason for hiding this comment

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

The NewUserAccountManager function call in the test TestAddingAndGettingUserAccountManagers is missing the new databaseStorage and hostRPCBindAddr parameters that were mentioned in the summary of changes. The test will not compile without passing these new required arguments.

- userAccountManager := NewUserAccountManager(unauthedClient, log.New(), nil, "ws://test")
+ userAccountManager := NewUserAccountManager(unauthedClient, log.New(), databaseStorage, "ws://test")

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func TestAddingAndGettingUserAccountManagers(t *testing.T) {
unauthedClient, _ := rpc.NewNetworkClient("ws://test")
userAccountManager := NewUserAccountManager(unauthedClient, log.New())
userID1 := "user1"
userID2 := "user2"
userAccountManager := NewUserAccountManager(unauthedClient, log.New(), nil, "ws://test")
userID1 := "4A6F686E20446F65"
userID2 := "7A65746F65A2676F"
// Test adding and getting account manager for userID1
userAccountManager.AddAndReturnAccountManager(userID1)
func TestAddingAndGettingUserAccountManagers(t *testing.T) {
unauthedClient, _ := rpc.NewNetworkClient("ws://test")
userAccountManager := NewUserAccountManager(unauthedClient, log.New(), databaseStorage, "ws://test")
userID1 := "4A6F686E20446F65"
userID2 := "7A65746F65A2676F"
// Test adding and getting account manager for userID1
userAccountManager.AddAndReturnAccountManager(userID1)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test is not testing restart. Not including those two parameters does not have an effect on current test.

Copy link

Choose a reason for hiding this comment

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

@zkokelj Understood, the parameters will be omitted as they are not relevant to the current test scope. Thank you for the clarification.

// start the database
databaseStorage, err := storage.New(config.DBType, config.DBConnectionURL, config.DBPathOverride)
if err != nil {
logger.Crit("unable to create database to store viewing keys ", log.ErrKey, err)
}
userAccountManager := useraccountmanager.NewUserAccountManager(unAuthedClient, logger, databaseStorage, hostRPCBindAddr)

// Get all the data from the database and add all the clients for all users
// todo (@ziga) - implement lazy loading for clients to reduce number of connections and speed up loading
Copy link

@coderabbitai coderabbitai bot Nov 23, 2023

Choose a reason for hiding this comment

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

Remove the outdated TODO comment as lazy loading has been implemented.

-	// todo (@ziga) - implement lazy loading for clients to reduce number of connections and speed up loading

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// todo (@ziga) - implement lazy loading for clients to reduce number of connections and speed up loading

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

Copy link

Choose a reason for hiding this comment

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

@zkokelj Thank you for the update. If there's anything else that needs attention, please let me know!

return userAccManager, nil
}
return nil, fmt.Errorf("UserAccountManager doesn't exist for user: %s", userID)

databseAccounts, err := m.storage.GetAccounts(userIDbytes)
Copy link
Contributor

Choose a reason for hiding this comment

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

databseAccounts -> databaseAccounts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Comment on lines 65 to 69
// log that we don't have a storage, but still return existing userAccountManager
if m.storage == nil {
m.logger.Error("storage is nil in UserAccountManager")
return userAccManager, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This should never happen - but if it's used for tests then it's fine we just need a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added a comment

@ten-protocol ten-protocol deleted a comment from coderabbitai bot Nov 23, 2023
@ten-protocol ten-protocol deleted a comment from coderabbitai bot Nov 23, 2023
@ten-protocol ten-protocol deleted a comment from coderabbitai bot Nov 23, 2023
@ten-protocol ten-protocol deleted a comment from coderabbitai bot Nov 23, 2023
@ten-protocol ten-protocol deleted a comment from coderabbitai bot Nov 23, 2023
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 8

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 7dd2351 and dd679c9.
Files selected for processing (3)
  • tools/walletextension/container/walletextension_container.go (3 hunks)
  • tools/walletextension/useraccountmanager/user_account_manager.go (3 hunks)
  • tools/walletextension/wallet_extension.go (2 hunks)
Additional comments: 4
tools/walletextension/container/walletextension_container.go (3)
  • 7-12: The import of github.com/ethereum/go-ethereum/common has been removed as mentioned in the summary. Ensure that there are no usages of this package left in the file that would lead to compilation errors.

  • 37-51: The changes made here reflect the new strategy of deferring client creation. The error handling for the creation of unAuthedClient and databaseStorage has been updated to terminate the program if an error occurs, which aligns with the previous review comments. This is a critical change that ensures the program does not continue running in an unstable state.

  • 59-66: The loop that previously created clients for all users has been removed, which is in line with the new strategy of lazy client creation. This should reduce the number of connections at startup. Ensure that the userAccountManager is correctly handling the creation of clients when they are actually needed.

tools/walletextension/useraccountmanager/user_account_manager.go (1)
  • 115-122:
    The addressAlreadyExists helper function is correctly implemented.

)

type UserAccountManager struct {
userAccountManager map[string]*accountmanager.AccountManager
unauthenticatedClient rpc.Client
storage storage.Storage
hostRPCBinAddr string
Copy link

Choose a reason for hiding this comment

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

Typo in the struct field name.

- hostRPCBinAddr        string
+ hostRPCBindAddr       string

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
hostRPCBinAddr string
hostRPCBindAddr string

}

// create a new client
encClient, err := wecommon.CreateEncClient(m.hostRPCBinAddr, account.AccountAddress, userPrivateKey, account.Signature, m.logger)
Copy link

Choose a reason for hiding this comment

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

Error handling is missing after creating a new client. If CreateEncClient fails, the error should be handled appropriately, possibly by returning the error to the caller.

// create a new client
encClient, err := wecommon.CreateEncClient(m.hostRPCBinAddr, account.AccountAddress, userPrivateKey, account.Signature, m.logger)
if err != nil {
m.logger.Error(fmt.Errorf("error creating new client, %w", err).Error())
Copy link

Choose a reason for hiding this comment

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

The error from client creation is logged but not handled, which could lead to an inconsistent state.

}

// add a client to requested userAccountManager
userAccManager.AddClient(common.BytesToAddress(account.AccountAddress), encClient)
Copy link

Choose a reason for hiding this comment

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

Potential addition of a nil encClient to userAccManager if CreateEncClient fails.

Comment on lines 144 to +150
signature[64] -= 27

vk.Signature = signature

err := w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)
Copy link

Choose a reason for hiding this comment

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

The subtraction of 27 from the signature's last byte is done to conform to the Ethereum signature format, but this operation modifies the original signature array directly, which could lead to unexpected behavior if the signature is used elsewhere after this method. Consider copying the signature before modifying it to ensure that the original signature remains intact.

- signature[64] -= 27
+ modifiedSignature := make([]byte, len(signature))
+ copy(modifiedSignature, signature)
+ modifiedSignature[64] -= 27

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
signature[64] -= 27
vk.Signature = signature
err := w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)
modifiedSignature := make([]byte, len(signature))
copy(modifiedSignature, signature)
modifiedSignature[64] -= 27
vk.Signature = modifiedSignature
err := w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)


err := w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)
Copy link

Choose a reason for hiding this comment

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

The error message in the fmt.Errorf call should wrap the original error using %w to allow for error unwrapping by the caller.

- return fmt.Errorf("error saving user: %s", common.DefaultUser)
+ return fmt.Errorf("error saving user: %s - %w", common.DefaultUser, err)

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
return fmt.Errorf("error saving user: %s", common.DefaultUser)
return fmt.Errorf("error saving user: %s - %w", common.DefaultUser, err)

Comment on lines 162 to 167

defaultAccountManager.AddClient(address, client)

err = w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)
}

err = w.storage.AddAccount([]byte(common.DefaultUser), vk.Account.Bytes(), vk.Signature)
if err != nil {
return fmt.Errorf("error saving account %s for user %s", vk.Account.Hex(), common.DefaultUser)
Copy link

Choose a reason for hiding this comment

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

The error message in the fmt.Errorf call should wrap the original error using %w to allow for error unwrapping by the caller.

- return fmt.Errorf("error saving account %s for user %s", vk.Account.Hex(), common.DefaultUser)
+ return fmt.Errorf("error saving account %s for user %s - %w", vk.Account.Hex(), common.DefaultUser, err)

Commitable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
defaultAccountManager.AddClient(address, client)
err = w.storage.AddUser([]byte(common.DefaultUser), crypto.FromECDSA(vk.PrivateKey.ExportECDSA()))
if err != nil {
return fmt.Errorf("error saving user: %s", common.DefaultUser)
}
err = w.storage.AddAccount([]byte(common.DefaultUser), vk.Account.Bytes(), vk.Signature)
if err != nil {
return fmt.Errorf("error saving account %s for user %s", vk.Account.Hex(), common.DefaultUser)
defaultAccountManager.AddClient(address, client)
err = w.storage.AddAccount([]byte(common.DefaultUser), vk.Account.Bytes(), vk.Signature)
if err != nil {
return fmt.Errorf("error saving account %s for user %s - %w", vk.Account.Hex(), common.DefaultUser, err)

The AddAccount method is called after the client is added to the defaultAccountManager, but if AddAccount fails, the client remains added. This could lead to an inconsistent state where the client is available but the account is not properly saved. Consider adding error handling to remove the client if saving the account fails.

@zkokelj zkokelj merged commit d37c0c7 into main Nov 23, 2023
3 of 5 checks passed
@zkokelj zkokelj deleted the ziga/remove_loading_all_encclient_on_startup branch November 23, 2023 16:15
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.

2 participants