-
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
Generate DBLayer tests with quickcheck-state-machine #259
Merged
+1,103
−158
Merged
Changes from 9 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
10d9ee5
Generate DBLayer tests with quickcheck-state-machine
rvl ad0c18e
Move cleanDB to DBLayer
rvl ddfeb8c
run sqlite migration silently
KtorZ 2691f0b
Sqlite: Make listWallets ordering explicit
rvl aa5e7a6
Sqlite: Transaction inputs need to be ordered
rvl e070326
Disable QSM parallel tests until we're sure they work
rvl e6a456d
QSM: Adjust the putTxHistory model to handle updating transactions
rvl e4b8064
Sqlite: Allow adding the same transaction with putTxHistory
rvl bb7895b
SqliteSpec: Skip TxHistory put+read tests for Sqlite
rvl 2ddf77d
DBLayer QSM: Remove WalletId expressions
rvl 575746d
DBSpec: Fix comment on Arbitrary TxIn
rvl 8987eb1
re-enable prop_sequential_put for tx history
KtorZ a503220
Call 'cleanDB' before each property run.
KtorZ 8d973f2
remove redundant constraints
KtorZ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
{-# LANGUAGE AllowAmbiguousTypes #-} | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE DeriveGeneric #-} | ||
{-# LANGUAGE DuplicateRecordFields #-} | ||
{-# LANGUAGE LambdaCase #-} | ||
{-# LANGUAGE OverloadedLabels #-} | ||
|
@@ -14,6 +15,7 @@ | |
|
||
module Cardano.Wallet.DB.Sqlite | ||
( newDBLayer | ||
, DummyState(..) | ||
) where | ||
|
||
import Prelude | ||
|
@@ -71,8 +73,6 @@ import Control.Monad.Trans.Maybe | |
( MaybeT (..) ) | ||
import Control.Monad.Trans.Resource | ||
( runResourceT ) | ||
import Data.Bifunctor | ||
( bimap ) | ||
import Data.Coerce | ||
( coerce ) | ||
import Data.Either | ||
|
@@ -97,7 +97,7 @@ import Database.Persist.Sql | |
, insert_ | ||
, putMany | ||
, rawExecute | ||
, runMigration | ||
, runMigrationSilent | ||
, runSqlConn | ||
, selectFirst | ||
, selectKeysList | ||
|
@@ -112,6 +112,8 @@ import Database.Persist.Sqlite | |
( SqlBackend, SqlPersistM, SqlPersistT, wrapConnection ) | ||
import Database.Sqlite | ||
( Error (ErrorConstraint), SqliteException (SqliteException) ) | ||
import GHC.Generics | ||
( Generic ) | ||
import System.IO | ||
( stderr ) | ||
import System.Log.FastLogger | ||
|
@@ -184,7 +186,7 @@ newDBLayer fp = do | |
conn <- createSqliteBackend fp (dbLogs [LevelError]) | ||
let runQuery' = withMVar bigLock . const . runQuery conn | ||
|
||
runQuery' $ void $ runMigration migrateAll | ||
runQuery' $ void $ runMigrationSilent migrateAll | ||
runQuery' addIndexes | ||
|
||
return $ DBLayer | ||
|
@@ -213,7 +215,8 @@ newDBLayer fp = do | |
Nothing -> pure $ Left $ ErrNoSuchWallet wid | ||
|
||
, listWallets = runQuery' $ | ||
map (PrimaryKey . unWalletKey) <$> selectKeysList [] [] | ||
map (PrimaryKey . unWalletKey) <$> | ||
selectKeysList [] [Asc WalTableId] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wondering: is there any particular reason for this ordering? |
||
|
||
{----------------------------------------------------------------------- | ||
Checkpoints | ||
|
@@ -267,9 +270,7 @@ newDBLayer fp = do | |
Just _ -> do | ||
let (metas, txins, txouts) = mkTxHistory wid txs | ||
putTxMetas wid metas | ||
putMany txins | ||
putMany txouts | ||
deleteLooseTransactions | ||
putTxs (TxId <$> Map.keys txs) txins txouts | ||
pure $ Right () | ||
Nothing -> pure $ Left $ ErrNoSuchWallet wid | ||
|
||
|
@@ -381,11 +382,10 @@ mkCheckpointEntity | |
-> W.Wallet s t | ||
-> (Checkpoint, [UTxO], [PendingTx], [TxIn], [TxOut]) | ||
mkCheckpointEntity wid wal = | ||
( cp, utxo, map (pendingTx . fst) pending | ||
, concatMap (dist pendingTxIn . fmap W.inputs) pending | ||
, concatMap (dist pendingTxOut . fmap (zip [0..] . W.outputs)) pending ) | ||
(cp, utxo, map (pendingTx . TxId . fst) pending, ins, outs) | ||
where | ||
pending = [(TxId (W.txId @t tx), tx) | tx <- Set.toList (W.getPending wal)] | ||
pending = [(W.txId @t tx, tx) | tx <- Set.toList (W.getPending wal)] | ||
(ins, outs) = mkTxInputsOutputs pending | ||
sl = W.currentTip wal | ||
cp = Checkpoint | ||
{ checkpointTableWalletId = wid | ||
|
@@ -396,22 +396,12 @@ mkCheckpointEntity wid wal = | |
, pendingTxTableCheckpointSlot = sl | ||
, pendingTxTableId2 = tid | ||
} | ||
pendingTxIn tid txIn = TxIn | ||
{ txInputTableTxId = tid | ||
, txInputTableSourceTxId = TxId (W.inputId txIn) | ||
, txInputTableSourceIndex = W.inputIx txIn | ||
} | ||
pendingTxOut tid (ix, txOut) = TxOut | ||
{ txOutputTableTxId = tid | ||
, txOutputTableIndex = ix | ||
, txOutputTableAddress = W.address txOut | ||
, txOutputTableAmount = W.coin txOut | ||
} | ||
utxo = [ UTxO wid sl (TxId input) ix addr coin | ||
| (W.TxIn input ix, W.TxOut addr coin) <- utxoMap ] | ||
utxoMap = Map.assocs (W.getUTxO (W.totalUTxO wal)) | ||
|
||
-- inputs and outputs must be sorted by txid, then ix | ||
-- note: TxIn records must already be sorted by order | ||
-- and TxOut records must already by sorted by index. | ||
checkpointFromEntity | ||
:: forall s t. (W.IsOurs s, NFData s, Show s, W.TxId t) | ||
=> Checkpoint | ||
|
@@ -426,7 +416,7 @@ checkpointFromEntity (Checkpoint _ tip) utxo ins outs = | |
utxo' = W.UTxO . Map.fromList $ | ||
[ (W.TxIn input ix, W.TxOut addr coin) | ||
| UTxO _ _ (TxId input) ix addr coin <- utxo ] | ||
ins' = [(txid, W.TxIn src ix) | TxIn txid (TxId src) ix <- ins] | ||
ins' = [(txid, W.TxIn src ix) | TxIn txid _ (TxId src) ix <- ins] | ||
outs' = [ (txid, W.TxOut addr amt) | ||
| TxOut txid _ix addr amt <- outs ] | ||
txids = Set.fromList $ map fst ins' ++ map fst outs' | ||
|
@@ -440,25 +430,36 @@ mkTxHistory | |
:: W.WalletId | ||
-> Map.Map (W.Hash "Tx") (W.Tx, W.TxMeta) | ||
-> ([TxMeta], [TxIn], [TxOut]) | ||
mkTxHistory wid txs = | ||
( map (uncurry (mkTxMetaEntity wid)) metas | ||
, concatMap (dist mkTxIn . fmap W.inputs) hist | ||
, concatMap (dist mkTxOut . fmap (zip [0..] . W.outputs)) hist ) | ||
mkTxHistory wid txs = (map (uncurry (mkTxMetaEntity wid)) metas, ins, outs) | ||
where | ||
pairs = Map.toList txs | ||
metas = fmap snd <$> pairs | ||
hist = bimap TxId fst <$> pairs | ||
mkTxIn tid txIn = TxIn | ||
{ txInputTableTxId = tid | ||
hist = fmap fst <$> pairs | ||
(ins, outs) = mkTxInputsOutputs hist | ||
|
||
mkTxInputsOutputs :: [(W.Hash "Tx", W.Tx)] -> ([TxIn], [TxOut]) | ||
mkTxInputsOutputs txs = | ||
( concatMap (dist mkTxIn . ordered W.inputs) txs | ||
, concatMap (dist mkTxOut . ordered W.outputs) txs ) | ||
where | ||
mkTxIn tid (ix, txIn) = TxIn | ||
{ txInputTableTxId = TxId tid | ||
, txInputTableOrder = ix | ||
, txInputTableSourceTxId = TxId (W.inputId txIn) | ||
, txInputTableSourceIndex = W.inputIx txIn | ||
} | ||
mkTxOut tid (ix, txOut) = TxOut | ||
{ txOutputTableTxId = tid | ||
{ txOutputTableTxId = TxId tid | ||
, txOutputTableIndex = ix | ||
, txOutputTableAddress = W.address txOut | ||
, txOutputTableAmount = W.coin txOut | ||
} | ||
ordered f = fmap (zip [0..] . f) | ||
-- | Distribute `a` accross many `b`s using the given function. | ||
-- >>> dist TxOut (addr, [Coin 1, Coin 42, Coin 14]) | ||
-- [TxOut addr (Coin 1), TxOut addr (Coin 42), TxOut addr (Coin 14)] | ||
dist :: (a -> b -> c) -> (a, [b]) -> [c] | ||
dist f (a, bs) = [f a b | b <- bs] | ||
|
||
mkTxMetaEntity :: W.WalletId -> W.Hash "Tx" -> W.TxMeta -> TxMeta | ||
mkTxMetaEntity wid txid meta = TxMeta | ||
|
@@ -471,7 +472,8 @@ mkTxMetaEntity wid txid meta = TxMeta | |
} | ||
where getAmount (Quantity n) = n | ||
|
||
-- note: TxOut records must already be sorted by index | ||
-- note: TxIn records must already be sorted by order | ||
-- and TxOut records must already be sorted by index | ||
txHistoryFromEntity | ||
:: [TxMeta] | ||
-> [TxIn] | ||
|
@@ -548,6 +550,14 @@ putTxMetas wid metas = do | |
, TxMetaTableTxId <-. map txMetaTableTxId metas ] | ||
insertMany_ metas | ||
|
||
-- | Insert multiple transactions, removing old instances first. | ||
putTxs :: [TxId] -> [TxIn] -> [TxOut] -> SqlPersistM () | ||
putTxs txIds txins txouts = do | ||
deleteWhere [TxInputTableTxId <-. txIds] | ||
putMany txins | ||
deleteWhere [TxOutputTableTxId <-. txIds] | ||
putMany txouts | ||
|
||
-- | Delete transactions that aren't referred to by either Pending or TxMeta of | ||
-- any wallet. | ||
deleteLooseTransactions :: SqlPersistM () | ||
|
@@ -584,7 +594,7 @@ selectTxs | |
-> SqlPersistM ([TxIn], [TxOut]) | ||
selectTxs txids = do | ||
ins <- fmap entityVal <$> selectList [TxInputTableTxId <-. txids] | ||
[Asc TxInputTableTxId, Asc TxInputTableSourceIndex] | ||
[Asc TxInputTableTxId, Asc TxInputTableOrder] | ||
outs <- fmap entityVal <$> selectList [TxOutputTableTxId <-. txids] | ||
[Asc TxOutputTableTxId, Asc TxOutputTableIndex] | ||
pure (ins, outs) | ||
|
@@ -595,10 +605,7 @@ selectTxHistory | |
selectTxHistory wid = do | ||
metas <- fmap entityVal <$> selectList [TxMetaTableWalletId ==. wid] [] | ||
let txids = map txMetaTableTxId metas | ||
ins <- fmap entityVal <$> selectList [TxInputTableTxId <-. txids] | ||
[Asc TxInputTableTxId, Asc TxInputTableSourceIndex] | ||
outs <- fmap entityVal <$> selectList [TxOutputTableTxId <-. txids] | ||
[Asc TxOutputTableTxId, Asc TxOutputTableIndex] | ||
(ins, outs) <- selectTxs txids | ||
pure $ txHistoryFromEntity metas ins outs | ||
|
||
--------------------------------------------------------------------------- | ||
|
@@ -692,11 +699,11 @@ selectSeqStatePendingIxs ssid = | |
where | ||
fromRes = fmap (W.Index . seqStatePendingIxIndex . entityVal) | ||
|
||
---------------------------------------------------------------------------- | ||
-- Utilities | ||
data DummyState = DummyState | ||
deriving (Show, Eq, Generic) | ||
|
||
-- | Distribute `a` accross many `b`s using the given function. | ||
-- >>> dist TxOut (addr, [Coin 1, Coin 42, Coin 14]) | ||
-- [TxOut addr (Coin 1), TxOut addr (Coin 42), TxOut addr (Coin 14)] | ||
dist :: (a -> b -> c) -> (a, [b]) -> [c] | ||
dist f (a, bs) = [f a b | b <- bs] | ||
instance PersistState DummyState where | ||
insertState (wid, sl) _ = insert_ (SeqState wid sl) | ||
selectState (wid, sl) = fmap (const DummyState) <$> | ||
selectFirst [SeqStateTableWalletId ==. wid, SeqStateTableCheckpointSlot ==. sl] [] | ||
deleteState wid = deleteWhere [SeqStateTableWalletId ==. wid] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be in the source code IMO :/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 am not sure we do want to keep this in the source code. This is purely for testing.