diff --git a/src/protocol.h b/src/protocol.h --- a/src/protocol.h +++ b/src/protocol.h @@ -310,6 +310,12 @@ * Sent in response to a "avapoll" message. */ extern const char *AVARESPONSE; +/** + * Contains an avalanche::Proof. + * Sent in response to a "getdata" message with inventory type + * MSG_AVA_PROOF. + */ +extern const char *AVAPROOF; /** * Indicate if the message is used to transmit the content of a block. @@ -495,6 +501,7 @@ MSG_FILTERED_BLOCK = 3, //! Defined in BIP152 MSG_CMPCT_BLOCK = 4, + MSG_AVA_PROOF = 0x1f000001, }; /** diff --git a/src/protocol.cpp b/src/protocol.cpp --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -54,6 +54,7 @@ const char *AVAHELLO = "avahello"; const char *AVAPOLL = "avapoll"; const char *AVARESPONSE = "avaresponse"; +const char *AVAPROOF = "avaproof"; bool IsBlockLike(const std::string &strCommand) { return strCommand == NetMsgType::BLOCK || diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -26,6 +26,7 @@ import socket import struct import time +import unittest from typing import List @@ -63,6 +64,7 @@ MSG_BLOCK = 2 MSG_FILTERED_BLOCK = 3 MSG_CMPCT_BLOCK = 4 +MSG_AVA_PROOF = 0x1f000001 MSG_TYPE_MASK = 0xffffffff >> 2 FILTER_TYPE_BASIC = 0 @@ -302,7 +304,8 @@ MSG_TX: "TX", MSG_BLOCK: "Block", MSG_FILTERED_BLOCK: "filtered Block", - MSG_CMPCT_BLOCK: "CompactBlock" + MSG_CMPCT_BLOCK: "CompactBlock", + MSG_AVA_PROOF: "avalanche proof", } def __init__(self, t=0, h=0): @@ -830,6 +833,24 @@ self.blockhash, repr(self.transactions)) +class AvalancheProof: + __slots__ = ("blob") + + def __init__(self, blob: bytes = b""): + self.blob: bytes = blob + + def deserialize(self, f): + self.blob = f.read() + + def serialize(self): + r = b"" + r += self.blob + return r + + def __repr__(self): + return "AvalancheProof({})".format(self.serialize().hex()) + + class AvalanchePoll(): __slots__ = ("round", "invs") @@ -1800,6 +1821,25 @@ self.filter_type, self.stop_hash) +class msg_avaproof(): + __slots__ = ("proof",) + msgtype = b"avaproof" + + def __init__(self): + self.proof = AvalancheProof() + + def deserialize(self, f): + self.proof.deserialize(f) + + def serialize(self): + r = b"" + r += self.proof.serialize() + return r + + def __repr__(self): + return "msg_avaproof(proof={})".format(repr(self.proof)) + + class msg_avapoll(): __slots__ = ("poll",) msgtype = b"avapoll" @@ -1874,3 +1914,27 @@ def __repr__(self): return "msg_avahello(response={})".format(repr(self.hello)) + + +class TestFrameworkMessages(unittest.TestCase): + def test_serialization_round_trip(self): + """Verify that messages and serialized objects are unchanged after + a round-trip of deserialization-serialization. + """ + avaproof = AvalancheProof() + proof_hex = ( + "2a00000000000000fff053650000000021030b4c866585dd868a9d62348a9cd00" + "8d6a312937048fff31670e7e920cfc7a74401b7fc19792583e9cb39843fc5e22a" + "4e3648ab1cb18a70290b341ee8d4f550ae2400000000102700000000000078881" + "4004104d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df" + "42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c9764" + "8cb0ac3052d58da74de7404e84ebe2940ed2b0fe85578d8230788d8387aeaa618" + "274b0f2edc73679fd398f60e6315258c9ec348df7fcc09340ae1af37d009719b0" + "665" + ) + avaproof.deserialize(BytesIO(bytes.fromhex(proof_hex))) + self.assertEqual(avaproof.serialize().hex(), proof_hex) + + msg_proof = msg_avaproof() + msg_proof.proof = avaproof + self.assertEqual(msg_proof.serialize().hex(), proof_hex) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -30,6 +30,7 @@ msg_addr, msg_addrv2, msg_avapoll, + msg_avaproof, msg_tcpavaresponse, msg_avahello, msg_block, @@ -74,6 +75,7 @@ b"addr": msg_addr, b"addrv2": msg_addrv2, b"avapoll": msg_avapoll, + b"avaproof": msg_avaproof, b"avaresponse": msg_tcpavaresponse, b"avahello": msg_avahello, b"block": msg_block, @@ -385,6 +387,8 @@ def on_avapoll(self, message): pass + def on_avaproof(self, message): pass + def on_avaresponse(self, message): pass def on_avahello(self, message): pass diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -77,6 +77,7 @@ TEST_FRAMEWORK_MODULES = [ "address", "blocktools", + "messages", "script", ]