Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
gaurav137 committed Dec 15, 2024
1 parent 01df49a commit 7546e41
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 75 deletions.
8 changes: 4 additions & 4 deletions doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,10 @@
"type": ["string", "null"],
"description": "Path to member data file (JSON)"
},
"recovery_owner": {
"type": "boolean",
"default": false,
"description": "Whether the member acts as a recovery owner and gets assigned the full recovery share"
"recovery_role": {
"type": "string",
"enum": ["NonParticipant", "Participant", "Owner"],
"description": "Whether the member acts as a recovery participant and gets assigned a single share or as an owner and gets assigned the full recovery share"
}
},
"required": ["certificate_file"],
Expand Down
12 changes: 10 additions & 2 deletions doc/schemas/gov_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@
"member_data": {
"$ref": "#/components/schemas/json"
},
"recovery_owner": {
"$ref": "#/components/schemas/boolean"
"recovery_role": {
"$ref": "#/components/schemas/MemberRecoveryRole"
},
"status": {
"$ref": "#/components/schemas/MemberStatus"
Expand Down Expand Up @@ -415,6 +415,14 @@
},
"type": "object"
},
"MemberRecoveryRole": {
"enum": [
"NonParticipant",
"Participant",
"Owner"
],
"type": "string"
},
"MemberStatus": {
"enum": [
"Accepted",
Expand Down
38 changes: 24 additions & 14 deletions include/ccf/service/tables/members.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ namespace ccf
DECLARE_JSON_ENUM(
MemberStatus,
{{MemberStatus::ACCEPTED, "Accepted"}, {MemberStatus::ACTIVE, "Active"}});

enum class MemberRecoveryRole
{
NonParticipant,
Participant,

/** If set then the member is to receive a full share ("super-share")
allowing it to single-handedly recover the network without
requiring any other recovery member to submit their shares. */
Owner
};
DECLARE_JSON_ENUM(
MemberRecoveryRole,
{{MemberRecoveryRole::NonParticipant, "NonParticipant"},
{MemberRecoveryRole::Participant, "Participant"},
{MemberRecoveryRole::Owner, "Owner"}});
}

namespace ccf
Expand All @@ -36,34 +52,31 @@ namespace ccf
std::optional<ccf::crypto::Pem> encryption_pub_key = std::nullopt;
nlohmann::json member_data = nullptr;

/** If set then the member is to receive a full share ("super-share")
allowing it to single-handedly recover the network without
requiring any other recovery member to submit their shares. */
std::optional<bool> recovery_owner = std::nullopt;
std::optional<MemberRecoveryRole> recovery_role = std::nullopt;

NewMember() {}

NewMember(
const ccf::crypto::Pem& cert_,
const std::optional<ccf::crypto::Pem>& encryption_pub_key_ = std::nullopt,
const nlohmann::json& member_data_ = nullptr,
const std::optional<bool>& recovery_owner_ = std::nullopt) :
const std::optional<MemberRecoveryRole>& recovery_role_ = std::nullopt) :
cert(cert_),
encryption_pub_key(encryption_pub_key_),
member_data(member_data_),
recovery_owner(recovery_owner_)
recovery_role(recovery_role_)
{}

bool operator==(const NewMember& rhs) const
{
return cert == rhs.cert && encryption_pub_key == rhs.encryption_pub_key &&
member_data == rhs.member_data && recovery_owner == rhs.recovery_owner;
member_data == rhs.member_data && recovery_role == rhs.recovery_role;
}
};
DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(NewMember)
DECLARE_JSON_REQUIRED_FIELDS(NewMember, cert)
DECLARE_JSON_OPTIONAL_FIELDS(
NewMember, encryption_pub_key, member_data, recovery_owner)
NewMember, encryption_pub_key, member_data, recovery_role)

struct MemberDetails
{
Expand All @@ -73,20 +86,17 @@ namespace ccf
members for example. */
nlohmann::json member_data = nullptr;

/** If set then the member is to receive a full share ("super-share")
allowing it to single-handedly recover the network without
requiring any other recovery member to submit their shares. */
std::optional<bool> recovery_owner = std::nullopt;
std::optional<MemberRecoveryRole> recovery_role = std::nullopt;

bool operator==(const MemberDetails& rhs) const
{
return status == rhs.status && member_data == rhs.member_data &&
recovery_owner == rhs.recovery_owner;
recovery_role == rhs.recovery_role;
}
};
DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(MemberDetails)
DECLARE_JSON_REQUIRED_FIELDS(MemberDetails, status)
DECLARE_JSON_OPTIONAL_FIELDS(MemberDetails, member_data, recovery_owner)
DECLARE_JSON_OPTIONAL_FIELDS(MemberDetails, member_data, recovery_role)

using MemberInfo = ServiceMap<MemberId, MemberDetails>;

Expand Down
40 changes: 23 additions & 17 deletions samples/constitutions/default/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ function invalidateOtherOpenProposals(proposalIdToRetain) {
}

function setServiceCertificateValidityPeriod(validFrom, validityPeriodDays) {
const rawConfig =
ccf.kv["public:ccf.gov.service.config"].get(getSingletonKvKey());
const rawConfig = ccf.kv["public:ccf.gov.service.config"].get(
getSingletonKvKey(),
);
if (rawConfig === undefined) {
throw new Error("Service configuration could not be found");
}
Expand Down Expand Up @@ -216,8 +217,9 @@ function setNodeCertificateValidityPeriod(
throw new Error(`Node ${nodeId} has no certificate signing request`);
}

const rawConfig =
ccf.kv["public:ccf.gov.service.config"].get(getSingletonKvKey());
const rawConfig = ccf.kv["public:ccf.gov.service.config"].get(
getSingletonKvKey(),
);
if (rawConfig === undefined) {
throw new Error("Service configuration could not be found");
}
Expand Down Expand Up @@ -359,16 +361,16 @@ const actions = new Map([
function (args) {
checkX509CertBundle(args.cert, "cert");
checkType(args.member_data, "object?", "member_data");
checkType(args.recovery_owner, "boolean?", "recovery_owner");
checkType(args.recovery_role, "string?", "recovery_role");

if (
args.encryption_pub_key == null &&
args.encryption_pub_key == undefined &&
args.recovery_owner !== null &&
args.recovery_owner !== undefined
args.recovery_role !== null &&
args.recovery_role !== undefined
) {
throw new Error(
"Cannot specify a recovery_owner value when encryption_pub_key is not specified",
"Cannot specify a recovery_role value when encryption_pub_key is not specified",
);
}
// Also check that public encryption key is well formed, if it exists
Expand Down Expand Up @@ -400,15 +402,16 @@ const actions = new Map([

let member_info = {};
member_info.member_data = args.member_data;
member_info.recovery_owner = args.recovery_owner;
member_info.recovery_role = args.recovery_role;
member_info.status = "Accepted";
ccf.kv["public:ccf.gov.members.info"].set(
rawMemberId,
ccf.jsonCompatibleToBuf(member_info),
);

const rawSignature =
ccf.kv["public:ccf.internal.signatures"].get(getSingletonKvKey());
const rawSignature = ccf.kv["public:ccf.internal.signatures"].get(
getSingletonKvKey(),
);
if (rawSignature === undefined) {
ccf.kv["public:ccf.gov.members.acks"].set(rawMemberId);
} else {
Expand Down Expand Up @@ -450,8 +453,9 @@ const actions = new Map([
// would still be a sufficient number of recovery members left
// to recover the service
if (isActiveMember && isRecoveryMember) {
const rawConfig =
ccf.kv["public:ccf.gov.service.config"].get(getSingletonKvKey());
const rawConfig = ccf.kv["public:ccf.gov.service.config"].get(
getSingletonKvKey(),
);
if (rawConfig === undefined) {
throw new Error("Service configuration could not be found");
}
Expand Down Expand Up @@ -1189,8 +1193,9 @@ const actions = new Map([
}
},
function (args) {
const rawConfig =
ccf.kv["public:ccf.gov.service.config"].get(getSingletonKvKey());
const rawConfig = ccf.kv["public:ccf.gov.service.config"].get(
getSingletonKvKey(),
);
if (rawConfig === undefined) {
throw new Error("Service configuration could not be found");
}
Expand Down Expand Up @@ -1273,8 +1278,9 @@ const actions = new Map([
checkEntityId(args.node_id, "node_id");
},
function (args) {
const rawConfig =
ccf.kv["public:ccf.gov.service.config"].get(getSingletonKvKey());
const rawConfig = ccf.kv["public:ccf.gov.service.config"].get(
getSingletonKvKey(),
);
if (rawConfig === undefined) {
throw new Error("Service configuration could not be found");
}
Expand Down
4 changes: 2 additions & 2 deletions src/host/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace host
std::string certificate_file;
std::optional<std::string> encryption_public_key_file = std::nullopt;
std::optional<std::string> data_json_file = std::nullopt;
std::optional<bool> recovery_owner = std::nullopt;
std::optional<ccf::MemberRecoveryRole> recovery_role = std::nullopt;

bool operator==(const ParsedMemberInfo& other) const = default;
};
Expand All @@ -59,7 +59,7 @@ namespace host
ParsedMemberInfo,
encryption_public_key_file,
data_json_file,
recovery_owner);
recovery_role);

struct CCHostConfig : public ccf::CCFConfig
{
Expand Down
24 changes: 8 additions & 16 deletions src/host/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,6 @@ int main(int argc, char** argv)
config.ledger.directory));
}

for (auto const& m : config.command.start.members)
{
if (
!m.encryption_public_key_file.has_value() &&
m.recovery_owner.has_value())
{
throw std::logic_error(fmt::format(
"No public encryption key has been specified but recovery owner "
"value has been set for a member"));
}
}

// Count members with public encryption key who are not recovery
// owners as only these members will be handed a recovery share
// that accrues towards the recovery threshold.
Expand All @@ -240,7 +228,8 @@ int main(int argc, char** argv)
{
if (
m.encryption_public_key_file.has_value() &&
(!m.recovery_owner.has_value() || !m.recovery_owner.value()))
m.recovery_role.value_or(ccf::MemberRecoveryRole::Participant) !=
ccf::MemberRecoveryRole::Owner)
{
members_with_pubk_count++;
}
Expand Down Expand Up @@ -620,14 +609,17 @@ int main(int argc, char** argv)
for (auto const& m : config.command.start.members)
{
std::optional<ccf::crypto::Pem> public_encryption_key = std::nullopt;
std::optional<bool> recovery_owner = std::nullopt;
std::optional<ccf::MemberRecoveryRole> recovery_role = std::nullopt;
if (
m.encryption_public_key_file.has_value() &&
!m.encryption_public_key_file.value().empty())
{
public_encryption_key = ccf::crypto::Pem(
files::slurp(m.encryption_public_key_file.value()));
recovery_owner = m.recovery_owner;
if (m.recovery_role.has_value())
{
recovery_role = m.recovery_role.value();
}
}

nlohmann::json md = nullptr;
Expand All @@ -640,7 +632,7 @@ int main(int argc, char** argv)
ccf::crypto::Pem(files::slurp(m.certificate_file)),
public_encryption_key,
md,
recovery_owner);
recovery_role);
}
startup_config.start.constitution = "";
for (const auto& constitution_path :
Expand Down
19 changes: 19 additions & 0 deletions src/node/gov/handlers/service_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ namespace ccf::gov::endpoints
member["publicEncryptionKey"] = enc_key.value().str();
}

ccf::MemberRecoveryRole recovery_role;
if (member_details.recovery_role.has_value())
{
recovery_role = member_details.recovery_role.value();
}
else
{
if (enc_key.has_value())
{
recovery_role = ccf::MemberRecoveryRole::Participant;
}
else
{
recovery_role = ccf::MemberRecoveryRole::NonParticipant;
}
}

member["recoveryRole"] = recovery_role;

return member;
}

Expand Down
Loading

0 comments on commit 7546e41

Please sign in to comment.