Skip to content

Commit

Permalink
Deny historical TX early for prev. epochs on recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
maxtropets committed Sep 28, 2024
1 parent e213df0 commit b422596
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/node/historical_queries_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,28 @@ namespace ccf::historical
}
}

// If recovery in progress, prohibit any historical queries for previous
// epochs.
auto service = args.tx.template ro<ccf::Service>(Tables::SERVICE);
auto active_service = service->get();
if (active_service && active_service->status != ServiceStatus::OPEN)
{
if (
active_service->current_service_create_txid &&
target_tx_id.view < active_service->current_service_create_txid->view)
{
auto reason = fmt::format(
"Historical transaction {} is not signed by the current service "
"identity key and can't be retrieved until recovery is complete.",
target_tx_id.to_str());
ehandler(
HistoricalQueryErrorCode::TransactionInvalid,
std::move(reason),
args);
return;
}
}

// We need a handle to determine whether this request is the 'same' as a
// previous one. For simplicity we use target_tx_id.seqno. This means we
// keep a lot of state around for old requests! It should be cleaned up
Expand Down
22 changes: 21 additions & 1 deletion tests/recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ def test_recover_service_with_wrong_identity(network, args):
network.save_service_identity(args)
first_service_identity_file = args.previous_service_identity_file

with old_primary.client() as c:
last_view, last_seq = (
c.get('/node/commit').body.json()['transaction_id'].split('.')
)

network.stop_all_nodes()

current_ledger_dir, committed_ledger_dirs = old_primary.get_ledger()
Expand Down Expand Up @@ -254,8 +259,23 @@ def test_recover_service_with_wrong_identity(network, args):
snapshots_dir=snapshots_dir,
)

recovered_network.recover(args)
primary, _ = recovered_network.find_primary()
with primary.client() as cli:
curr_view, curr_seq = (
cli.get('/node/commit').body.json()['transaction_id'].split('.')
)
response = cli.get(f"/node/receipt?transaction_id={last_view}.{last_seq}")
assert response.status_code == http.HTTPStatus.NOT_FOUND, response
assert (
"not signed by the current servic"
in response.body.json()["error"]["message"]
), response

curr_receipt = primary.get_receipt(curr_view, curr_seq)
# verify_receipt(curr_receipt.json(), network.cert)
# verify_receipt fails - missing path?..

recovered_network.recover(args)
return recovered_network


Expand Down

0 comments on commit b422596

Please sign in to comment.