Skip to content

Commit 676e3f3

Browse files
cjen1-msftachamayouCopilot
authored
Refactor local-sealing and self-healing-open into sealing-recovery (#7679)
Co-authored-by: Amaury Chamayou <amchamay@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ef9a9e1 commit 676e3f3

31 files changed

Lines changed: 945 additions & 764 deletions

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [7.0.0-dev12]
9+
10+
[7.0.0-dev12]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.0-dev12
11+
12+
### Changed
13+
14+
- Refactored the user facing surface of self-healing-open and local sealing. The whole feature is now `sealing-recovery` with `self-healing-open` now referred to as the `recovery-decision-protocol`. (#7679)
15+
- Local sealing is enabled by setting the `sealing-recovery` config field (for both the sealing node, and the unsealing recovery node)
16+
- The local sealing identity is under `sealing-recovery.location.name`
17+
- The recovery-decision-protocol is configured via `sealing-recovery.recovery_decision_protocol`
18+
819
## [7.0.0-dev11]
920

1021
[7.0.0-dev11]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.0-dev11

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ endif()
369369
set(CCF_IMPL_SOURCE
370370
${CCF_DIR}/src/enclave/main.cpp ${CCF_DIR}/src/enclave/thread_local.cpp
371371
${CCF_DIR}/src/node/quote.cpp ${CCF_DIR}/src/node/uvm_endorsements.cpp
372-
${CCF_DIR}/src/node/self_healing_open_impl.cpp
372+
${CCF_DIR}/src/node/recovery_decision_protocol.cpp
373373
)
374374

375375
add_ccf_static_library(
@@ -749,7 +749,7 @@ if(BUILD_TESTS)
749749
${CMAKE_CURRENT_SOURCE_DIR}/src/node/rpc/test/frontend_test.cpp
750750
${CCF_DIR}/src/node/quote.cpp
751751
${CCF_DIR}/src/node/uvm_endorsements.cpp
752-
${CCF_DIR}/src/node/self_healing_open_impl.cpp
752+
${CCF_DIR}/src/node/recovery_decision_protocol.cpp
753753
)
754754
target_link_libraries(
755755
frontend_test
@@ -789,7 +789,7 @@ if(BUILD_TESTS)
789789
${CMAKE_CURRENT_SOURCE_DIR}/src/node/rpc/test/node_frontend_test.cpp
790790
${CCF_DIR}/src/node/quote.cpp
791791
${CCF_DIR}/src/node/uvm_endorsements.cpp
792-
${CCF_DIR}/src/node/self_healing_open_impl.cpp
792+
${CCF_DIR}/src/node/recovery_decision_protocol.cpp
793793
)
794794
target_link_libraries(
795795
node_frontend_test

doc/audit/builtin_maps.rst

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -581,64 +581,69 @@ While the contents themselves are encrypted, the table is public so as to be acc
581581
:project: CCF
582582
:members:
583583

584+
``sealing_recovery_names``
585+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
586+
587+
Mapping from sealing recovery names to node IDs for nodes that support local sealing. This table is used alongside ``nodes.sealed_recovery_keys`` to fetch the sealed recovery key when a node is recovering.
588+
589+
**Key** Sealing recovery name of the node, represented as a string.
590+
591+
**Value** Node ID: SHA-256 digest of the node public key, represented as a hex-encoded string.
592+
584593
``last_recovery_type``
585594
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
586595
**Value** The mechanism by which the ledger secret was recovered.
587596

588597
.. doxygenenum:: ccf::RecoveryType
589598
:project: CCF
590599

591-
``self_healing_open.nodes``
592-
~~~~~~~~~~~~~~~~~~~~~~~~~~~
600+
``recovery_decision_protocol.nodes``
601+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
593602

594-
**Key** Intrinsic node ID: A string which is unique to a particular node role within a cluster.
603+
**Key** Location name: A string which is unique to the location of a particular node within a network.
595604

596605
**Value**
597606

598-
.. doxygenstruct:: ccf::self_healing_open::NodeInfo
607+
.. doxygenstruct:: ccf::recovery_decision_protocol::NodeInfo
599608
:project: CCF
600609
:members:
601610

602-
``self_healing_open.gossip``
603-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
604-
605-
**Key** Intrinsic node ID of the source of the gossip message.
611+
``recovery_decision_protocol.gossip``
612+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
606613

607-
**Value**
614+
**Key** Location name of the source of the gossip message.
608615

609-
.. doxygenstruct:: ccf::self_healing_open::GossipRequest
610-
:project: CCF
611-
:members:
616+
**Value** The TxID of the last recovered signed transaction known by the source node.
612617

613-
``self_healing_open.chosen_node``
614-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
618+
``recovery_decision_protocol.chosen_node``
619+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
615620

616-
**Value** The intrinsic node ID of the chosen node. This will either be the node this node voted for, or the node that is has received an `IAmOpen` message from.
621+
**Value** The location name of the chosen node. This will either be the node this node voted for, or the node that it has received an `IAmOpen` message from.
617622

618-
``self_healing_open.votes``
619-
~~~~~~~~~~~~~~~~~~~~~~~~~~~
623+
``recovery_decision_protocol.votes``
624+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
620625

621-
**Key** Intrinsic node ID of the node which has voted for this node to be opened.
626+
**Key** Location name of the node which has voted for this node to be opened.
622627

623-
``self_healing_open.sm_state``
624-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
628+
``recovery_decision_protocol.sm_state``
629+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
625630

626-
**Value** State machine state of the self-healing open protocol.
631+
**Value** State machine state of the recovery decision protocol.
627632

628-
.. doxygenenum:: ccf::self_healing_open::StateMachine
633+
.. doxygenenum:: ccf::recovery_decision_protocol::StateMachine
629634
:project: CCF
630635

631-
``self_healing_open.timeout_sm_state``
632-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
636+
``recovery_decision_protocol.timeout_sm_state``
637+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
633638

634-
**Value** Timeout state machine state of the self-healing open protocol. Ticks based on `failover_timeout` and advances `self_healing_open.sm_state` if it falls behind.
639+
**Value** Timeout state machine state of the recovery decision protocol. Ticks based on `failover_timeout` and advances `recovery_decision_protocol.sm_state` if it falls behind.
635640

636-
See :cpp:enum:`ccf::self_healing_open::StateMachine` above.
641+
See :cpp:enum:`ccf::recovery_decision_protocol::StateMachine` above.
637642

638-
``self_healing_open.open_kind``
639-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
643+
``recovery_decision_protocol.open_kind``
644+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
640645

641646
**Value** The kind of recovery that was performed, either `Quorum`-based which guarantees that there is at most one recovered service using this path, or `Failover`-based which could allow multiple services to recover.
642647

643-
.. doxygenenum:: ccf::self_healing_open::OpenKinds
644-
:project: CCF
648+
.. doxygenenum:: ccf::recovery_decision_protocol::OpenKinds
649+
:project: CCF

doc/host_config_schema/cchost_config.json

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -356,55 +356,6 @@
356356
"previous_service_identity_file": {
357357
"type": "string",
358358
"description": "Path to the previous service certificate (PEM) file"
359-
},
360-
"previous_local_sealing_identity": {
361-
"type": ["string", "null"],
362-
"description": "The identity of the previous node which sealed the ledger secrets. Required if local sealing is enabled"
363-
},
364-
"self_healing_open": {
365-
"type": "object",
366-
"properties": {
367-
"identity": {
368-
"type": "object",
369-
"properties": {
370-
"intrinsic_id": {
371-
"type": "string",
372-
"description": "Intrinsic identifier of this node, used to identify it in the self-healing-open protocol"
373-
},
374-
"published_address": {
375-
"type": "string",
376-
"description": "Published address (host:port) of this node, used to identify it in the self-healing-open protocol"
377-
}
378-
}
379-
},
380-
"cluster_identities": {
381-
"type": "array",
382-
"items": {
383-
"type": "object",
384-
"properties": {
385-
"intrinsic_id": {
386-
"type": "string",
387-
"description": "Intrinsic identifier of the node, used to identify it in the self-healing-open protocol"
388-
},
389-
"published_address": {
390-
"type": "string",
391-
"description": "Published address (host:port) of the node, used for communication during the self-healing-open protocol"
392-
}
393-
}
394-
},
395-
"description": "List of identities for all nodes in the cluster"
396-
},
397-
"retry_timeout": {
398-
"type": "string",
399-
"default": "100ms",
400-
"description": "Interval (time string) at which the node re-sends self-healing-open messages. This should be significantly less than 'failover_timeout'"
401-
},
402-
"failover_timeout": {
403-
"type": "string",
404-
"default": "2000ms",
405-
"description": "Interval (time string) after which the node forcibly advances to the next phase of the self-healing-open protocol"
406-
}
407-
}
408359
}
409360
},
410361
"required": ["previous_service_identity_file"],
@@ -710,10 +661,59 @@
710661
"default": "512MB",
711662
"description": "Historical queries cache soft limit (as size string)"
712663
},
713-
"enable_local_sealing": {
714-
"type": "boolean",
715-
"default": false,
716-
"description": "Enable sealing of ledger secrets using platform derived key capabilities (e.g. AMD SEV-SNP derived keys). This allows the node to unilaterally recover its ledger secrets on restart without needing to reconstruct them from recovery shares."
664+
"sealing_recovery": {
665+
"type": "object",
666+
"description": "Optional. Controls the behaviour of sealing-based recovery. If set, enables sealing of ledger secrets using platform derived key capabilities (e.g. AMD SEV-SNP derived keys). This allows a future recovering node to unilaterally recover its ledger secrets on restart without needing to reconstruct them from recovery shares.",
667+
"properties": {
668+
"location": {
669+
"type": "object",
670+
"properties": {
671+
"name": {
672+
"type": "string"
673+
},
674+
"address": {
675+
"type": "string"
676+
}
677+
},
678+
"required": ["name", "address"],
679+
"additionalProperties": false
680+
},
681+
"recovery_decision_protocol": {
682+
"type": "object",
683+
"properties": {
684+
"expected_locations": {
685+
"type": "array",
686+
"description": "List of locations that the recovery_decision_protocol expects to be part of the previous network.",
687+
"items": {
688+
"type": "object",
689+
"properties": {
690+
"name": {
691+
"type": "string"
692+
},
693+
"address": {
694+
"type": "string"
695+
}
696+
},
697+
"required": ["name", "address"],
698+
"additionalProperties": false
699+
}
700+
},
701+
"message_retry_timeout": {
702+
"type": "string",
703+
"default": "100ms"
704+
},
705+
"failover_timeout": {
706+
"type": "string",
707+
"default": "2000ms",
708+
"description": "Timeout duration before failover forcibly advances the recovery_decision_protocol, allowing recovery to proceed even in the presence of unresponsive nodes. Set to 0 to disable failover."
709+
}
710+
},
711+
"required": ["expected_locations"],
712+
"additionalProperties": false
713+
}
714+
},
715+
"required": ["location"],
716+
"additionalProperties": false
717717
}
718718
},
719719
"required": ["network", "command"],

0 commit comments

Comments
 (0)