-
Notifications
You must be signed in to change notification settings - Fork 220
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
Optional change address #4129
Optional change address #4129
Conversation
0312415
to
a076070
Compare
4a69010
to
9c88c24
Compare
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.
Thank you! 😊 I have finally found the time to take a first look.
As for the user-facing design, I'm a bit unsure whether a state flag oneChangeAddressMode
is the best solution — one alternative design would be to allow the user to supply an explicit change address in the "balance transaction" endpoint. That said, while this alternative has the advantage of avoiding more state, I'm not sure about it either. 🤔 In the end, I agree the state flag is reasonable.
Concerning the implementation, I have three larger requests:
- Instead of using
Bool
, could you use a more "speaking" enumeration type? I.e.
data SeqState … = { …
, changeAddressMode :: ChangeAddressMode
}
data ChangeAddressMode
= SingleChangeAddress
| IncreasingChangeAddresses
This makes the code easier to understand and maintain in the long run.
-
For the implementation of
setOneChangeAddressMode
andsetOneChangeAddressModeShared
, we are now in the excellent position that we can work with theWalletState
data type directly — it captures the entire state of the wallet in an ordinary Haskell data type, the state is no longer implicit in the database.I have taken care of this point and added a commit which rewrites these two functions as pure functions with a little glue code
onWalletState
. -
For the database, please use the
Migration.New
facilities — the old way is dead; the new way is much more robust. You will need to implement a migration and add it torunNewStyleMigrations
. Implementing a newMigration
is straightforward, see for examplemigrateDelegations
incardano-wallet/lib/wallet/src/Cardano/Wallet/DB/Store/Delegations/Migration.hs
Lines 94 to 110 in 6986d98
migration :: UpdateStore (SqlPersistT IO) (Operation SlotNo PoolId) -> ReadDBHandle IO () migration store = do conn <- asks dbConn r <- liftIO $ isFieldPresent conn $ DBField StakeKeyCertSlot case r of TableMissing -> return () ColumnMissing -> return () ColumnPresent -> withReaderT dbBackend $ do old <- readOldEncoding writeS store old rawExecute "DROP TABLE stake_key_certificate" [] rawExecute "DROP TABLE delegation_certificate" [] migrateDelegations :: Migration (ReadDBHandle IO) 2 3 migrateDelegations = mkMigration $ migration mkStoreDelegations
But other than that, I think this looks good.
ff7a0be
to
e3481ec
Compare
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.
Thanks! 😊 I have a couple more requests:
- With the "speaking" constructors for
ChangeAddressMode
, the nameoneChangeAddresMode
no longer makes sense —changeAddresMode
is better. I had change it in many places, but not all of them — could you complete this? - A couple of requests on the use of the
Migration.New
facilities. In particular, could you move the module where the migration is define to theCheckpoints.Migration
?
I'll take another look at the documentation after that.
data ChangeAddressMode | ||
= SingleChangeAddress | ||
| IncreasingChangeAddresses | ||
deriving stock (Generic, Show, Eq) |
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.
data ChangeAddressMode | |
= SingleChangeAddress | |
| IncreasingChangeAddresses | |
deriving stock (Generic, Show, Eq) | |
-- | How to generate change addresses. | |
data ChangeAddressMode | |
= SingleChangeAddress | |
-- ^ Use a single address for all change outputs. | |
| IncreasingChangeAddresses | |
-- ^ For every change output, increase a counter and derive an address from that. | |
deriving stock (Generic, Show, Eq) |
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.
done
, oneChangeAddressMode :: ChangeAddressMode | ||
-- ^ One change address mode. If switched on then next transactions will | ||
-- use the same change address. If no then next change index for | ||
-- each next transaction is used |
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.
, oneChangeAddressMode :: ChangeAddressMode | |
-- ^ One change address mode. If switched on then next transactions will | |
-- use the same change address. If no then next change index for | |
-- each next transaction is used | |
, changeAddressMode :: ChangeAddressMode | |
-- ^ How to generate change addresses. |
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.
done
{ internalPool = newSeqAddressPool @n accXPub g | ||
, externalPool = newSeqAddressPool @n accXPub g | ||
, accountXPub = accXPub | ||
, policyXPub = policyXPubM | ||
, rewardAccountKey = rewardXPub | ||
, pendingChangeIxs = emptyPendingIxs | ||
, derivationPrefix = DerivationPrefix ( purpose, coinTypeAda, minBound ) | ||
, oneChangeAddressMode = change |
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.
, oneChangeAddressMode = change | |
, changeAddressMode = change |
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.
done
if oneChangeAddressMode st == SingleChangeAddress then | ||
( ixMin, updatePending (pendingChangeIxs st) ) | ||
else | ||
nextChangeIndex (getPool $ internalPool st) (pendingChangeIxs st) |
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.
if oneChangeAddressMode st == SingleChangeAddress then | |
( ixMin, updatePending (pendingChangeIxs st) ) | |
else | |
nextChangeIndex (getPool $ internalPool st) (pendingChangeIxs st) | |
case changeAddressMode st of | |
SingleChangeAddress -> | |
( ixMin, updatePending (pendingChangeIxs st) ) | |
IncreasingChangeAddresses -> | |
nextChangeIndex (getPool $ internalPool st) (pendingChangeIxs st) |
A case
statement "speaks" more, making it clearer which case is supposed to do what. 🤓
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.
done
, oneChangeAddressMode :: ChangeAddressMode | ||
-- ^ One change address mode. If switched on then next transactions will | ||
-- use the same change address. If no then next change index for | ||
-- each next transaction is used |
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.
, oneChangeAddressMode :: ChangeAddressMode | |
-- ^ One change address mode. If switched on then next transactions will | |
-- use the same change address. If no then next change index for | |
-- each next transaction is used | |
, changeAddressMode :: ChangeAddressMode | |
-- ^ How to generate change addresses. |
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.
done
@@ -346,6 +347,7 @@ SeqState | |||
seqStatePolicyXPub B8.ByteString Maybe sql=policy_xpub | |||
seqStateRewardXPub B8.ByteString sql=reward_xpub | |||
seqStateDerivationPrefix W.DerivationPrefix sql=derivation_prefix | |||
seqStateOneChangeAddrMode W.ChangeAddressMode sql=change_addr_mode |
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.
seqStateOneChangeAddrMode W.ChangeAddressMode sql=change_addr_mode | |
seqStateChangeAddrMode W.ChangeAddressMode sql=change_addr_mode |
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.
done
@@ -433,6 +435,7 @@ SharedState | |||
sharedStateDelegationScript (Script Cosigner) Maybe sql=delegation_script | |||
sharedStateRewardAccount W.RewardAccount Maybe sql=reward_account | |||
sharedStateDerivationPrefix W.DerivationPrefix sql=derivation_prefix | |||
sharedStateOneChangeAddrMode W.ChangeAddressMode sql=change_addr_mode |
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.
sharedStateOneChangeAddrMode W.ChangeAddressMode sql=change_addr_mode | |
sharedStateChangeAddrMode W.ChangeAddressMode sql=change_addr_mode |
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.
done
-- | Adds an 'one_change_addr_mode' column to the 'seq_state' | ||
-- table if it is missing. | ||
-- | ||
addOneChangeAddrModeIfMissing :: Sqlite.Connection -> IO () | ||
addOneChangeAddrModeIfMissing conn = do | ||
addColumn_ conn True (DBField SeqStateOneChangeAddrMode) value | ||
where | ||
value = "FALSE" | ||
|
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.
-- | Adds an 'one_change_addr_mode' column to the 'seq_state' | |
-- table if it is missing. | |
-- | |
addOneChangeAddrModeIfMissing :: Sqlite.Connection -> IO () | |
addOneChangeAddrModeIfMissing conn = do | |
addColumn_ conn True (DBField SeqStateOneChangeAddrMode) value | |
where | |
value = "FALSE" |
This goes away now.
@@ -170,6 +170,7 @@ migrateManually tr key defaultFieldValues = | |||
, moveRndUnusedAddresses | |||
, cleanupSeqStateTable | |||
, addPolicyXPubIfMissing | |||
, addOneChangeAddrModeIfMissing |
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.
, addOneChangeAddrModeIfMissing |
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.
done
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.
Could you please move this module to Cardano.Wallet.DB.Store.Checkpoints.Migration
? That puts it closer to the thing that is being migrated (i.e. the address state).
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.
done
127105d
to
42de1ff
Compare
42de1ff
to
2229d7d
Compare
fd8163f
to
3db4946
Compare
05e5e67
to
0937343
Compare
corrections
f161566
to
288700e
Compare
…nts the work accomplished in this PR. Before you submit, don't forget to: CODE-OF-CONDUCT.md CONTRIBUTING.md LICENSE MAINTAINERS.md README.md cabal.project default.nix docker-compose.yml docs flake.lock flake.nix floskell.json fourmolu.yaml hie-direnv.yaml justfile lib nix prototypes reports scripts shell.nix specifications test touch.me.CI weeder.dhall Make sure the GitHub PR fields are correct: ✓ Set a good Title for your PR. ✓ Assign yourself to the PR. ✓ Assign one or more reviewer(s). ✓ Link to a Jira issue, and/or other GitHub issues or PRs. ✓ In the PR description delete any empty sections and all text commented in <!--, so that this text does not appear in merge commit messages. CODE-OF-CONDUCT.md CONTRIBUTING.md LICENSE MAINTAINERS.md README.md cabal.project default.nix docker-compose.yml docs flake.lock flake.nix floskell.json fourmolu.yaml hie-direnv.yaml justfile lib nix prototypes reports scripts shell.nix specifications test touch.me.CI weeder.dhall Don't waste reviewers' time: ✓ If it's a draft, select the Create Draft PR option. ✓ Self-review your changes to make sure nothing unexpected slipped through. CODE-OF-CONDUCT.md CONTRIBUTING.md LICENSE MAINTAINERS.md README.md cabal.project default.nix docker-compose.yml docs flake.lock flake.nix floskell.json fourmolu.yaml hie-direnv.yaml justfile lib nix prototypes reports scripts shell.nix specifications test touch.me.CI weeder.dhall Try to make your intent clear: ✓ Write a good Description that explains what this PR is meant to do. ✓ Jira will detect and link to this PR once created, but you can also link this PR in the description of the corresponding Jira ticket. ✓ Highlight what Testing you have done. ✓ Acknowledge any changes required to the Documentation. --> - [x] adjust post wallet api and enabling one change addr flag - [x] extend SeqState - [x] adjust nextChangeIndex - [x] update db schema and related code - [x] handle db migration - [x] add integration test proving the case - [x] allow wallet to go from multi-change-address to one-change-address mode and vice versa (update wallet api change) - [x] show the case in integration testing - [x] add spec - [x] add PUT for shared wallets - [x] do the same like for shelley for shared wallet ### Comments <!-- Additional comments, links, or screenshots to attach, if any. --> ### Issue Number ADP-3145 Source commit: e5a6ca6
Comments
Issue Number
ADP-3145