Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit ef83f32

Browse files
iohk-bors[bot]KtorZdisassembler
committed
Merge #4112
4112: [DEVOPS-1250] backport RCD-47 fix about 'hasSpendingPassword' metadata with extra sanity check r=disassembler a=KtorZ ## Description <!--- A brief description of this PR and the problem is trying to solve --> Since a few users have already ran the migration, they might have migrated wallet with incorrect metadata, wrongly stating that their wallet has no spending password, and as a consequence, preventing them from doing anything with their wallet. So, we do now run an extra sanity check upon every start to make sure that the wallet acid state metadata matches what we find in the keystore. ## Linked issue <!--- Put here the relevant issue from YouTrack --> [[DEVOPS-150]](https://iohk.myjetbrains.com/youtrack/issue/DEVOPS-1250) Co-authored-by: KtorZ <[email protected]> Co-authored-by: Samuel Leathers <[email protected]>
2 parents 35e8f14 + 7877219 commit ef83f32

File tree

4 files changed

+69
-12
lines changed

4 files changed

+69
-12
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## Cardano SL 3.0.1
4+
5+
### Fixes
6+
7+
- Fix inconsistent 'hasSpendingPassword' resolution from legacy data layer migration ([DEVOPS-1250](https://iohk.myjetbrains.com/youtrack/issue/DEVOPS-1250) [#4112](https://github.com/input-output-hk/cardano-sl/pull/4112))
8+
39
## Cardano SL 3.0.0
410

511
### Fixes

lib/configuration.yaml

+7-7
Original file line numberDiff line numberDiff line change
@@ -14851,7 +14851,7 @@ mainnet_wallet_win64: &mainnet_wallet_win64
1485114851
<<: *mainnet_full
1485214852
update:
1485314853
applicationName: csl-daedalus
14854-
applicationVersion: 13
14854+
applicationVersion: 14
1485514855
lastKnownBlockVersion:
1485614856
bvMajor: 0
1485714857
bvMinor: 1
@@ -14861,7 +14861,7 @@ mainnet_wallet_macos64: &mainnet_wallet_macos64
1486114861
<<: *mainnet_full
1486214862
update:
1486314863
applicationName: csl-daedalus
14864-
applicationVersion: 13
14864+
applicationVersion: 14
1486514865
lastKnownBlockVersion:
1486614866
bvMajor: 0
1486714867
bvMinor: 1
@@ -14871,7 +14871,7 @@ mainnet_wallet_linux64: &mainnet_wallet_linux64
1487114871
<<: *mainnet_full
1487214872
update:
1487314873
applicationName: csl-daedalus
14874-
applicationVersion: 13
14874+
applicationVersion: 14
1487514875
lastKnownBlockVersion:
1487614876
bvMajor: 0
1487714877
bvMinor: 1
@@ -14945,7 +14945,7 @@ testnet_wallet: &testnet_wallet
1494514945
<<: *testnet_full
1494614946
update: &testnet_wallet_update
1494714947
applicationName: csl-daedalus
14948-
applicationVersion: 9
14948+
applicationVersion: 10
1494914949
lastKnownBlockVersion:
1495014950
bvMajor: 0
1495114951
bvMinor: 0
@@ -14984,7 +14984,7 @@ mainnet_dryrun_wallet_win64: &mainnet_dryrun_wallet_win64
1498414984
<<: *mainnet_dryrun_full
1498514985
update:
1498614986
applicationName: csl-daedalus
14987-
applicationVersion: 22
14987+
applicationVersion: 23
1498814988
lastKnownBlockVersion:
1498914989
bvMajor: 0
1499014990
bvMinor: 2
@@ -14994,7 +14994,7 @@ mainnet_dryrun_wallet_macos64: &mainnet_dryrun_wallet_macos64
1499414994
<<: *mainnet_dryrun_full
1499514995
update:
1499614996
applicationName: csl-daedalus
14997-
applicationVersion: 22
14997+
applicationVersion: 23
1499814998
lastKnownBlockVersion:
1499914999
bvMajor: 0
1500015000
bvMinor: 2
@@ -15004,7 +15004,7 @@ mainnet_dryrun_wallet_linux64: &mainnet_dryrun_wallet_linux64
1500415004
<<: *mainnet_dryrun_full
1500515005
update:
1500615006
applicationName: csl-daedalus
15007-
applicationVersion: 22
15007+
applicationVersion: 23
1500815008
lastKnownBlockVersion:
1500915009
bvMajor: 0
1501015010
bvMinor: 2

wallet/src/Cardano/Wallet/Action.hs

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import Cardano.Wallet.Kernel (PassiveWallet)
2222
import qualified Cardano.Wallet.Kernel as Kernel
2323
import qualified Cardano.Wallet.Kernel.Internal as Kernel.Internal
2424
import qualified Cardano.Wallet.Kernel.Keystore as Keystore
25-
import Cardano.Wallet.Kernel.Migration (migrateLegacyDataLayer)
25+
import Cardano.Wallet.Kernel.Migration (migrateLegacyDataLayer,
26+
sanityCheckSpendingPassword)
2627
import qualified Cardano.Wallet.Kernel.Mode as Kernel.Mode
2728
import qualified Cardano.Wallet.Kernel.NodeStateAdaptor as NodeStateAdaptor
2829
import Cardano.Wallet.Server.CLI (WalletBackendParams,
@@ -68,6 +69,7 @@ actionWithWallet params genesisConfig walletConfig txpConfig ntpConfig nodeParam
6869
let pm = configProtocolMagic genesisConfig
6970
WalletLayer.Kernel.bracketPassiveWallet pm dbMode logMessage' keystore nodeState (npFInjects nodeParams) $ \walletLayer passiveWallet -> do
7071
migrateLegacyDataLayer passiveWallet dbPath (getFullMigrationFlag params)
72+
sanityCheckSpendingPassword passiveWallet
7173

7274
let plugs = plugins (walletLayer, passiveWallet) dbMode
7375

wallet/src/Cardano/Wallet/Kernel/Migration.hs

+53-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
module Cardano.Wallet.Kernel.Migration (migrateLegacyDataLayer) where
1+
{-# LANGUAGE LambdaCase #-}
2+
3+
module Cardano.Wallet.Kernel.Migration
4+
( migrateLegacyDataLayer
5+
, sanityCheckSpendingPassword
6+
) where
27

38
import Universum
49

10+
import Data.Acid.Advanced (update')
511
import Data.Text (pack)
612
import Data.Time (defaultTimeLocale, formatTime, getCurrentTime,
713
iso8601DateFormat)
14+
import Pos.Crypto.Signing (checkPassMatches)
815
import System.Directory (doesDirectoryExist, makeAbsolute, renamePath)
916

1017
import Formatting ((%))
@@ -15,10 +22,15 @@ import Pos.Crypto (EncryptedSecretKey)
1522
import Pos.Util.Wlog (Severity (..))
1623

1724
import qualified Cardano.Wallet.Kernel as Kernel
25+
import Cardano.Wallet.Kernel.DB.AcidState (UpdateHdRootPassword (..))
1826
import qualified Cardano.Wallet.Kernel.DB.HdWallet as HD
27+
import Cardano.Wallet.Kernel.DB.InDb (InDb (..))
28+
import qualified Cardano.Wallet.Kernel.DB.Read as Kernel
1929
import qualified Cardano.Wallet.Kernel.Internal as Kernel
2030
import Cardano.Wallet.Kernel.Keystore as Keystore
31+
import qualified Cardano.Wallet.Kernel.Read as Kernel
2132
import Cardano.Wallet.Kernel.Restore (restoreWallet)
33+
import Cardano.Wallet.Kernel.Util.Core (getCurrentTimestamp)
2234

2335
{-------------------------------------------------------------------------------
2436
Pure helper functions for migration.
@@ -104,9 +116,7 @@ restore pw forced esk = do
104116
rootId = HD.eskToHdRootId nm esk
105117

106118
let -- DEFAULTS for wallet restoration
107-
-- we don't have a spending password during migration
108-
hasSpendingPassword = False
109-
-- we cannot derive an address without a spending password
119+
hasSpendingPassword = isNothing $ checkPassMatches mempty esk
110120
defaultAddress = Nothing
111121
defaultWalletName = HD.WalletName "<Migrated Wallet>"
112122
defaultAssuranceLevel = HD.AssuranceLevelStrict
@@ -132,3 +142,42 @@ restore pw forced esk = do
132142
True -> do
133143
logMsg Error ("Migration failed! " <> msg <> " You are advised to delete the newly created db and try again.")
134144
exitFailure
145+
146+
-- | Verify that the spending password metadata are correctly set. We mistakenly
147+
-- forgot to port a fix from RCD-47 done on 2.0.x onto 3.0.0 and, for a few
148+
-- users, have migrated / restored their wallet with a wrong spending password
149+
-- metadata (arbitrarily set to `False`), making their wallet completely
150+
-- unusable.
151+
--
152+
-- This checks makes sure that the 'hasSpendingPassword' metadata correctly
153+
-- reflects the wallet condition. To be run on each start-up, unfortunately.
154+
sanityCheckSpendingPassword
155+
:: Kernel.PassiveWallet
156+
-> IO ()
157+
sanityCheckSpendingPassword pw = do
158+
let nm = makeNetworkMagic (pw ^. Kernel.walletProtocolMagic)
159+
wKeys <- Keystore.getKeys (pw ^. Kernel.walletKeystore)
160+
db <- Kernel.getWalletSnapshot pw
161+
lastUpdateNow <- InDb <$> getCurrentTimestamp
162+
forM_ wKeys $ \esk -> do
163+
let hasSpendingPassword = case checkPassMatches mempty esk of
164+
Nothing -> HD.HasSpendingPassword lastUpdateNow
165+
Just _ -> HD.NoSpendingPassword
166+
let rootId = HD.eskToHdRootId nm esk
167+
whenDiscrepancy db rootId hasSpendingPassword restoreTruth >>= \case
168+
Left (HD.UnknownHdRoot _) ->
169+
logMsg Error "Failed to update spending password status, HDRoot is gone?"
170+
Right _ ->
171+
return ()
172+
where
173+
logMsg = pw ^. Kernel.walletLogMessage
174+
whenDiscrepancy db rootId hasSpendingPassword action = do
175+
case (hasSpendingPassword, Kernel.lookupHdRootId db rootId) of
176+
(_, Left e) ->
177+
return $ Left e
178+
(HD.HasSpendingPassword _, Right root) | root ^. HD.hdRootHasPassword == HD.NoSpendingPassword ->
179+
action rootId hasSpendingPassword
180+
_ -> -- Avoid making a DB update when there's no need
181+
return $ Right ()
182+
restoreTruth rootId hasSpendingPassword =
183+
void <$> update' (pw ^. Kernel.wallets) (UpdateHdRootPassword rootId hasSpendingPassword)

0 commit comments

Comments
 (0)