Skip to content
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

Redesign GYTxMonad and its instances to be able to submit transactions #322

Merged
merged 28 commits into from
Jul 24, 2024

Conversation

TotallyNotChase
Copy link
Contributor

@TotallyNotChase TotallyNotChase commented Jul 10, 2024

Summary

Closes #316

This is a long overdue redesign of GYTxMonad. It adds the ability to submit transactions to the monad and splits it into a more lawful hierarchy. In particular:

  • GYTxQueryMonad - For common utxo and similar queries

    Instance: GYTxQueryMonadIO

  • GYTxQueryMonad => GYTxSpecialQueryMonad - For uncommon queries such as protocol parameters, era history etc. (this could potentially be removed, see note below)

    Instance: GYTxQueryMonadIO

  • GYTxQueryMonad => GYTxUserQueryMonad - For queries while acting as a user (having access to own wallet for querying purposes not signing purposes)

    Instance: GYTxBuilderMonadIO - see below.

  • (GYTxSpecialQueryMonad, GYTxUserQueryMonad, Default (TxBuilderStrategy)) => GYTxBuilderMonad - For building transactions while acting as a user. This allows different instances to choose their own transaction building method. If TxBuilderStrategy is set to GYCoinSelectionStrategy (default), the implementation defaults to the pre-existing transaction building methods. Therefore, simply anyclass deriving this class will be enough to use the transaction building unchanged.

    instance: GYTxBuilderMonadIO

  • GYTxBuilderMonad => GYTxMonad - For interacting with the blockchain in a way that mutates its state. E.g building and submitting transactions etc. Also is able to sign as a user.

    Instance: GYTxMonadIO

  • (GYTxMonad (TxMonadOf m), GYTxSpecialQueryMonad m) => GYTxGameMonad m - This is an entirely new feature. This allows simulating multiple users interacting in an environment, building and submitting transactions etc. This is extremely useful in testing. Where we model an environment with many users interacting, waiting for events etc.

    Each "game' monad has its own "tx" monad. The tx monad code can be lifted into the "game" monad and assigned a user to perform it as.

    Instance: GYTxGameMonadIO

I suggest putting this brief note about the monad hierarchy in the docs so people can choose which monad they need, instead of always reaching for the most powerful one

Note the distinction between a TxQuery monad and the Tx monad. The query monad classes are meant to be non-mutating. In other words, if you are given a GYTxUserQueryMonad m => m a for example, and you run it (using a relevant interpreter) - you can be sure that it did not mutate anything on the chain. However, that guarantee does not exist for GYTxMonad.

This sort of a lawful type classes helps in "coloring" functions with types to define their expected behavior. Most code in the GY codebase (where the backend only builds transactions and passes it to frontend) can use just a query monad!

This makes running the monad instances (e.g GYTxMonadIO, renamed from GYTxMonadNode) much simpler. There is no traversable hack anymore. It's a simple monad interpreter. As you'd expect from any other proper monad in the ecosystem. As a result, transaction defining, building, signing, and submitting - all under one monad feels much more ergonomic.

I understand that this is a large PR with breaking changes, but I really think it's for the best. I will annotate most of the significant changes with comments in this PR to make reviewing easier. I will post a summary with each important commit.

Furthermore, almost all commits are self-contained (they are granular and they compile). The only exception is the commit titled "Add 'submitTx' and 'awaitTxConfirmed' under 'GYTxMonad' and refine monad hierarchy". The subsequent commit is required to build the project.

Migration guide

For code that uses submission after building, migration is a bit more work but has a simple pattern. This pattern can be observed in Privnet code, for example.

- txBodyPlace <- ctxRunI ctx (ctxUserF ctx) $ do
+ ctxRun ctx (ctxUserF ctx) $ do
      addr <- scriptAddress giftValidatorV1
-     return $ mconcat
+     txBodyPlace <- buildTxBody $ mconcat
           [ mustHaveOutput $ mkGYTxOut addr (valueSingleton goldAC 10) (datumFromPlutusData ())
           ]
- void $ submitTx ctx (ctxUserF ctx) txBodyPlace
+     submitTxBodyConfirmed_ txBodyPlace [ctxUserF ctx]

Code that previously used traversing functions such as rrunGYTxMonadNodeF in order to build a GYTxSkeleton contained within a traversable (e.g for interpeting GYTxMonadNode (Maybe (GYTxSkeleton v))) will simply use well-known helpers to traverse instead, making things much simpler:

- grabGiftsTx' <- ctxRunF ctx (ctxUser2 ctx) $ grabGifts  @'PlutusV2 giftValidatorV2
- mapM_ (submitTx ctx (ctxUser2 ctx)) grabGiftsTx'
+ ctxRun ctx (ctxUser2 ctx) $ do
+    grabGiftsTx' <- grabGifts @'PlutusV2 giftValidatorV2 >>= traverse buildTxBody
+    mapM_ (`submitTxBodyConfirmed` [ctxUser2 ctx]) grabGiftsTx'

For code that only built transactions but did not submit them, it is advised to replace the GYTxMonadNode usage with GYTxBuilderMonadIO. Instead of returning a skeleton, it should use buildTxBody on the skeleton. So you'd have: GYTxBuilderMonadIO GYTxBody. This can be run with runGYTxBuilderMonadIO to obtain the GYTxBody like before. Alternative, define a function buildAndRunGYTxBuilderMonadIO :: GYTxBuilderMonadIO (GYTxSkeleton v) -> GYTxBody, which is simply a composition of buildTxBody followed by runGYTxBuilderMonadIO.

- txBodyPlace <- runGYTxMonadNode nid providers addrs change collateral $ do
+ txBodyPlace <- buildAndRunGYTxBuilderMonadIO nid providers addrs change collateral $ do
      addr <- scriptAddress giftValidatorV1
      return $ mconcat
           [ mustHaveOutput $ mkGYTxOut addr (valueSingleton goldAC 10) (datumFromPlutusData ())
           ]

where:

buildAndRunGYTxBuilderMonadIO :: GYTxBuilderMonadIO (GYTxSkeleton v) -> GYTxBody
buildAndRunGYTxBuilderMonadIO act = runGYTxBuilderMonadIO $ act >>= buildTxBody 

This way, a very simple find and replace action will complete most of the migration.

Extended ideas

  • There could be a GYTxMonad m => GYTxGameMonad m, which could allow a "game situation" where we have multiple users building and submitting contracts, interacting with one another etc. This would essentially have methods like waitUntilSlot, waitUntilBlock etc. There needs to be a function asUser :: (GYTxMonad m, GYTxGameMonad n) => User -> m a -> n a to facilitate the "game" flow. Added.
  • Related to someUTxO does not actually update envUsedSomeUTxOs in GYTxMonadNode #318 - GYTxBuilderMonadIO should actually have its envUsedSomeUTxO somehow exposed to GYTxMonadIO so that the submitTx implementation of GYTxMonadIO can reset it. I'd suggest making this field mutable. That way, a stateful flow can be achieved - which is necessary since envUsedSomeUTxO is meant to be stateful. I would discourage the usage of the state monad. Just utilize ReaderT _ IO which we already have.
  • Some day, this codebase should use an effect system instead. effectful will probably be a good choice. Or eff, if it's no longer experimental.

Type of Change

Please mark the relevant option(s) for your pull request:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code refactoring (improving code quality without changing its behavior)
  • Documentation update (adding or updating documentation related to the project)

Checklist

Please ensure that your pull request meets the following criteria:

  • I have read the Contributing Guide
  • My code follows the project's coding style and best practices
  • My code is appropriately commented and includes relevant documentation
  • I have added tests to cover my changes
  • All new and existing tests pass
  • I have updated the documentation, if necessary

Testing

Please describe the tests you have added or modified, and provide any additional context or instructions needed to run the tests.

  • Test A
  • Test B

Additional Information

If you have any additional information or context to provide, such as screenshots, relevant issues, or other details, please include them here.

@TotallyNotChase TotallyNotChase requested a review from a team as a code owner July 10, 2024 22:19
@TotallyNotChase
Copy link
Contributor Author

Summary of important commits:

  • Common MTL transformer instances (also remove ExceptT instance)

    This adds some MTL transformer instances so downstream (user code) can easily compose with our monad in easy ways.

    I have removed the ExceptT instasnce. Please read the associated note added in the commit.

  • Reorder GYInScript type variables

    Mostly unrelated to the main purpose of the PR, but greatly helpful for users using TypeApps. This is a breaking change. Helped get rid of a verbose type signature in a privnet test.

  • Add ownChangeAddress and ownCollateral to GYTxMonad

    Simple change that allows building transactions within the monad later on

    Note the added law on someUTxO. See: someUTxO does not actually update envUsedSomeUTxOs in GYTxMonadNode #318

  • Remove BuildTxException, rename to GYBuildTxError

    Consistent naming and exceptions mechanism

    Since transaction building is part of the monad now, transaction build errors ought to also be part of the monad errors.

  • Add submitTx and awaitTxConfirmed to GYTxMonad

    Main commit amending the monad class declaration and hierarchy. Upto GYTxUserQueryMonad denotes query monad capabilities (non chain mutating).

    GYTxSpecialQueryMonad could potentially be removed. See note added in the commit.

    Note the laws around submission and how it relates to someUTxO.

  • Make transaction building a part of GYTxMonad utilities

    Main commit amending the monad instances and their usage.

    This showcases what changes might be required in user code as well. See changes in Privnet code.

  • Use pre-provided submission utils rather than privnet defined ones.

    Note that the submission functions only sign with the payment key. Previously, they checked whether stake key was required and added it if necessary. This is done manually now.

    Upon inspection, it seems like this feature of detecting the necessity for stake key was not necessary since the Stake utils test do that on their own anyway.

Note how the Privnet code utilizes ctxRunQuery, ctxRun, and ctxRunBuilder etc. to limit expectations and mutation.

@TotallyNotChase
Copy link
Contributor Author

I suggest reviewing this PR commit by commit. Most of the changes to the Privnet code can be ignored. It's simply updating usage and its summarized in here. My commit summary above might help in reviewing as well.

Before, merging - I need to know how the parallel and chaining building could be amended. I'm thinking of removing the whole Traversable f thing from buildTxCore entirely and then exposing the parallel and chaining functions. They are currently in GeniusYield.TxBuilder but not exposed.

ctxRunBuilder :: Ctx -> User -> GYTxBuilderMonadIO a -> IO a
ctxRunBuilder ctx User {..} = runGYTxBuilderMonadIO (ctxNetworkId ctx) (ctxProviders ctx) [userAddr] userAddr Nothing
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be the change required in most GY app code. Since the app code probably just needs to build tranasactions, not submit them.

addRefScriptCtx ctx user script = do
txBodyRefScript <- ctxRunF ctx user $ Limbo.addRefScript script
addRefScriptCtx ctx user script = ctxRun ctx user $ do
txBodyRefScript <- Limbo.addRefScript script >>= traverse buildTxBody
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traversing manually instead of having the hack with GYTxMonadNode over a Traversable f

Right body -> do
let refs = Limbo.findRefScriptsInBody body
ref <- case Map.lookup (Some script) refs of
Just ref -> return ref
Nothing -> fail "Shouldn't happen: no ref in body"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MonadFail removed since we want to unify exceptions as much as possible

Nothing -> fail "Shouldn't happen: no ref in body"
void $ submitTx ctx user body
return ref
Nothing -> throwAppError $ someBackendError "Shouldn't happen: no ref in body"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably better to throw some typed error.

void $ submitTx ctx user body
return ref
Nothing -> throwAppError $ someBackendError "Shouldn't happen: no ref in body"
signAndSubmitConfirmed_ body
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GYTxMonadIO (should really be used for bot-like usecase, use GYTxBuilderMonadIO for app-like usecases) now contains the user keys. So signAndSubmitConfirmed_ is a helper that uses the payment key.

@@ -31,6 +31,7 @@ import Control.Monad.Except
import Control.Monad.Random
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More updates to this module will follow in a different PR. Said PR will be able to unify privnet and clb code

Comment on lines +93 to +94
-- | Errors encountered during transaction building related functions.
GYBuildTxException :: GYBuildTxError -> GYTxMonadException
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transaction building errors are now a part of GYTxMonadException

Stability : develop

-}
module GeniusYield.TxBuilder.IO (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously known as GYTxMonadNode. Its interface is vastly simplified now. And it is composed with other less powerful monads that are also usable to a library user.

See PR comment about GYTxMonad hierarchy.

Comment on lines 53 to 54
, envPaymentSKey :: !GYPaymentSigningKey
, envStakeSKey :: !(Maybe GYStakeSigningKey)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It now contains the user's payment and stake signing key.

Note that this monad is likely not necessary for app-like usecases. E.g the GY app code should probably use GYTxBuilderMonadIO instead. Also exported here.

Comment on lines +247 to +256
newtype RawLogger = RawLogger { unRawLogger :: GYLogContexts -> GYLogNamespace -> GYLogSeverity -> Text -> IO () }

-- | A logger that does ignores the logs.
unitRawLogger :: RawLogger
unitRawLogger = RawLogger $ \_ _ _ _ -> pure ()

-- | A logger that ignores context and namespace and filters messages based on severity.
simpleRawLogger :: GYLogSeverity -> (Text -> IO ()) -> RawLogger
simpleRawLogger targetSev putLog = RawLogger $ \_ _ sev -> when (targetSev <= sev) . putLog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simple logger can filter based on log severity.

@TotallyNotChase
Copy link
Contributor Author

TotallyNotChase commented Jul 15, 2024

I just added GYTxGameMonad, which will be extremely beneficial for elegant testing code. I suggest you take a look! It's a really cool feature. It allows having multiple GYTxMonad code blocks be lifted into one environment and performed as different users (as given)!

81b8370

@@ -52,10 +55,12 @@ import GeniusYield.Types
-- Setup
-------------------------------------------------------------------------------

-- | This setup represents a two argument function where first argument is for logging & second represents for continuation, in need of `Ctx`.
-- | This setup represents a three argument function where first two arguments are for logging & second is for the continuation, in need of `Ctx`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- | This setup represents a three argument function where first two arguments are for logging & second is for the continuation, in need of `Ctx`.
-- | This setup represents a three argument function where first two arguments are for logging & third is for the continuation, in need of `Ctx`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 30 to 32
-- If something is
-- it as well. But if boolean is `True`, framework would only use it as collateral and reserve it, if value in the given UTxO
-- is exactly 5 ada.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- If something is
-- it as well. But if boolean is `True`, framework would only use it as collateral and reserve it, if value in the given UTxO
-- is exactly 5 ada.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

GYTxBuildFailure be -> throwError . GYBuildTxException $ GYBuildTxBalancingError be
-- We know there is precisely one input.
GYTxBuildNoInputs -> error "runGYTxMonadIOF: absurd"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
GYTxBuildNoInputs -> error "runGYTxMonadIOF: absurd"
GYTxBuildNoInputs -> error "buildTxBodyF: absurd"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

-> m GYTxBody
buildTxBodyWithStrategy = buildTxBodyWithStrategy'

buildTxBody :: GYTxBuilderMonad m => GYTxSkeleton v -> m GYTxBody
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Add haddock.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for missing this! I added it now. It's a pretty simple haddock for now but I think it suffices.

--
-- /Law:/ 'someUTxO' calls made after a call to 'submitTx' may return previously returned UTxOs
-- if they were not affected by the submitted transaction.
submitTx :: GYTx -> m GYTxId
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should put submitTx and awaitTxConfirmed' to some other monad as the current structures assumes the requirement of a signing key but what if built transaction doesn't require signing by such a key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Yes, the monad you're looking for is GYTxBuilderMonad. That's essentially the replacement for current GYTxMonad. See txmonad hierarchy and migration guide above and also these two comments:

#322 (comment)

#322 (comment)

I think for app-like usecases (most of GY codebase from what I remember) will just switch to GYTxBuilderMonad m => ... and runGYTxBuilderMonadIO and that's pretty much it. That won't require the keys.


-- | Wait for a _recently_ submitted transaction to be confirmed.
--
-- /Note:/ If used on a transaction submitted long ago, the behavior is undefined.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Can we avoid it being undefined.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's behaviour is well defined, this can be part of query monad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea! This should definitely be part of the query monad because yes, it is indeed just a query.

I'd like to wait for the behavior to be defined first, indeed.


-- | This is expected to give the slot of the latest block. We say "expected" as we cache the result for 5 seconds, that is to say, suppose slot was cached at time @T@, now if query for current block's slot comes within time duration @(T, T + 5)@, then we'll return the cached slot but if say, query happened at time @(T + 5, T + 21)@ where @21@ was taken as an arbitrary number above 5, then we'll query the chain tip and get the slot of the latest block seen by the provider and then store it in our cache, thus new cached value would be served for requests coming within time interval of @(T + 21, T + 26)@.
--
-- __NOTE:__ It's behaviour is slightly different, solely for our plutus simple model provider where it actually returns the value of the @currentSlot@ variable maintained inside plutus simple model library.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Need to update this haddock in regards to CLB.

-- | Get available own UTxOs that can be operated upon.
availableUTxOs :: m GYUTxOs

-- | Return some unspend transaction output translatable to the given language corresponding to the script in question.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- | Return some unspend transaction output translatable to the given language corresponding to the script in question.
-- | Return some unspent transaction output translatable to the given language corresponding to the script in question.

achieve what it is meant to achieve? The purpose of that contraint is to signal
that the query methods _should_ throw errors of type 'GYTxMonadException'.
After all, some queries are bound to fail. But this expectation does not really
restrict the type of exceptinos. In fact, an IO based monad could still
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
restrict the type of exceptinos. In fact, an IO based monad could still
restrict the type of exceptions. In fact, an IO based monad could still


-- | 'GYTxQueryMonad' interpretation run under IO.
type role GYTxQueryMonadIO representational
newtype GYTxQueryMonadIO a = GYTxQueryMonadIO { runGYTxQueryMonadIO' :: GYTxQueryIOEnv -> IO a }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't it be a newtype wrapper around ReaderT GYTxQueryIOEnv IO a?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But even o/w let's not bother about making this change now as we already used similar representation earlier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I started with indeed! But actually it changes the type roles. The a in ReaderT is set to nominal (we cannot change this). We're looking for representational (to allow coercions). The function arrow ((->)) doesn't have this restriction.

@sourabhxyz
Copy link
Member

sourabhxyz commented Jul 23, 2024

I'd suggest making this field mutable. That way, a stateful flow can be achieved - which is necessary since envUsedSomeUTxO is meant to be stateful.

I am fine with it as I see merit in ReaderT design pattern.

@@ -241,8 +244,18 @@ closeScribes genv = genv & logEnvToKatip & K.closeScribes <&> logEnvFromKatip
-- Log configuration
-------------------------------------------------------------------------------

newtype RawLogger = RawLogger { unRawLogger :: GYLogContexts -> GYLogNamespace -> GYLogSeverity -> Text -> IO () }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Can the cfgLogDirector be just GYLogEnv instead of Either GYLogEnv GYRawLog so as to just have Katip as log provider? Maybe info from testCaseSteps could be registered as a scribe inside Katip.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds good.

@@ -261,7 +274,7 @@ cfgAddContext i cfg = cfg { cfgLogContexts = addContext i (cfgLogContexts cfg) }
logRun :: (HasCallStack, MonadIO m, StringConv a Text) => GYLogConfiguration -> GYLogSeverity -> a -> m ()
logRun GYLogConfiguration {..} sev msg = case cfgLogDirector of
Left cfgLogEnv -> withFrozenCallStack $ K.runKatipT (logEnvToKatip cfgLogEnv) $ K.logLoc (logContextsToKatip cfgLogContexts) (logNamespaceToKatip cfgLogNamespace) (logSeverityToKatip sev) (K.logStr msg)
Right GYRawLog {..} -> liftIO $ rawLogRun (toS @Text @String $ "[Namespaces: " <> Text.intercalate ", " (K.unNamespace $ logNamespaceToKatip cfgLogNamespace) <> "]" <> "[Contexts: " <> logContextsToS cfgLogContexts <> "] " <> toS @_ @Text msg)
Right GYRawLog {..} -> liftIO $ unRawLogger rawLogRun cfgLogContexts cfgLogNamespace sev $ toS msg
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that this change no longer shows contexts & namespaces for privnet logs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think that should be added to RawLogger. I agree that it should exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think this should still be able to show contexts and namespaces but it depends on the GYRawLog. So it's now controlled higher up the call stack. Specifically, it will depend on the GYLogConfiguration and how it was obtained. The pre-provided simpleRawLogger does not log them. (I found them to be extra noise in privnet tests).

Feel free to add a more verbose RawLogger!

@sourabhxyz
Copy link
Member

Thanks @TotallyNotChase for much need contribution and also thanks for making review easy with thorough comments!

@sourabhxyz
Copy link
Member

Before, merging - I need to know how the parallel and chaining building could be amended. I'm thinking of removing the whole Traversable f thing from buildTxCore entirely and then exposing the parallel and chaining functions. They are currently in GeniusYield.TxBuilder but not exposed.

What is the motivation of getting rid of Traversable f here? Unfortunately it's not clear to me the alternative implementation you are proposing. I am fine with just exposing

@TotallyNotChase
Copy link
Contributor Author

Before, merging - I need to know how the parallel and chaining building could be amended. I'm thinking of removing the whole Traversable f thing from buildTxCore entirely and then exposing the parallel and chaining functions. They are currently in GeniusYield.TxBuilder but not exposed.

What is the motivation of getting rid of Traversable f here? Unfortunately it's not clear to me the alternative implementation you are proposing. I am fine with just exposing

The Traversable thing is just a shoehorning thing. The same usability can be achieved by simply calling traverse on the result now. Because the monad is actually composable now. The reason it existed prior is because that composition was impossible before, and the only way to obtain the a from GYTxMonad a, was to use Const and a shoehorned traversable in the implementation. This is completely useless now, and therefore there's no point in making the type signature more complicated.

@TotallyNotChase
Copy link
Contributor Author

I have removed the Traversable f parameter entirely in the last commit. Most places that were using it before were really just using it as either Identity (entirely unnecessary) or Const (no longer necessary, just run the monad). But anyway, the same usability as before can be achieved by essentially calling fSkeletons >>= traverse buildTxBody etc. within the monad. That's way simpler and conforming to the "usual" Haskell APIs.

Copy link
Member

@sourabhxyz sourabhxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @TotallyNotChase! PR looks good to me.

Copy link
Contributor

@4TT1L4 4TT1L4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Thank you for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add submitTx, awaitTxConfirmed to GYTxQueryMonad
3 participants