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

Add a backwards-compatible proposal for future-proofing the type-bits #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions spec/cashaddr.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ The payload is a base32 encoded stream of data.
| +24 | c | e | 6 | m | u | a | 7 | l |

The payload is composed of 3 elements:
1. A version byte indicating the type of address.
1. A version variable-sized integer [[4]](#varint)
2. A hash.
3. A 40 bits checksum.

#### Version byte
#### Version VarInt
Copy link
Contributor

Choose a reason for hiding this comment

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

This is implied by the reservation of the leftmost bit being 0, but it may be good to make this explicit. @deadalnix

Also we should update the version number.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simply saying that the leftmost bit is reserved is not the same thing as implying that it is to be interpreted as a 0xFD 0xFE 0xFF Bitcoin VarInt. :) I don't know of any implementations that do that If that's the case, we should make it explicit now (like I've done in the pull request).

Like actually say that if the first byte is 0xFD then there are two more bytes of version, 0xFE for 4 bytes, 0xFF for 8 bytes, like in the rest of the Bitcoin code, would be nice.

Copy link
Contributor

@avl42 avl42 May 22, 2018

Choose a reason for hiding this comment

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

Slightly confused... are we turning the whole version byte into a VarInt, or just the type part of it? If it's about the full version byte, then we'd also need to define how many of the LSBits will then be the payload-size part for each of the VarInt-sizes.

Copy link
Contributor Author

@Steve132 Steve132 May 22, 2018

Choose a reason for hiding this comment

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

The whole version byte becomes a varint. That's necessary in order to maintain backcompat with existing spec for MSB=0. It also simplifies the implementation quite a bit.

This doesn't extend the potential sizes of the payload, because that's beyond the scope of this spec, which is designed to be simple. The sizes are still the 8 sizes defined in the spec. Under this change, the sizes are still the 8 sizes defined in the spec.

However, we could later define a region of the larger 64-bit type space for which the sizes are extended if we wanted. However, that's impossible unless we first extend the type space.

Side note: is there a reason that CashAddr doesn't simply do what bech32 does and actually use a serialization of the scriptPubKey? That would allow us to skip a large headache with all of these different address types and stuff completely and then people would be able to automatically see what kind of address it was (if there's any weird non-standard scriptPubKeys) from the serialization.

Maybe a separate discussion should be added for implementing that as a type (like type 04?) and cut off a lot of the need for weird new types off at the pass? Pros: new weird smart contracts with weird scriptPubKeys don't need a new type for each kind of smart contract, because the whole thing is in the address. Cons: It would be possible to construct two valid addresses for a p2sh or p2pkh address (one the 'standard' way and one by encoding the scriptPubKey)

Copy link
Contributor

Choose a reason for hiding this comment

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

If we first extended the type-range, it would otoh be impossible to later define different payload-sizes for certain sub-ranges of types...

Copy link
Contributor Author

@Steve132 Steve132 May 24, 2018

Choose a reason for hiding this comment

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

If we first extended the type-range, it would otoh be impossible to later define different payload-sizes for certain sub-ranges of types...

That's not the case. In fact, it's the opposite. What we're really doing here is extending the entire version byte to potentially be larger to be a version int.

For example, later extensions could say that if the version int is between 0x4000 and 0x8000, then in that case the bottom 8 bits define the size instead of the bottom 3. Parsers that don't recognize 0x4000 as a valid type will then simply fail to parse and explain why (unsupported version) versus the status quo.

My proposal allows for backwards compatibility with existing code while still allowing forwards extensions like you're proposing.

The version varint is between 8 and 72 bits representing a variable-sized integer as defined in [[4]](#varint).

The version byte's most signficant bit is reserved and must be 0. The 4 next bits indicate the type of address and the 3 least significant bits indicate the size of the hash.
The 3 least significant bits of the version varint indicate the size of the hash.

| Size bits | Hash size in bits |
| --------: | ----------------: |
Expand All @@ -60,7 +61,9 @@ The version byte's most signficant bit is reserved and must be 0. The 4 next bit

Encoding the size of the hash in the version field ensure that it is possible to check that the length of the address is correct.

| Type bits | Meaning | Version byte value |
The higher bits (bits 3 and above) of the version varint indicate the "type" of the address. The version varint *must* use the minimum possible sized encoding for the integer it represents. (e.g, a version int of 8 must be represented by 1 byte 0x08, and may not be represented by 0xFD0008)

| Type bits | Meaning | Version varint value |
| --------: | :---------------: | -----------------: |
| 0 | P2KH | 0 |
| 1 | P2SH | 8 |
Expand Down Expand Up @@ -154,3 +157,5 @@ The following addresses are given in the legacy and new format.
<a name="bip173">[2]</a> https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki

<a name="alphanumqr">[3]</a> http://www.thonky.com/qr-code-tutorial/alphanumeric-mode-encoding

<a name="varint">[4]</a> https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer