From cec92a4302fd358d7b46202daa961c14a76b940c Mon Sep 17 00:00:00 2001 From: euonymos Date: Fri, 6 Dec 2024 11:39:42 -0600 Subject: [PATCH] chore: clean up the code --- cabal.project | 2 +- cem-script.cabal | 16 ++- src-lib/cardano-extras/Cardano/Extras.hs | 1 - src-lib/data-spine/Data/Spine.hs | 2 - src/Cardano/CEM.hs | 8 +- src/Cardano/CEM/Indexing/Event.hs | 1 - src/Cardano/CEM/Monads.hs | 5 +- src/Cardano/CEM/Monads/CLB.hs | 4 +- src/Cardano/CEM/Monads/L1.hs | 151 ----------------------- src/Cardano/CEM/Monads/L1Commons.hs | 27 ++-- src/Cardano/CEM/OffChain.hs | 6 +- src/Cardano/CEM/Testing/StateMachine.hs | 40 +++--- test/Oura/Communication.hs | 27 ++-- test/Voting.hs | 15 ++- 14 files changed, 61 insertions(+), 244 deletions(-) delete mode 100644 src/Cardano/CEM/Monads/L1.hs diff --git a/cabal.project b/cabal.project index 0fff610..8c20c37 100644 --- a/cabal.project +++ b/cabal.project @@ -22,7 +22,7 @@ source-repository-package tag: d5b0e7ce07258482d53704ce19383013b1fa6610 --sha256: 6+Os/mQDzBOU+TkTD+n/T1MFcI+Mn0/tcBMJhLRfqyA= --- FIXME: Cannot use new commit, because it requires `plutus-ledger-api==1.29` +-- Cannot use new commit, because it requires `plutus-ledger-api==1.29` source-repository-package type: git location: https://github.com/Plutonomicon/plutarch-plutus diff --git a/cem-script.cabal b/cem-script.cabal index b1defbd..5c4896b 100644 --- a/cem-script.cabal +++ b/cem-script.cabal @@ -15,9 +15,11 @@ flag dev default: True manual: False -common common-lang - -- Options from MLabs styleguide +flag force-recomp + description: Compile with -fforce-recomp and -Wunused-packages + default: False +common common-lang ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints @@ -26,6 +28,12 @@ common common-lang if !flag(dev) ghc-options: -Werror + if flag(dev) + default-extensions: PartialTypeSignatures + + if flag(force-recomp) + ghc-options: -fforce-recomp -Wunused-packages + build-depends: , base , extra @@ -53,9 +61,6 @@ common common-lang UndecidableInstances ViewPatterns - if flag(dev) - default-extensions: PartialTypeSignatures - default-language: GHC2021 common common-onchain @@ -150,7 +155,6 @@ library Cardano.CEM.Indexing.Tx Cardano.CEM.Monads Cardano.CEM.Monads.CLB - Cardano.CEM.Monads.L1 Cardano.CEM.OffChain Cardano.CEM.OnChain Cardano.CEM.Testing.StateMachine diff --git a/src-lib/cardano-extras/Cardano/Extras.hs b/src-lib/cardano-extras/Cardano/Extras.hs index 3186fc5..1826335 100644 --- a/src-lib/cardano-extras/Cardano/Extras.hs +++ b/src-lib/cardano-extras/Cardano/Extras.hs @@ -275,7 +275,6 @@ mintedTokens :: [(AssetName, Quantity)] -> Cardano.TxMintValue BuildTx Era mintedTokens script redeemer assets = - -- FIXME: is hardcoding era correct? TxMintValue Cardano.MaryEraOnwardsBabbage mintedTokens' mintedWitnesses' where mintedTokens' = valueFromList (fmap (first (AssetId policyId)) assets) diff --git a/src-lib/data-spine/Data/Spine.hs b/src-lib/data-spine/Data/Spine.hs index 33b699c..ff8d68b 100644 --- a/src-lib/data-spine/Data/Spine.hs +++ b/src-lib/data-spine/Data/Spine.hs @@ -88,8 +88,6 @@ deriveSpine name = do suffix = "Spine" spineName = addSuffix name suffix spineDec <- deriveTags name suffix [''Eq, ''Ord, ''Enum, ''Show] - -- TODO: derive Sing - -- TODO: derive HasField (OfSpine ...) decls <- [d| diff --git a/src/Cardano/CEM.hs b/src/Cardano/CEM.hs index 71f0c2e..69ec9a8 100644 --- a/src/Cardano/CEM.hs +++ b/src/Cardano/CEM.hs @@ -111,7 +111,7 @@ class type EqShow datatype = ( Prelude.Eq datatype , Prelude.Show datatype - -- TODO: add IsData here? (now it breaks Plutus compilation) + -- Shoul we add IsData here? (now it breaks Plutus compilation) ) {- | All associated types for 'CEMScript' class defined separately to simplify @@ -223,7 +223,7 @@ data TxFanKind -- | Constraint on a single tx fan data TxFanFilter script = MkTxFanFilter { address :: AddressSpec - , rest :: FilterDatum script -- TODO: not ideal naming + , datumFilter :: FilterDatum script } deriving stock (Show, Prelude.Eq) @@ -252,8 +252,8 @@ bySameCEM = UnsafeBySameCEM . toBuiltinData -- | How many tx fans should satify a 'TxFansConstraint' data Quantifier - = ExactlyNFans Integer -- TODO: use natural numbers - | FansWithTotalValueOfAtLeast Value -- TODO: use natural numbers + = ExactlyNFans Integer -- Here we'd better use natural numbers + | FansWithTotalValueOfAtLeast Value deriving stock (Show) -- | A constraint on Tx inputs or Outputs. diff --git a/src/Cardano/CEM/Indexing/Event.hs b/src/Cardano/CEM/Indexing/Event.hs index 11241e5..8199c23 100644 --- a/src/Cardano/CEM/Indexing/Event.hs +++ b/src/Cardano/CEM/Indexing/Event.hs @@ -43,7 +43,6 @@ import Prelude (3) For the final transition the situation is like (2) except the target datum is missing, which doesn't matter. - TODO: How we can improve this in the future: * API is probably bad, as we always have some transition like Init state - which you can decode, as you have State. If one changes data diff --git a/src/Cardano/CEM/Monads.hs b/src/Cardano/CEM/Monads.hs index 68a308f..713ba94 100644 --- a/src/Cardano/CEM/Monads.hs +++ b/src/Cardano/CEM/Monads.hs @@ -29,7 +29,6 @@ data CEMAction script deriving stock instance (CEMScript script) => Show (CEMAction script) --- FIXME: use generic Some data SomeCEMAction where MkSomeCEMAction :: forall script. @@ -38,7 +37,6 @@ data SomeCEMAction where SomeCEMAction instance Show SomeCEMAction where - -- FIXME: show script name show :: SomeCEMAction -> String show (MkSomeCEMAction action) = show action @@ -54,8 +52,7 @@ data TxSpec = MkTxSpec data BlockchainParams = MkBlockchainParams { protocolParameters :: PParams LedgerEra , systemStart :: SystemStart - , -- FIXME: rename - eraHistory :: LedgerEpochInfo + , ledgerEpochInfo :: LedgerEpochInfo , stakePools :: Set PoolId } deriving stock (Show) diff --git a/src/Cardano/CEM/Monads/CLB.hs b/src/Cardano/CEM/Monads/CLB.hs index 14d6f95..5c73f28 100644 --- a/src/Cardano/CEM/Monads/CLB.hs +++ b/src/Cardano/CEM/Monads/CLB.hs @@ -60,14 +60,14 @@ instance queryBlockchainParams = do protocolParameters <- gets (mockConfigProtocol . mockConfig) slotConfig <- gets (mockConfigSlotConfig . mockConfig) - eraHistory <- LedgerEpochInfo <$> getEpochInfo + ledgerEpochInfo <- LedgerEpochInfo <$> getEpochInfo let systemStart = SystemStart $ posixTimeToUTCTime $ scSlotZeroTime slotConfig return $ MkBlockchainParams { protocolParameters , systemStart - , eraHistory + , ledgerEpochInfo , -- Staking is not supported stakePools = Set.empty } diff --git a/src/Cardano/CEM/Monads/L1.hs b/src/Cardano/CEM/Monads/L1.hs deleted file mode 100644 index b6d613d..0000000 --- a/src/Cardano/CEM/Monads/L1.hs +++ /dev/null @@ -1,151 +0,0 @@ -{-# OPTIONS_GHC -Wno-unrecognised-pragmas -Wno-missing-methods #-} - -module Cardano.CEM.Monads.L1 where - -import Prelude - -import Control.Monad.Reader (MonadReader (..), ReaderT (..)) -import Data.ByteString qualified as BS -import Data.Set qualified as Set - --- Cardano imports -import Cardano.Api hiding (queryUtxo) -import Cardano.Api.InMode (TxValidationError (..)) -import Ouroboros.Network.Protocol.LocalStateQuery.Type (Target (..)) - --- Project imports - -import Cardano.CEM.Monads ( - BlockchainParams (MkBlockchainParams), - MonadBlockchainParams (..), - MonadQueryUtxo (..), - MonadSubmitTx (..), - MonadTest (..), - ResolvedTx, - TxSubmittingError (..), - UtxoQuery (..), - ) -import Cardano.CEM.Monads.L1Commons (cardanoTxBodyFromResolvedTx) -import Cardano.CEM.OffChain (fromPlutusAddressInMonad) -import Cardano.Extras (Era, addressInEraToAny, cardanoModeParams, parseSigningKeyTE) - -newtype ExecutionContext = MkExecutionContext - { localNode :: LocalNodeConnectInfo - } - -newtype L1Runner a = MkL1Runner - { unL1Runner :: ReaderT ExecutionContext IO a - } - deriving newtype - ( Functor - , Applicative - , Monad - , MonadIO - , MonadFail - , MonadReader ExecutionContext - ) - --- Monad implementations - -instance MonadBlockchainParams L1Runner where - askNetworkId = localNodeNetworkId . localNode <$> ask - queryCurrentSlot = do - node <- localNode <$> ask - tip <- liftIO $ getLocalChainTip node - case tip of - ChainTipAtGenesis -> pure 0 - ChainTip slotNo _ _ -> pure slotNo - - queryBlockchainParams = do - MkBlockchainParams - <$> queryCardanoNodeWrapping QueryProtocolParameters - <*> queryCardanoNode QuerySystemStart - <*> (toLedgerEpochInfo <$> queryCardanoNode QueryEraHistory) - <*> queryCardanoNodeWrapping QueryStakePools - - -- FIXME - logEvent _ = return () - eventList = return [] - -queryCardanoNodeWrapping :: QueryInShelleyBasedEra Era b -> L1Runner b -queryCardanoNodeWrapping query = - handleEitherEra =<< queryCardanoNode wrapped - where - handleEitherEra (Right x) = return x - handleEitherEra (Left _) = fail "Unexpected era mismatch" - wrapped = QueryInEra (QueryInShelleyBasedEra shelleyBasedEra query) - --- Design inspired by `Hydra.Chain.CardanoClient` helpers -queryCardanoNode :: - QueryInMode b -> L1Runner b -queryCardanoNode query = do - node <- localNode <$> ask - result <- liftIO $ queryNodeLocalState node VolatileTip query - case result of - -- FIXME: better handling of wrong-era exceptions - Right x -> return x - _ -> fail "Unhandled Cardano API error" - -instance MonadQueryUtxo L1Runner where - queryUtxo query = do - utxoQuery <- case query of - ByTxIns txIns -> - return $ QueryUTxOByTxIn (Set.fromList txIns) - ByAddresses addresses -> do - cardanoAddresses <- - map addressInEraToAny <$> mapM fromPlutusAddressInMonad addresses - return $ QueryUTxOByAddress (Set.fromList cardanoAddresses) - queryCardanoNodeWrapping $ QueryUTxO utxoQuery - -instance MonadSubmitTx L1Runner where - -- FIXME: code duplication, probably refactor out - submitResolvedTx :: ResolvedTx -> L1Runner (Either TxSubmittingError TxId) - submitResolvedTx tx = do - ci <- localNode <$> ask - cardanoTxBodyFromResolvedTx tx >>= \case - Right (_, body, txInMode, _) -> - liftIO $ - submitTxToNodeLocal ci txInMode >>= \case - SubmitSuccess -> - return $ Right $ getTxId body - -- FIXME: check other eras support - SubmitFail (TxValidationErrorInCardanoMode (ShelleyTxValidationError ShelleyBasedEraBabbage e)) -> - return $ Left $ UnhandledNodeSubmissionError e - SubmitFail (TxValidationErrorInCardanoMode _) -> - error "Era mismatch error" - SubmitFail (TxValidationEraMismatch _) -> - error "Era mismatch error" - Left e -> return $ Left $ UnhandledAutobalanceError e - -instance MonadTest L1Runner where - -- FIXME: cache keys and better error handling - getTestWalletSks = do - mapM keyN [0 .. 2] - where - keyN n = do - keyBytes <- liftIO $ BS.readFile $ keysPaths !! fromInteger n - case parseSigningKeyTE keyBytes of - Just key -> return key - Nothing -> fail "Could not read key" - keysPaths = - [ "./devnet/credentials/faucet.sk" - , "./devnet/credentials/bob.sk" - , "./devnet/credentials/carol.sk" - ] - --- | Starting local devnet -localDevnetNetworkId :: NetworkId -localDevnetNetworkId = Testnet $ NetworkMagic 42 - -execOnLocalDevnet :: L1Runner a -> IO a -execOnLocalDevnet action = - runReaderT (unL1Runner action) localNodeContext - where - localNodeContext = - MkExecutionContext - { localNode = - LocalNodeConnectInfo - cardanoModeParams - localDevnetNetworkId - "./devnet/node.socket" - } diff --git a/src/Cardano/CEM/Monads/L1Commons.hs b/src/Cardano/CEM/Monads/L1Commons.hs index 12ea6e3..96b3ef2 100644 --- a/src/Cardano/CEM/Monads/L1Commons.hs +++ b/src/Cardano/CEM/Monads/L1Commons.hs @@ -3,31 +3,23 @@ -- | Code common for resolving Tx of backends which use `cardano-api` module Cardano.CEM.Monads.L1Commons where -import Prelude - -import Data.List (nub) -import Data.Map qualified as Map - --- Cardano imports import Cardano.Api hiding (queryUtxo) import Cardano.Api.Shelley (LedgerProtocolParameters (..)) - --- Project imports import Cardano.CEM.Monads import Cardano.CEM.OffChain import Cardano.Extras +import Data.List (nub) +import Data.Map qualified as Map import Data.Maybe (mapMaybe) +import Prelude --- Main function - +-- | Main function cardanoTxBodyFromResolvedTx :: (MonadQueryUtxo m, MonadBlockchainParams m) => ResolvedTx -> m (Either (TxBodyErrorAutoBalance Era) (TxBodyContent BuildTx Era, TxBody Era, TxInMode, UTxO Era)) cardanoTxBodyFromResolvedTx (MkResolvedTx {..}) = do - -- (lowerBound, upperBound) <- convertValidityBound validityBound - -- FIXME: proper fee coverage selection utxo <- queryUtxo $ ByAddresses [signingKeyToAddress signer] let feeTxIns = Map.keys $ unUTxO utxo @@ -41,8 +33,7 @@ cardanoTxBodyFromResolvedTx (MkResolvedTx {..}) = do let preBody = TxBodyContent - { -- FIXME: duplicate TxIn for coin-selection redeemer bug - txIns = nub allTxIns + { txIns = nub allTxIns -- duplicate TxIn for coin-selection redeemer bug , txInsCollateral = TxInsCollateral AlonzoEraOnwardsBabbage feeTxIns , txInsReference = @@ -98,14 +89,14 @@ cardanoTxBodyFromResolvedTx (MkResolvedTx {..}) = do recordFee txInsUtxo body@(TxBody content) = do case txFee content of TxFeeExplicit era coin -> do - MkBlockchainParams {protocolParameters, systemStart, eraHistory} <- + MkBlockchainParams {protocolParameters, systemStart, ledgerEpochInfo} <- queryBlockchainParams Right report <- return $ evaluateTransactionExecutionUnits (shelleyBasedToCardanoEra era) systemStart - eraHistory + ledgerEpochInfo (LedgerProtocolParameters protocolParameters) txInsUtxo body @@ -150,13 +141,13 @@ callBodyAutoBalance preBody utxo changeAddress = do - MkBlockchainParams {protocolParameters, systemStart, eraHistory, stakePools} <- + MkBlockchainParams {protocolParameters, systemStart, ledgerEpochInfo, stakePools} <- queryBlockchainParams let result = makeTransactionBodyAutoBalance @Era shelleyBasedEra systemStart - eraHistory + ledgerEpochInfo (LedgerProtocolParameters protocolParameters) stakePools Map.empty -- Stake credentials diff --git a/src/Cardano/CEM/OffChain.hs b/src/Cardano/CEM/OffChain.hs index 7fa7c48..dbb1d62 100644 --- a/src/Cardano/CEM/OffChain.hs +++ b/src/Cardano/CEM/OffChain.hs @@ -184,7 +184,7 @@ resolveAction datum = case filterSpec of AnyDatum -> TxOutDatumNone ByDatum datum' -> mkInlineDatum datum' - -- FIXME: Can be optimized via Plutarch + -- This case probably can be optimized via Plutarch UnsafeBySameCEM newState -> let cemDatum :: CEMScriptDatum script @@ -196,10 +196,8 @@ resolveAction in mkInlineDatum cemDatum address = addressSpecToAddress scriptAddress addressSpec - -- TODO: protocol params - -- calculateMinimumUTxO era txout bpp + -- TODO: protocol params calculateMinimumUTxO era txout bpp minUtxoValue = convertTxOut $ lovelaceToValue 3_000_000 - -- TODO convertTxOut x = TxOutValueShelleyBased shelleyBasedEra $ toMaryValue x diff --git a/src/Cardano/CEM/Testing/StateMachine.hs b/src/Cardano/CEM/Testing/StateMachine.hs index caeec10..7778c96 100644 --- a/src/Cardano/CEM/Testing/StateMachine.hs +++ b/src/Cardano/CEM/Testing/StateMachine.hs @@ -1,27 +1,30 @@ {-# OPTIONS_GHC -Wno-orphans #-} -{- | Generic utils for using `quickcheck-dynamic` -FIXME: refactor and add documentation --} +-- | Generic utils for using `quickcheck-dynamic` module Cardano.CEM.Testing.StateMachine where import Prelude +import Cardano.Api (PaymentKey, SigningKey, Value) +import Cardano.CEM (CEMParams (..)) +import Cardano.CEM hiding (scriptParams) +import Cardano.CEM.Monads (CEMAction (..), MonadSubmitTx (..), ResolvedTx (..), SomeCEMAction (..), TxSpec (..)) +import Cardano.CEM.Monads.CLB (ClbRunner, execOnIsolatedClb) +import Cardano.CEM.OffChain +import Cardano.CEM.OnChain (CEMScriptCompiled) +import Cardano.Extras (signingKeyToPKH) +import Clb (ClbT) import Control.Monad (void) import Control.Monad.Except (ExceptT (..), runExceptT) import Control.Monad.Trans (MonadIO (..)) import Data.Bifunctor (Bifunctor (..)) import Data.Data (Typeable) import Data.List (permutations) -import Data.Maybe (mapMaybe) +import Data.Maybe (isJust, mapMaybe) import Data.Set qualified as Set - +import Data.Spine (HasSpine (..), deriveSpine) import PlutusLedgerApi.V1 (PubKeyHash) import PlutusTx.IsData (FromData (..)) - -import Cardano.Api (PaymentKey, SigningKey, Value) - -import Clb (ClbT) import Test.QuickCheck import Test.QuickCheck.DynamicLogic (DynLogicModel) import Test.QuickCheck.Gen qualified as Gen @@ -38,16 +41,6 @@ import Test.QuickCheck.StateModel ( ) import Text.Show.Pretty (ppShow) -import Cardano.CEM (CEMParams (..)) -import Cardano.CEM hiding (scriptParams) -import Cardano.CEM.Monads (CEMAction (..), MonadSubmitTx (..), ResolvedTx (..), SomeCEMAction (..), TxSpec (..)) -import Cardano.CEM.Monads.CLB (ClbRunner, execOnIsolatedClb) -import Cardano.CEM.OffChain -import Cardano.CEM.OnChain (CEMScriptCompiled) -import Cardano.Extras (signingKeyToPKH) -import Data.Spine (HasSpine (..), deriveSpine) - --- FIXME: add more mutations and documentation data TxMutation = RemoveTxFan TxFanKind | ShuffleTxFan TxFanKind Int deriving stock (Eq, Show) @@ -180,10 +173,9 @@ instance (CEMScriptArbitrary script) => StateModel (ScriptState script) where -- Unreachable precondition _ _ = False - -- XXX: Check on ScriptState and it fields is required for shrinking - -- FIXME: docs on QD generation hacks + -- Check on ScriptState and it fields is required for shrinking validFailingAction (ScriptState {finished, state}) (ScriptTransition _ mutation) = - isNegativeMutation mutation && state /= Nothing && not finished + isNegativeMutation mutation && isJust state && not finished validFailingAction _ _ = False nextState Void (SetupConfig config) _var = ConfigSet config @@ -216,7 +208,7 @@ instance (CEMScriptArbitrary script) => StateModel (ScriptState script) where error "This StateModel instance support only with single-output scripts" outStates spec = mapMaybe decodeOutState $ constraints spec - decodeOutState c = case rest (txFansCFilter c) of + decodeOutState c = case datumFilter (txFansCFilter c) of UnsafeBySameCEM stateBS -> fromBuiltinData @(State script) stateBS _ -> Nothing @@ -336,7 +328,7 @@ runActionsInClb :: runActionsInClb genesisValue actions = monadic (ioProperty . execOnIsolatedClb genesisValue) $ void $ - runActions @(ScriptState state) @(ClbRunner) actions + runActions @(ScriptState state) @ClbRunner actions -- Orphans diff --git a/test/Oura/Communication.hs b/test/Oura/Communication.hs index e24f374..f55edfc 100644 --- a/test/Oura/Communication.hs +++ b/test/Oura/Communication.hs @@ -18,8 +18,8 @@ module Oura.Communication ( Interval (MkIntervalMs, unIntervalMs), ) where -import Prelude - +import Cardano.CEM.Indexing.Oura (SinkPath, SourcePath (MkSourcePath), unSinkPath) +import Cardano.CEM.Indexing.Oura qualified as Indexing import Control.Concurrent ( Chan, ThreadId, @@ -31,35 +31,26 @@ import Control.Concurrent ( threadDelay, writeList2Chan, ) -import Control.Monad (forever) -import Data.ByteString qualified as BS -import Data.Foldable (for_) -import Data.Text qualified as T -import Data.Traversable (for) -import Network.Socket qualified as Socket -import Network.Socket.ByteString qualified as Socket.BS - -import Prelude - -import Cardano.CEM.Indexing.Oura qualified as Indexing -import Control.Concurrent (threadDelay) import Control.Concurrent.Async (Async) import Control.Concurrent.Async qualified as Async -import Control.Monad (void) +import Control.Monad (forever, void) import Control.Monad.Cont (ContT (ContT, runContT)) import Control.Monad.Trans (lift) import Data.ByteString qualified as BS +import Data.ByteString.Char8 qualified as BS.Char8 +import Data.Foldable (for_) import Data.String (IsString (fromString)) import Data.Text qualified as T import Data.Text.IO qualified as T.IO +import Data.Traversable (for) +import Network.Socket qualified as Socket +import Network.Socket.ByteString qualified as Socket.BS import System.Directory (removeFile) import System.Process qualified as Process import Toml (Table) import Utils (withNewFile) import Utils qualified - -import Cardano.CEM.Indexing.Oura (SinkPath, SourcePath (MkSourcePath), unSinkPath) -import Data.ByteString.Char8 qualified as BS.Char8 +import Prelude {- | A time required for oura to start up and create a socket, in microseconds. diff --git a/test/Voting.hs b/test/Voting.hs index 06be3bb..bc9e3b2 100644 --- a/test/Voting.hs +++ b/test/Voting.hs @@ -1,24 +1,23 @@ module Voting (votingSpec) where -import Prelude hiding (readFile) - -import Control.Monad.IO.Class (MonadIO (..)) - -import Test.Hspec (describe, shouldBe) - import Cardano.CEM import Cardano.CEM.Examples.Compilation () import Cardano.CEM.Examples.Voting import Cardano.CEM.Monads import Cardano.CEM.OffChain import Cardano.Extras (signingKeyToPKH) - +import Control.Monad.IO.Class (MonadIO (..)) +import Test.Hspec (describe, shouldBe) import Utils +import Prelude hiding (readFile) + votingSpec = describe "Voting" $ do let ignoreTest (_name :: String) = const (return ()) - -- FIXME: fix Voting budget or fix this issue https://github.com/mlabs-haskell/clb/issues/50 + -- TODO: fix Voting budget + -- https://github.com/mlabs-haskell/cem-script/issues/108 + -- https://github.com/mlabs-haskell/clb/issues/50 ignoreTest "Successfull flow" $ execClb $ do jury1 : jury2 : creator : _ <- getTestWalletSks