Skip to content

Commit

Permalink
Use wallet state for private key management.
Browse files Browse the repository at this point in the history
  • Loading branch information
paolino committed May 30, 2023
1 parent e442282 commit fe734a6
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 249 deletions.
4 changes: 2 additions & 2 deletions lib/wallet/api/http/Cardano/Wallet/Api/Http/Shelley/Server.hs
Expand Up @@ -192,6 +192,7 @@ import Cardano.Wallet
, logger
, manageRewardBalance
, networkLayer
, readPrivateKey
, readWalletMeta
, transactionLayer
, utxoAssumptionsForWallet
Expand Down Expand Up @@ -1262,13 +1263,12 @@ patchSharedWallet ctx liftKey cred (ApiT wid) body = do
db & \W.DBLayer
{ atomically
, readCheckpoint
, readPrivateKey
, walletState
} -> do
cp <- atomically readCheckpoint
let state = getState cp
--could be for account and root key wallets
prvKeyM <- atomically readPrivateKey
prvKeyM <- atomically $ readPrivateKey walletState
meta <- atomically (readWalletMeta walletState)
pure (state, prvKeyM, meta)

Expand Down
29 changes: 26 additions & 3 deletions lib/wallet/src/Cardano/Wallet.hs
Expand Up @@ -76,6 +76,7 @@ module Cardano.Wallet
, getWalletUtxoSnapshot
, listUtxoStatistics
, readWallet
, readPrivateKey
, restoreWallet
, updateWallet
, updateWalletPassphraseWithOldPassphrase
Expand Down Expand Up @@ -221,6 +222,7 @@ module Cardano.Wallet
, WalletFollowLog (..)
, WalletLog (..)
, TxSubmitLog (..)
, putPrivateKey
) where

import Prelude hiding
Expand Down Expand Up @@ -441,6 +443,8 @@ import Cardano.Wallet.Primitive.Types.Address
( Address (..), AddressState (..) )
import Cardano.Wallet.Primitive.Types.Coin
( Coin (..) )
import Cardano.Wallet.Primitive.Types.Credentials
( Credentials (..), PrivateKey )
import Cardano.Wallet.Primitive.Types.Hash
( Hash (..) )
import Cardano.Wallet.Primitive.Types.RewardAccount
Expand Down Expand Up @@ -561,6 +565,8 @@ import Data.ByteString
( ByteString )
import Data.DBVar
( DBVar, readDBVar )
import Data.Delta
( Replace (..) )
import Data.Delta.Update
( onDBVar, update )
import Data.Either
Expand Down Expand Up @@ -870,6 +876,23 @@ checkWalletIntegrity db gp = db & \DBLayer{..} -> do
readWalletMeta :: Functor f => DBVar f (DeltaWalletState s) -> f WalletMetadata
readWalletMeta walletState = walletMeta . info <$> readDBVar walletState

readPrivateKey
:: Functor stm
=> DBVar stm (DeltaWalletState s)
-> stm (Maybe (PrivateKey (KeyOf s), PassphraseHash))
readPrivateKey walletState =
readDBVar walletState <&> \mc -> do
(Credentials pk h) <- credentials mc
pure (pk, h)

putPrivateKey
:: Monad m
=> DBVar m (DeltaWalletState s)
-> (PrivateKey (KeyOf s), PassphraseHash)
-> m ()
putPrivateKey walletState (pk, hpw) = onDBVar walletState $ update $ \_ ->
[UpdateCredentials $ Replace $ Just $ Credentials pk hpw]

-- | Retrieve the wallet state for the wallet with the given ID.
readWallet
:: forall ctx s
Expand Down Expand Up @@ -3022,10 +3045,10 @@ attachPrivateKey
-> (KeyOf s 'RootK XPrv, PassphraseHash)
-> PassphraseScheme
-> IO ()
attachPrivateKey db (xprv, hpwd) scheme = db & \DBLayer{..} -> do
attachPrivateKey db pk scheme = db & \DBLayer{..} -> do
now <- liftIO getCurrentTime
atomically $ do
putPrivateKey (xprv, hpwd)
putPrivateKey walletState pk
meta <- readWalletMeta walletState
let modify x = x
{ passphraseInfo = Just $ WalletPassphraseInfo
Expand Down Expand Up @@ -3063,7 +3086,7 @@ withRootKey DBLayer{..} wid pwd embed action = do
(xprv, scheme) <- withExceptT embed . ExceptT . atomically $ do
wMetadata <- readWalletMeta walletState
let mScheme = passphraseScheme <$> passphraseInfo wMetadata
mXPrv <- readPrivateKey
mXPrv <- readPrivateKey walletState
pure $ case (mXPrv, mScheme) of
(Just (xprv, hpwd), Just scheme) ->
case checkPassphrase scheme pwd hpwd of
Expand Down
41 changes: 0 additions & 41 deletions lib/wallet/src/Cardano/Wallet/DB.hs
Expand Up @@ -29,7 +29,6 @@ module Cardano.Wallet.DB
, DBCheckpoints (..)
, DBDelegation (..)
, DBTxHistory (..)
, DBPrivateKey (..)
, mkDBLayerFromParts

, hoistDBLayer
Expand All @@ -40,10 +39,6 @@ module Cardano.Wallet.DB

import Prelude

import Cardano.Address.Derivation
( XPrv )
import Cardano.Wallet.Address.Derivation
( Depth (..) )
import Cardano.Wallet.DB.Errors
import Cardano.Wallet.DB.Store.Submissions.Layer
( getInSubmissionTransaction, getInSubmissionTransactions )
Expand All @@ -59,12 +54,8 @@ import Cardano.Wallet.DB.Store.Wallets.Model
( DeltaTxWalletsHistory )
import Cardano.Wallet.DB.WalletState
( DeltaWalletState, WalletState (submissions), updateSubmissions )
import Cardano.Wallet.Flavor
( KeyOf )
import Cardano.Wallet.Primitive.Model
( Wallet, currentTip )
import Cardano.Wallet.Primitive.Passphrase
( PassphraseHash )
import Cardano.Wallet.Primitive.Slotting
( TimeInterpreter, epochOf, hoistTimeInterpreter, interpretQuery )
import Cardano.Wallet.Primitive.Types
Expand Down Expand Up @@ -305,19 +296,6 @@ data DBLayer m s = forall stm. (MonadIO stm, MonadFail stm) => DBLayer
-- ^ Removes any expired transactions from the pending set and marks
-- their status as expired.

, putPrivateKey
:: (KeyOf s 'RootK XPrv, PassphraseHash)
-> stm ()
-- ^ Store or replace a private key for a given wallet. Note that wallet
-- _could_ be stored and manipulated without any private key associated
-- to it. A private key is only seldomly required for very specific
-- operations (like transaction signing).

, readPrivateKey
:: stm (Maybe (KeyOf s 'RootK XPrv, PassphraseHash))
-- ^ Read a previously stored private key and its associated passphrase
-- hash.

, readGenesisParameters
:: stm (Maybe GenesisParameters)
-- ^ Read the *Byron* genesis parameters.
Expand Down Expand Up @@ -402,7 +380,6 @@ data DBLayerCollection stm m s = DBLayerCollection
{ dbCheckpoints :: DBCheckpoints stm s
, dbDelegation :: DBDelegation stm
, dbTxHistory :: DBTxHistory stm
, dbPrivateKey :: DBPrivateKey stm (KeyOf s)

-- The following two functions will need to be split up
-- and distributed the smaller layer parts as well.
Expand Down Expand Up @@ -486,8 +463,6 @@ mkDBLayerFromParts ti wid_ DBLayerCollection{..} = DBLayer
, rollForwardTxSubmissions = \tip txs ->
updateSubmissionsNoError dbCheckpoints
$ \_ -> Sbms.rollForwardTxSubmissions tip txs
, putPrivateKey = putPrivateKey_ dbPrivateKey
, readPrivateKey = readPrivateKey_ dbPrivateKey
, readGenesisParameters = readGenesisParameters_ dbCheckpoints
, rollbackTo = rollbackTo_
, atomically = atomically_
Expand Down Expand Up @@ -611,22 +586,6 @@ data DBTxHistory stm = DBTxHistory
}


-- | A database layer for storing the private key.
data DBPrivateKey stm k = DBPrivateKey
{ putPrivateKey_
:: (k 'RootK XPrv, PassphraseHash)
-> stm ()
-- ^ Store or replace a private key for a given wallet. Note that wallet
-- _could_ be stored and manipulated without any private key associated
-- to it. A private key is only seldomly required for very specific
-- operations (like transaction signing).

, readPrivateKey_
:: stm (Maybe (k 'RootK XPrv, PassphraseHash))
-- ^ Read a previously stored private key and its associated passphrase
-- hash.
}

{-----------------------------------------------------------------------------
Helper functions
------------------------------------------------------------------------------}
Expand Down
59 changes: 0 additions & 59 deletions lib/wallet/src/Cardano/Wallet/DB/Layer.hs
Expand Up @@ -41,8 +41,6 @@ module Cardano.Wallet.DB.Layer

import Prelude

import Cardano.Address.Derivation
( XPrv )
import Cardano.BM.Data.Severity
( Severity (..) )
import Cardano.BM.Data.Tracer
Expand All @@ -64,10 +62,6 @@ import Cardano.DB.Sqlite.Delete
)
import Cardano.Slotting.Slot
( WithOrigin (..) )
import Cardano.Wallet.Address.Derivation
( Depth (..) )
import Cardano.Wallet.Address.Keys.PersistPrivateKey
( serializeXPrv, unsafeDeserializeXPrv )
import Cardano.Wallet.Address.Keys.WalletKey
( keyTypeDescriptor )
import Cardano.Wallet.Checkpoints
Expand All @@ -81,7 +75,6 @@ import Cardano.Wallet.DB
, DBLayerCollection (..)
, DBLayerParams (..)
, DBOpen (..)
, DBPrivateKey (..)
, DBTxHistory (..)
, ErrNotGenesisBlockHeader (ErrNotGenesisBlockHeader)
, ErrWalletAlreadyInitialized (ErrWalletAlreadyInitialized)
Expand All @@ -97,7 +90,6 @@ import Cardano.Wallet.DB.Sqlite.Schema
, DelegationReward (..)
, EntityField (..)
, Key (..)
, PrivateKey (..)
, StakeKeyCertificate (..)
, TxMeta (..)
, Wallet (..)
Expand Down Expand Up @@ -143,8 +135,6 @@ import Cardano.Wallet.DB.WalletState
)
import Cardano.Wallet.Flavor
( KeyFlavorS, WalletFlavorS, keyOfWallet )
import Cardano.Wallet.Primitive.Passphrase.Types
( PassphraseHash )
import Cardano.Wallet.Primitive.Slotting
( TimeInterpreter, firstSlotInEpoch, hoistTimeInterpreter, interpretQuery )
import Cardano.Wallet.Read.Eras.EraValue
Expand Down Expand Up @@ -190,7 +180,6 @@ import Database.Persist.Sql
, Filter
, SelectOpt (..)
, deleteWhere
, insert_
, repsert
, selectFirst
, selectKeysList
Expand All @@ -216,7 +205,6 @@ import UnliftIO.MVar
( modifyMVar, modifyMVar_, newMVar, readMVar, withMVar )

import qualified Cardano.Wallet.Primitive.Model as W
import qualified Cardano.Wallet.Primitive.Passphrase as W
import qualified Cardano.Wallet.Primitive.Types as W
import qualified Cardano.Wallet.Primitive.Types.Coin as Coin
import qualified Cardano.Wallet.Primitive.Types.Hash as W
Expand Down Expand Up @@ -649,8 +637,6 @@ newDBFreshFromDBOpen wF ti wid_ DBOpen{atomically=atomically_} =
dbDelegation = mkDBDelegation ti wid_


dbPrivateKey = mkDBPrivateKey (keyOfWallet wF) wid_

mkDBFreshFromParts
:: forall stm m s
. ( PersistAddressBook s
Expand Down Expand Up @@ -833,42 +819,7 @@ genesisParametersFromEntity (Wallet _ _ _ _ _ hash startTime) =
, W.getGenesisBlockDate = W.StartTime startTime
}

{-----------------------------------------------------------------------
Private Key store
-----------------------------------------------------------------------}
mkDBPrivateKey
:: forall k
. KeyFlavorS k
-> W.WalletId
-> DBPrivateKey (SqlPersistT IO) k
mkDBPrivateKey keyF wid = DBPrivateKey
{ putPrivateKey_ = \key -> do
deleteWhere [PrivateKeyWalletId ==. wid]
insert_ (mkPrivateKeyEntity keyF wid key)
, readPrivateKey_ = selectPrivateKey keyF wid
}

mkPrivateKeyEntity
:: forall k
. KeyFlavorS k
-> W.WalletId
-> (k 'RootK XPrv, W.PassphraseHash)
-> PrivateKey
mkPrivateKeyEntity keyF wid kh = PrivateKey
{ privateKeyWalletId = wid
, privateKeyRootKey = root
, privateKeyHash = hash
}
where
(root, hash) = serializeXPrv keyF kh

privateKeyFromEntity
:: forall k
. KeyFlavorS k
-> PrivateKey
-> (k 'RootK XPrv, PassphraseHash)
privateKeyFromEntity keyF (PrivateKey _ k h) =
unsafeDeserializeXPrv keyF (k, h)

{-------------------------------------------------------------------------------
SQLite database operations
Expand Down Expand Up @@ -948,16 +899,6 @@ selectTransactionInfo ti tip lookupTx lookupTxOut meta = do
Left _ -> error "failed to extract cbor for era"
liftIO . evaluate $ force result

selectPrivateKey
:: forall k m
. MonadIO m
=> KeyFlavorS k
-> W.WalletId
-> SqlPersistT m (Maybe (k 'RootK XPrv, PassphraseHash))
selectPrivateKey keyF wid = do
keys <- selectFirst [PrivateKeyWalletId ==. wid] []
pure $ (privateKeyFromEntity keyF . entityVal) <$> keys

selectGenesisParameters
:: MonadIO m
=> W.WalletId
Expand Down
10 changes: 0 additions & 10 deletions lib/wallet/src/Cardano/Wallet/DB/Pure/Layer.hs
Expand Up @@ -33,12 +33,10 @@ import Cardano.Wallet.DB.Pure.Implementation
, mPutCheckpoint
, mPutDelegationCertificate
, mPutDelegationRewardBalance
, mPutPrivateKey
, mPutTxHistory
, mReadCheckpoint
, mReadDelegationRewardBalance
, mReadGenesisParameters
, mReadPrivateKey
, mReadTxHistory
, mRollbackTo
)
Expand Down Expand Up @@ -159,14 +157,6 @@ newDBFresh timeInterpreter wid = do
[] -> pure Nothing
t:_ -> pure $ Just t

{-----------------------------------------------------------------------
Keystore
-----------------------------------------------------------------------}

, putPrivateKey = noErrorAlterDB db . mPutPrivateKey

, readPrivateKey = join <$> readDBMaybe db mReadPrivateKey

{-----------------------------------------------------------------------
Pending Tx
-----------------------------------------------------------------------}
Expand Down
3 changes: 1 addition & 2 deletions lib/wallet/src/Cardano/Wallet/DB/Store/PrivateKey/Store.hs
Expand Up @@ -11,7 +11,6 @@
-- License: Apache-2.0
module Cardano.Wallet.DB.Store.PrivateKey.Store
( mkStorePrivateKey
, HashedCredentials (..)
, DeltaPrivateKey
, StorePrivateKey
) where
Expand All @@ -25,7 +24,7 @@ import Cardano.Wallet.Flavor
import Cardano.Wallet.Primitive.Types
( WalletId )
import Cardano.Wallet.Primitive.Types.Credentials
( Credentials (..), HashedCredentials (..) )
( Credentials (..), HashedCredentials )
import Control.Exception
( SomeException (..) )
import Control.Monad.Class.MonadThrow
Expand Down
4 changes: 3 additions & 1 deletion lib/wallet/src/Cardano/Wallet/DB/WalletState.hs
Expand Up @@ -53,7 +53,7 @@ import Cardano.Wallet.Checkpoints
import Cardano.Wallet.DB.Store.Info.Store
( DeltaWalletInfo, WalletInfo (..) )
import Cardano.Wallet.DB.Store.PrivateKey.Store
( DeltaPrivateKey, HashedCredentials )
( DeltaPrivateKey )
import Cardano.Wallet.DB.Store.Submissions.Layer
( emptyTxSubmissions )
import Cardano.Wallet.DB.Store.Submissions.Operations
Expand All @@ -62,6 +62,8 @@ import Cardano.Wallet.Flavor
( KeyOf )
import Cardano.Wallet.Primitive.Types
( BlockHeader )
import Cardano.Wallet.Primitive.Types.Credentials
( HashedCredentials )
import Cardano.Wallet.Primitive.Types.UTxO
( UTxO )
import Data.Delta
Expand Down

0 comments on commit fe734a6

Please sign in to comment.