Author

Topic: Are block/Tx versions signed or unsigned? Why? (Read 291 times)

legendary
Activity: 1456
Merit: 1175
Always remember the cause!
December 09, 2018, 01:27:39 PM
#9
Still, they are not meaningful numbers. We use int or unsigned int data types when we are dealing with quantities in respected ranges or there is any possibility for such a use case in future.

In block version number case and BIP 34 we are using least significant byte to signal a compatibility level and in txn it is always set to 1 for compatibility purposes and AFAIK occasionally Shipshift sets it to 2. again sort of signaling.

Suppose we declare txn version number as char[4], then we would assert txnVN[3] should be set to a value between 1 and the highest version number.

If you think that way then everything else can only be interpreted as an array of bytes instead of a variable type. But setting the 4 bytes as an int makes things easier. For instance when you get a block and deserialize its transactions it is easier to put the first 4 bytes in an int instead of a byte array and then in the verification process you just say if version<2 && has OP_CHECKSEQUENCEVERIFY then reject as invalid rather than saying if byte[0]<2 && byte[1]==0 && byte[2]==0 && byte[3]==0 && hash OP_.....
And transaction version does have a meaning. Check BIP68.
I'm not discussing generally  Cheesy
You don't need to check other bytes, just byte[3] < 2 suffices (it is little endian AFAIK). The point is,  for the fields under discussion there is no signed or unsigned int use case ever.
Block version number is mostly used in ASIC Boost implementation for anthropy purposes, it is no int.
This is worse for txn version notto be confused with sequence number) , it is mostly set to 1 with very rare exceptions that are set to 2 by some wallets. again it is no int.
I personally don't like such a style in using integer data type when it comes to encoding I prefer to use properly sized byte arrays and int for quantization.
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
Still, they are not meaningful numbers. We use int or unsigned int data types when we are dealing with quantities in respected ranges or there is any possibility for such a use case in future.

In block version number case and BIP 34 we are using least significant byte to signal a compatibility level and in txn it is always set to 1 for compatibility purposes and AFAIK occasionally Shipshift sets it to 2. again sort of signaling.

Suppose we declare txn version number as char[4], then we would assert txnVN[3] should be set to a value between 1 and the highest version number.

If you think that way then everything else can only be interpreted as an array of bytes instead of a variable type. But setting the 4 bytes as an int makes things easier. For instance when you get a block and deserialize its transactions it is easier to put the first 4 bytes in an int instead of a byte array and then in the verification process you just say if version<2 && has OP_CHECKSEQUENCEVERIFY then reject as invalid rather than saying if byte[0]<2 && byte[1]==0 && byte[2]==0 && byte[3]==0 && hash OP_.....
And transaction version does have a meaning. Check BIP68.
legendary
Activity: 1456
Merit: 1175
Always remember the cause!
Actually nobody uses those fields as a meaningful number, they are just 4 consecutive bytes.
Incorrect.

For the block version number, due to BIP 34 style soft fork deployments, the block version number must be greater than or equal to 4. This check is always done because of those soft forks. Furthermore, because it is signed, this requirement means that the highest bit cannot be set For this reason, BIP 9 specifies that the highest most bit must be a 0.

For the transaction version number, the version number is always interpreted as a meaningful number. A standard transaction must have a version number between 1 and the maximum version number inclusive. At this time, the maximum is 2.
ُStill, they are not meaningful numbers. We use int or unsigned int data types when we are dealing with quantities in respected ranges or there is any possibility for such a use case in future.

In block version number case and BIP 34 we are using least significant byte to signal a compatibility level and in txn it is always set to 1 for compatibility purposes and AFAIK occasionally Shipshift sets it to 2. again sort of signaling.

Suppose we declare txn version number as char[4], then we would assert txnVN[3] should be set to a value between 1 and the highest version number.
staff
Activity: 3458
Merit: 6793
Just writing some code
Actually nobody uses those fields as a meaningful number, they are just 4 consecutive bytes.
Incorrect.

For the block version number, due to BIP 34 style soft fork deployments, the block version number must be greater than or equal to 4. This check is always done because of those soft forks. Furthermore, because it is signed, this requirement means that the highest bit cannot be set For this reason, BIP 9 specifies that the highest most bit must be a 0.

For the transaction version number, the version number is always interpreted as a meaningful number. A standard transaction must have a version number between 1 and the maximum version number inclusive. At this time, the maximum is 2.
legendary
Activity: 1456
Merit: 1175
Always remember the cause!
As for why, it's because satoshi chose to use an int instead of an unsigned int in the original code, so the signedness has stuck around since then.

I could find no history of or a reason for either fields, tx/block version number, to be used as a signed integer, hence there would be no side-effect in case of declaring them as unsigned in the code, Right?

That said, I don't understand how would it make any difference at all? As of my understanding of the client code, they are used neither as signed nor as unsigned integer right now.  I mean, we could just declare them as char[4], Couldn't we?


In short whether you implement it as uint or Int you will be compatible with bitcoin core implementation until version 2147483647!

But technically it should never matter as long as nobody sets the last byte bigger than 127 because that is where Int32 and UInt32 start to differ. A signed integer uses the highest bit of the last byte for its sign. For example {255, 255, 255, 255} is 4294967295 as uint but is -1 if interpreted as Int.

Actually nobody uses those fields as a meaningful number, they are just 4 consecutive bytes.
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
As for why, it's because satoshi chose to use an int instead of an unsigned int in the original code, so the signedness has stuck around since then.

I could find no history of or a reason for either fields, tx/block version number, to be used as a signed integer, hence there would be no side-effect in case of declaring them as unsigned in the code, Right?

That said, I don't understand how would it make any difference at all? As of my understanding of the client code, they are used neither as signed nor as unsigned integer right now.  I mean, we could just declare them as char[4], Couldn't we?


In short whether you implement it as uint or Int you will be compatible with bitcoin core implementation until version 2147483647!

But technically it should never matter as long as nobody sets the last byte bigger than 127 because that is where Int32 and UInt32 start to differ. A signed integer uses the highest bit of the last byte for its sign. For example {255, 255, 255, 255} is 4294967295 as uint but is -1 if interpreted as Int.
legendary
Activity: 1456
Merit: 1175
Always remember the cause!
As for why, it's because satoshi chose to use an int instead of an unsigned int in the original code, so the signedness has stuck around since then.

I could find no history of or a reason for either fields, tx/block version number, to be used as a signed integer, hence there would be no side-effect in case of declaring them as unsigned in the code, Right?

That said, I don't understand how would it make any difference at all? As of my understanding of the client code, they are used neither as signed nor as unsigned integer right now.  I mean, we could just declare them as char[4], Couldn't we?
staff
Activity: 3458
Merit: 6793
Just writing some code
Both version numbers are signed. In most cases, whether the version number is signed or not doesn't really matter. The same applies for almost every other integer used in Bitcoin.

As for why, it's because satoshi chose to use an int instead of an unsigned int in the original code, so the signedness has stuck around since then.

The only number that changed signedness was nLocktime which was originally an int. At some point, satoshi changed this to an unsigned int.
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
Bitcoin under the hood has a tendency of surprising me!
The latest one which I can't find anything about is why is block version and transaction versions defined as signed integers instead of being unsigned integers like any other 4 byte "numbers" that exists in them?

While we are on the subject, developer's reference is saying data type is uint32_t for transaction version. I wanted to open a PR but I thought maybe I am missing something since my C++ understanding is limited! (bitcoin core code?)
Jump to: