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).
This commit is contained in:
Jack Grigg 2021-09-03 01:37:16 +01:00
parent 34954e39d0
commit d715f4ecac
4 changed files with 78 additions and 9 deletions

View File

@ -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("<i", f.read(4))[0]
self.hash = deser_uint256(f)
if self.type == 5:
self.hash_aux = deser_uint256(f)
elif self.type == 1:
self.hash_aux = ((1 << 256) - 1)
def serialize(self):
r = b""
r += struct.pack("<i", self.type)
r += ser_uint256(self.hash)
if self.type == 5:
r += ser_uint256(self.hash_aux)
return r
def __repr__(self):
return "CInv(type=%s hash=%064x)" \
% (self.typemap[self.type], self.hash)
return "CInv(type=%s hash=%064x hash_aux=%064x)" \
% (self.typemap[self.type], self.hash, self.hash_aux)
class CBlockLocator(object):

View File

@ -87,17 +87,33 @@ CInv::CInv()
{
type = 0;
hash.SetNull();
hashAux.SetNull();
}
CInv::CInv(int typeIn, const uint256& hashIn)
{
assert(typeIn != MSG_WTX);
type = typeIn;
hash = hashIn;
if (typeIn == MSG_TX) {
hashAux = uint256S("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
} else {
hashAux.SetNull();
}
}
CInv::CInv(int typeIn, const uint256& hashIn, const uint256& hashAuxIn)
{
type = typeIn;
hash = hashIn;
hashAux = hashAuxIn;
}
bool operator<(const CInv& a, const CInv& b)
{
return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
return (a.type < b.type ||
(a.type == b.type && a.hash < b.hash) ||
(a.type == b.type && a.hash == b.hash && a.hashAux < b.hashAux));
}
std::string CInv::GetCommand() const
@ -107,13 +123,34 @@ std::string CInv::GetCommand() const
{
case MSG_TX: return cmd.append("tx");
case MSG_BLOCK: return cmd.append("block");
// WTX is not a message type, just an inv type
case MSG_WTX: return cmd.append("wtx");
case MSG_FILTERED_BLOCK: return cmd.append("merkleblock");
default:
throw std::out_of_range(strprintf("CInv::GetCommand(): type=%d unknown type", type));
}
}
std::vector<unsigned char> CInv::GetWideHash() const
{
assert(type != MSG_BLOCK);
if (type == MSG_TX) {
for (auto byte : hashAux) {
assert(byte == 0xff);
}
};
std::vector<unsigned char> 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());
}
}

View File

@ -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 <typename Stream, typename Operation>
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<unsigned char> 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

View File

@ -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