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

Jörmungandr: mkNetworkLayer with networkTip #383

Merged
merged 1 commit into from
Jun 11, 2019

Conversation

Anviking
Copy link
Member

@Anviking Anviking commented Jun 6, 2019

Issue Number

#219

Overview

  • Implemented mkNetworkLayer with networkTip
  • I have no tests

Comments

On ExceptT ErrNetworkUnreachable m (Maybe Block)

I found it particularly nightmarish to chain getTipId and getBlock.

Therefore I made all JormungandrLayer functions return ExceptT ErrNetworkUnreachable, favouring Right $ Nothing to indicate 404. f011447

  • Implementing NetworkLayer becomes easier.
  • There is no need for descriptive errors in JormungandrLayer. I don't see why we can't handle that in the NetworkLayer instead.

Alternative

  • Closest I got was
        t@(BlockId hash) <- lift $ getTipId j
        let r = runExceptT $ getBlock j t
        case _runM r of -- need to deal with the `m` somehow
            Left (ErrGetBlockNetworkUnreachable msg) -> throwE $ ErrNetworkTipNetworkUnreachable msg
            Left e@(ErrGetBlockNotFound _) -> undefined throwM e
            Right b -> return (hash, header b)

Edit: the throwIO made it complicated, but I now realise that it actually was I who introduced the throwIO. The HttpBridge's throwIO (actually throwM) is for a different class of errors.

@Anviking Anviking requested a review from KtorZ June 6, 2019 23:18
@Anviking Anviking self-assigned this Jun 6, 2019
@Anviking
Copy link
Member Author

Anviking commented Jun 7, 2019

nextBlocks would then be like

    , nextBlocks = \_slotId -> do
        let blockId = undefined
        let chunkSize = 1000
        ids <- getDescendantIds j blockId chunkSize >>= \case
            Just a -> return a
            Nothing -> liftIO . throwIO $ ErrGetBlockNotFound blockId
        forM ids getBlock'

    , postTx = undefined
    }
  where
    getBlock' :: BlockId -> ExceptT ErrNetworkUnreachable m Block
    getBlock' t = getBlock j t >>= \case
            Just b -> return b
            Nothing -> liftIO . throwIO $ ErrGetBlockNotFound t

t@(BlockId hash) <- lift $ getTipId j
lift $ getBlock j t >>= \case
(Just b) -> return (hash, header b)
Nothing -> liftIO . throwIO $ ErrGetBlockNotFound t
Copy link
Member Author

Choose a reason for hiding this comment

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

Could wrap this in some ErrInternalPanicOrSomething-wrapper… or handle the error entirely differently

Copy link
Contributor

Choose a reason for hiding this comment

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

I think adding another constructor to ErrNetworkTip would be fine.
networkTip is used to find out the tip slot id.

Copy link
Contributor

@rvl rvl left a comment

Choose a reason for hiding this comment

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

Good, looks like all that's left in this PR is handling Nothing from getBlock. 👍

t@(BlockId hash) <- lift $ getTipId j
lift $ getBlock j t >>= \case
(Just b) -> return (hash, header b)
Nothing -> liftIO . throwIO $ ErrGetBlockNotFound t
Copy link
Contributor

Choose a reason for hiding this comment

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

I think adding another constructor to ErrNetworkTip would be fine.
networkTip is used to find out the tip slot id.

lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs Outdated Show resolved Hide resolved
@@ -102,7 +102,7 @@ type PostSignedTx
-- TODO: Replace SignedTx with something real
data SignedTx

newtype BlockId = BlockId (Hash "block")
newtype BlockId = BlockId (Hash "BlockHeader")
Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, I think Hash "BlockHeader" is correct, and BlockId probably isn't needed - as either a newtype or type synonym.

Copy link
Member Author

@Anviking Anviking Jun 7, 2019

Choose a reason for hiding this comment

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

It doubles as an ApiT to avoid orphans so it is needed (in the Api type). I kept it in JormungandrLayer for now.

Also I introduced it because jormungandr/JormungandrLayer often refers to "id" in the method-names.

@@ -75,9 +88,9 @@ data JormungandrLayer m = JormungandrLayer
{ getTipId
:: ExceptT ErrNetworkUnreachable m BlockId
, getBlock
:: BlockId -> ExceptT ErrGetBlock m Block
:: BlockId -> ExceptT ErrNetworkUnreachable m (Maybe Block)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nothing denotes that the node is not aware of a block with that hash. Maybe put that in a comment.

Copy link
Member

Choose a reason for hiding this comment

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

As discussed in another review, returning Maybe here isn't very ideal since in most (all?) cases, we are actually expecting a block when calling getBlock. Using Maybe, we are loosing information (hence the need for an extra comment). With a clear error, there's no need for a comment or any doubt about what the behavior of that function is.

lib/jormungandr/src/Cardano/Wallet/Jormungandr/Network.hs Outdated Show resolved Hide resolved
@KtorZ
Copy link
Member

KtorZ commented Jun 7, 2019

@Anviking

I found it particularly nightmarish to chain getTipId and getBlock.

May I ask what is nightmarish here? In an Except e monad, you can most likely get away with withExceptT to map an error to some common ones and to be honest, I don't see how using Maybes makes it better 🤔 ?

@KtorZ
Copy link
Member

KtorZ commented Jun 7, 2019

@Anviking

I don't see why we can't handle that in the NetworkLayer instead.

That would be a much more logical choice in my opinion. We didn't bother with this in the bridge but, for Jormungandr, being more resilient to and more expressive about faults is a good idea. So instead of making Jormungandr internals less expressive, can't we make the network layer more expressive if that makes it easier?

@Anviking
Copy link
Member Author

Anviking commented Jun 7, 2019

Yes, without throwIO we can use withExceptT.

        t@(BlockId hash) <- (getTipId j)
            `mappingError` ErrNetworkTipNetworkUnreachable
        b <- (getBlock j t)
            `mappingError` \case
            ErrGetBlockNotFound (BlockId h) ->
                ErrNetworkTipBlockNotFound h
            ErrGetBlockNetworkUnreachable e ->
                ErrNetworkTipNetworkUnreachable e
        return (hash, header b)
  where
    mappingError = flip withExceptT

I believe Maybe still has two small advantages:

  • No need to map ErrGetBlockNetworkUnreachable e -> ErrNetworkTipNetworkUnreachable e
  • Less verbose (don't have to pattern-match on ErrGetBlockNotFound, which is irrelevant information given the context)

@Anviking Anviking force-pushed the anviking/219/network-layer branch 5 times, most recently from 15dba9e to efc81f2 Compare June 7, 2019 14:18
Copy link
Member Author

@Anviking Anviking left a comment

Choose a reason for hiding this comment

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

  • I kept the errors in JormungandrLayer now
  • Some small awkwardness caused from extending ErrNetworkTip but I think it should be fine, really

@@ -148,6 +148,8 @@ rbNextBlocks bridge start = maybeTip (getNetworkTip bridge) >>= \case

maybeTip = mapExceptT $ fmap $ \case
Left (ErrNetworkTipNetworkUnreachable e) -> Left e
Left (ErrNetworkTipBlockNotFound _) -> Right Nothing
-- HttpBridge never throws ErrNetworkTipBlockNotFound.
Copy link
Member Author

Choose a reason for hiding this comment

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

Semi-awkward

@Anviking Anviking requested a review from KtorZ June 10, 2019 10:54
@KtorZ KtorZ merged commit b08524f into master Jun 11, 2019
@KtorZ KtorZ deleted the anviking/219/network-layer branch June 11, 2019 13:57
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.

3 participants