Skip to content

Commit 5ee6b76

Browse files
committed
Merge bitcoin/bitcoin#29325: consensus: Store transaction nVersion as uint32_t
429ec1a refactor: Rename CTransaction::nVersion to version (Ava Chow) 27e70f1 consensus: Store transaction nVersion as uint32_t (Ava Chow) Pull request description: 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. ACKs for top commit: maflcko: ACK 429ec1a 🐿 glozow: ACK 429ec1a shaavan: ACK 429ec1a 💯 Tree-SHA512: 0bcd92a245d7d16c3665d2d4e815a4ef28207ad4a1fb46c6f0203cdafeab1b82c4e95e4bdce7805d80a4f4a46074f6542abad708e970550d38a00d759e3dcef1
2 parents 416e26c + 429ec1a commit 5ee6b76

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+157
-149
lines changed

contrib/signet/miner

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ def signet_txs(block, challenge):
5858
sd += block.nTime.to_bytes(4, "little")
5959

6060
to_spend = CTransaction()
61-
to_spend.nVersion = 0
61+
to_spend.version = 0
6262
to_spend.nLockTime = 0
6363
to_spend.vin = [CTxIn(COutPoint(0, 0xFFFFFFFF), b"\x00" + CScriptOp.encode_op_pushdata(sd), 0)]
6464
to_spend.vout = [CTxOut(0, challenge)]
6565
to_spend.rehash()
6666

6767
spend = CTransaction()
68-
spend.nVersion = 0
68+
spend.version = 0
6969
spend.nLockTime = 0
7070
spend.vin = [CTxIn(COutPoint(to_spend.sha256, 0), b"", 0)]
7171
spend.vout = [CTxOut(0, b"\x6a")]

doc/policy/mempool-replacements.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ other consensus and policy rules, each of the following conditions are met:
1212

1313
1. The directly conflicting transactions all signal replaceability explicitly. A transaction is
1414
signaling BIP125 replaceability if any of its inputs have an nSequence number less than (0xffffffff - 1).
15-
A transaction also signals replaceability if its nVersion field is set to 3.
15+
A transaction also signals replaceability if its version field is set to 3.
1616

1717
*Rationale*: See [BIP125
1818
explanation](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#motivation).

src/bitcoin-tx.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,12 @@ static CAmount ExtractAndValidateValue(const std::string& strValue)
203203

204204
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
205205
{
206-
int64_t newVersion;
207-
if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) {
206+
uint32_t newVersion;
207+
if (!ParseUInt32(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) {
208208
throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
209209
}
210210

211-
tx.nVersion = (int) newVersion;
211+
tx.version = newVersion;
212212
}
213213

214214
static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)

src/compressor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ struct ScriptCompression
5555
{
5656
/**
5757
* make this static for now (there are only 6 special scripts defined)
58-
* this can potentially be extended together with a new nVersion for
59-
* transactions, in which case this value becomes dependent on nVersion
58+
* this can potentially be extended together with a new version for
59+
* transactions, in which case this value becomes dependent on version
6060
* and nHeight of the enclosing transaction.
6161
*/
6262
static const unsigned int nSpecialScripts = 6;

src/consensus/tx_verify.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,7 @@ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags
4848
int nMinHeight = -1;
4949
int64_t nMinTime = -1;
5050

51-
// tx.nVersion is signed integer so requires cast to unsigned otherwise
52-
// we would be doing a signed comparison and half the range of nVersion
53-
// wouldn't support BIP 68.
54-
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
55-
&& flags & LOCKTIME_VERIFY_SEQUENCE;
51+
bool fEnforceBIP68 = tx.version >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE;
5652

5753
// Do not enforce sequence numbers as a relative lock time
5854
// unless we have been instructed to

src/core_write.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
174174

175175
entry.pushKV("txid", tx.GetHash().GetHex());
176176
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
177-
// Transaction version is actually unsigned in consensus checks, just signed in memory,
178-
// so cast to unsigned before giving it to the user.
179-
entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
177+
entry.pushKV("version", tx.version);
180178
entry.pushKV("size", tx.GetTotalSize());
181179
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
182180
entry.pushKV("weight", GetTransactionWeight(tx));

src/kernel/chainparams.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
3030
{
3131
CMutableTransaction txNew;
32-
txNew.nVersion = 1;
32+
txNew.version = 1;
3333
txNew.vin.resize(1);
3434
txNew.vout.resize(1);
3535
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));

src/policy/policy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
9393

9494
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
9595
{
96-
if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) {
96+
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) {
9797
reason = "version";
9898
return false;
9999
}

src/policy/policy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
131131
// Changing the default transaction version requires a two step process: first
132132
// adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later
133133
// allowing the new transaction version in the wallet/RPC.
134-
static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{3};
134+
static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3};
135135

136136
/**
137137
* Check for standard transaction types

src/policy/v3_policy.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ struct ParentInfo {
4343
const Txid& m_txid;
4444
/** Wtxid used for debug string */
4545
const Wtxid& m_wtxid;
46-
/** nVersion used to check inheritance of v3 and non-v3 */
47-
decltype(CTransaction::nVersion) m_version;
46+
/** version used to check inheritance of v3 and non-v3 */
47+
decltype(CTransaction::version) m_version;
4848
/** If parent is in mempool, whether it has any descendants in mempool. */
4949
bool m_has_mempool_descendant;
5050

5151
ParentInfo() = delete;
52-
ParentInfo(const Txid& txid, const Wtxid& wtxid, decltype(CTransaction::nVersion) version, bool has_mempool_descendant) :
52+
ParentInfo(const Txid& txid, const Wtxid& wtxid, decltype(CTransaction::version) version, bool has_mempool_descendant) :
5353
m_txid{txid}, m_wtxid{wtxid}, m_version{version},
5454
m_has_mempool_descendant{has_mempool_descendant}
5555
{}
@@ -66,7 +66,7 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
6666
const auto in_package_parents{FindInPackageParents(package, ptx)};
6767

6868
// Now we have all ancestors, so we can start checking v3 rules.
69-
if (ptx->nVersion == TRUC_VERSION) {
69+
if (ptx->version == TRUC_VERSION) {
7070
// SingleV3Checks should have checked this already.
7171
if (!Assume(vsize <= V3_MAX_VSIZE)) {
7272
return strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
@@ -94,14 +94,14 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
9494
Assume(mempool_parent->GetCountWithDescendants() == 1);
9595
return ParentInfo{mempool_parent->GetTx().GetHash(),
9696
mempool_parent->GetTx().GetWitnessHash(),
97-
mempool_parent->GetTx().nVersion,
97+
mempool_parent->GetTx().version,
9898
/*has_mempool_descendant=*/mempool_parent->GetCountWithDescendants() > 1};
9999
} else {
100100
auto& parent_index = in_package_parents.front();
101101
auto& package_parent = package.at(parent_index);
102102
return ParentInfo{package_parent->GetHash(),
103103
package_parent->GetWitnessHash(),
104-
package_parent->nVersion,
104+
package_parent->version,
105105
/*has_mempool_descendant=*/false};
106106
}
107107
}();
@@ -146,14 +146,14 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
146146
} else {
147147
// Non-v3 transactions cannot have v3 parents.
148148
for (auto it : mempool_ancestors) {
149-
if (it->GetTx().nVersion == TRUC_VERSION) {
149+
if (it->GetTx().version == TRUC_VERSION) {
150150
return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
151151
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
152152
it->GetSharedTx()->GetHash().ToString(), it->GetSharedTx()->GetWitnessHash().ToString());
153153
}
154154
}
155155
for (const auto& index: in_package_parents) {
156-
if (package.at(index)->nVersion == TRUC_VERSION) {
156+
if (package.at(index)->version == TRUC_VERSION) {
157157
return strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
158158
ptx->GetHash().ToString(),
159159
ptx->GetWitnessHash().ToString(),
@@ -172,12 +172,12 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra
172172
{
173173
// Check v3 and non-v3 inheritance.
174174
for (const auto& entry : mempool_ancestors) {
175-
if (ptx->nVersion != TRUC_VERSION && entry->GetTx().nVersion == TRUC_VERSION) {
175+
if (ptx->version != TRUC_VERSION && entry->GetTx().version == TRUC_VERSION) {
176176
return std::make_pair(strprintf("non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s)",
177177
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
178178
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
179179
nullptr);
180-
} else if (ptx->nVersion == TRUC_VERSION && entry->GetTx().nVersion != TRUC_VERSION) {
180+
} else if (ptx->version == TRUC_VERSION && entry->GetTx().version != TRUC_VERSION) {
181181
return std::make_pair(strprintf("v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s)",
182182
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
183183
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
@@ -189,8 +189,8 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleV3Checks(const CTra
189189
static_assert(V3_ANCESTOR_LIMIT == 2);
190190
static_assert(V3_DESCENDANT_LIMIT == 2);
191191

192-
// The rest of the rules only apply to transactions with nVersion=3.
193-
if (ptx->nVersion != TRUC_VERSION) return std::nullopt;
192+
// The rest of the rules only apply to transactions with version=3.
193+
if (ptx->version != TRUC_VERSION) return std::nullopt;
194194

195195
if (vsize > V3_MAX_VSIZE) {
196196
return std::make_pair(strprintf("v3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",

0 commit comments

Comments
 (0)