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

Read networkId from environment #4666

Closed
wants to merge 1 commit into from

Conversation

MarcFontaine
Copy link
Contributor

@MarcFontaine MarcFontaine commented Nov 25, 2022

Read network ID from environment.
Two formats are supported

  • CARDANO_NODE_NETWORK_ID=mainnet
  • CARDANO_NODE_NETWORK_ID=testnet-xx
    where xx parses as Word32

@MarcFontaine MarcFontaine self-assigned this Nov 25, 2022
@MarcFontaine MarcFontaine added the WIP Work In Progress (cannot be merged yet) label Nov 25, 2022
@MarcFontaine
Copy link
Contributor Author

#4418

@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch 3 times, most recently from e9cf022 to 03d1119 Compare November 30, 2022 15:35
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch from 03d1119 to 4b9a6c5 Compare December 13, 2022 15:45
@MarcFontaine MarcFontaine marked this pull request as ready for review December 13, 2022 15:46
@CarlosLopezDeLara
Copy link
Contributor

dcouts jimbo can you guys help me please im learning fast but i seriously need some help to retreave my byron wallet and rewards i tried to code the other day for the first time ever

For support please reach out to our support team https://iohk.zendesk.com/hc/en-us/requests/new

@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch 4 times, most recently from 7416ee9 to 771c004 Compare December 14, 2022 13:46
@Jimbo4350
Copy link
Contributor

@FonziFonzarelli Open an issue or go the the link @CarlosLopezDeLara pasted above. Do not hijack open PRs, you will not receive help.

@IntersectMBO IntersectMBO deleted a comment Dec 14, 2022
@IntersectMBO IntersectMBO deleted a comment Dec 14, 2022
@IntersectMBO IntersectMBO deleted a comment Dec 14, 2022
@MarcFontaine MarcFontaine removed the WIP Work In Progress (cannot be merged yet) label Dec 14, 2022
cardano-api/src/Cardano/Api.hs Show resolved Hide resolved
cardano-api/src/Cardano/Api/Environment.hs Outdated Show resolved Hide resolved
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch 2 times, most recently from 99a54fa to 14c9fe0 Compare December 22, 2022 13:52
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch from 14c9fe0 to 837f998 Compare January 3, 2023 15:33
Copy link
Contributor

@Jimbo4350 Jimbo4350 left a comment

Choose a reason for hiding this comment

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

Nice, a few comments.

cardano-api/src/Cardano/Api/Environment.hs Outdated Show resolved Hide resolved
cardano-cli/src/Cardano/CLI/Shelley/Run/Address.hs Outdated Show resolved Hide resolved
cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs Outdated Show resolved Hide resolved
cardano-cli/src/Cardano/CLI/Shelley/Util.hs Show resolved Hide resolved
cardano-cli/src/Cardano/CLI/Shelley/Util.hs Show resolved Hide resolved
displayErrorText :: Error e => e -> Text
displayErrorText = Text.pack . displayError

rescue :: Functor m => m (Either x a) -> (x -> y) -> ExceptT y m a
Copy link
Contributor

Choose a reason for hiding this comment

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

rescue is a weird name for this. What about firstNewExceptT? That's a bit more indicative and you should consider swapping around the parameters if it doesn't make its usage awkward i.e firstNewExceptT :: Functor m => (x -> y) -> m (Either x a) -> ExceptT y m a

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 is called rescue in Ruby.
I like rescue much better than firstNewExceptT .
Also it is more readable to add " `rescue` ErrorTag" trailing at the end of the line.
Then the good- case comes first and error handling is less distracting when reading the code.
(The rescue pattern exists in several other languages..)

Copy link
Contributor

Choose a reason for hiding this comment

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

rescue is still vague IMO and because it exists in other languages doesn't necessarily mean it's a good name. What about liftMapError? Let's get @newhoggy 's input on this

Copy link
Contributor Author

@MarcFontaine MarcFontaine Jan 17, 2023

Choose a reason for hiding this comment

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

For me rescue is much easier to read and type than liftMapError. 7 vs 12 char and no need for Caps.
Some Haskell guys would even introduce a &%> style operator for that.
For and old coder, who needs thick glasses and uses ever bigger font sizes readability is important.
Some IDEs even show the type when hovering the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is a bit tangential but relevant.

I had something thoughts about error handling in general.

A function like rescue seems generic - but then if it is generic it should go in some generic error handling module, but when we do that we might eventually encounter a problem:

A function like rescue seems fine by itself, but in practise, we might need a family of functions and would then have trouble naming them. For example:

rescue :: Functor m =>  m (Either x a) -> (x -> y) -> ExceptT y m a

rescue :: Functor m =>  Either x a -> (x -> y) -> ExceptT y m a

rescue :: Functor m =>  ExceptT x m a -> (x -> y) -> ExceptT y m a

I was unhappy with my earlier PR that introduced onNothingThrow for this reason. It was defined like this:

onNothingThrow :: Monad m => e -> Maybe a -> ExceptT e m a

But then what about all these other possibilities?

onNothingThrow :: Monad m => e -> Maybe a -> ExceptT e m a

onNothingThrow :: Monad m => e -> m (Maybe a) -> ExceptT e m a

onNothingThrow :: Monad m => e -> ExceptT e m (Maybe a) -> ExceptT e m a

I decided I only need the last one because everything else can be lifted to it.

See this PR: #4807

Interested in your thoughts.

(Note, I'm intending to restructure oops to use more readable English names and avoid the explosion of permutations in a similar way)

Copy link
Contributor

@newhoggy newhoggy Jan 18, 2023

Choose a reason for hiding this comment

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

Nevermind I closed the PR and favouring hoistMaybe instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest we don't define rescue and should instead inline it:

getNetworkId :: NetworkIdArg -> (EnvNetworkIdError -> e) -> ExceptT e IO NetworkId
getNetworkId arg errorTag
  = firstExceptT errorTag $ ExceptT $ getNetworkId' arg

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with defining it inline.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is not one use site of the rescue function but there are about ca 100 possible use sites.
This is the 101 of programming: if there are multiple repetitions of the same pattern one defines a function.
Otherwise the code becomes extremely ugly and hard to maintain.
(As is already the case.)
If there is a need for a family of functions which all do something similar like lifting and error handling
then that is indeed a case for a type class.
It makes no sense at all to just refuse to add any kind of abstraction, just because people cannot agree on a common name for a function.
Once an abstraction is in place, it is very easy to rename the function.
It is better to start with a simple abstraction and think about a type classs later.

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 had something thoughts about error handling in general.
A function like rescue seems generic - but then if it is generic it should go in some generic error handling
module, but when we do that we might eventually encounter a problem:
A function like rescue seems fine by itself, but in practise, we might need a family of functions and would then
have trouble naming them. For example:

This kind of argument is well know and it goes by the phrase:
"Perfect is the enemy of good"

As stated earlier, there are lots and lots of places in the code that could be simplified by using rescue.
If there is need for a more elegant and more generic solution in the future
then replacing the repetitive pattern with a function like rescue now is still a very good step in that direction.

NetworkIdFromCLI x -> return $ Right x
NetworkIdFromEnv -> readEnvNetworkId

getNetworkId :: NetworkIdArg -> (EnvNetworkIdError -> e) -> ExceptT e IO NetworkId
Copy link
Contributor

Choose a reason for hiding this comment

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

We should export getNetworkId' as getNetworkId. Leave it as a vanilla function with no ExceptT usage. Then we should rename getNetworkId to firstGetNetworkId or something like that to make it more obvious that we are transforming the error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Primed names can be problematic in general, but here is no danger of ever using getNetworkId' instead of getNetworkId because they have different types.
getNetworkId is the primary function with 47 call sites.
getNetworkId' an auxiliary function with 7 call sites.
The simple name should be used for the primary function with more call sites
and the more complex name for the auxiliary function with fewer call sites.

Copy link
Contributor

Choose a reason for hiding this comment

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

getNetworkId is specialized for our use case in the cli. This should be renamed to indicate we are mapping over the error hence the name firstGetNetworkId. These functions are likely to end up in cardano-api, which is why I am suggesting we rename getNetworkId' :: NetworkIdArg -> IO (Either EnvNetworkIdError NetworkId) to getNetworkId. We should not impose our specific cli design decisions (ExceptT) on users.

--
data SignForNetworkId
= SignForNetworkId !NetworkId
| TakeNetworkIdFromKey
Copy link
Contributor

@Jimbo4350 Jimbo4350 Jan 3, 2023

Choose a reason for hiding this comment

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

Instead of creating a new sum type and new parsers why not just use Maybe NetworkId like before? SignForNetworkId doesn't really bring much value over Maybe NetworkId. Also the constructor TakeNetworkIdFromKey is misleading.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What you suggest is the situation as it is.
And this situation is very unsatisfactory because at the moment Maybe NetworkId is used with two different meanings and two different interpretations in the (existing) code.
Some of the commands resolve Maybe NetworkId using the network ID from the environment or the flag.
But there is also the one that takes the network ID from the key in the Nothing case.
The best way to handle that is to create a new data type in Haskell.
That is very cheap and helps to cleanup stuff a lot.
It is a common pattern to use
data MyFeature = HaveFeature | DontHaveFeature
instead of
type MyFeature = Bool

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure but I doubt it's worth further increasing the complexity + size of the codebase to differentiate between these two cases. We already have numerous data definitions in the cli and I don't want to introduce anymore unless the benefit is significant. I don't see that being the case here.

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 is much more readable, adds very little overhead and helps to avoid bugs.
When adding support for networkId from env it was necessary to differentiate between these two cases.
if done right (!) it can even help to reduce code complexity and code size.
Also can help to get better help messages in the CLI.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is an example.
Maybe NetworkId is defaulted to Mainnet right in the middle of some code.
With a proper datatype it would be easier to spot and avoid unwanted defaults.

Copy link
Contributor

@Jimbo4350 Jimbo4350 Feb 7, 2023

Choose a reason for hiding this comment

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

The way to fix that is to change the function type signature from:

runTxCalculateMinFee
  :: TxBodyFile
  -> Maybe NetworkId

to

runTxCalculateMinFee
  :: TxBodyFile
  -> NetworkId

Which eliminates the need to add another data definition here because we don't want defaults.

@IntersectMBO IntersectMBO deleted a comment Jan 3, 2023
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch from 837f998 to a8c491d Compare January 6, 2023 14:24
@MarcFontaine MarcFontaine requested a review from Jimbo4350 January 6, 2023 17:03
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch from a8c491d to 6a5fe53 Compare January 9, 2023 13:06
cardano-api/src/Cardano/Api.hs Show resolved Hide resolved
--
data SignForNetworkId
= SignForNetworkId !NetworkId
| TakeNetworkIdFromKey
Copy link
Contributor

Choose a reason for hiding this comment

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

Sure but I doubt it's worth further increasing the complexity + size of the codebase to differentiate between these two cases. We already have numerous data definitions in the cli and I don't want to introduce anymore unless the benefit is significant. I don't see that being the case here.

cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs Outdated Show resolved Hide resolved
cardano-cli/src/Cardano/CLI/Shelley/Util.hs Show resolved Hide resolved
displayErrorText :: Error e => e -> Text
displayErrorText = Text.pack . displayError

rescue :: Functor m => m (Either x a) -> (x -> y) -> ExceptT y m a
Copy link
Contributor

Choose a reason for hiding this comment

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

rescue is still vague IMO and because it exists in other languages doesn't necessarily mean it's a good name. What about liftMapError? Let's get @newhoggy 's input on this

NetworkIdFromCLI x -> return $ Right x
NetworkIdFromEnv -> readEnvNetworkId

getNetworkId :: NetworkIdArg -> (EnvNetworkIdError -> e) -> ExceptT e IO NetworkId
Copy link
Contributor

Choose a reason for hiding this comment

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

getNetworkId is specialized for our use case in the cli. This should be renamed to indicate we are mapping over the error hence the name firstGetNetworkId. These functions are likely to end up in cardano-api, which is why I am suggesting we rename getNetworkId' :: NetworkIdArg -> IO (Either EnvNetworkIdError NetworkId) to getNetworkId. We should not impose our specific cli design decisions (ExceptT) on users.

Two formats are supported
* CARDANO_NODE_NETWORK_ID=mainnet
* CARDANO_NODE_NETWORK_ID=testnet-xx
   where xx parses as Word32
@MarcFontaine MarcFontaine force-pushed the mafo/4418-networkId-from-env branch from 6a5fe53 to 41c9003 Compare January 31, 2023 13:56
@newhoggy
Copy link
Contributor

Implemented in #5119 so closing this PR

@newhoggy newhoggy closed this Apr 26, 2023
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.

5 participants