Repository: bitcoin/bitcoin
File: src/addresstype.h (C/C++)

Code before:
{
    WitnessV0KeyHash() : BaseHash() {}
    explicit WitnessV0KeyHash(const uint160& hash) : BaseHash(hash) {}
    explicit WitnessV0KeyHash(const CPubKey& pubkey);
    explicit WitnessV0KeyHash(const PKHash& pubkey_hash);
};
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash);

struct WitnessV1Taproot : public XOnlyPubKey
{
    WitnessV1Taproot() : XOnlyPubKey() {}
    explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
};

//! CTxDestination subtype to encode any future Witness version
struct WitnessUnknown
{
private:
    unsigned int m_version;
    std::vector<unsigned char> m_program;

public:
    WitnessUnknown(unsigned int version, const std::vector<unsigned char>& program) : m_version(version), m_program(program) {}
    WitnessUnknown(int version, const std::vector<unsigned char>& program) : m_version(static_cast<unsigned int>(version)), m_program(program) {}

    unsigned int GetWitnessVersion() const { return m_version; }
    const std::vector<unsigned char>& GetWitnessProgram() const LIFETIMEBOUND { return m_program; }

    friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
        if (w1.GetWitnessVersion() != w2.GetWitnessVersion()) return false;
        return w1.GetWitnessProgram() == w2.GetWitnessProgram();
    }

    friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
        if (w1.GetWitnessVersion() < w2.GetWitnessVersion()) return true;
        if (w1.GetWitnessVersion() > w2.GetWitnessVersion()) return false;
        return w1.GetWitnessProgram() < w2.GetWitnessProgram();
    }
};

/**
 * A txout script categorized into standard templates.
 *  * CNoDestination: Optionally a script, no corresponding address.
 *  * PubKeyDestination: TxoutType::PUBKEY (P2PK), no corresponding address
 *  * PKHash: TxoutType::PUBKEYHASH destination (P2PKH address)
 *  * ScriptHash: TxoutType::SCRIPTHASH destination (P2SH address)
 *  * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH address)
 *  * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH address)
 *  * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR address)
 *  * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W??? address)
 *  A CTxDestination is the internal data type encoded in a bitcoin address

Review comment (suggestion):

Is there something that will prevent us from deriving `PayToAnchor` from `WitnessUnknown`?

```c++
struct PayToAnchor: public WitnessUnknown
{
    PayToAnchor() : WitnessUnknown(1, {0x4e, 0x73}) {};
    friend bool operator==(const PayToAnchor& a1, const PayToAnchor& a2) {
        return true;
    }
    friend bool operator<(const PayToAnchor& a1, const PayToAnchor& a2) {
        return true;
    }
};
```

This way we can reuse the `WitnessUnknown` operator() that should be reused.

<details>
<summary>diff</summary>

```diff
diff --git a/src/addresstype.cpp b/src/addresstype.cpp
index bfcc6cc62a4..1b22484c85b 100644
--- a/src/addresstype.cpp
+++ b/src/addresstype.cpp
@@ -143,11 +143,6 @@ public:
         return CScript() << OP_1 << ToByteVector(tap);
     }
 
-    CScript operator()(const PayToAnchor& anchor) const
-    {
-        return CScript() << OP_1 << std::vector<unsigned char>{0x4e, 0x73};
-    }
-
     CScript operator()(const WitnessUnknown& id) const
     {
         return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
diff --git a/src/addresstype.h b/src/addresstype.h
index ea59578f760..fdb2230d8ed 100644
--- a/src/addresstype.h
+++ b/src/addresstype.h
@@ -90,18 +90,6 @@ struct WitnessV1Taproot : public XOnlyPubKey
     explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
 };
 
-struct PayToAnchor
-{
-    PayToAnchor() = default;
-
-    friend bool operator==(const PayToAnchor& a1, const PayToAnchor& a2) {
-        return true;
-    }
-
-    friend bool operator<(const PayToAnchor& a1, const PayToAnchor& a2) {
-        return false;
-    }
-};
 
 //! CTxDestination subtype to encode any future Witness version
 struct WitnessUnknown
@@ -129,6 +117,18 @@ public:
     }
 };
 
+
+struct PayToAnchor: public WitnessUnknown
+{
+    PayToAnchor() : WitnessUnknown(1, {0x4e, 0x73}) {};
+    friend bool operator==(const PayToAnchor& a1, const PayToAnchor& a2) {
+        return true;
+    }
+    friend bool operator<(const PayToAnchor& a1, const PayToAnchor& a2) {
+        return true;
+    }
+};
+
 /**
  * A txout script categorized into standard templates.
  *  * CNoDestination: Optionally a script, no corresponding address.
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 6e869de8a5b..bba10011c1f 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -64,16 +64,6 @@ public:
         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, tap.begin(), tap.end());
         return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
     }
-
-    std::string operator()(const PayToAnchor& anchor) const
-    {
-        std::vector<unsigned char> data = {1};
-        std::vector<unsigned char> program = {0x4e, 0x73};
-        data.reserve(1 + (2 * 8 + 4) / 5);
-        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, program.begin(), program.end());
-        return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
-    }
-
     std::string operator()(const WitnessUnknown& id) const
     {
         const std::vector<unsigned char>& program = id.GetWitnessProgram();
``` 
</details>


Code after:
struct WitnessV0KeyHash : public BaseHash<uint160>
{
    WitnessV0KeyHash() : BaseHash() {}
    explicit WitnessV0KeyHash(const uint160& hash) : BaseHash(hash) {}
    explicit WitnessV0KeyHash(const CPubKey& pubkey);
    explicit WitnessV0KeyHash(const PKHash& pubkey_hash);
};
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash);

struct WitnessV1Taproot : public XOnlyPubKey
{
    WitnessV1Taproot() : XOnlyPubKey() {}
    explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
};

//! CTxDestination subtype to encode any future Witness version
struct WitnessUnknown
{
private:
    unsigned int m_version;
    std::vector<unsigned char> m_program;

public:
    WitnessUnknown(unsigned int version, const std::vector<unsigned char>& program) : m_version(version), m_program(program) {}
    WitnessUnknown(int version, const std::vector<unsigned char>& program) : m_version(static_cast<unsigned int>(version)), m_program(program) {}

    unsigned int GetWitnessVersion() const { return m_version; }
    const std::vector<unsigned char>& GetWitnessProgram() const LIFETIMEBOUND { return m_program; }

    friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
        if (w1.GetWitnessVersion() != w2.GetWitnessVersion()) return false;
        return w1.GetWitnessProgram() == w2.GetWitnessProgram();
    }

    friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
        if (w1.GetWitnessVersion() < w2.GetWitnessVersion()) return true;
        if (w1.GetWitnessVersion() > w2.GetWitnessVersion()) return false;
        return w1.GetWitnessProgram() < w2.GetWitnessProgram();
    }
};

struct PayToAnchor : public WitnessUnknown
{
    PayToAnchor() : WitnessUnknown(1, {0x4e, 0x73}) {
        Assume(CScript::IsPayToAnchor(1, {0x4e, 0x73}));
    };
};

/**
 * A txout script categorized into standard templates.
 *  * CNoDestination: Optionally a script, no corresponding address.