-
Notifications
You must be signed in to change notification settings - Fork 219
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
feat: refactor key-related field operations to be atomic #5178
feat: refactor key-related field operations to be atomic #5178
Conversation
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.
utACK
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.
utaCK
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.
Happy to merge after the map_errs are removed
connection | ||
.transaction::<_, Error, _>(|| { | ||
secondary_key_version = WalletSettingSql::get(&DbKey::SecondaryKeyVersion, connection) | ||
.map_err(|_| Error::RollbackTransaction)?; |
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 mapping is not actually needed. Any Err will rollback the transaction. The docs on diesel.rs don't reflect this in v1.4, but have been updated in the 2.0 docs on docs.rs. In either case, I checked the source and it rolls back on Err.
So it's better to just return the error with ?
and have the original error find their way to the logs
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.
I had tried this initially, but the compiler complained that the internal error couldn't be converted to a diesel
error.
.transaction::<_, Error, _>(|| { | ||
WalletSettingSql::new(DbKey::SecondaryKeyVersion, self.secondary_key_version.to_string()) | ||
.set(connection) | ||
.map_err(|_| Error::RollbackTransaction)?; |
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.
Same comment here
280f98e
Description
Refactors key-related database field operations to be atomic.
Closes issue 5177.
Motivation and Context
Key-related database fields always travel together. We need a consistent set of secondary key version identifier, secondary key salt, and encrypted main key in order to set up the
XChaCha20-Poly1305
cipher used for database encryption operations and passphrase changes.While a recent PR ensures that write operations for these fields are done atomically via a write transaction, there is no corresponding read transaction. It's therefore possible that those fields are inconsistent. While this should only result in an error and require the user to load their wallet again, it seemed like a smart idea to ensure that reads are consistent for any future use cases.
This PR refactors the handling of those fields to reduce redundancy and ensure atomicity for reads and writes. It introduces a new
DatabaseKeyFields
struct that handles reads and writes, and additionally takes care of encoding and decoding of the underlying data.It also makes the handling of the three fields more consistent. Previously, individual reads and writes required the use of a complex
match
to handle different states. This functionality has been mostly moved intoDatabaseKeyFields
to make these states more apparent.How Has This Been Tested?
Existing unit tests pass. Manually tested the following operations:
It does not seem possible to directly test read operation inconsistency caused by a simultaneous write operation.