Dead Code Analysis: Witness & Wallet Version
1. Witness Dead Code
Tapyrus does not support SegWit/witness, but the codebase retains extensive witness scaffolding inherited from Bitcoin Core. The findings are split into two tiers.
Tier 1 — Entirely Unreachable (safest to delete)
| Item |
File(s) |
Notes |
BlockWitnessMerkleRoot() |
consensus/merkle.cpp:80-89, merkle.h:28 |
No callsites in production code |
if (tx->HasWitness()) block rejection |
validation.cpp:1423-1424 |
Always false; the reject path is dead |
HasWitness() branch in miner |
miner.cpp:205 |
Dead branch — scriptWitness is never populated |
MSG_WITNESS_TX / MSG_WITNESS_BLOCK / MSG_FILTERED_WITNESS_BLOCK cases |
net_processing.cpp:1097,1121,1244,1263,1406 |
No peer sends these message types |
IsWitnessStandard() |
policy/policy.cpp:183-232, policy.h:71 |
Only callsite is inside #ifdef DEBUG gated on HasWitness() — never reached |
Witness execution path in VerifyScript |
script/interpreter.cpp (~lines 1625-1749) |
Guarded by SCRIPT_VERIFY_WITNESS which is never included in production flags |
CountWitnessSigOps() inner body |
script/interpreter.cpp:1727+ |
Returns 0 immediately at the (flags & SCRIPT_VERIFY_WITNESS) == 0 check; the call in tx_verify.cpp:154 is a no-op |
"WITNESS" service label in GUI |
qt/guiutil.cpp:879 |
No Tapyrus node ever has NODE_WITNESS set |
Tier 2 — Present but Always No-Op (clean up for clarity)
| Item |
File(s) |
Notes |
SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000 |
primitives/transaction.h:16 |
The serializer never reads this flag; ~15 callsites pass it pointlessly (validation.cpp:603,1331, tx_verify.cpp:167, net_processing.cpp:1262,1286,1297,1383,1437,3583, rpc/rawtransaction.cpp:295,315, rpc/server.cpp:567, etc.) |
m_witness_hash field + ComputeWitnessHash() + GetWitnessHash() |
primitives/transaction.h:243,249,275, transaction.cpp:77-83,97,107,116 |
ComputeWitnessHash() always returns hash because HasWitness() is always false. All callers (core_write.cpp:186, rpc/mining.cpp:557, validation.cpp:1121) can use GetHashMalFix() directly |
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE in STANDARD_SCRIPT_VERIFY_FLAGS |
script/interpreter.h:118 |
Witness flag — has no effect since SCRIPT_VERIFY_WITNESS is never activated |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM in standard flags |
script/interpreter.h:115 |
Same — witness-guarded, never activated |
CTxIn::scriptWitness field |
primitives/transaction.h:71 |
Never serialized (not written by SerializeTransaction), never populated |
MSG_WITNESS_FLAG, MSG_WITNESS_TX, MSG_WITNESS_BLOCK constants |
protocol.h:369,384-386 |
Only MSG_WITNESS_FLAG is needed to support the peer-disconnection check; the message type constants are unused in reachable code |
NODE_WITNESS service flag |
protocol.h:262-264 |
Kept only to be checked-against and rejected; the constant itself signals a capability Tapyrus will never have |
Notes on specific callers
rpc/server.cpp:567 — GetSerializeFlags() returns SERIALIZE_TRANSACTION_NO_WITNESS as its sole flag, as if this still meaningfully strips witness data from RPC responses. It does not.
validation.cpp:1121 — script execution cache is keyed on GetWitnessHash() which always equals the regular hashMalFix. The cache works correctly but uses an unnecessarily indirect accessor.
transaction.cpp:152 — CTransaction::ToString() prints tx_in.scriptWitness.ToString() which always produces an empty string.
txmempool.h:450 — comment says totalTxSize "Differs from serialized tx size since witness data is discounted. Defined in BIP 141." This is misleading — Tapyrus has no witness discount.
transaction.h:283-287 — GetTotalSize() doc comment says "including witness data" and references BIP141/BIP144 — dead documentation.
Recommended Approach for Witness Cleanup
- Tier 1 first (zero risk — unreachable): Delete
BlockWitnessMerkleRoot, IsWitnessStandard, the MSG_WITNESS_* cases in net_processing, the HasWitness() guards in miner.cpp and validation.cpp.
- Remove
m_witness_hash / ComputeWitnessHash / GetWitnessHash: Replace all callers with GetHashMalFix().
- Remove
SERIALIZE_TRANSACTION_NO_WITNESS and all its callsites.
- Remove
CTxIn::scriptWitness and the witness print in ToString().
- Remove witness flags from
STANDARD_SCRIPT_VERIFY_FLAGS: SCRIPT_VERIFY_WITNESS_PUBKEYTYPE and SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM.
2. Wallet Version Dead Code
Root Cause
In wallet.h:80-96, every FEATURE_* constant was collapsed to FEATURE_BASE = 10500 (compared to Bitcoin Core where they have distinct values like FEATURE_HD = 130000, FEATURE_HD_SPLIT = 139900):
enum WalletFeature
{
FEATURE_BASE = 10500,
FEATURE_WALLETCRYPT = FEATURE_BASE, // was 40000 in Bitcoin Core
FEATURE_COMPRPUBKEY = FEATURE_BASE, // was 60000 in Bitcoin Core
FEATURE_HD = FEATURE_BASE, // was 130000 in Bitcoin Core
FEATURE_HD_SPLIT = FEATURE_BASE, // was 139900 in Bitcoin Core
FEATURE_NO_DEFAULT_KEY = FEATURE_BASE, // was 159900 in Bitcoin Core
FEATURE_PRE_SPLIT_KEYPOOL = FEATURE_BASE, // was 169900 in Bitcoin Core
FEATURE_LATEST = FEATURE_BASE // = 10500
};
Because every constant equals 10500:
CanSupportFeature(FEATURE_X) always returns true — nWalletMaxVersion starts at FEATURE_BASE and all targets equal it
SetMinVersion(FEATURE_X) is always a no-op — nWalletVersion starts at 10500 and the early-return if (nWalletVersion >= nVersion) fires immediately for every FEATURE_*
- All version-conditional branches have a permanently dead else-branch
Dead Code Resulting from Collapsed Constants
| Item |
Location |
Impact |
| Uncompressed key path |
wallet.cpp:179-185 |
CanSupportFeature(FEATURE_COMPRPUBKEY) always true → the fCompressed = false branch is dead; Tapyrus always uses compressed keys |
CHDChain::VERSION_HD_BASE path |
wallet.cpp:1487 |
CanSupportFeature(FEATURE_HD_SPLIT) always true → always picks VERSION_HD_CHAIN_SPLIT; the HD_BASE branch is dead |
split_upgrade / MarkPreSplitKeys() |
wallet.cpp:4168-4172 |
FEATURE_HD_SPLIT > prev_version evaluates to 10500 > 10500 = always false; MarkPreSplitKeys() is never called |
SetMinVersion() body |
wallet.cpp:480-501 |
Always returns at the first guard; WriteMinVersion() and all upgrade logic below it are dead |
SetMaxVersion() |
wallet.cpp:503-513 |
Functionally vacuous — the range [nWalletVersion, nWalletMaxVersion] is always a single point |
All CanSupportFeature() callsites |
wallet.cpp:179,189,231,692,1487,3415,3460,3563,4155,4165,4168, rpcwallet.cpp:2429 |
Always true; all else-branches are dead |
nMinVersion > FEATURE_LATEST guard |
walletdb.cpp:536,634 |
10500 > 10500 — the DBErrors::TOO_NEW path is dead |
FEATURE_WALLETCRYPT through FEATURE_PRE_SPLIT_KEYPOOL enum values |
wallet.h:80-96 |
Dead as distinct version guards; semantically equivalent to FEATURE_BASE |
-upgradewallet upgrade logic |
wallet.cpp:4130-4180 |
All version comparisons resolve trivially; no actual upgrade steps are performed |
Still Active
| Item |
Notes |
GetVersion() |
Used by getwalletinfo RPC to report walletversion — keep |
FEATURE_BASE = 10500 |
Defines the version number written to DB and reported via RPC — keep |
LoadMinVersion() in walletdb.cpp |
Reads stored version from DB — keep the read; the TOO_NEW guard can be repurposed for the new version |
Recommended Approach for Wallet Version Cleanup
Tapyrus now has two wallet versions: the original (10500) and a new one introduced with coloured coin GUI support. The right path forward:
- Keep
FEATURE_BASE = 10500 as the legacy version.
- Add a new constant (e.g.
FEATURE_COLORED_COIN = 10501 or a round number like 20000) for the new wallet format introduced by coloured coin GUI support.
- Set
FEATURE_LATEST = FEATURE_COLORED_COIN.
- Delete all intermediate
FEATURE_* constants (FEATURE_WALLETCRYPT, FEATURE_COMPRPUBKEY, FEATURE_HD, FEATURE_HD_SPLIT, FEATURE_NO_DEFAULT_KEY, FEATURE_PRE_SPLIT_KEYPOOL) — they were inherited from Bitcoin Core and were never meaningful in Tapyrus.
- Remove
CanSupportFeature(), SetMaxVersion(), nWalletMaxVersion — replace any remaining feature checks with a direct GetVersion() >= FEATURE_X comparison.
- Simplify
SetMinVersion() to just write the version to DB when it actually changes (i.e. nWalletVersion < nVersion).
- Remove the uncompressed key branch in
wallet.cpp:179-185 — Tapyrus always uses compressed keys; the branch is unreachable.
- Repurpose the
nMinVersion > FEATURE_LATEST guard in walletdb.cpp to actually gate on the new FEATURE_COLORED_COIN version, so old wallet binaries refuse to open new-format wallets gracefully.
Dead Code Analysis: Witness & Wallet Version
1. Witness Dead Code
Tapyrus does not support SegWit/witness, but the codebase retains extensive witness scaffolding inherited from Bitcoin Core. The findings are split into two tiers.
Tier 1 — Entirely Unreachable (safest to delete)
BlockWitnessMerkleRoot()consensus/merkle.cpp:80-89,merkle.h:28if (tx->HasWitness())block rejectionvalidation.cpp:1423-1424HasWitness()branch in minerminer.cpp:205scriptWitnessis never populatedMSG_WITNESS_TX/MSG_WITNESS_BLOCK/MSG_FILTERED_WITNESS_BLOCKcasesnet_processing.cpp:1097,1121,1244,1263,1406IsWitnessStandard()policy/policy.cpp:183-232,policy.h:71#ifdef DEBUGgated onHasWitness()— never reachedVerifyScriptscript/interpreter.cpp(~lines 1625-1749)SCRIPT_VERIFY_WITNESSwhich is never included in productionflagsCountWitnessSigOps()inner bodyscript/interpreter.cpp:1727+(flags & SCRIPT_VERIFY_WITNESS) == 0check; the call intx_verify.cpp:154is a no-op"WITNESS"service label in GUIqt/guiutil.cpp:879NODE_WITNESSsetTier 2 — Present but Always No-Op (clean up for clarity)
SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000primitives/transaction.h:16validation.cpp:603,1331,tx_verify.cpp:167,net_processing.cpp:1262,1286,1297,1383,1437,3583,rpc/rawtransaction.cpp:295,315,rpc/server.cpp:567, etc.)m_witness_hashfield +ComputeWitnessHash()+GetWitnessHash()primitives/transaction.h:243,249,275,transaction.cpp:77-83,97,107,116ComputeWitnessHash()always returnshashbecauseHasWitness()is always false. All callers (core_write.cpp:186,rpc/mining.cpp:557,validation.cpp:1121) can useGetHashMalFix()directlySCRIPT_VERIFY_WITNESS_PUBKEYTYPEinSTANDARD_SCRIPT_VERIFY_FLAGSscript/interpreter.h:118SCRIPT_VERIFY_WITNESSis never activatedSCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAMin standard flagsscript/interpreter.h:115CTxIn::scriptWitnessfieldprimitives/transaction.h:71SerializeTransaction), never populatedMSG_WITNESS_FLAG,MSG_WITNESS_TX,MSG_WITNESS_BLOCKconstantsprotocol.h:369,384-386MSG_WITNESS_FLAGis needed to support the peer-disconnection check; the message type constants are unused in reachable codeNODE_WITNESSservice flagprotocol.h:262-264Notes on specific callers
rpc/server.cpp:567—GetSerializeFlags()returnsSERIALIZE_TRANSACTION_NO_WITNESSas its sole flag, as if this still meaningfully strips witness data from RPC responses. It does not.validation.cpp:1121— script execution cache is keyed onGetWitnessHash()which always equals the regularhashMalFix. The cache works correctly but uses an unnecessarily indirect accessor.transaction.cpp:152—CTransaction::ToString()printstx_in.scriptWitness.ToString()which always produces an empty string.txmempool.h:450— comment saystotalTxSize"Differs from serialized tx size since witness data is discounted. Defined in BIP 141." This is misleading — Tapyrus has no witness discount.transaction.h:283-287—GetTotalSize()doc comment says "including witness data" and references BIP141/BIP144 — dead documentation.Recommended Approach for Witness Cleanup
BlockWitnessMerkleRoot,IsWitnessStandard, theMSG_WITNESS_*cases innet_processing, theHasWitness()guards inminer.cppandvalidation.cpp.m_witness_hash/ComputeWitnessHash/GetWitnessHash: Replace all callers withGetHashMalFix().SERIALIZE_TRANSACTION_NO_WITNESSand all its callsites.CTxIn::scriptWitnessand the witness print inToString().STANDARD_SCRIPT_VERIFY_FLAGS:SCRIPT_VERIFY_WITNESS_PUBKEYTYPEandSCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM.2. Wallet Version Dead Code
Root Cause
In
wallet.h:80-96, everyFEATURE_*constant was collapsed toFEATURE_BASE = 10500(compared to Bitcoin Core where they have distinct values likeFEATURE_HD = 130000,FEATURE_HD_SPLIT = 139900):Because every constant equals
10500:CanSupportFeature(FEATURE_X)always returnstrue—nWalletMaxVersionstarts atFEATURE_BASEand all targets equal itSetMinVersion(FEATURE_X)is always a no-op —nWalletVersionstarts at10500and the early-returnif (nWalletVersion >= nVersion)fires immediately for everyFEATURE_*Dead Code Resulting from Collapsed Constants
wallet.cpp:179-185CanSupportFeature(FEATURE_COMPRPUBKEY)always true → thefCompressed = falsebranch is dead; Tapyrus always uses compressed keysCHDChain::VERSION_HD_BASEpathwallet.cpp:1487CanSupportFeature(FEATURE_HD_SPLIT)always true → always picksVERSION_HD_CHAIN_SPLIT; theHD_BASEbranch is deadsplit_upgrade/MarkPreSplitKeys()wallet.cpp:4168-4172FEATURE_HD_SPLIT > prev_versionevaluates to10500 > 10500= alwaysfalse;MarkPreSplitKeys()is never calledSetMinVersion()bodywallet.cpp:480-501WriteMinVersion()and all upgrade logic below it are deadSetMaxVersion()wallet.cpp:503-513[nWalletVersion, nWalletMaxVersion]is always a single pointCanSupportFeature()callsiteswallet.cpp:179,189,231,692,1487,3415,3460,3563,4155,4165,4168,rpcwallet.cpp:2429nMinVersion > FEATURE_LATESTguardwalletdb.cpp:536,63410500 > 10500— theDBErrors::TOO_NEWpath is deadFEATURE_WALLETCRYPTthroughFEATURE_PRE_SPLIT_KEYPOOLenum valueswallet.h:80-96FEATURE_BASE-upgradewalletupgrade logicwallet.cpp:4130-4180Still Active
GetVersion()getwalletinfoRPC to reportwalletversion— keepFEATURE_BASE = 10500LoadMinVersion()inwalletdb.cppTOO_NEWguard can be repurposed for the new versionRecommended Approach for Wallet Version Cleanup
Tapyrus now has two wallet versions: the original (
10500) and a new one introduced with coloured coin GUI support. The right path forward:FEATURE_BASE = 10500as the legacy version.FEATURE_COLORED_COIN = 10501or a round number like20000) for the new wallet format introduced by coloured coin GUI support.FEATURE_LATEST = FEATURE_COLORED_COIN.FEATURE_*constants (FEATURE_WALLETCRYPT,FEATURE_COMPRPUBKEY,FEATURE_HD,FEATURE_HD_SPLIT,FEATURE_NO_DEFAULT_KEY,FEATURE_PRE_SPLIT_KEYPOOL) — they were inherited from Bitcoin Core and were never meaningful in Tapyrus.CanSupportFeature(),SetMaxVersion(),nWalletMaxVersion— replace any remaining feature checks with a directGetVersion() >= FEATURE_Xcomparison.SetMinVersion()to just write the version to DB when it actually changes (i.e.nWalletVersion < nVersion).wallet.cpp:179-185— Tapyrus always uses compressed keys; the branch is unreachable.nMinVersion > FEATURE_LATESTguard inwalletdb.cppto actually gate on the newFEATURE_COLORED_COINversion, so old wallet binaries refuse to open new-format wallets gracefully.