Skip to content

Commit e42277d

Browse files
[release/5.x] Cherry pick: Logging nulled snapshots (#7298) (#7302)
Co-authored-by: Amaury Chamayou <amchamay@microsoft.com> Co-authored-by: Amaury Chamayou <amaury@xargs.fr>
1 parent b3f2b86 commit e42277d

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1111

1212
### Added
1313

14+
- Better logging of invalid snapshots (#7302)
1415
- Logging of snapshot digests
1516

1617
## [5.0.22]

src/node/snapshot_serdes.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ namespace ccf
5050
auto store_snapshot_size =
5151
sizeof(ccf::kv::SerialisedEntryHeader) + tx_hdr.size;
5252

53+
if (tx_hdr.size == 0)
54+
{
55+
throw std::logic_error("Snapshot transaction size should not be zero");
56+
}
57+
5358
auto receipt_data = data + store_snapshot_size;
5459
auto receipt_size = size - store_snapshot_size;
5560

@@ -58,6 +63,20 @@ namespace ccf
5863
throw std::logic_error("No receipt included in snapshot");
5964
}
6065

66+
LOG_INFO_FMT("Deserialising snapshot receipt (size: {}).", receipt_size);
67+
constexpr size_t max_printed_size = 1024;
68+
if (receipt_size > max_printed_size)
69+
{
70+
LOG_INFO_FMT(
71+
"Receipt size ({}) exceeds max printed size ({}), only printing "
72+
"first {} bytes",
73+
receipt_size,
74+
max_printed_size,
75+
max_printed_size);
76+
}
77+
auto printed_size = std::min<size_t>(receipt_size, max_printed_size);
78+
LOG_INFO_FMT("{}", ds::to_hex(receipt_data, receipt_data + printed_size));
79+
6180
auto j = nlohmann::json::parse(receipt_data, receipt_data + receipt_size);
6281
auto receipt_p = j.get<ReceiptPtr>();
6382
auto receipt = std::dynamic_pointer_cast<ccf::ProofReceipt>(receipt_p);

tests/e2e_operations.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,40 @@ def test_empty_snapshot(network, args):
288288
)
289289

290290

291+
def test_nulled_snapshot(network, args):
292+
293+
with tempfile.TemporaryDirectory() as snapshots_dir:
294+
LOG.debug(f"Using {snapshots_dir} as snapshots directory")
295+
296+
snapshot_name = "snapshot_1000_1500.committed"
297+
298+
with open(
299+
os.path.join(snapshots_dir, snapshot_name), "wb+"
300+
) as temp_empty_snapshot:
301+
302+
LOG.debug(f"Created empty snapshot {temp_empty_snapshot.name}")
303+
temp_empty_snapshot.write(b"\x00" * 64)
304+
305+
LOG.info(
306+
"Attempt to join a node using the corrupted snapshot copy (should fail)"
307+
)
308+
new_node = network.create_node("local://localhost")
309+
failed = False
310+
try:
311+
network.join_node(
312+
new_node,
313+
args.package,
314+
args,
315+
snapshots_dir=snapshots_dir,
316+
)
317+
except Exception as e:
318+
failed = True
319+
LOG.info(f"Node failed to join as expected: {e}")
320+
321+
# (Existing assertion logic retained)
322+
assert failed, "Node should not have joined successfully"
323+
324+
291325
def split_all_ledger_files_in_dir(input_dir, output_dir):
292326
# A ledger file can only be split at a seqno that contains a signature
293327
# (so that all files end on a signature that verifies their integrity).
@@ -376,6 +410,7 @@ def run_file_operations(args):
376410
test_forced_snapshot(network, args)
377411
test_large_snapshot(network, args)
378412
test_empty_snapshot(network, args)
413+
test_nulled_snapshot(network, args)
379414

380415
primary, _ = network.find_primary()
381416
# Scoped transactions are not handled by historical range queries

0 commit comments

Comments
 (0)