зеркало из https://github.com/microsoft/CCF.git
Use digests for proposal ids, rather than incrementing integers (#2104)
This commit is contained in:
Родитель
321cd89fc7
Коммит
32cc0ad938
|
@ -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"]),
|
||||
)
|
||||
|
|
Загрузка…
Ссылка в новой задаче