Use digests for proposal ids, rather than incrementing integers (#2104)

This commit is contained in:
Amaury Chamayou 2021-01-25 14:05:33 +00:00 коммит произвёл GitHub
Родитель 321cd89fc7
Коммит 32cc0ad938
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 199 добавлений и 93 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -28,3 +28,4 @@ env/
python/setup.py
node_modules
package-lock.json
.cache

Просмотреть файл

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Governance proposal ids are now digests, hex-encoded as strings.
## [0.17.1]
### Changed

Просмотреть файл

@ -23,21 +23,21 @@ A member proposes to recover the network and other members can vote on the propo
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member1_privk --cert member1_cert --data-binary @accept_recovery.json -H "content-type: application/json"
{
"proposal_id": 1,
"proposal_id": "1b7cae1585077104e99e1860ad740efe28ebd498dbf9988e0e7b299e720c5377",
"proposer_id": 0,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/1/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/1b7cae1585077104e99e1860ad740efe28ebd498dbf9988e0e7b299e720c5377/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept.json -H "content-type: application/json"
{
"proposal_id": 1,
"proposal_id": "1b7cae1585077104e99e1860ad740efe28ebd498dbf9988e0e7b299e720c5377",
"proposer_id": 0,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/1/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/1b7cae1585077104e99e1860ad740efe28ebd498dbf9988e0e7b299e720c5377/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept.json -H "content-type: application/json"
{
"proposal_id": 1,
"proposal_id": "1b7cae1585077104e99e1860ad740efe28ebd498dbf9988e0e7b299e720c5377",
"proposer_id": 0,
"state": "ACCEPTED"
}

Просмотреть файл

@ -61,21 +61,21 @@ To limit the scope of key compromise, members of the consortium can refresh the
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member1_privk --cert member1_cert --data-binary @rekey_ledger.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "2f739d154b8cddacd7fc6d03cc8d4d20626e477ec4b1af10a74c670bb38bed5e",
"proposer_id": 1,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/4/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/2f739d154b8cddacd7fc6d03cc8d4d20626e477ec4b1af10a74c670bb38bed5e/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "2f739d154b8cddacd7fc6d03cc8d4d20626e477ec4b1af10a74c670bb38bed5e",
"proposer_id": 1,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/4/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/2f739d154b8cddacd7fc6d03cc8d4d20626e477ec4b1af10a74c670bb38bed5e/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "2f739d154b8cddacd7fc6d03cc8d4d20626e477ec4b1af10a74c670bb38bed5e",
"proposer_id": 1,
"state": "ACCEPTED"
}
@ -103,21 +103,21 @@ The number of member shares required to restore the private ledger (``recovery_t
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member1_privk --cert member1_cert --data-binary @set_recovery_threshold.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "b9c08b3861395eca904d913427dcb436136e277cf4712eb14e9e9cddf9d231a8",
"proposer_id": 1,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/5/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/b9c08b3861395eca904d913427dcb436136e277cf4712eb14e9e9cddf9d231a8/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "b9c08b3861395eca904d913427dcb436136e277cf4712eb14e9e9cddf9d231a8",
"proposer_id": 1,
"state": "OPEN"
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/5/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/b9c08b3861395eca904d913427dcb436136e277cf4712eb14e9e9cddf9d231a8/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept_1.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "b9c08b3861395eca904d913427dcb436136e277cf4712eb14e9e9cddf9d231a8",
"proposer_id": 1,
"state": "ACCEPTED"
}

Просмотреть файл

@ -22,7 +22,7 @@ Then, the certificates of trusted users should be registered in CCF via the memb
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member0_privk --cert member0_cert --data-binary @add_user.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "f665047e3d1eb184a7b7921944a8ab543cfff117aab5b6358dc87f9e70278253",
"proposer_id": 0,
"state": "OPEN"
}
@ -38,9 +38,9 @@ Other members are then allowed to vote for the proposal, using the proposal id r
}
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/5/votes --cacert network_cert --key member1_privk --cert member1_cert --data-binary @vote_accept.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/f665047e3d1eb184a7b7921944a8ab543cfff117aab5b6358dc87f9e70278253/votes --cacert network_cert --key member1_privk --cert member1_cert --data-binary @vote_accept.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "f665047e3d1eb184a7b7921944a8ab543cfff117aab5b6358dc87f9e70278253",
"proposer_id": 0,
"state": "OPEN"
}
@ -52,9 +52,9 @@ Other members are then allowed to vote for the proposal, using the proposal id r
}
}
$ scurl.sh https://<ccf-node-address>/gov/proposals/5/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_conditional.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/f665047e3d1eb184a7b7921944a8ab543cfff117aab5b6358dc87f9e70278253/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_conditional.json -H "content-type: application/json"
{
"proposal_id": 5,
"proposal_id": "f665047e3d1eb184a7b7921944a8ab543cfff117aab5b6358dc87f9e70278253",
"proposer_id": 0,
"state": "ACCEPTED"
}
@ -134,7 +134,7 @@ Once users are added to the opening network, members should create a proposal to
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member0_privk --cert member0_cert --data-binary @open_network.json -H "content-type: application/json"
{
"proposal_id": 10,
"proposal_id": "77374e16de0b2d61f58aec84d01e6218205d19c9401d2df127d893ce62576b81",
"proposer_id": 0,
"state": "OPEN"
}

Просмотреть файл

@ -112,7 +112,7 @@ For example, ``member1`` may submit a proposal to add a new member (``member4``)
$ scurl.sh https://<ccf-node-address>/gov/proposals --cacert network_cert --key member1_privk --cert member1_cert --data-binary @add_member.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd",
"proposer_id": 1,
"state": "OPEN"
}
@ -138,17 +138,17 @@ In this case, a new proposal with id ``4`` has successfully been created and the
}
# Member 2 rejects the proposal (votes in favour: 1/3)
$ scurl.sh https://<ccf-node-address>/gov/proposals/4/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_reject.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd/votes --cacert network_cert --key member2_privk --cert member2_cert --data-binary @vote_reject.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd",
"proposer_id": 1,
"state": "OPEN"
}
# Member 3 accepts the proposal (votes in favour: 2/3)
$ scurl.sh https://<ccf-node-address>/gov/proposals/4/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept.json -H "content-type: application/json"
$ scurl.sh https://<ccf-node-address>/gov/proposals/d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd/votes --cacert network_cert --key member3_privk --cert member3_cert --data-binary @vote_accept.json -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd",
"proposer_id": 1,
"state": "ACCEPTED"
}
@ -167,7 +167,7 @@ The details of pending proposals, including the proposer member id, proposal scr
.. code-block:: bash
# The full proposal state, including votes, can still be retrieved by any member
$ scurl.sh https://<ccf-node-address>/gov/proposals/4 --cacert networkcert.pem --key member3_privk.pem --cert member3_cert.pem -H "content-type: application/json" -X GET
$ scurl.sh https://<ccf-node-address>/gov/proposals/d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd --cacert networkcert.pem --key member3_privk.pem --cert member3_cert.pem -H "content-type: application/json" -X GET
{
"parameter": {...},
"proposer": 1,
@ -204,7 +204,7 @@ At any stage during the voting process, before the proposal is accepted, the pro
$ scurl.sh https://<ccf-node-address>/gov/proposals/<proposal-id>/withdraw --cacert networkcert.pem --key member1_privk.pem --cert member1_cert.pem -H "content-type: application/json"
{
"proposal_id": 4,
"proposal_id": "d4ec2de82267f97d3d1b464020af0bd3241f1bedf769f0fee73cd00f08e9c7fd",
"proposer_id": 1,
"state": "WITHDRAWN"
}

Просмотреть файл

@ -173,7 +173,7 @@
"ProposalInfo": {
"properties": {
"proposal_id": {
"$ref": "#/components/schemas/uint64"
"$ref": "#/components/schemas/string"
},
"proposer_id": {
"$ref": "#/components/schemas/uint64"

Просмотреть файл

@ -153,6 +153,7 @@ namespace ccf
tls::Pem member_cert;
nlohmann::json member_data;
SignedReq signed_request;
std::vector<uint8_t> request_digest;
};
class MemberSignatureAuthnPolicy : public AuthnPolicy
@ -187,15 +188,20 @@ namespace ccf
"Members and member certs tables do not match");
}
std::vector<uint8_t> digest;
auto verifier = verifiers.get_verifier(member->cert);
if (verifier->verify(
signed_request->req, signed_request->sig, signed_request->md))
signed_request->req,
signed_request->sig,
signed_request->md,
digest))
{
auto identity = std::make_unique<MemberSignatureAuthnIdentity>();
identity->member_id = member_id.value();
identity->member_cert = member->cert;
identity->member_data = member->member_data;
identity->signed_request = signed_request.value();
identity->request_digest = std::move(digest);
return identity;
}
else

Просмотреть файл

@ -93,11 +93,12 @@ namespace ccf
DECLARE_JSON_REQUIRED_FIELDS(
Proposal, script, parameter, proposer, state, votes)
using Proposals = kv::Map<ObjectId, Proposal>;
using ProposalId = std::string;
using Proposals = kv::Map<ProposalId, Proposal>;
struct ProposalInfo
{
ObjectId proposal_id;
ProposalId proposal_id;
MemberId proposer_id;
ProposalState state;
};

Просмотреть файл

@ -505,6 +505,24 @@ namespace ccf
return true;
}
template <>
bool get_path_param(
const enclave::PathParams& params,
const std::string& param_name,
std::string& value,
std::string& error)
{
const auto it = params.find(param_name);
if (it == params.end())
{
error = fmt::format("No parameter named '{}' in path", param_name);
return false;
}
value = it->second;
return true;
}
protected:
EndpointPtr default_endpoint;
std::map<std::string, std::map<RESTVerb, EndpointPtr>>

Просмотреть файл

@ -32,6 +32,8 @@
namespace ccf
{
constexpr auto INVALID_PROPOSAL_ID = "INVALID";
static oe_result_t oe_verify_attestation_certificate_with_evidence_cb(
oe_claim_t* claims, size_t claims_length, void* arg)
{
@ -356,7 +358,7 @@ namespace ccf
bool set_jwt_public_signing_keys(
kv::Tx& tx,
ObjectId proposal_id,
const ProposalId& proposal_id,
std::string issuer,
const JwtIssuerMetadata& issuer_metadata,
const JsonWebKeySet& jwks)
@ -365,9 +367,9 @@ namespace ccf
auto key_issuer =
tx.get_view(this->network.jwt_public_signing_key_issuer);
auto log_prefix = proposal_id != INVALID_ID ?
fmt::format("Proposal {}", proposal_id) :
"JWT key auto-refresh";
auto log_prefix = proposal_id == INVALID_PROPOSAL_ID ?
"JWT key auto-refresh" :
fmt::format("Proposal {}", proposal_id);
// add keys
if (jwks.keys.empty())
@ -515,7 +517,7 @@ namespace ccf
kv::Tx& tx,
const CodeDigest& new_code_id,
CodeIDs& code_id_table,
ObjectId proposal_id)
const ProposalId& proposal_id)
{
auto code_ids = tx.get_view(code_id_table);
auto existing_code_id = code_ids->get(new_code_id);
@ -535,7 +537,7 @@ namespace ccf
kv::Tx& tx,
const CodeDigest& code_id,
CodeIDs& code_id_table,
ObjectId proposal_id)
const ProposalId& proposal_id)
{
auto code_ids = tx.get_view(code_id_table);
auto existing_code_id = code_ids->get(code_id);
@ -554,41 +556,41 @@ namespace ccf
//! Table of functions that proposal scripts can propose to invoke
const std::unordered_map<
std::string,
std::function<bool(ObjectId, kv::Tx&, const nlohmann::json&)>>
std::function<bool(const ProposalId&, kv::Tx&, const nlohmann::json&)>>
hardcoded_funcs = {
// set the js application script
{"set_js_app",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const std::string app = args;
set_js_scripts(tx, lua::Interpreter().invoke<nlohmann::json>(app));
return true;
}},
// deploy the js application bundle
{"deploy_js_app",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto parsed = args.get<DeployJsApp>();
return deploy_js_app(tx, parsed.bundle);
}},
// undeploy/remove the js application
{"remove_js_app",
[this](ObjectId, kv::Tx& tx, const nlohmann::json&) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json&) {
return remove_js_app(tx);
}},
// add/update a module
{"set_module",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto parsed = args.get<SetModule>();
return set_module(tx, parsed.name, parsed.module);
}},
// remove a module
{"remove_module",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto name = args.get<std::string>();
return remove_module(tx, name);
}},
// add a new member
{"new_member",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto parsed = args.get<MemberPubInfo>();
GenesisGenerator g(this->network, tx);
g.add_member(parsed);
@ -597,7 +599,7 @@ namespace ccf
}},
// retire an existing member
{"retire_member",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto member_id = args.get<MemberId>();
GenesisGenerator g(this->network, tx);
@ -629,7 +631,10 @@ namespace ccf
return true;
}},
{"set_member_data",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<SetMemberData>();
auto members_view = tx.get_view(this->network.members);
auto member_info = members_view->get(parsed.member_id);
@ -647,7 +652,7 @@ namespace ccf
return true;
}},
{"new_user",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto user_info = args.get<ccf::UserInfo>();
GenesisGenerator g(this->network, tx);
@ -656,7 +661,10 @@ namespace ccf
return true;
}},
{"remove_user",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const UserId user_id = args;
GenesisGenerator g(this->network, tx);
@ -670,7 +678,10 @@ namespace ccf
return r;
}},
{"set_user_data",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<SetUserData>();
auto users_view = tx.get_view(this->network.users);
auto user_info = users_view->get(parsed.user_id);
@ -688,7 +699,10 @@ namespace ccf
return true;
}},
{"set_ca_cert",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<SetCaCert>();
auto ca_certs = tx.get_view(this->network.ca_certs);
std::vector<uint8_t> cert_der;
@ -709,14 +723,17 @@ namespace ccf
return true;
}},
{"remove_ca_cert",
[this](ObjectId, kv::Tx& tx, const nlohmann::json& args) {
[this](const ProposalId&, kv::Tx& tx, const nlohmann::json& args) {
const auto cert_name = args.get<std::string>();
auto ca_certs = tx.get_view(this->network.ca_certs);
ca_certs->remove(cert_name);
return true;
}},
{"set_jwt_issuer",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<SetJwtIssuer>();
auto issuers = tx.get_view(this->network.jwt_issuers);
auto ca_certs = tx.get_read_only_view(this->network.ca_certs);
@ -783,7 +800,10 @@ namespace ccf
return success;
}},
{"remove_jwt_issuer",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<RemoveJwtIssuer>();
const auto issuer = parsed.issuer;
auto issuers = tx.get_view(this->network.jwt_issuers);
@ -800,7 +820,10 @@ namespace ccf
return true;
}},
{"set_jwt_public_signing_keys",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto parsed = args.get<SetJwtPublicSigningKeys>();
auto issuers = tx.get_view(this->network.jwt_issuers);
@ -820,7 +843,10 @@ namespace ccf
}},
// accept a node
{"trust_node",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto node_id = args.get<NodeId>();
try
{
@ -837,7 +863,10 @@ namespace ccf
}},
// retire a node
{"retire_node",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto id = args.get<NodeId>();
auto nodes = tx.get_view(this->network.nodes);
auto node_info = nodes->get(id);
@ -860,7 +889,10 @@ namespace ccf
}},
// accept new node code ID
{"new_node_code",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
return this->add_new_code_id(
tx,
args.get<CodeDigest>(),
@ -869,7 +901,10 @@ namespace ccf
}},
// retire node code ID
{"retire_node_code",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
return this->retire_code_id(
tx,
args.get<CodeDigest>(),
@ -877,7 +912,8 @@ namespace ccf
proposal_id);
}},
{"accept_recovery",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json&) {
[this](
const ProposalId& proposal_id, kv::Tx& tx, const nlohmann::json&) {
if (node.is_part_of_public_network())
{
const auto accept_recovery = node.accept_recovery(tx);
@ -895,7 +931,8 @@ namespace ccf
}
}},
{"open_network",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json&) {
[this](
const ProposalId& proposal_id, kv::Tx& tx, const nlohmann::json&) {
// On network open, the service checks that a sufficient number of
// recovery members have become active. If so, recovery shares are
// allocated to each recovery member
@ -926,7 +963,8 @@ namespace ccf
return network_opened;
}},
{"rekey_ledger",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json&) {
[this](
const ProposalId& proposal_id, kv::Tx& tx, const nlohmann::json&) {
const auto ledger_rekeyed = node.rekey_ledger(tx);
if (!ledger_rekeyed)
{
@ -935,7 +973,8 @@ namespace ccf
return ledger_rekeyed;
}},
{"update_recovery_shares",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json&) {
[this](
const ProposalId& proposal_id, kv::Tx& tx, const nlohmann::json&) {
try
{
share_manager.issue_shares(tx);
@ -951,7 +990,10 @@ namespace ccf
return true;
}},
{"set_recovery_threshold",
[this](ObjectId proposal_id, kv::Tx& tx, const nlohmann::json& args) {
[this](
const ProposalId& proposal_id,
kv::Tx& tx,
const nlohmann::json& args) {
const auto new_recovery_threshold = args.get<size_t>();
GenesisGenerator g(this->network, tx);
@ -986,7 +1028,7 @@ namespace ccf
};
ProposalInfo complete_proposal(
kv::Tx& tx, const ObjectId proposal_id, Proposal& proposal)
kv::Tx& tx, const ProposalId& proposal_id, Proposal& proposal)
{
if (proposal.state != ProposalState::OPEN)
{
@ -1144,14 +1186,14 @@ namespace ccf
}
static ProposalInfo get_proposal_info(
ObjectId proposal_id, const Proposal& proposal)
const ProposalId& proposal_id, const Proposal& proposal)
{
return ProposalInfo{proposal_id, proposal.proposer, proposal.state};
}
bool get_proposal_id_from_path(
const enclave::PathParams& params,
ObjectId& proposal_id,
ProposalId& proposal_id,
std::string& error)
{
return get_path_param(params, "proposal_id", proposal_id, error);
@ -1292,8 +1334,9 @@ namespace ccf
}
const auto in = params.get<Propose::In>();
const auto proposal_id = get_next_id(
ctx.tx.get_view(this->network.values), ValueIds::NEXT_PROPOSAL_ID);
const auto proposal_id =
fmt::format("{:02x}", fmt::join(caller_identity.request_digest, ""));
Proposal proposal(in.script, in.parameter, caller_identity.member_id);
auto proposals = ctx.tx.get_view(this->network.proposals);
@ -1321,7 +1364,7 @@ namespace ccf
"Member is not active.");
}
ObjectId proposal_id;
ProposalId proposal_id;
std::string error;
if (!get_proposal_id_from_path(
ctx.rpc_ctx->get_request_path_params(), proposal_id, error))
@ -1362,7 +1405,7 @@ namespace ccf
"Member is not active.");
}
ObjectId proposal_id;
ProposalId proposal_id;
std::string error;
if (!get_proposal_id_from_path(
ctx.rpc_ctx->get_request_path_params(), proposal_id, error))
@ -1435,7 +1478,7 @@ namespace ccf
"Member is not active.");
}
ObjectId proposal_id;
ProposalId proposal_id;
std::string error;
if (!get_proposal_id_from_path(
ctx.rpc_ctx->get_request_path_params(), proposal_id, error))
@ -1505,7 +1548,7 @@ namespace ccf
}
std::string error;
ObjectId proposal_id;
ProposalId proposal_id;
if (!get_proposal_id_from_path(
ctx.rpc_ctx->get_request_path_params(), proposal_id, error))
{
@ -1967,7 +2010,11 @@ namespace ccf
}
if (!set_jwt_public_signing_keys(
ctx.tx, INVALID_ID, parsed.issuer, issuer_metadata, parsed.jwks))
ctx.tx,
INVALID_PROPOSAL_ID,
parsed.issuer,
issuer_metadata,
parsed.jwks))
{
LOG_FAIL_FMT(
"JWT key auto-refresh: error while storing signing keys for issuer "

Просмотреть файл

@ -169,7 +169,9 @@ auto frontend_process(
}
auto get_proposal(
MemberRpcFrontend& frontend, size_t proposal_id, const tls::Pem& caller)
MemberRpcFrontend& frontend,
const ProposalId& proposal_id,
const tls::Pem& caller)
{
const auto getter =
create_request(nullptr, fmt::format("proposals/{}", proposal_id), HTTP_GET);
@ -180,7 +182,7 @@ auto get_proposal(
auto get_vote(
MemberRpcFrontend& frontend,
size_t proposal_id,
ProposalId proposal_id,
MemberId voter,
const tls::Pem& caller)
{
@ -366,7 +368,7 @@ DOCTEST_TEST_CASE("Proposer ballot")
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
size_t proposal_id;
ProposalId proposal_id;
const ccf::Script vote_for("return true");
const ccf::Script vote_against("return false");
@ -468,7 +470,7 @@ DOCTEST_TEST_CASE("Reject duplicate vote")
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
size_t proposal_id;
ProposalId proposal_id;
const ccf::Script vote_for("return true");
const ccf::Script vote_against("return false");
@ -573,7 +575,6 @@ DOCTEST_TEST_CASE("Add new members until there are 7 then reject")
auto i = 0ul;
for (auto& new_member : new_members)
{
const auto proposal_id = i;
new_member.id = initial_members + i++;
// new member certificate
@ -600,12 +601,13 @@ DOCTEST_TEST_CASE("Add new members until there are 7 then reject")
const auto propose =
create_signed_request(proposal, "proposals", kp, member_cert);
ProposalId proposal_id;
{
const auto r = frontend_process(frontend, propose, member_cert);
const auto result = parse_response_body<Propose::Out>(r);
// the proposal should be accepted, but not succeed immediately
DOCTEST_CHECK(result.proposal_id == proposal_id);
proposal_id = result.proposal_id;
DOCTEST_CHECK(result.state == ProposalState::OPEN);
}
@ -801,7 +803,7 @@ DOCTEST_TEST_CASE("Accept node")
}
// m0 proposes adding new node
ObjectId trust_node_proposal_id;
ProposalId trust_node_proposal_id;
{
Script proposal(R"xxx(
local tables, node_id = ...
@ -855,7 +857,7 @@ DOCTEST_TEST_CASE("Accept node")
}
// m0 proposes retire node
ObjectId retire_node_proposal_id;
ProposalId retire_node_proposal_id;
{
Script proposal(R"xxx(
local tables, node_id = ...
@ -986,7 +988,7 @@ ProposalInfo test_raw_writes(
}
// propose
const auto proposal_id = 0ul;
ProposalId proposal_id;
{
const uint8_t proposer_id = 0;
const auto propose =
@ -997,7 +999,7 @@ ProposalInfo test_raw_writes(
const auto expected_state =
(n_members == 1) ? ProposalState::ACCEPTED : ProposalState::OPEN;
DOCTEST_CHECK(r.state == expected_state);
DOCTEST_CHECK(r.proposal_id == proposal_id);
proposal_id = r.proposal_id;
if (r.state == ProposalState::ACCEPTED)
return r;
}
@ -1162,7 +1164,7 @@ DOCTEST_TEST_CASE("Remove proposal")
gen.finalize();
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
auto proposal_id = 0;
ProposalId proposal_id;
auto wrong_proposal_id = 1;
ccf::Script proposal_script(R"xxx(
local tables, param = ...
@ -1182,7 +1184,7 @@ DOCTEST_TEST_CASE("Remove proposal")
const auto r = parse_response_body<Propose::Out>(
frontend_process(frontend, propose, member_cert));
DOCTEST_CHECK(r.proposal_id == proposal_id);
proposal_id = r.proposal_id;
DOCTEST_CHECK(r.state == ProposalState::OPEN);
}
@ -1294,7 +1296,7 @@ DOCTEST_TEST_CASE("Vetoed proposal gets rejected")
{
DOCTEST_INFO("Check proposal was rejected");
const auto proposal = get_proposal(frontend, 0, voter_a_cert);
const auto proposal = get_proposal(frontend, r.proposal_id, voter_a_cert);
DOCTEST_CHECK(proposal.state == ProposalState::REJECTED);
}
@ -1347,7 +1349,6 @@ DOCTEST_TEST_CASE("Add and remove user via proposed calls")
frontend_process(frontend, vote, member_cert));
DOCTEST_CHECK(r.state == ProposalState::ACCEPTED);
DOCTEST_CHECK(r.proposal_id == 0);
auto tx1 = network.tables->create_tx();
const auto uid = tx1.get_view(network.values)->get(ValueIds::NEXT_USER_ID);
@ -1385,7 +1386,6 @@ DOCTEST_TEST_CASE("Add and remove user via proposed calls")
frontend_process(frontend, vote, member_cert));
DOCTEST_CHECK(r.state == ProposalState::ACCEPTED);
DOCTEST_CHECK(r.proposal_id == 1);
auto tx1 = network.tables->create_tx();
auto user = tx1.get_view(network.users)->get(0);
@ -1440,7 +1440,7 @@ DOCTEST_TEST_CASE(
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
size_t proposal_id;
ProposalId proposal_id;
size_t proposer_id = 1;
size_t voter_id = 2;
@ -1578,7 +1578,7 @@ DOCTEST_TEST_CASE("Passing operator change" * doctest::test_suite("operator"))
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
size_t proposal_id;
ProposalId proposal_id;
const ccf::Script vote_for("return true");
const ccf::Script vote_against("return false");
@ -1759,7 +1759,7 @@ DOCTEST_TEST_CASE(
MemberRpcFrontend frontend(network, node, share_manager);
frontend.open();
size_t proposal_id;
ProposalId proposal_id;
const ccf::Script vote_for("return true");
const ccf::Script vote_against("return false");

Просмотреть файл

@ -121,6 +121,21 @@ namespace tls
md_type);
}
bool verify(
const std::vector<uint8_t>& contents,
const std::vector<uint8_t>& signature,
mbedtls_md_type_t md_type,
HashBytes& hash_bytes) const
{
return verify(
contents.data(),
contents.size(),
signature.data(),
signature.size(),
md_type,
hash_bytes);
}
bool verify(
const uint8_t* contents,
size_t contents_size,
@ -134,6 +149,18 @@ namespace tls
return verify_hash(hash, sig, sig_size, md_type);
}
bool verify(
const uint8_t* contents,
size_t contents_size,
const uint8_t* sig,
size_t sig_size,
mbedtls_md_type_t md_type,
HashBytes& hash_bytes) const
{
do_hash(cert->pk, contents, contents_size, hash_bytes, md_type);
return verify_hash(hash_bytes, sig, sig_size, md_type);
}
const mbedtls_x509_crt* raw()
{
return cert.get();

Просмотреть файл

@ -269,7 +269,7 @@ class Consortium:
for proposal_id, attr in r.body.json().items():
proposals.append(
infra.proposal.Proposal(
proposal_id=int(proposal_id),
proposal_id=proposal_id,
proposer_id=int(attr["proposer"]),
state=infra.proposal.ProposalState(attr["state"]),
)