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

Word16 overflow in Jörmungandr binary (SlotId) #1025

Closed
2 tasks done
KtorZ opened this issue Nov 14, 2019 · 9 comments
Closed
2 tasks done

Word16 overflow in Jörmungandr binary (SlotId) #1025

KtorZ opened this issue Nov 14, 2019 · 9 comments
Assignees

Comments

@KtorZ
Copy link
Member

KtorZ commented Nov 14, 2019

Release Operating System Cause
v2019-11-12 Windows & OSX & Linux) Code

Context

https://github.com/input-output-hk/cardano-wallet/blob/master/lib/jormungandr/src/Cardano/Wallet/Jormungandr/Binary.hs#L196

The actual slot number goes up to 32 bits!

Steps to Reproduce

  1. It crashes if it encounters a value that is too big.

Expected behavior

Actual behavior


Resolution Plan

PR

Number Base
#1026 master

QA

Regression test added -> https://github.com/input-output-hk/cardano-wallet/blob/master/lib/jormungandr/test/unit/Cardano/Wallet/Jormungandr/BinarySpec.hs#L134

@KtorZ KtorZ self-assigned this Nov 14, 2019
@KtorZ KtorZ mentioned this issue Nov 14, 2019
2 tasks
iohk-bors bot added a commit that referenced this issue Nov 14, 2019
1026: Fix SlotNo Word16 Overflow r=KtorZ a=KtorZ

# Issue Number

<!-- Put here a reference to the issue this PR relates to and which requirements it tackles -->

#1025 

# Overview

<!-- Detail in a few bullet points the work accomplished in this PR -->

- [x] I have added a regression test and... didn't saw it fail until I forced the evaluation to WHNF :'( (alternatively, could have added a bang `!` on the BlockHeader field, but I thought we might as well check everything!)

- [x] I have fixed the slot no to be `Word16`

# Comments

<!-- Additional comments or screenshots to attach if any -->

We still use this `flatSlot` to store the slot id into the database. This means that in practice, the `Epoch` can't be greater than `2^32 = 4294967296`, which, if we had a new epoch every seconds which still give us `3268` years to find a better solution to this problem.

<!-- 
Don't forget to:

 ✓ Self-review your changes to make sure nothing unexpected slipped through
 ✓ Assign yourself to the PR
 ✓ Assign one or several reviewer(s)
 ✓ Once created, link this PR to its corresponding ticket
 ✓ Acknowledge any changes required to the Wiki
-->


Co-authored-by: KtorZ <[email protected]>
@KtorZ KtorZ added this to the Usability & Compatibility milestone Nov 15, 2019
@piotr-iohk
Copy link
Contributor

@Anviking
Copy link
Member

#1048 (comment)

Ok, re-opening this then.

There was a remaining silent problem fixed by #1046.

But we should make sure to have regression tests and maybe make it fail harder / faster with an explicit invariant.

Long discussion at https://input-output-rnd.slack.com/archives/GBT05825V/p1574113682014100

@piotr-iohk
Copy link
Contributor

@Anviking OK.
I thought we'll be tracking the above under another issue, but that's also fine. Putting to in progress then.

If I understand correctly we're missing regression test for #1046.

@KtorZ
Copy link
Member Author

KtorZ commented Nov 20, 2019

And the addition of a proper invariant in the code*

@jonathanknowles
Copy link
Member

jonathanknowles commented Nov 21, 2019

@KtorZ wrote:

Define a smart-constructor with enforced invariants for EpochNo to make sure that it is never greater than 31-bit ==> TODO

Perhaps one way to enforce this invariant might be to define EpochNo in terms of a Word31:

newtype EpochNo = EpochNo { unEpochNo :: Word31 }   
    deriving stock (Show, Read, Eq, Ord, Generic)   
    deriving newtype (Num, Enum)   

And then at the point where we decode epoch numbers from binary, fail loudly if we decode something that's wider than 31 bits.

I coded up an experimental branch here: https://github.com/input-output-hk/cardano-wallet/tree/jonathanknowles/experimental-word31-epochno

@KtorZ
Copy link
Member Author

KtorZ commented Nov 21, 2019

Sounds like a good idea. Would you mind making this a PR, I'll pick it up later today 🙏

@jonathanknowles
Copy link
Member

@jonathanknowles wrote:

Perhaps one way to enforce this invariant might be to define EpochNo in terms of a Word31

@KtorZ responded:

Sounds like a good idea. Would you mind making this a PR, I'll pick it up later today pray

Sure, no problem.

Question: In terms of "failing loudly" at the point of decoding something that's wider than 31 bits, what would be your preferred mode of failure?

We could use error (along with a suitable message), but that would cause the wallet to crash. Perhaps there is a better way here.

@jonathanknowles jonathanknowles self-assigned this Nov 21, 2019
@KtorZ
Copy link
Member Author

KtorZ commented Nov 21, 2019

Failing loudly is a synonym of "crashing" from my perspective. This is clearly something that should make the application inoperative and there's no way to recover from that.

In practice, it'd only kill the servant request thread and fail with a 500, which is, acceptable.

We don't need to be really fancy here but:

λ> toEnum 875 :: Word8
*** Exception: Enum.toEnum{Word8}: tag (875) is outside of bounds (0,255)

This is already a clear enough message for example.

iohk-bors bot added a commit that referenced this issue Nov 22, 2019
1057: Use `Word31` as underlying type for `EpochNo`. r=KtorZ a=jonathanknowles

# Issue Number

#1025 

# Overview

This PR:

- [x] Changes the underlying type of `EpochNo` from `Word64` to `Word31`.
- [x] Adds validation to our Byron CBOR and Jörmungandr decoders that fail fast when encountering epoch numbers that are out of bounds.

# Outstanding work

- [x] Revise and/or simplify multiple `Arbitrary` instances for `SlotId` and `EpochNo`.
- [x] Verify that the `NFData` instance for `EpochNo` is correct.
- [x] Figure out why `fromFlatSlot . flatSlot` is failing, and fix the test (or the code).
- [x] Write tests to demonstrate that arbitrary values of `SlotId` can be persisted to the database and read back successfully.
- [ ] Write tests to demonstrate that binary decoders fail when given out-of-bounds epoch numbers.



Co-authored-by: Jonathan Knowles <[email protected]>
Co-authored-by: KtorZ <[email protected]>
iohk-bors bot added a commit that referenced this issue Nov 22, 2019
1057: Use `Word31` as underlying type for `EpochNo`. r=KtorZ a=jonathanknowles

# Issue Number

#1025 

# Overview

This PR:

- [x] Changes the underlying type of `EpochNo` from `Word64` to `Word31`.
- [x] Adds validation to our Byron CBOR and Jörmungandr decoders that fail fast when encountering epoch numbers that are out of bounds.

# Outstanding work

- [x] Revise and/or simplify multiple `Arbitrary` instances for `SlotId` and `EpochNo`.
- [x] Verify that the `NFData` instance for `EpochNo` is correct.
- [x] Figure out why `fromFlatSlot . flatSlot` is failing, and fix the test (or the code).
- [x] Write tests to demonstrate that arbitrary values of `SlotId` can be persisted to the database and read back successfully.
- [ ] Write tests to demonstrate that binary decoders fail when given out-of-bounds epoch numbers.



Co-authored-by: Jonathan Knowles <[email protected]>
Co-authored-by: KtorZ <[email protected]>
@piotr-iohk
Copy link
Contributor

ok.

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

No branches or pull requests

4 participants