@@ -38,24 +38,40 @@ def dash_cli(*args, datadir=None):
3838 return None
3939
4040
41- # Must match src/version.h PROTOCOL_VERSION. The Dash-specific deserialize/
42- # roundtrip fuzz harnesses (src/test/fuzz/deserialize_dash.cpp,
43- # src/test/fuzz/roundtrip_dash.cpp) read a 4-byte little-endian int from the
44- # start of the buffer and use it as the stream version before deserializing
45- # the object. Chain data we extract is serialized at PROTOCOL_VERSION, so we
46- # prepend that value to seeds for those targets.
47- DASH_STREAM_VERSION = 70240
48- DASH_STREAM_VERSION_PREFIX = DASH_STREAM_VERSION .to_bytes (4 , byteorder = "little" , signed = False )
41+ # Must match src/version.h PROTOCOL_VERSION. Several fuzz harnesses read a
42+ # 4-byte little-endian int from the start of the buffer and use it as the
43+ # stream version before deserializing the object:
44+ # * The Dash-specific helpers DashDeserializeFromFuzzingInput /
45+ # DashRoundtripFromFuzzingInput (src/test/fuzz/deserialize_dash.cpp,
46+ # src/test/fuzz/roundtrip_dash.cpp), used by dash_*_deserialize and
47+ # dash_*_roundtrip targets.
48+ # * The upstream block target (src/test/fuzz/block.cpp), which reads the
49+ # version int inline before deserializing CBlock.
50+ # * The upstream block_deserialize target (src/test/fuzz/deserialize.cpp),
51+ # via DeserializeFromFuzzingInput when no explicit protocol_version is
52+ # passed.
53+ # Chain data we extract is serialized at PROTOCOL_VERSION, so we prepend
54+ # that value to seeds for those targets.
55+ STREAM_VERSION = 70240
56+ STREAM_VERSION_PREFIX = STREAM_VERSION .to_bytes (4 , byteorder = "little" , signed = False )
57+
58+ # Non-Dash targets (outside the dash_* naming convention) whose harnesses
59+ # also consume the 4-byte stream version prefix described above.
60+ _NON_DASH_STREAM_VERSION_TARGETS = frozenset ({"block" , "block_deserialize" })
4961
5062
5163def _needs_stream_version_prefix (target_name ):
5264 """Return True if this target's harness consumes a 4-byte stream version prefix.
5365
5466 Matches the DashDeserializeFromFuzzingInput / DashRoundtripFromFuzzingInput
55- helpers used by every dash_*_deserialize and dash_*_roundtrip target. Non-Dash
56- targets (block_deserialize, block, decode_tx, ...) don't use that helper and
57- must be left untouched.
67+ helpers used by every dash_*_deserialize and dash_*_roundtrip target, plus
68+ the upstream ``block`` and ``block_deserialize`` targets which do the same
69+ (see src/test/fuzz/block.cpp and src/test/fuzz/deserialize.cpp). Other
70+ non-Dash targets (decode_tx, ...) don't consume such a prefix and must be
71+ left untouched.
5872 """
73+ if target_name in _NON_DASH_STREAM_VERSION_TARGETS :
74+ return True
5975 return target_name .startswith ("dash_" ) and (
6076 target_name .endswith ("_deserialize" ) or target_name .endswith ("_roundtrip" )
6177 )
@@ -73,7 +89,7 @@ def save_corpus_input(output_dir, target_name, data_hex):
7389 return False
7490
7591 if _needs_stream_version_prefix (target_name ):
76- raw_bytes = DASH_STREAM_VERSION_PREFIX + raw_bytes
92+ raw_bytes = STREAM_VERSION_PREFIX + raw_bytes
7793
7894 filename = hashlib .sha256 (raw_bytes ).hexdigest ()[:16 ]
7995 filepath = target_dir / filename
@@ -315,7 +331,42 @@ def extract_masternode_list(output_dir, datadir=None):
315331 if not protx_hash :
316332 continue
317333
318- raw_tx = dash_cli ("getrawtransaction" , protx_hash , datadir = datadir )
334+ state = mn .get ("state" )
335+ if not isinstance (state , dict ):
336+ print (f"WARNING: Missing state for protx { protx_hash } , skipping" , file = sys .stderr )
337+ continue
338+
339+ registered_height = state .get ("registeredHeight" )
340+ try :
341+ registered_height = int (registered_height )
342+ except (TypeError , ValueError ):
343+ print (
344+ f"WARNING: Invalid registeredHeight for protx { protx_hash } : { registered_height !r} " ,
345+ file = sys .stderr ,
346+ )
347+ continue
348+
349+ block_hash = dash_cli ("getblockhash" , str (registered_height ), datadir = datadir )
350+ if not block_hash :
351+ continue
352+
353+ block_json = dash_cli ("getblock" , block_hash , "1" , datadir = datadir )
354+ if not block_json :
355+ continue
356+
357+ try :
358+ block = json .loads (block_json )
359+ except json .JSONDecodeError :
360+ continue
361+
362+ if protx_hash not in block .get ("tx" , []):
363+ print (
364+ f"WARNING: ProRegTx { protx_hash } not found in registeredHeight block { registered_height } ({ block_hash } ), skipping" ,
365+ file = sys .stderr ,
366+ )
367+ continue
368+
369+ raw_tx = dash_cli ("getrawtransaction" , protx_hash , "false" , block_hash , datadir = datadir )
319370 if not raw_tx :
320371 continue
321372
@@ -325,7 +376,7 @@ def extract_masternode_list(output_dir, datadir=None):
325376
326377 # Extract the special payload for payload-specific targets
327378 # ProRegTx type is 1, get extraPayloadSize from verbose tx
328- verbose_tx = dash_cli ("getrawtransaction" , protx_hash , "true" , datadir = datadir )
379+ verbose_tx = dash_cli ("getrawtransaction" , protx_hash , "true" , block_hash , datadir = datadir )
329380 if not verbose_tx :
330381 continue
331382 try :
0 commit comments