From d715f4ecace85f194d33077d81cc3ba85b8309a8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 3 Sep 2021 01:37:16 +0100 Subject: [PATCH] Implement CInv message type MSG_WTX This adds the double-hash message variant. The extra hash field is set to null for block message types, and to all-ones for MSG_TX (to match the legacy authHash value used for pre-v5 transactions in the Merkle tree). --- qa/rpc-tests/test_framework/mininode.py | 19 +++++++++--- src/protocol.cpp | 41 +++++++++++++++++++++++-- src/protocol.h | 23 ++++++++++++-- src/version.h | 4 +++ 4 files changed, 78 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 07d4e64d2..4ba38ce11 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -334,25 +334,36 @@ class CInv(object): typemap = { 0: b"Error", 1: b"TX", - 2: b"Block"} + 2: b"Block", + 5: b"WTX", + } - def __init__(self, t=0, h=0): + def __init__(self, t=0, h=0, h_aux=0): self.type = t self.hash = h + self.hash_aux = h_aux + if self.type == 1: + self.hash_aux = ((1 << 256) - 1) def deserialize(self, f): self.type = struct.unpack(" CInv::GetWideHash() const +{ + assert(type != MSG_BLOCK); + if (type == MSG_TX) { + for (auto byte : hashAux) { + assert(byte == 0xff); + } + }; + std::vector vData(hash.begin(), hash.end()); + vData.insert(vData.end(), hashAux.begin(), hashAux.end()); + return vData; +} + std::string CInv::ToString() const { - return strprintf("%s %s", GetCommand(), hash.ToString()); + switch (type) + { + case MSG_WTX: + return strprintf("%s(%s, %s)", GetCommand(), hash.ToString(), hashAux.ToString()); + default: + return strprintf("%s %s", GetCommand(), hash.ToString()); + } } diff --git a/src/protocol.h b/src/protocol.h index fd6be3105..46d575811 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -121,12 +121,12 @@ public: * to mention it in the respective ZIP, as well as checking for collisions with * BIPs we might want to backport. */ -enum GetDataMsg -{ +enum GetDataMsg : uint32_t { UNDEFINED = 0, MSG_TX = 1, MSG_BLOCK = 2, - // The following can only occur in getdata. Invs always use TX or BLOCK. + MSG_WTX = 5, //!< Defined in ZIP 239 + // The following can only occur in getdata. Invs always use TX/WTX or BLOCK. MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37 }; @@ -136,25 +136,42 @@ class CInv public: CInv(); CInv(int typeIn, const uint256& hashIn); + CInv(int typeIn, const uint256& hashIn, const uint256& hashAuxIn); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); READWRITE(type); READWRITE(hash); + if (type == MSG_WTX && nVersion >= CINV_WTX_VERSION) { + READWRITE(hashAux); + } else if (type == MSG_TX && ser_action.ForRead()) { + // Ensure that this value is set consistently in memory for MSG_TX. + hashAux = uint256S("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + } } friend bool operator<(const CInv& a, const CInv& b); std::string GetCommand() const; + std::vector GetWideHash() const; std::string ToString() const; // TODO: make private (improves encapsulation) public: int type; + // The main hash. This is: + // - MSG_BLOCK: the block hash. + // - MSG_TX and MSG_WTX: the txid. uint256 hash; + // The auxiliary hash. This is: + // - MSG_BLOCK: null (all-zeroes) and not parsed or serialized. + // - MSG_TX: legacy auth digest (all-ones) and not parsed or serialized. + // - MSG_WTX: the auth digest. + uint256 hashAux; }; #endif // BITCOIN_PROTOCOL_H diff --git a/src/version.h b/src/version.h index f8376bfb8..d66ae7a56 100644 --- a/src/version.h +++ b/src/version.h @@ -33,4 +33,8 @@ static const int MEMPOOL_GD_VERSION = 60002; //! "filter*" commands are disabled without NODE_BLOOM after and including this version static const int NO_BLOOM_VERSION = 170004; +//! Changes to CInv parsing, starting with this version: +//! - MSG_WTX type defined, which contains two 32-byte hashes. +static const int CINV_WTX_VERSION = 170014; + #endif // BITCOIN_VERSION_H