Skip to content

Refactor tapyrus-core and remove witness code and irrelevant wallet versioning. #405

@Naviabheeman

Description

@Naviabheeman

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:567GetSerializeFlags() 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:152CTransaction::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-287GetTotalSize() doc comment says "including witness data" and references BIP141/BIP144 — dead documentation.

Recommended Approach for Witness Cleanup

  1. 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.
  2. Remove m_witness_hash / ComputeWitnessHash / GetWitnessHash: Replace all callers with GetHashMalFix().
  3. Remove SERIALIZE_TRANSACTION_NO_WITNESS and all its callsites.
  4. Remove CTxIn::scriptWitness and the witness print in ToString().
  5. 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 truenWalletMaxVersion starts at FEATURE_BASE and all targets equal it
  • SetMinVersion(FEATURE_X) is always a no-opnWalletVersion 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:

  1. Keep FEATURE_BASE = 10500 as the legacy version.
  2. 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.
  3. Set FEATURE_LATEST = FEATURE_COLORED_COIN.
  4. 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.
  5. Remove CanSupportFeature(), SetMaxVersion(), nWalletMaxVersion — replace any remaining feature checks with a direct GetVersion() >= FEATURE_X comparison.
  6. Simplify SetMinVersion() to just write the version to DB when it actually changes (i.e. nWalletVersion < nVersion).
  7. Remove the uncompressed key branch in wallet.cpp:179-185 — Tapyrus always uses compressed keys; the branch is unreachable.
  8. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions