Skip to content

Commit

Permalink
WIP Sqlite: Add a class for saving/restoring wallet state
Browse files Browse the repository at this point in the history
  • Loading branch information
rvl committed May 16, 2019
1 parent 6e98bb6 commit 80bcb7f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 10 deletions.
15 changes: 14 additions & 1 deletion lib/core/src/Cardano/Wallet/DB.hs
Expand Up @@ -12,6 +12,7 @@ module Cardano.Wallet.DB
( -- * Interface
DBLayer(..)
, PrimaryKey(..)
, PersistState(..)

-- * Errors
, ErrNoSuchWallet(..)
Expand All @@ -30,6 +31,8 @@ import Cardano.Wallet.Primitive.Types
( Hash, Tx, TxId, TxMeta, WalletId, WalletMetadata )
import Control.DeepSeq
( NFData )
import Control.Monad.IO.Class
( MonadIO (..) )
import Control.Monad.Trans.Except
( ExceptT )
import Data.Map.Strict
Expand All @@ -39,7 +42,7 @@ import Data.Map.Strict
-- | A Database interface for storing various things in a DB. In practice,
-- we'll need some extra contraints on the wallet state that allows us to
-- serialize and unserialize it (e.g. @forall s. (Serialize s) => ...@)
data (IsOurs s, NFData s, Show s, TxId t) => DBLayer m s t = DBLayer
data (IsOurs s, NFData s, Show s, PersistState s, TxId t) => DBLayer m s t = DBLayer
{ createWallet
:: PrimaryKey WalletId
-> Wallet s t
Expand Down Expand Up @@ -150,3 +153,13 @@ newtype ErrWalletAlreadyExists
-- (like for instance, the last known network tip).
newtype PrimaryKey key = PrimaryKey key
deriving (Eq, Ord)

----------------------------------------------------------------------------

class PersistState s where
putState :: MonadIO m => Wallet s t -> s -> m ()
readState :: MonadIO m => Wallet s t -> m (Maybe s)
addressScheme :: Wallet s t -> Int
-- putState :: MonadIO m => (WalletId, SlotId) -> s -> ReaderT SqlBackend m ()
-- readState :: MonadIO m => (WalletId, SlotId) -> ReaderT SqlBackend m (Maybe s)
-- addressScheme :: s -> AddressScheme
3 changes: 2 additions & 1 deletion lib/core/src/Cardano/Wallet/DB/MVar.hs
Expand Up @@ -21,6 +21,7 @@ import Cardano.Wallet.DB
, ErrNoSuchWallet (..)
, ErrWalletAlreadyExists (..)
, PrimaryKey (..)
, PersistState (..)
)
import Cardano.Wallet.Primitive.AddressDerivation
( Depth (..), Key, XPrv )
Expand Down Expand Up @@ -53,7 +54,7 @@ data Database s t = Database
-- | Instantiate a new in-memory "database" layer that simply stores data in
-- a local MVar. Data vanishes if the software is shut down.
newDBLayer
:: forall s t. (IsOurs s, NFData s, Show s, TxId t)
:: forall s t. (IsOurs s, PersistState s, NFData s, Show s, TxId t)
=> IO (DBLayer IO s t)
newDBLayer = do
lock <- newMVar ()
Expand Down
13 changes: 7 additions & 6 deletions lib/core/src/Cardano/Wallet/DB/Sqlite.hs
Expand Up @@ -28,6 +28,7 @@ import Cardano.Wallet.DB
( DBLayer (..)
, ErrNoSuchWallet (..)
, ErrWalletAlreadyExists (..)
, PersistState (..)
, PrimaryKey (..)
)
import Cardano.Wallet.DB.SqliteTypes
Expand Down Expand Up @@ -291,7 +292,7 @@ runQuery conn = ExceptT . try . runResourceT . runNoLoggingT . flip runSqlConn c
-- If the given file path does not exist, it will be created by the sqlite
-- library.
newDBLayer
:: forall s t. (IsOurs s, NFData s, Show s, W.TxId t)
:: forall s t. (IsOurs s, PersistState s, NFData s, Show s, W.TxId t)
=> Maybe FilePath
-- ^ Database file location, or Nothing for in-memory database
-> IO (DBLayer IO s t)
Expand All @@ -310,7 +311,7 @@ newDBLayer fp = do
Just _ ->
pure $ Left $ ErrWalletAlreadyExists wid
Nothing -> Right <$> do
insert_ (mkWalletEntity wid meta)
insert_ (mkWalletEntity wid (toEnum $ addressScheme cp))
insertCheckpoint wid cp

, removeWallet = \(PrimaryKey wid) ->
Expand Down Expand Up @@ -414,16 +415,16 @@ delegationFromText :: Maybe Text -> W.WalletDelegation W.PoolId
delegationFromText Nothing = W.NotDelegating
delegationFromText (Just pool) = W.Delegating (W.PoolId pool)

mkWalletEntity :: W.WalletId -> W.WalletMetadata -> Wallet
mkWalletEntity wid meta = Wallet
mkWalletEntity :: W.WalletId -> W.WalletMetadata -> AddressScheme -> Wallet
mkWalletEntity wid meta s = Wallet
{ walTableId = wid
, walTableName = meta ^. #name . coerce
, walTablePassphraseLastUpdatedAt = case meta ^. #passphraseInfo of
Nothing -> Nothing
Just (W.WalletPassphraseInfo passInfo) -> Just passInfo
, walTableStatus = meta ^. #status
, walTableDelegation = delegationToText $ meta ^. #delegation
, walTableAddressScheme = Sequential -- fixme: depends on wallet
, walTableAddressScheme = s
}

mkWalletMetadataUpdate :: W.WalletMetadata -> [Update Wallet]
Expand Down Expand Up @@ -614,7 +615,7 @@ selectWallet :: MonadIO m => W.WalletId -> ReaderT SqlBackend m (Maybe Wallet)
selectWallet wid = fmap entityVal <$> selectFirst [WalTableId ==. wid] []

insertCheckpoint
:: (MonadIO m, W.TxId t)
:: (MonadIO m, PersistState s, W.TxId t)
=> W.WalletId
-> W.Wallet s t
-> ReaderT SqlBackend m ()
Expand Down
9 changes: 7 additions & 2 deletions lib/core/src/Cardano/Wallet/DB/SqliteTypes.hs
Expand Up @@ -23,6 +23,10 @@ import Cardano.Wallet.Primitive.Types
)
import Control.Monad
( (>=>) )
import Control.Monad.IO.Class
( MonadIO (..) )
import Control.Monad.Trans.Reader
( ReaderT (..) )
import Data.Aeson
( FromJSON (..)
, ToJSON (..)
Expand Down Expand Up @@ -52,7 +56,7 @@ import Data.Text.Class
import Data.Word
( Word64, Word8 )
import Database.Persist.Sqlite
( PersistField (..), PersistFieldSql (..), PersistValue )
( PersistField (..), PersistFieldSql (..), PersistValue, SqlBackend )
import GHC.Generics
( Generic )
import Web.HttpApiData
Expand All @@ -62,6 +66,7 @@ import Web.PathPieces

import qualified Data.Text as T


----------------------------------------------------------------------------
-- Helper functions

Expand Down Expand Up @@ -130,7 +135,7 @@ instance PathPiece WalletId where
----------------------------------------------------------------------------
-- AddressScheme

data AddressScheme = Sequential | Random | Any deriving (Show, Eq, Generic)
data AddressScheme = Sequential | Random | Any deriving (Show, Eq, Generic, Enum)

instance PersistField AddressScheme where
toPersistValue = toPersistValue . toText
Expand Down

0 comments on commit 80bcb7f

Please sign in to comment.