Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
76d0215
commit 2127aba
Showing
5 changed files
with
169 additions
and
24 deletions.
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 |
---|---|---|
@@ -0,0 +1,70 @@ | ||
{-# LANGUAGE DeriveAnyClass #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
|
||
module Hydra.Generator where | ||
|
||
import Hydra.Prelude hiding (size) | ||
|
||
import Control.Monad (foldM) | ||
import qualified Data.List as List | ||
import Hydra.Ledger (Utxo) | ||
import Hydra.Ledger.Cardano ( | ||
CardanoKeyPair, | ||
CardanoTx, | ||
genFixedSizeSequenceOfValidTransactions, | ||
genKeyPair, | ||
genOneUtxoFor, | ||
genUtxo, | ||
mkSimpleCardanoTx, | ||
mkVkAddress, | ||
utxoFromTx, | ||
utxoToList, | ||
utxoValue, | ||
verificationKey, | ||
) | ||
import Test.QuickCheck (Gen, generate) | ||
import Test.QuickCheck.Gen (Gen (MkGen)) | ||
import Test.QuickCheck.Random (mkQCGen) | ||
|
||
-- | A 'Dataset' that can be run for testing purpose. | ||
-- The 'transactionSequence' is guaranteed to be applicable, in sequence, to the 'initialUtxo' | ||
-- set. | ||
data Dataset = Dataset | ||
{ initialUtxo :: Utxo CardanoTx | ||
, transactionsSequence :: [CardanoTx] | ||
} | ||
deriving (Eq, Show, Generic, ToJSON, FromJSON) | ||
|
||
-- | Generate an arbitrary UTXO set and a sequence of transactions for this set. | ||
generateDataset :: Int -> IO Dataset | ||
generateDataset sequenceLength = do | ||
initialUtxo <- generate genUtxo | ||
transactionsSequence <- generate $ genFixedSizeSequenceOfValidTransactions sequenceLength initialUtxo | ||
pure Dataset{initialUtxo, transactionsSequence} | ||
|
||
-- | Generate a 'Dataset' which does not grow the UTXO set over time. | ||
generateConstantUtxoDataset :: Int -> IO Dataset | ||
generateConstantUtxoDataset = generate . genConstantUtxoDataset | ||
|
||
genConstantUtxoDataset :: Int -> Gen Dataset | ||
genConstantUtxoDataset len = do | ||
keyPair <- genKeyPair | ||
initialUtxo <- genOneUtxoFor (verificationKey keyPair) | ||
|
||
transactionsSequence <- reverse . thrd <$> foldM generateOneTransfer (initialUtxo, keyPair, []) [1 .. len] | ||
pure $ Dataset{initialUtxo, transactionsSequence} | ||
where | ||
thrd (_, _, c) = c | ||
generateOneTransfer (utxo, keyPair, txs) _ = do | ||
recipient <- genKeyPair | ||
let txin = List.head $ utxoToList utxo | ||
tx = mkSimpleCardanoTx txin (mkVkAddress (verificationKey recipient), utxoValue utxo) keyPair | ||
utxo' = utxoFromTx tx | ||
pure $ (utxo', recipient, tx : txs) | ||
|
||
mkCredentials :: Int -> CardanoKeyPair | ||
mkCredentials = generateWith genKeyPair | ||
|
||
generateWith :: Gen a -> Int -> a | ||
generateWith (MkGen runGen) seed = | ||
runGen (mkQCGen seed) 30 |
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 |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{-# OPTIONS_GHC -Wno-deprecations #-} | ||
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} | ||
|
||
module Test.GeneratorSpec where | ||
|
||
import Hydra.Prelude | ||
import Test.Hydra.Prelude | ||
|
||
import Data.Aeson (eitherDecode, encode) | ||
import qualified Data.ByteString.Lazy as LBS | ||
import Data.Text (unpack) | ||
import Hydra.Generator (Dataset (..), genConstantUtxoDataset) | ||
import Hydra.Ledger (Utxo, applyTransactions) | ||
import Hydra.Ledger.Cardano as Ledger | ||
import Test.QuickCheck (Positive (Positive), Property, counterexample, forAll) | ||
|
||
spec :: Spec | ||
spec = parallel $ do | ||
prop "compute values from UTXO set" prop_computeValueFromUtxo | ||
prop "generates a Dataset that keeps UTXO constant" prop_keepsUtxoConstant | ||
it "correctly applies generated dataset" $ do | ||
let result = eitherDecode sample | ||
case result of | ||
Left err -> failure $ show err | ||
Right Dataset{initialUtxo, transactionsSequence} -> do | ||
let finalUtxo = foldl' apply initialUtxo transactionsSequence | ||
|
||
Ledger.size finalUtxo `shouldBe` Ledger.size initialUtxo | ||
|
||
sample :: LBS.ByteString | ||
sample = "{\"initialUtxo\":{\"03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314#355\":{\"address\":\"addr_test1vp5thrqjwutvmyuv7z29m4d89m920hx0esa4k62v3sn69vq6wd4s9\",\"value\":{\"lovelace\":1}}},\"transactionsSequence\":[{\"witnesses\":{\"scripts\":{},\"keys\":[\"820082582081822e271db8f620bd5114ea5ab6230893f2a4023dcbc22af4534dc57aaa6c57584013c7f57c39b2496c4f1394cb72f9e2dd8c1c09cbf91002c0084a9444430b7cf531e2e9faf412a8a7eed984d8af2df06aa4cd0d78127ca753bb827f9a313cbb03\"]},\"body\":{\"outputs\":[{\"address\":\"addr_test1vzfngrkamuwyl4l7c0a7hmvgw6c8n23cpxgvte0a9jrnvts47xzsz\",\"value\":{\"lovelace\":1}}],\"mint\":{\"lovelace\":0},\"auxiliaryDataHash\":null,\"withdrawals\":[],\"certificates\":[],\"fees\":0,\"inputs\":[\"03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314#355\"],\"validity\":{\"notBefore\":null,\"notAfter\":null}},\"id\":\"45d2b14e693c054e5263c9cd21fb7425c71fec21d800dff55e26e0ede4257ef0\",\"auxiliaryData\":null},{\"witnesses\":{\"scripts\":{},\"keys\":[\"8200825820639edbce929ccafb73bc1bdf9b9cc909895c91a92607c245a36008d989a8194a584043ffeb945ed3d01a2119b7b0ddaeab60b9b8c6c7eb068542ac6c274ae8519fc4c48b7e642120618b926ae74f599c9aeba64d274a41ed0fd6a5ce355a4ebeab0d\"]},\"body\":{\"outputs\":[{\"address\":\"addr_test1vr8x79xestxpf6zr9699h6wcp9gdlrs3mf0fgrznz4akylgzvg0ra\",\"value\":{\"lovelace\":1}}],\"mint\":{\"lovelace\":0},\"auxiliaryDataHash\":null,\"withdrawals\":[],\"certificates\":[],\"fees\":0,\"inputs\":[\"45d2b14e693c054e5263c9cd21fb7425c71fec21d800dff55e26e0ede4257ef0#0\"],\"validity\":{\"notBefore\":null,\"notAfter\":null}},\"id\":\"0f454f74df9f83e5b604570d87b1c44d9aeb3ed745dbc560242568d193ac5620\",\"auxiliaryData\":null}]}" | ||
|
||
prop_computeValueFromUtxo :: Property | ||
prop_computeValueFromUtxo = | ||
forAll genUtxo $ \utxo -> | ||
utxoValue utxo /= mempty | ||
|
||
prop_keepsUtxoConstant :: Property | ||
prop_keepsUtxoConstant = | ||
forAll arbitrary $ \(Positive n) -> | ||
forAll (genConstantUtxoDataset n) $ \Dataset{initialUtxo, transactionsSequence} -> | ||
let finalUtxo = foldl' apply initialUtxo transactionsSequence | ||
in Ledger.size finalUtxo == Ledger.size initialUtxo | ||
& counterexample ("\ntransactions: " <> jsonString transactionsSequence) | ||
& counterexample ("\nutxo: " <> jsonString initialUtxo) | ||
|
||
apply :: Utxo CardanoTx -> CardanoTx -> Utxo CardanoTx | ||
apply utxo tx = | ||
case applyTransactions Ledger.cardanoLedger utxo [tx] of | ||
Left err -> error $ "invalid generated data set" <> show err | ||
Right finalUtxo -> finalUtxo | ||
|
||
jsonString :: ToJSON a => a -> String | ||
jsonString = unpack . decodeUtf8 . encode |