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

Allow callers of selectAssets to specify seed for random selection. #3014

Conversation

jonathanknowles
Copy link
Contributor

@jonathanknowles jonathanknowles commented Nov 12, 2021

Issue Number

ADP-1257

Summary

This PR makes it possible for callers of selectAssets to specify a seed for random selection.

Ultimately, it will be possible to specify a seed through the API, but this PR does not make any changes to the API. That part is left to future PRs.

Details

This PR adds the following field to SelectAssetParams:

data SelectAssetsParams s result = SelectAssetsParams
      { outputs :: [TxOut]
      , pendingTxs :: Set Tx
+     , randomSeed :: Maybe StdGenSeed
      , txContext :: TransactionCtx
      , utxoAvailableForCollateral :: UTxO
      , utxoAvailableForInputs :: UTxOSelection
      , wallet :: Wallet s
      }

Additionally, this PR:

  • provides a new type StdGenSeed, which is interconvertible with StdGen, but provides a representation that is more convenient for construction and serialization.
  • provides a JSON serialization for StdGenSeed.

@jonathanknowles jonathanknowles self-assigned this Nov 12, 2021
@jonathanknowles jonathanknowles marked this pull request as draft November 15, 2021 03:53
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/adp-1257/coin-selection-random-seed-part-1 branch 3 times, most recently from aef175c to 5f6802c Compare November 15, 2021 05:06
@jonathanknowles jonathanknowles marked this pull request as ready for review November 15, 2021 05:06
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/adp-1257/coin-selection-random-seed-part-1 branch from 5f6802c to b7ebcad Compare November 15, 2021 06:43
@sevanspowell
Copy link
Contributor

Looks good 🙂

I think my one niggle is that selectAssets is parameterised by the generator twice, once with the MonadRandom constraint, and again with the randomSeed in SelectAssetsParams . From the outside perspective it's unclear what generator is used in what circumstance.

i.e.
-- Given some function that runs in a MonadRandom context
someFn :: MonadRandom m => m Bool

-- I can run that function with a custom seed in the StdGen generator, IO monad:
bool <- evalRandT someFn (stdGenFromSeed someSeed)

-- Now, if we also add a seed argument to someFn
someFn' :: MonadRandom m => StdGenSeed -> m Bool

-- We can call the function with two different seeds:
bool <- evalRandT (someFn' someOtherSeed) (stdGenFromSeed someSeed)

-- It's unclear which seed influences what part of the randomness of someFn'

That is to say, selectAssets is already parameterised by a seed (actually a generator, but equivalent), and so there is no need to change the API to selectAssets.

We just need to get the seed in from the HTTP API to the call to selectAssets (where necessary):

- W.selectAssets W.SelectAssetsParams
                        { ...
                        , randomSeed = Just seed
                        , ...
                        }
+ flip evalRandT (stdGenFromSeed seed) $ W.selectAssets ...

(I'm simplifying the code a bit there)

@sevanspowell
Copy link
Contributor

Looks good slightly_smiling_face

I think my one niggle is that selectAssets is parameterised by the generator twice, once with the MonadRandom constraint, and again with the randomSeed in SelectAssetsParams . From the outside perspective it's unclear what generator is used in what circumstance.

i.e.
-- Given some function that runs in a MonadRandom context
someFn :: MonadRandom m => m Bool

-- I can run that function with a custom seed in the StdGen generator, IO monad:
bool <- evalRandT someFn (stdGenFromSeed someSeed)

-- Now, if we also add a seed argument to someFn
someFn' :: MonadRandom m => StdGenSeed -> m Bool

-- We can call the function with two different seeds:
bool <- evalRandT (someFn' someOtherSeed) (stdGenFromSeed someSeed)

-- It's unclear which seed influences what part of the randomness of someFn'

That is to say, selectAssets is already parameterised by a seed (actually a generator, but equivalent), and so there is no need to change the API to selectAssets.

We just need to get the seed in from the HTTP API to the call to selectAssets (where necessary):

- W.selectAssets W.SelectAssetsParams
                        { ...
                        , randomSeed = Just seed
                        , ...
                        }
+ flip evalRandT (stdGenFromSeed seed) $ W.selectAssets ...

(I'm simplifying the code a bit there)

I've heavily investigated this option (my suggestion), but it was hampered by compiler errors caused by our prevalent use of typeclasses (in the form of "capabilities") and generic-lens.

IOHK and others added 14 commits November 15, 2021 10:26
This module provides functions and types that extend those provided by
the `Control.Monad.Random` module hierarchy.
This module provides functions and types that extend functionality
provided by the `aeson` package.
This change replaces the use of the `Identity` type with the `NonRandom`
type in contexts that require non-randomness.

As a result, we can remove the orphan instance of `MonadRandom` for
`Identity`.
This will allow the `selectAssets` function to manipulate the state of
the random number generator associated with the `MonadRandom` context,
allowing it to read and write the seed used for random number
generation.
This will allow callers of `selectAssets` to optionally specify a seed value,
to be used by the random number generator when performing random selection.
With this change, we can run coin selection with a random number
generator seeded with a seed specified by the caller.

If no seed is specified by the caller, then we use the `MonadRandom`
context to provide us with a seed.
This class is no longer necessary, now that we are using `evalRand`
within `selectAssets`.
This function creates a new `StdGenSeed` from within a random monadic context.
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/adp-1257/coin-selection-random-seed-part-1 branch from b7ebcad to 39ea80f Compare November 15, 2021 10:27
@jonathanknowles
Copy link
Contributor Author

That is to say, selectAssets is already parameterised by a seed (actually a generator, but equivalent), and so there is no need to change the API to selectAssets.

I've heavily investigated this option (my suggestion), but it was hampered by compiler errors caused by our prevalent use of typeclasses (in the form of "capabilities") and generic-lens.

Thanks for investigating this @sevanspowell.

I completely agree with your sentiments here.

Perhaps we can view this PR as a starting point, and merge it as-is, but continue to improve on this incrementally with future PRs, if/when we figure out a better way to achieve what we want.

To make things clearer for now, I've added some commentary to selectAssets, so that callers will know what to expect.

@jonathanknowles jonathanknowles merged commit fe7632e into master Nov 15, 2021
@jonathanknowles jonathanknowles deleted the jonathanknowles/adp-1257/coin-selection-random-seed-part-1 branch November 15, 2021 11:17
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.

2 participants