Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Key shares and consortium update #1032

Merged
merged 16 commits into from
Apr 6, 2020
Merged
11 changes: 4 additions & 7 deletions samples/apps/txregulator/tests/txregulatorclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ def run(args):
transactions.append(json_tx)

# Manager is granted special privileges by members, which is later read by app to enforce access restrictions
response = network.consortium.propose(
0,
proposal = network.consortium.get_any_active_member().propose(
primary,
f"""
return Calls:call(
Expand All @@ -94,22 +93,20 @@ def run(args):
)
""",
)
network.consortium.vote_using_majority(primary, response.result["proposal_id"])
network.consortium.vote_using_majority(primary, proposal)

# Check permissions are enforced
with primary.user_client(user_id=regulator.name) as c:
check(
c.rpc("REG_register"),
error=check_status(http.HTTPStatus.FORBIDDEN),
c.rpc("REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
)
check(
c.rpc("BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
)

with primary.user_client(user_id=banks[0].name) as c:
check(
c.rpc("REG_register"),
error=check_status(http.HTTPStatus.FORBIDDEN),
c.rpc("REG_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
)
check(
c.rpc("BK_register"), error=check_status(http.HTTPStatus.FORBIDDEN),
Expand Down
3 changes: 2 additions & 1 deletion src/enclave/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ struct CCFConfig
{
std::vector<ccf::MemberPubInfo> members_info;
std::string gov_script;
MSGPACK_DEFINE(members_info, gov_script);
size_t recovery_threshold;
MSGPACK_DEFINE(members_info, gov_script, recovery_threshold);
};
Genesis genesis = {};

Expand Down
84 changes: 65 additions & 19 deletions src/host/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,16 @@ int main(int argc, char** argv)
"Initial consortium members information (public identity,public key share)")
->required();

std::optional<size_t> recovery_threshold;
start
->add_option(
"--recovery-threshold",
recovery_threshold,
"Number of member shares required for recovery. Defaults to total number "
"of initial consortium members.")
->check(CLI::PositiveNumber)
->type_name("UINT");

auto join = app.add_subcommand("join", "Join existing network");
join->configurable();

Expand Down Expand Up @@ -358,26 +368,59 @@ int main(int argc, char** argv)
public_rpc_address = rpc_address;
}

if (domain.empty() && !ds::is_valid_ip(rpc_address.hostname.c_str()))
uint32_t oe_flags = 0;
achamayou marked this conversation as resolved.
Show resolved Hide resolved
try
jumaffre marked this conversation as resolved.
Show resolved Hide resolved
{
throw std::logic_error(fmt::format(
"--rpc-address ({}) does not appear to specify valid IP address. "
"Please specify a domain name via the --domain option.",
rpc_address.hostname));
}
if (domain.empty() && !ds::is_valid_ip(rpc_address.hostname.c_str()))
{
throw std::logic_error(fmt::format(
"--rpc-address ({}) does not appear to specify valid IP address. "
"Please specify a domain name via the --domain option.",
rpc_address.hostname));
}

uint32_t oe_flags = 0;
switch (enclave_type)
if (*start)
{
if (!recovery_threshold.has_value())
{
LOG_INFO_FMT(
"--recovery-threshold unset. Defaulting to number of initial "
"consortium members ({}).",
members_info.size());
recovery_threshold = members_info.size();
}
else if (recovery_threshold.value() > members_info.size())
{
throw std::logic_error(fmt::format(
"--recovery-threshold cannot be greater than total number "
"of initial consortium members (specified via --member-info "
"options)"));
}
}

switch (enclave_type)
{
case EnclaveType::DEBUG:
{
oe_flags |= OE_ENCLAVE_FLAG_DEBUG;
break;
}
case EnclaveType::VIRTUAL:
{
oe_flags = ENCLAVE_FLAG_VIRTUAL;
break;
}
default:
{
throw std::logic_error(
fmt::format("Invalid enclave type: {}", enclave_type));
}
}
}
catch (const std::logic_error& e)
{
case EnclaveType::DEBUG:
oe_flags |= OE_ENCLAVE_FLAG_DEBUG;
break;
case EnclaveType::VIRTUAL:
oe_flags = ENCLAVE_FLAG_VIRTUAL;
break;
default:
throw std::logic_error(
fmt::format("Invalid enclave type: {}", enclave_type));
LOG_FATAL_FMT("{}. Exiting.", e.what());
return static_cast<int>(CLI::ExitCodes::ValidationError);
}

// Write PID to disk
Expand Down Expand Up @@ -463,9 +506,12 @@ int main(int argc, char** argv)
files::slurp(m_info.cert_file), files::slurp(m_info.keyshare_pub_file));
}
ccf_config.genesis.gov_script = files::slurp_string(gov_script);
ccf_config.genesis.recovery_threshold = recovery_threshold.value();
LOG_INFO_FMT(
"Creating new node: new network (with {} initial member(s))",
ccf_config.genesis.members_info.size());
"Creating new node: new network (with {} initial member(s) and {} "
"member(s) required for recovery)",
ccf_config.genesis.members_info.size(),
ccf_config.genesis.recovery_threshold);
}
else if (*join)
{
Expand Down
2 changes: 1 addition & 1 deletion src/lua_interp/tx_script_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#pragma once
#include "lua_interp/lua_interp.h"
#include "lua_interp/lua_kv.h"
#include "node/networktables.h"
#include "node/network_tables.h"
#include "node/rpc/rpc_exception.h"

#include <sstream>
Expand Down
25 changes: 25 additions & 0 deletions src/node/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

#include "ds/json.h"
#include "entities.h"

#include <msgpack/msgpack.hpp>

namespace ccf
{
struct Config
{
// Number of required shares to decrypt ledger secrets (recovery)
size_t recovery_threshold;

MSGPACK_DEFINE(recovery_threshold)
};
DECLARE_JSON_TYPE(Config)
DECLARE_JSON_REQUIRED_FIELDS(Config, recovery_threshold)

// The key for this table is always 0 as there is always only one active
// configuration.
using Configuration = Store::Map<size_t, Config>;
}
1 change: 1 addition & 0 deletions src/node/entities.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ namespace ccf
static constexpr auto SERVICE = "ccf.service";
static constexpr auto SHARES = "ccf.shares";
static constexpr auto USER_CODE_IDS = "ccf.users.code_ids";
static constexpr auto CONFIGURATION = "ccf.config";
};

using StoreSerialiser = kv::KvStoreSerialiser;
Expand Down
50 changes: 49 additions & 1 deletion src/node/genesis_gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "lua_interp/lua_interp.h"
#include "lua_interp/lua_util.h"
#include "members.h"
#include "networktables.h"
#include "network_tables.h"
#include "node_info_network.h"
#include "nodes.h"
#include "rpc/consts.h"
Expand Down Expand Up @@ -130,6 +130,36 @@ namespace ccf
return id;
}

bool retire_member(MemberId member_id)
{
auto m = tx.get_view(tables.members);
auto member_to_retire = m->get(member_id);
if (!member_to_retire.has_value())
{
LOG_FAIL_FMT(
"Could not retire member {}: member does not exist", member_id);
return false;
}

auto member_info = member_to_retire.value();
member_info.status = MemberStatus::RETIRED;
m->put(member_id, member_info);

return true;
}

std::optional<MemberInfo> get_member_info(MemberId member_id)
{
auto m = tx.get_view(tables.members);
auto member = m->get(member_id);
if (!member.has_value())
{
return {};
}

return member.value();
}

auto add_user(const std::vector<uint8_t>& user_cert_pem)
{
auto [u, uc, v] =
Expand Down Expand Up @@ -349,5 +379,23 @@ namespace ccf
auto shares_view = tx.get_view(tables.shares);
shares_view->put(0, key_share_info);
}

void set_recovery_threshold(size_t threshold)
{
auto config_view = tx.get_view(tables.config);
config_view->put(0, {threshold});
}

size_t get_recovery_threshold()
{
auto config_view = tx.get_view(tables.config);
auto config = config_view->get(0);
if (!config.has_value())
{
throw std::logic_error(
"Failed to get recovery threshold: No active configuration found");
}
return config->recovery_threshold;
}
};
}
7 changes: 5 additions & 2 deletions src/node/members.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ namespace ccf
enum class MemberStatus
{
ACCEPTED = 0,
ACTIVE = 1
ACTIVE = 1,
RETIRED = 2
};
DECLARE_JSON_ENUM(
MemberStatus,
{{MemberStatus::ACCEPTED, "ACCEPTED"}, {MemberStatus::ACTIVE, "ACTIVE"}});
{{MemberStatus::ACCEPTED, "ACCEPTED"},
{MemberStatus::ACTIVE, "ACTIVE"},
{MemberStatus::RETIRED, "RETIRED"}});
}

MSGPACK_ADD_ENUM(ccf::MemberStatus);
Expand Down
2 changes: 1 addition & 1 deletion src/node/network_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "identity.h"
#include "ledger_secrets.h"
#include "network_encryption.h"
#include "networktables.h"
#include "network_tables.h"

namespace ccf
{
Expand Down
5 changes: 5 additions & 0 deletions src/node/networktables.h → src/node/network_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "certs.h"
#include "client_signatures.h"
#include "code_id.h"
#include "config.h"
#include "consensus.h"
#include "consensus/pbft/pbft_pre_prepares.h"
#include "consensus/pbft/pbft_requests.h"
Expand Down Expand Up @@ -48,6 +49,7 @@ namespace ccf
GovernanceHistory& governance_history;
ClientSignatures& member_client_signatures;
Shares& shares;
Configuration& config;

//
// User tables
Expand Down Expand Up @@ -112,6 +114,8 @@ namespace ccf
shares(
tables->create<Shares>(Tables::SHARES, kv::SecurityDomain::PUBLIC)),
users(tables->create<Users>(Tables::USERS)),
config(tables->create<Configuration>(
Tables::CONFIGURATION, kv::SecurityDomain::PUBLIC)),
user_certs(tables->create<Certs>(Tables::USER_CERTS)),
user_code_ids(tables->create<CodeIDs>(
Tables::USER_CODE_IDS, kv::SecurityDomain::PUBLIC)),
Expand Down Expand Up @@ -153,6 +157,7 @@ namespace ccf
std::ref(member_acks),
std::ref(governance_history),
std::ref(member_client_signatures),
std::ref(config),
std::ref(users),
std::ref(user_certs),
std::ref(user_client_signatures),
Expand Down
1 change: 1 addition & 0 deletions src/node/node_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,7 @@ namespace ccf
std::vector<uint8_t>(std::begin(node_code_id), std::end(node_code_id));
create_params.node_info_network = args.config.node_info_network;
create_params.consensus_type = network.consensus_type;
create_params.recovery_threshold = args.config.genesis.recovery_threshold;

const auto body = jsonrpc::pack(create_params, jsonrpc::Pack::Text);

Expand Down
2 changes: 1 addition & 1 deletion src/node/quote.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# include "code_id.h"
# include "enclave/oe_shim.h"
# include "entities.h"
# include "networktables.h"
# include "network_tables.h"

# include <openenclave/bits/report.h>
# include <openenclave/bits/result.h>
Expand Down
Loading