20 template <
typename Input>
22 std::function<std::optional<ErrorDetails>(
25 template <
typename Input>
30 return [cb = std::move(cb), &node_context](
34 if (config ==
nullptr || node_operation ==
nullptr)
37 HTTP_STATUS_BAD_REQUEST,
38 ccf::errors::InvalidNodeState,
39 "Unable to open recovery-decision-protocol subsystems");
43 !config->get().node_config.sealing_recovery.has_value() ||
45 .node_config.sealing_recovery->recovery_decision_protocol
49 HTTP_STATUS_BAD_REQUEST,
50 ccf::errors::InvalidNodeState,
51 "This node cannot do recovery-decision-protocol");
54 auto in = params.get<Input>();
60 args.
rpc_ctx->get_session_context()->caller_cert);
64 args.
tx, info.quote_info, cert_der, measurement, std::nullopt,
nullptr);
67 const auto [code, message] = quote_verification_error(verify_result);
69 "Recovery-decision-protocol message from {} has an invalid quote: {} "
74 return make_error(code, ccf::errors::InvalidQuote, message);
78 "Recovery-decision-protocol message from location name {} has a valid "
86 auto* node_info_handle =
88 Tables::RECOVERY_DECISION_PROTOCOL_NODES);
89 auto existing_node_info = node_info_handle->get(info.location.name);
91 if (existing_node_info.has_value())
94 if (existing_node_info->node_cert_der != cert_der)
96 auto message = fmt::format(
97 "Recovery-decision-protocol message from location {} is "
99 "certificate public key has changed",
103 HTTP_STATUS_BAD_REQUEST, ccf::errors::NodeAlreadyExists, message);
112 node_info_handle->put(info.location.name, src_info);
117 auto ret = cb(args, in);
128 node_operation->recovery_decision_protocol().advance(args.
tx,
false);
130 catch (
const std::logic_error& e)
133 "Recovery-decision-protocol failed to advance state: {}", e.what());
135 HTTP_STATUS_INTERNAL_SERVER_ERROR,
136 ccf::errors::InternalError,
138 "Failed to advance recovery-decision-protocol state: {}",
146 static void init_recovery_decision_protocol_handlers(
150 auto recovery_decision_protocol_gossip =
152 -> std::optional<ErrorDetails> {
154 "Recovery-decision-protocol: receive gossip from {}",
155 in.info.location.name);
158 auto chosen_replica =
159 args.tx.template ro<recovery_decision_protocol::ChosenNode>(
160 Tables::RECOVERY_DECISION_PROTOCOL_CHOSEN_NODE);
161 if (chosen_replica->get().has_value())
164 .
status = HTTP_STATUS_INTERNAL_SERVER_ERROR,
165 .code = ccf::errors::InternalError,
167 "This node has already voted for {}",
168 chosen_replica->get().value())};
172 args.tx.template rw<recovery_decision_protocol::Gossips>(
173 Tables::RECOVERY_DECISION_PROTOCOL_GOSSIPS);
174 if (gossip_handle->get(in.info.location.name).has_value())
177 "Node {} already gossiped, skipping", in.info.location.name);
180 gossip_handle->put(in.info.location.name, in.txid);
185 "/recovery_decision_protocol/gossip",
188 recovery_decision_protocol::GossipRequest>(
189 recovery_decision_protocol_gossip, node_context)),
195 auto recovery_decision_protocol_vote =
196 [](
auto& args, recovery_decision_protocol::TaggedWithNodeInfo in)
197 -> std::optional<ErrorDetails> {
199 "Recovery-decision-protocol: receive vote from {}",
200 in.info.location.name);
203 .template rw<recovery_decision_protocol::Votes>(
204 Tables::RECOVERY_DECISION_PROTOCOL_VOTES)
205 ->insert(in.info.location.name);
211 "/recovery_decision_protocol/vote",
214 recovery_decision_protocol::TaggedWithNodeInfo>(
215 recovery_decision_protocol_vote, node_context)),
221 auto recovery_decision_protocol_iamopen =
222 [&node_context](
auto& args, recovery_decision_protocol::IAmOpenRequest in)
223 -> std::optional<ErrorDetails> {
224 auto sm_state = args.tx
225 .template ro<recovery_decision_protocol::SMState>(
226 Tables::RECOVERY_DECISION_PROTOCOL_SM_STATE)
228 if (!sm_state.has_value())
230 throw std::logic_error(
231 "Recovery-decision-protocol state machine state is not set");
238 auto node_operation =
240 auto& self_iamopen_request =
241 node_operation->recovery_decision_protocol().get_iamopen_request(
244 auto myid = fmt::format(
245 "{}:{} previously {}@{}",
246 self_iamopen_request.info.location.name,
249 self_iamopen_request.info.service_cert_der)),
250 self_iamopen_request.prev_service_fingerprint,
251 self_iamopen_request.txid.to_str());
252 auto inid = fmt::format(
253 "{}:{} previously {}@{}",
254 in.info.location.name,
257 in.prev_service_fingerprint,
260 "{} is already open, ignoring IAmOpen from {}", myid, inid);
263 .status = HTTP_STATUS_BAD_REQUEST,
264 .code = ccf::errors::InvalidNodeState,
265 .msg =
"Node is already open, ignoring iamopen request"};
269 "Recovery-decision-protocol: receive IAmOpen from {}",
270 in.info.location.name);
272 .template rw<recovery_decision_protocol::SMState>(
273 Tables::RECOVERY_DECISION_PROTOCOL_SM_STATE)
276 .template rw<recovery_decision_protocol::ChosenNode>(
277 Tables::RECOVERY_DECISION_PROTOCOL_CHOSEN_NODE)
278 ->put(in.info.location.name);
283 "/recovery_decision_protocol/iamopen",
286 recovery_decision_protocol::IAmOpenRequest>(
287 recovery_decision_protocol_iamopen, node_context)),
293 auto recovery_decision_protocol_timeout = [&](
295 const nlohmann::json& params) {
297 auto config = node_context.
get_subsystem<NodeConfigurationSubsystem>();
298 auto node_operation = node_context.
get_subsystem<AbstractNodeOperation>();
299 if (config ==
nullptr || node_operation ==
nullptr)
302 HTTP_STATUS_BAD_REQUEST,
303 ccf::errors::InvalidNodeState,
304 "Unable to open recovery-decision-protocol subsystems");
307 auto sealing_recovery_config = config->get().node_config.sealing_recovery;
310 !sealing_recovery_config.has_value() ||
311 !sealing_recovery_config->recovery_decision_protocol.has_value())
314 HTTP_STATUS_BAD_REQUEST,
315 ccf::errors::InvalidNodeState,
316 "This node cannot do recovery-decision-protocol");
319 LOG_TRACE_FMT(
"Recovery-decision-protocol timeout received");
322 auto primary_id = node_operation->get_primary();
323 if (!primary_id.has_value())
325 LOG_FAIL_FMT(
"recovery-decision-protocol timeout: primary unknown");
327 HTTP_STATUS_INTERNAL_SERVER_ERROR,
328 ccf::errors::InternalError,
329 "Primary is unknown");
331 const auto& sig_auth_ident =
332 args.template get_caller<ccf::NodeCertAuthnIdentity>();
333 if (primary_id.value() != sig_auth_ident.node_id)
336 "recovery-decision-protocol timeout: request does not originate from "
339 HTTP_STATUS_INTERNAL_SERVER_ERROR,
340 ccf::errors::InternalError,
341 "Request does not originate from primary.");
346 node_operation->recovery_decision_protocol().advance(args.tx,
true);
348 catch (
const std::logic_error& e)
351 "Recovery-decision-protocol failed to advance state: {}", e.what());
353 HTTP_STATUS_INTERNAL_SERVER_ERROR,
354 ccf::errors::InternalError,
356 "Failed to advance recovery-decision-protocol state: {}",
360 "Recovery-decision-protocol timeout processed successfully");
364 "/recovery_decision_protocol/timeout",
367 {std::make_shared<NodeCertAuthnPolicy>()})
Definition node_operation_interface.h:24
Definition node_configuration_subsystem.h:13
Definition endpoint_registry.h:128
virtual Endpoint make_endpoint(const std::string &method, RESTVerb verb, const EndpointFunction &f, const AuthnPolicies &ap)
Definition endpoint_registry.cpp:282
M::Handle * rw(M &m)
Definition tx.h:211
#define LOG_INFO_FMT
Definition internal_logger.h:15
#define LOG_TRACE_FMT
Definition internal_logger.h:13
#define LOG_FAIL_FMT
Definition internal_logger.h:16
ccf::crypto::Pem cert_der_to_pem(const std::vector< uint8_t > &der)
Definition verifier.cpp:33
std::vector< uint8_t > public_key_der_from_cert(const std::vector< uint8_t > &der)
Definition verifier.cpp:43
std::variant< ErrorDetails, RedirectDetails, AlreadyPopulatedResponse, nlohmann::json > JsonAdapterResponse
Definition json_handler.h:62
Definition file_serving_handlers.h:15
std::function< std::optional< ErrorDetails >(endpoints::EndpointContext &args, Input &in)> RecoveryDecisionProtocolHandler
Definition self_healing_open_handlers.h:23
std::string service_fingerprint_from_pem(const ccf::crypto::Pem &pem)
Definition self_healing_open.h:36
jsonhandler::JsonAdapterResponse make_success()
Definition json_handler.cpp:108
std::function< jsonhandler::JsonAdapterResponse(endpoints::EndpointContext &ctx, nlohmann::json &¶ms)> HandlerJsonParamsAndForward
Definition json_handler.h:85
QuoteVerificationResult
Definition quote.h:19
endpoints::EndpointFunction json_adapter(const HandlerJsonParamsAndForward &f)
Definition json_handler.cpp:142
jsonhandler::JsonAdapterResponse make_error(ccf::http_status status, const std::string &code, const std::string &msg)
Definition json_handler.cpp:124
Definition node_context.h:12
std::shared_ptr< T > get_subsystem() const
Definition node_context.h:60
Definition odata_error.h:58
http_status status
Definition odata_error.h:59
std::shared_ptr< ccf::RpcContext > rpc_ctx
Definition endpoint_context.h:34
Definition endpoint_context.h:58
ccf::kv::Tx & tx
Definition endpoint_context.h:64
Endpoint & set_openapi_hidden(bool hidden)
Definition endpoint.cpp:10
void install()
Definition endpoint.cpp:135
Endpoint & set_forwarding_required(ForwardingRequired fr)
Definition endpoint.cpp:74
Definition recovery_decision_protocol.h:24
Definition self_healing_open.h:54
Definition self_healing_open.h:44