Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f602f02
Always prefer peer's snapshot
eddyashton Sep 25, 2025
d73e522
Fix operations tests
eddyashton Sep 25, 2025
f47f3da
Overwrite existing snapshot if necessary
eddyashton Sep 26, 2025
5f17e31
Merge branch 'main' into prefer_peer_snapshot
achamayou Sep 29, 2025
1d2fa4d
Merge branch 'main' into prefer_peer_snapshot
achamayou Sep 30, 2025
9ebbd47
fixes
achamayou Sep 30, 2025
83aceda
pyproject
achamayou Sep 30, 2025
ba305fd
Merge branch 'main' into prefer_peer_snapshot
cjen1-msft Oct 8, 2025
d4c57d7
Merge branch 'main' into prefer_peer_snapshot
achamayou Oct 10, 2025
5fdbf2d
Merge branch 'main' of https://github.com/microsoft/CCF into prefer_p…
eddyashton Oct 28, 2025
90b1378
Re-merge
eddyashton Oct 28, 2025
bc9bf2e
Ditch this now-unused optional
eddyashton Oct 28, 2025
0f58d45
Redirect to primray during snapshot discovery
eddyashton Oct 28, 2025
36fca72
Merge branch 'main' of https://github.com/microsoft/CCF into prefer_p…
eddyashton Oct 29, 2025
39891e1
Format
eddyashton Oct 29, 2025
6f2be23
Update docs
eddyashton Oct 29, 2025
9d611ca
Support for e2e test
eddyashton Oct 30, 2025
ff104b9
Forced e2e test
eddyashton Oct 30, 2025
42a1d26
Actually call it
eddyashton Oct 30, 2025
b2df925
Merge branch 'main' of https://github.com/microsoft/CCF into prefer_p…
eddyashton Oct 30, 2025
56251eb
Remove TODO
eddyashton Oct 30, 2025
f0c1cd5
Revert this reorder
eddyashton Oct 30, 2025
e47a05d
Simplify (and massively speed-up) test
eddyashton Oct 30, 2025
f5eaec7
Hmm format
eddyashton Oct 30, 2025
cdf3931
lol
eddyashton Oct 31, 2025
cbd6d23
Restore error clearer
eddyashton Oct 31, 2025
89e0d9c
Merge branch 'main' of https://github.com/microsoft/CCF into prefer_p…
eddyashton Oct 31, 2025
27f1653
Merge branch 'main' into prefer_peer_snapshot
eddyashton Oct 31, 2025
1cce68b
Robot
eddyashton Oct 31, 2025
b294827
Merge branch 'prefer_peer_snapshot' of https://github.com/eddyashton/…
eddyashton Oct 31, 2025
e63896b
What is going on with this
eddyashton Nov 3, 2025
6c4dc52
Merge branch 'main' into prefer_peer_snapshot
eddyashton Nov 3, 2025
0f7bea9
Update CHANGELOG.md
eddyashton Nov 3, 2025
de3f019
Merge branch 'main' into prefer_peer_snapshot
achamayou Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed

- The `submit_recovery_share.sh` script will no longer try to create a virtual environment and install the CCF Python package on every call. Instead it will return an error if the package is not installed (specifically if the `ccf_cose_sign1` tool it relies on cannot be found) (#7306)
- When the `fetch_recent_snapshots` behaviour is enabled by the node config, the Joiner will now prefer the peer's snapshot over _any_ local snapshot, regardless of version.

### Removed

Expand Down
2 changes: 1 addition & 1 deletion doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@
"fetch_recent_snapshot": {
"type": "boolean",
"default": true,
"description": "Whether to ask the target for a newer snapshot before joining. The node will ask the target what their latest snapshot is, and if that is later than what the node has locally, will fetch it via RPC before launching. Should generally only be turned off for specific test cases"
"description": "Whether to ask the target for a snapshot before joining. The node will ask the target what their latest snapshot is and will fetch it via RPC before launching. Should generally only be turned off for specific test cases"
}
},
"required": ["target_rpc_address"],
Expand Down
18 changes: 7 additions & 11 deletions src/host/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,21 +847,15 @@ namespace ccf
config.command.type == StartType::Join ||
config.command.type == StartType::Recover)
{
auto latest_local_snapshot = snapshots.find_latest_committed_snapshot();

if (
config.command.type == StartType::Join &&
config.command.join.fetch_recent_snapshot)
{
// Try to fetch a recent snapshot from peer
const size_t latest_local_idx = latest_local_snapshot.has_value() ?
snapshots::get_snapshot_idx_from_file_name(
latest_local_snapshot->second) :
0;
auto latest_peer_snapshot = snapshots::fetch_from_peer(
config.command.join.target_rpc_address,
config.command.service_certificate_file,
latest_local_idx);
std::nullopt);

if (latest_peer_snapshot.has_value())
{
Expand All @@ -876,11 +870,10 @@ namespace ccf
fs::path(latest_peer_snapshot->snapshot_name);
if (files::exists(dst_path))
{
LOG_FATAL_FMT(
"Unable to write peer snapshot - already have a file at {}. "
"Exiting.",
LOG_FAIL_FMT(
"Overwriting existing snapshot at {} with data retrieved from "
"peer",
dst_path);
return static_cast<int>(CLI::ExitCodes::FileError);
}
files::dump(latest_peer_snapshot->snapshot_data, dst_path);
startup_snapshot = latest_peer_snapshot->snapshot_data;
Expand All @@ -889,6 +882,9 @@ namespace ccf

if (startup_snapshot.empty())
{
auto latest_local_snapshot =
snapshots.find_latest_committed_snapshot();

if (latest_local_snapshot.has_value())
{
auto& [snapshot_dir, snapshot_file] = latest_local_snapshot.value();
Expand Down
24 changes: 17 additions & 7 deletions src/snapshots/fetch.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace snapshots
static std::optional<SnapshotResponse> fetch_from_peer(
const std::string& peer_address,
const std::string& path_to_peer_cert,
size_t latest_local_snapshot)
std::optional<size_t> since_seqno)
{
try
{
Expand All @@ -53,10 +53,13 @@ namespace snapshots
ccf::curl::UniqueCURL curl_easy;
curl_easy.set_opt(CURLOPT_CAINFO, path_to_peer_cert.c_str());

auto initial_url = fmt::format(
"https://{}/node/snapshot?since={}",
peer_address,
latest_local_snapshot);
auto initial_url =
fmt::format("https://{}/node/snapshot", peer_address);

if (since_seqno.has_value())
{
initial_url += fmt::format("?since={}", since_seqno.value());
}

ccf::curl::UniqueSlist headers;

Expand All @@ -83,8 +86,15 @@ namespace snapshots
}
if (status_code == HTTP_STATUS_NOT_FOUND)
{
LOG_INFO_FMT(
"Peer has no snapshot newer than {}", latest_local_snapshot);
if (since_seqno.has_value())
{
LOG_INFO_FMT(
"Peer has no snapshot newer than {}", since_seqno.value());
}
else
{
LOG_INFO_FMT("Peer has no snapshot");
}
return std::nullopt;
}
EXPECT_HTTP_RESPONSE_STATUS(
Expand Down
11 changes: 10 additions & 1 deletion tests/e2e_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,14 @@ def test_empty_snapshot(network, args):

# Create new node and join network
new_node = network.create_node("local://localhost")
network.join_node(new_node, args.package, args, snapshots_dir=snapshots_dir)
network.join_node(
new_node,
args.package,
args,
snapshots_dir=snapshots_dir,
# Don't try to fetch a snapshot, look at the local files
fetch_recent_snapshot=False,
)
new_node.stop()

# Check that the empty snapshot is correctly skipped
Expand Down Expand Up @@ -428,6 +435,8 @@ def test_nulled_snapshot(network, args):
args.package,
args,
snapshots_dir=snapshots_dir,
# Don't try to fetch a snapshot, look at the local files
fetch_recent_snapshot=False,
)
except Exception as e:
failed = True
Expand Down