Skip to content

Commit

Permalink
Gracefully handle decoding more summaries than statically known eras
Browse files Browse the repository at this point in the history
Old wallets (or other clients) that are only aware of Byron and Shelley should
be able to communicate with nodes until the hard fork to Allegra actually takes
place. At that moment, they will stop functioning as they don't know about
Allegra. The `NodeToClient` versioning mechanism takes care of this.

However, we have noticed that when the update proposal for Allegra becomes
stable, the old clients' `Summary` decoder starts to fail with:

    Summary: expected between 1 and 2 eras but got 3

This is because after the update proposal for Allegra has become stable, the
node (which is compatible with Allegra) will extend its `Summary` with an
`EraSummary` of the Allegra era. The `Summary` decoder of the old client does
not support more `EraSummary`s (3) than eras it is aware of (2) and fails. This
is /before/ the hard fork has actually happened. While the window between this
and the actual hard fork, at which point the old client would stop functioning
anyway, is small, it would still be nicer if this were handled gracefully.

So instead of failing when we receive more `EraSummary`s than eras we statically
are aware of, we ignore them. For example, a client that thinks Shelley is the
final era will ignore the `EraSummary` of Allegra (and Mary) and will keep
acting as if Shelley is the final era. Of course, when the hard fork to the next
era actually happens, the client will stop functioning as before.

Note that this fix is too late for the upcoming Allegra hard fork: only clients
that haven't been upgraded to the last release will run into this problem.
Upgrading them to the next release that includes this fix already makes the
problem go away, as they will gain support for Allegra (and Mary).

This fix will thus only help the next time, i.e., when clients are running a
version that supports Allegra and Mary (and includes this fix) but not the era
after that, i.e., Alonzo, and the update proposal to Alonzo has become stable.
  • Loading branch information
mrBliss committed Dec 15, 2020
1 parent 7d0f3f2 commit c51cd3b
Showing 1 changed file with 31 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,35 @@ instance SListI xs => Serialise (Summary xs) where
encode (Summary eraSummaries) = encode (toList eraSummaries)
decode = do
eraSummaries <- decode
case Summary <$> nonEmptyFromList eraSummaries of
-- The sender might be running a newer version that is (statically) aware
-- of more eras (@xs@) than we are. In this case, we ignore the eras past
-- the final era we are aware of rather than failing to decode.
let knownEraSummaries = take numKnownEras eraSummaries

-- When we received as many summaries as known eras, the final end
-- bound must already be unbounded, in which case this is a no-op.
--
-- When we actually had to drop some unknown eras, the now final era
-- will have a bounded end bound, as it was followed by one or more
-- eras. In this case, we make that end bound unbounded, as is always
-- the case for the final era.
go | length knownEraSummaries == numKnownEras
= fixEndBound

-- Fewer end summaries than known eras, by definition the last one
-- will /not/ have an unbounded end bound. We don't have to modify.
| otherwise
= id

case Summary . go <$> nonEmptyFromList eraSummaries of
Just summary -> return summary
Nothing -> fail $
"Summary: expected between 1 and " <> show (lengthSList (Proxy @xs)) <>
" eras but got " <> show (length eraSummaries)
Nothing -> fail "Summary: expected at least one era summary"
where
-- | The number of statically known eras.
numKnownEras :: Int
numKnownEras = lengthSList (Proxy @xs)

-- | Make the last era's end bound unbounded.
fixEndBound :: NonEmpty xs' EraSummary -> NonEmpty xs' EraSummary
fixEndBound (NonEmptyCons e es) = NonEmptyCons e (fixEndBound es)
fixEndBound (NonEmptyOne e) = NonEmptyOne e { eraEnd = EraUnbounded }

0 comments on commit c51cd3b

Please sign in to comment.