-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
consensus: Store transaction nVersion as uint32_t #29325
base: master
Are you sure you want to change the base?
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
0a76440
to
59d0b7e
Compare
🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the Possibly this is due to a silent merge conflict (the changes in this pull request being Leave a comment here, if you need help tracking down a confusing failure. |
Concept ACK Another instance in the tests which could be adapted to 0xffffffff: bitcoin/src/test/transaction_tests.cpp Line 783 in 717103b
Slightly related to this PR: since this currently doesn't produce a warning, was it ever considered to enable -Wsign-conversion ?
|
Concept ACK on making transaction's Would it make sense to also rename the field to e.g.
For normal code I'd consider this measure overkill, but this is pretty fundamental consensus-critical code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that a rename of the field should be considered, but my preference would be just version
, as opposed to unsigned_version
. Otherwise, the code might be annoyingly verbose, even when it is clear to everyone that the transaction version is unsigned. (Maybe in a separate commit, so that if the changes are touching too many lines, or reviewers don't like it, it can be dropped again)
I think it is a common convention to write Luckily, if a sign isn't preserved at runtime, during the tests, the sanitizers will catch it. (See the CI failure) |
Concept ACK As someone quite familiar with Bitcoin's consensus rules but largely unfamiliar with Bitcoin Core's internals, I had no idea until recently that the version was stored as a signed integer. This should bring it in line with expectations of most future contributors. Also negative versions are just weird. |
Yea. See here for example output compiling master with GCC 13.2.0 + -Wsign-conversion: https://gist.github.com/fanquake/8e7a49dc1968afd07d89e822ffb4adac. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
Notes:
- Change the type of nVersion for transactions from
int32_t
→uint32_t
- Appropriately remove casts, from the codebase
- Introduce test cases to properly address the change in behavior
- Appropriately change the format form
<i
to<I
indicating the change from signed little-endian to unsigned little-endian when serializing and deserializing tx.nVersion.
Suggestions:
-
In
void static RandomTransaction(CMutableTransaction& tx, bool fSingle)
in sighash_tests.cpp file:tx.nVersion = int(InsecureRand32());
→tx.nVersion = InsecureRand32();
since the return type of the function isuint32_t
@@ -478,6 +478,20 @@ def transaction_version_number_tests(self): | |||
decrawtx = self.nodes[0].decoderawtransaction(rawtx) | |||
assert_equal(decrawtx['version'], 0x7fffffff) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: If we are removing the "signedness" of the tx.nVersion, should we think about removing the test cases that made sense for the signed nVersion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to leave them in to make sure that everything still matches previous versions.
59d0b7e
to
2026070
Compare
I've added a commit that renames |
d81929a
to
3a41d8c
Compare
|
3a41d8c
to
54e2d1d
Compare
Updated these. |
cc0d6bd
to
24d22af
Compare
24d22af
to
9355a50
Compare
9355a50
to
2431ecf
Compare
@maflcko @vostrnad @shaavan @naumenkogs reACKs would be appreciated |
ACK 2431ecf 🔳 Show signatureSignature:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 2431ecf 🚀
2431ecf
to
659663a
Compare
ACK 659663a 🚋 Show signatureSignature:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 659663a ⚡️
concept ACK + lgtm 659663a Seems like this is a remaining mention of Lines 57 to 60 in 659663a
Also noting that #29496 unfortunately conflicts and I would advocate for merging that first... but I'm happy to re-review |
Given that the use of a transaction's nVersion is always as an unsigned int, it doesn't make sense to store it as signed and then cast it to unsigned.
659663a
to
4855976
Compare
Rebased
Good catch, fixed. |
In order to ensure that the change of nVersion to a uint32_t in the previous commit has no effect, rename nVersion to version in this commit so that reviewers can easily spot if a spot was missed or if there is a check somewhere whose semantics have changed.
4855976
to
429ec1a
Compare
ACK 429ec1a 🐿 Show signatureSignature:
|
ACK 429ec1a Thank you for rebasing! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 429ec1a 💯
Given that the use of a transaction's nVersion is always as an unsigned int, it doesn't make sense to store it as signed and then cast it to unsigned everywhere it is used and displayed.
Since a few alternative implementations have recently been revealed to have made an error with this signedness that would have resulted in consensus failure, I think it makes sense for us to just make this always unsigned to make it clear that the version is treated as unsigned. This would also help us avoid future potential issues with signedness of this value.
I believe that this is safe and does not actually change what transactions would or would not be considered both standard and consensus valid. Within consensus, the only use of the version in consensus is in BIP68 validation which was already casting it to uint32_t. Within policy, although it is used as a signed int for the transaction version number check, I do not think that this change would change standardness. Standard transactions are limited to the range [1, 2]. Negative numbers would have fallen under the < 1 condition, but by making it unsigned, they are still non-standard under the > 2 condition.
Unsigned and signed ints are serialized and unserialized the same way so there is no change in serialization.