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

consensus: Store transaction nVersion as uint32_t #29325

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

achow101
Copy link
Member

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.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 25, 2024

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage

For detailed information about the code coverage, see the test coverage report.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK maflcko, glozow, shaavan
Concept ACK theStack, sipa
Stale ACK naumenkogs, vostrnad

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #30050 (refactor, wallet: get serialized size of CRecipients directly by josibake)
  • #29564 (wallet: clarify FundTransaction signature by S3RK)
  • #28710 (Remove the legacy wallet and BDB dependency by achow101)
  • #28676 ([WIP] Cluster mempool implementation by sdaftuar)
  • #21283 (Implement BIP 370 PSBTv2 by achow101)

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.

@achow101 achow101 changed the title consensus: Store transaction nVersion as uin32_t consensus: Store transaction nVersion as uint32_t Jan 25, 2024
@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the
documentation.

Possibly this is due to a silent merge conflict (the changes in this pull request being
incompatible with the current code in the target branch). If so, make sure to rebase on the latest
commit of the target branch.

Leave a comment here, if you need help tracking down a confusing failure.

Debug: https://github.com/bitcoin/bitcoin/runs/20879211240

@theStack
Copy link
Contributor

Concept ACK

Another instance in the tests which could be adapted to 0xffffffff:

t.nVersion = -1;

Slightly related to this PR: since this currently doesn't produce a warning, was it ever considered to enable -Wsign-conversion?

@sipa
Copy link
Member

sipa commented Jan 25, 2024

Concept ACK on making transaction's nVersion unsigned, as that is in practice how it already behaves.

Would it make sense to also rename the field to e.g. unsigned_version or so, so that:

  • Reviewing the diff makes it obvious whether any references to the field exist that aren't modified.
  • Any future contributor who missed this change won't accidentally assume the field still has signed semantics?

For normal code I'd consider this measure overkill, but this is pretty fundamental consensus-critical code.

Copy link
Member

@maflcko maflcko left a 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)

src/core_write.cpp Outdated Show resolved Hide resolved
test/functional/feature_taproot.py Outdated Show resolved Hide resolved
@maflcko
Copy link
Member

maflcko commented Jan 26, 2024

Slightly related to this PR: since this currently doesn't produce a warning, was it ever considered to enable -Wsign-conversion?

I think it is a common convention to write -1 as an alias for std::numeric_limits<unsigned ...>::max(). Also, I expect there will be many places where positive signed integers are sign-preserving converted to unsigned (and vice-versa). So enabling that compiler warning may not be possible without changing a lot more code.

Luckily, if a sign isn't preserved at runtime, during the tests, the sanitizers will catch it. (See the CI failure)

@vostrnad
Copy link

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.

@fanquake
Copy link
Member

So enabling that compiler warning may not be possible without changing a lot more code.

Yea. See here for example output compiling master with GCC 13.2.0 + -Wsign-conversion: https://gist.github.com/fanquake/8e7a49dc1968afd07d89e822ffb4adac.

Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

Concept ACK

Notes:
  1. Change the type of nVersion for transactions from int32_tuint32_t
  2. Appropriately remove casts, from the codebase
  3. Introduce test cases to properly address the change in behavior
  4. 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:

  1. 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 is uint32_t

@@ -478,6 +478,20 @@ def transaction_version_number_tests(self):
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['version'], 0x7fffffff)

Copy link
Contributor

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?

Copy link
Member Author

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.

@achow101
Copy link
Member Author

I've added a commit that renames nVersion to just version. Note that it is not a scripted diff since a bunch of different variables share the same name.

@dergoegge
Copy link
Member

  • CURRENT_VERSION should probably also change to uint32_t

  • CI failes here due to UB, can be fixed by changing to ConsumeIntegral<uint32_t>()

src/bitcoin-tx.cpp Outdated Show resolved Hide resolved
src/primitives/transaction.cpp Outdated Show resolved Hide resolved
src/primitives/transaction.cpp Outdated Show resolved Hide resolved
@achow101
Copy link
Member Author

achow101 commented Jan 29, 2024

  • CURRENT_VERSION should probably also change to uint32_t

  • CI failes here due to UB, can be fixed by changing to ConsumeIntegral<uint32_t>()

Updated these.

@achow101
Copy link
Member Author

achow101 commented Jun 4, 2024

@maflcko @vostrnad @shaavan @naumenkogs reACKs would be appreciated

@maflcko
Copy link
Member

maflcko commented Jun 5, 2024

ACK 2431ecf 🔳

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: ACK 2431ecff2fb6f4b68d3de0ea36e3bcc4403e94ba 🔳
xur9ZGGma5tikLjekGHRJ+CttEpJwRqGw/j5ke/6G6hfpK7N5+z+NP9z7nBzFBXKeGVFyAdjHuk/SQSxXJKrDQ==

Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK 2431ecf 🚀

@maflcko
Copy link
Member

maflcko commented Jun 7, 2024

ACK 659663a 🚋

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: ACK 659663af32f02c570e334e8f375fd5f5737258d7 🚋
d3lhhWY8KPIufcgBMSH5+n/TTcdj5RXJZN1O0Qj2O4NCepHVXB3nlSdnbSxKM7sufpYbbH2UrxxgSsPFbEO2Cw==

@DrahtBot DrahtBot requested a review from shaavan June 7, 2024 07:39
Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK 659663a ⚡️

@glozow
Copy link
Member

glozow commented Jun 7, 2024

concept ACK + lgtm 659663a

Seems like this is a remaining mention of CTransaction::nVersion?

bitcoin/src/compressor.h

Lines 57 to 60 in 659663a

* make this static for now (there are only 6 special scripts defined)
* this can potentially be extended together with a new nVersion for
* transactions, in which case this value becomes dependent on nVersion
* and nHeight of the enclosing transaction.

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.
@achow101
Copy link
Member Author

achow101 commented Jun 7, 2024

Rebased

Seems like this is a remaining mention of CTransaction::nVersion?

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.
@maflcko
Copy link
Member

maflcko commented Jun 9, 2024

ACK 429ec1a 🐿

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: ACK 429ec1aaaaafab150f11e27fcf132a99b57c4fc7 🐿
V0zhbzKiZuDg5Jhgt1TaDJ+/E32EhiOwnzfhBu5ZhuK2A8ZNVjfYRFlP0dTywWM3YcW0T2QOm47s8ncGNm7nAw==

@DrahtBot DrahtBot requested review from glozow and shaavan June 9, 2024 16:44
@glozow
Copy link
Member

glozow commented Jun 10, 2024

ACK 429ec1a

Thank you for rebasing!

Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK 429ec1a 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet