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

Integers in Tendermint #2684

Closed
ebuchman opened this issue Oct 21, 2018 · 3 comments
Closed

Integers in Tendermint #2684

ebuchman opened this issue Oct 21, 2018 · 3 comments
Labels
stale for use by stalebot T:encoding Type: Amino, ProtoBuf

Comments

@ebuchman
Copy link
Contributor

ebuchman commented Oct 21, 2018

Some time ago we resolved to use int64 for Height, primarily because signed ints are better when they might be used for arithmetic (https://blog.cosmos.network/choosing-a-type-for-blockchain-height-beware-of-unsigned-integers-714804dddf1d).

That said, recent events brought to light some issues with integers in the Tendermint codebase:

Amino

Ref #2682

Amino uses zig-zag encoding for int64 in Go, which matches sint64 in proto3, but not int64. Proto3 treats int64 and uint64 the same for positive values, but differs for sint64.

Even if we stick with signed values for fields that should never be negative, we probably don't want them zig-zag encoded (the whole point of zig-zag is more efficient negative numbers!)

If we fix this, we should be able to change the type to uint64 later without breaking the encoding

Input Validation

Ref #2683

Many messages contain vanilla int and don't perform any validation before handling, hence negative values can crash the program. Practically all the input validation that should happen is checking for negative numbers. All that code (yet to be written) would go away if we used uint.

Since moving to uint may take some time, we should meanwhile validate all our input. If we throw it away once switching to uint, so be it.

Consistency

We make mixed use of int and int64 throughout - eg. Height.Height and Header.NumTxs are int64, but Header.BlockID.PartSetHeader.Total is int. We also use int for Round.

We should probably be consistent, or at least specify the bit-size and have good reason why we go with 8/16/32/64 each time.

Summary

Arguably, the reason to stick with signed ints is because they are more natural to do arithmetic with.
First, you can't avoid being given int in Go, as it's the default value for integers (eg. x := 5, len(values), and for i, v := range values {). This means if you use anything else you have to cast to it everywhere (but note if we address the consistency issue, we'll have to do that anyways).

Second, even if some value should never be negative, you may still need to subtract two such values, and the difference could be negative. If you accidentally do this with uint you get a massive number, and it will be difficult to find out what went wrong. This can be worked around using strict linters to avoid naive arithmetic, but that makes the code a lot clunkier, though arguably much safer.

The main issue with int is that we have to ensure all objects (both those that we receive and those we create) are validated before being handled in data structures that expect non-negative numbers. It also means those data structures need to be explicit about this expectation in comments. Alternatively, we could add lots more checks for non-negativity, but as we've seen they're easy to forget.

I think we should proceed as follows:

  • Write Validation methods for all reactor input to reject negative values
  • Change Amino encoding of int64 to match proto3 int64 (and introduce a tag for zigzag, ie. to support sint64)
  • Consider iteratively moving to use uint64 everywhere and a linter that rejects any naive arithmetic
    • With the suggested Amino change, I think this should be doable without breaking encodings, but I could be mistaken.
@liamsi
Copy link
Contributor

liamsi commented Oct 22, 2018

Thanks for this summary @ebuchman!

I agree on:

Change Amino encoding of int64 to match proto3 int64 (and introduce a tag for zigzag, ie. to support sint64)

Independent from if we change to unsigned ints everywhere in tendermint or not.

Is 0.26.0 blocked on these changes (in amino)?

@tessr
Copy link
Contributor

tessr commented Nov 16, 2020

Is this still relevant now that we've switched so many things to proto? /cc @marbar3778

@tessr tessr added this to Untriaged 🥚 in Tendermint Core Project Board via automation Nov 16, 2020
@tac0turtle
Copy link
Contributor

This still applies. We need to switch all the ints to uints.

@tessr tessr moved this from Untriaged 🥚 to To Do 📝 in Tendermint Core Project Board Nov 16, 2020
@github-actions github-actions bot added the stale for use by stalebot label Sep 26, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale for use by stalebot T:encoding Type: Amino, ProtoBuf
Projects
No open projects
Development

No branches or pull requests

5 participants