зеркало из https://github.com/microsoft/CCF.git
Aft: refactor progress tracker and introduce mock framework (#1697)
This commit is contained in:
Родитель
21bad27af8
Коммит
09faf8e234
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Trompeloeil C++ mocking framework
|
||||
*
|
||||
* Copyright Björn Fahller 2014-2019
|
||||
*
|
||||
* Use, modification and distribution is subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Project home: https://github.com/rollbear/trompeloeil
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TROMPELOEIL_DOCTEST_HPP_
|
||||
#define TROMPELOEIL_DOCTEST_HPP_
|
||||
|
||||
#ifndef DOCTEST_VERSION_MAJOR
|
||||
#error "<doctest.h> must be included before <doctest/trompeloeil.hpp>"
|
||||
#endif
|
||||
|
||||
#include "../trompeloeil.hpp"
|
||||
|
||||
namespace trompeloeil
|
||||
{
|
||||
template <>
|
||||
inline void reporter<specialized>::send(
|
||||
severity s,
|
||||
const char* file,
|
||||
unsigned long line,
|
||||
const char* msg)
|
||||
{
|
||||
auto f = line ? file : "[file/line unavailable]";
|
||||
if (s == severity::fatal)
|
||||
{
|
||||
DOCTEST_ADD_FAIL_AT(f, line, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
DOCTEST_ADD_FAIL_CHECK_AT(f, line, msg);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void reporter<specialized>::sendOk(
|
||||
const char* trompeloeil_mock_calls_done_correctly)
|
||||
{
|
||||
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
|
||||
DOCTEST_REQUIRE_UNARY(trompeloeil_mock_calls_done_correctly);
|
||||
#else
|
||||
DOCTEST_REQUIRE_NE(doctest::String(trompeloeil_mock_calls_done_correctly), "");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //TROMPELOEIL_DOCTEST_HPP_
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -606,3 +606,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
|
||||
rollbear/trompeloeil 08cba57ed7207c8ad5c94fd2a20dc0bfecabe878 - BSL-1.0
|
||||
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
|
|
@ -135,6 +135,15 @@
|
|||
"commitHash": "83da75636cef3ee6e0c83cf8651e2929e1b87261"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/rollbear/trompeloeil",
|
||||
"commitHash": "08cba57ed7207c8ad5c94fd2a20dc0bfecabe878"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace aft
|
|||
using Nonce = std::array<uint8_t, 32>;
|
||||
struct RevealedNonce
|
||||
{
|
||||
ccf::NodeId node_id;
|
||||
kv::NodeId node_id;
|
||||
Nonce nonce;
|
||||
|
||||
MSGPACK_DEFINE(node_id, nonce);
|
||||
|
|
|
@ -1766,12 +1766,14 @@ namespace ccf
|
|||
{
|
||||
if (network.consensus_type == ConsensusType::BFT)
|
||||
{
|
||||
progress_tracker = std::make_shared<ccf::ProgressTracker>(
|
||||
auto store = std::make_unique<ccf::ProgressTrackerStoreAdapter>(
|
||||
*network.tables.get(),
|
||||
self,
|
||||
network.nodes,
|
||||
network.backup_signatures_map,
|
||||
network.revealed_nonces_map);
|
||||
|
||||
progress_tracker =
|
||||
std::make_shared<ccf::ProgressTracker>(std::move(store), self);
|
||||
network.tables->set_progress_tracker(progress_tracker);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,12 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "backup_signatures.h"
|
||||
#include "consensus/aft/revealed_nonces.h"
|
||||
#include "ds/ccf_assert.h"
|
||||
#include "ds/ccf_exception.h"
|
||||
#include "kv/kv_types.h"
|
||||
#include "kv/tx.h"
|
||||
#include "node_signature.h"
|
||||
#include "nodes.h"
|
||||
#include "tls/hash.h"
|
||||
#include "tls/tls.h"
|
||||
#include "tls/verifier.h"
|
||||
#include "progress_tracker_types.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
@ -23,30 +18,28 @@ namespace ccf
|
|||
{
|
||||
public:
|
||||
ProgressTracker(
|
||||
kv::AbstractStore& store_,
|
||||
kv::NodeId id_,
|
||||
ccf::Nodes& nodes_,
|
||||
ccf::BackupSignaturesMap& backup_signatures_,
|
||||
aft::RevealedNoncesMap& revealed_nonces_) :
|
||||
store(store_),
|
||||
std::unique_ptr<ProgressTrackerStore> store_, kv::NodeId id_) :
|
||||
store(std::move(store_)),
|
||||
id(id_),
|
||||
nodes(nodes_),
|
||||
backup_signatures(backup_signatures_),
|
||||
revealed_nonces(revealed_nonces_),
|
||||
entropy(tls::create_entropy())
|
||||
{}
|
||||
|
||||
std::unique_ptr<ProgressTrackerStore> store;
|
||||
|
||||
kv::TxHistory::Result add_signature(
|
||||
kv::TxID tx_id,
|
||||
kv::NodeId node_id,
|
||||
uint32_t signature_size,
|
||||
std::array<uint8_t, MBEDTLS_ECDSA_MAX_LEN>& sig,
|
||||
Nonce& hashed_nonce,
|
||||
Nonce hashed_nonce,
|
||||
uint32_t node_count,
|
||||
bool is_primary)
|
||||
{
|
||||
LOG_TRACE_FMT(
|
||||
"add_signature node_id:{}, seqno:{}", node_id, tx_id.version);
|
||||
"add_signature node_id:{}, seqno:{}, hashed_nonce:{}",
|
||||
node_id,
|
||||
tx_id.version,
|
||||
hashed_nonce);
|
||||
auto it = certificates.find(CertKey(tx_id));
|
||||
if (it == certificates.end())
|
||||
{
|
||||
|
@ -61,7 +54,7 @@ namespace ccf
|
|||
{
|
||||
if (
|
||||
node_id != id && it->second.have_primary_signature &&
|
||||
!verify_signature(
|
||||
!store->verify_signature(
|
||||
node_id, it->second.root, signature_size, sig.data()))
|
||||
{
|
||||
// NOTE: We need to handle this case but for now having this make a
|
||||
|
@ -82,15 +75,22 @@ namespace ccf
|
|||
}
|
||||
|
||||
std::vector<uint8_t> sig_vec;
|
||||
CCF_ASSERT(
|
||||
CCF_ASSERT_FMT(
|
||||
signature_size <= sig.size(),
|
||||
fmt::format(
|
||||
"Invalid signature size, signature_size:{}, sig.size:{}",
|
||||
signature_size,
|
||||
sig.size()));
|
||||
"Invalid signature size, signature_size:{}, sig.size:{}",
|
||||
signature_size,
|
||||
sig.size());
|
||||
sig_vec.assign(sig.begin(), sig.begin() + signature_size);
|
||||
|
||||
auto& cert = it->second;
|
||||
CCF_ASSERT(
|
||||
node_id != id ||
|
||||
std::equal(
|
||||
hashed_nonce.begin(),
|
||||
hashed_nonce.end(),
|
||||
get_my_hashed_nonce(tx_id).begin()),
|
||||
"hashed_nonce does not match my nonce");
|
||||
|
||||
BftNodeSignature bft_node_sig(std::move(sig_vec), node_id, hashed_nonce);
|
||||
try_match_unmatched_nonces(
|
||||
cert, bft_node_sig, tx_id.term, tx_id.version, node_id);
|
||||
|
@ -101,9 +101,6 @@ namespace ccf
|
|||
{
|
||||
if (is_primary)
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto backup_sig_view = tx.get_view(backup_signatures);
|
||||
|
||||
const CertKey& key = it->first;
|
||||
ccf::BackupSignatures sig_value(
|
||||
key.tx_id.term, key.tx_id.version, cert.root);
|
||||
|
@ -117,13 +114,7 @@ namespace ccf
|
|||
}
|
||||
}
|
||||
|
||||
backup_sig_view->put(0, sig_value);
|
||||
auto r = tx.commit();
|
||||
LOG_TRACE_FMT("Adding signatures to ledger, result:{}", r);
|
||||
CCF_ASSERT_FMT(
|
||||
r == kv::CommitSuccess::OK,
|
||||
"Commiting backup signatures failed r:{}",
|
||||
r);
|
||||
store->write_backup_signatures(sig_value);
|
||||
}
|
||||
return kv::TxHistory::Result::SEND_SIG_RECEIPT_ACK;
|
||||
}
|
||||
|
@ -134,9 +125,14 @@ namespace ccf
|
|||
kv::TxID tx_id,
|
||||
kv::NodeId node_id,
|
||||
crypto::Sha256Hash& root,
|
||||
Nonce& hashed_nonce,
|
||||
Nonce hashed_nonce,
|
||||
uint32_t node_count = 0)
|
||||
{
|
||||
LOG_TRACE_FMT(
|
||||
"record_primary node_id:{}, seqno:{}, hashed_nonce:{}",
|
||||
node_id,
|
||||
tx_id.version,
|
||||
hashed_nonce);
|
||||
auto n = entropy->random(hashed_nonce.size());
|
||||
Nonce my_nonce;
|
||||
std::copy(n.begin(), n.end(), my_nonce.begin());
|
||||
|
@ -146,6 +142,12 @@ namespace ccf
|
|||
std::copy(h.begin(), h.end(), hashed_nonce.begin());
|
||||
}
|
||||
|
||||
LOG_TRACE_FMT(
|
||||
"record_primary node_id:{}, seqno:{}, hashed_nonce:{}",
|
||||
node_id,
|
||||
tx_id.version,
|
||||
hashed_nonce);
|
||||
|
||||
auto it = certificates.find(CertKey(tx_id));
|
||||
if (it == certificates.end())
|
||||
{
|
||||
|
@ -181,7 +183,7 @@ namespace ccf
|
|||
{
|
||||
if (
|
||||
!sig.second.is_primary &&
|
||||
!verify_signature(
|
||||
!store->verify_signature(
|
||||
sig.second.node,
|
||||
cert.root,
|
||||
sig.second.sig.size(),
|
||||
|
@ -224,15 +226,10 @@ namespace ccf
|
|||
kv::TxHistory::Result receive_backup_signatures(
|
||||
kv::TxID& tx_id, uint32_t node_count, bool is_primary)
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto sigs_tv = tx.get_view(backup_signatures);
|
||||
auto sigs = sigs_tv->get(0);
|
||||
if (!sigs.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT("No signatures found in signatures map");
|
||||
return kv::TxHistory::Result::FAIL;
|
||||
}
|
||||
ccf::BackupSignatures& sigs_value = sigs.value();
|
||||
std::optional<ccf::BackupSignatures> sigs =
|
||||
store->get_backup_signatures();
|
||||
CCF_ASSERT(sigs.has_value(), "sigs does not have a value");
|
||||
auto sigs_value = sigs.value();
|
||||
|
||||
auto it = certificates.find(CertKey({sigs_value.view, sigs_value.seqno}));
|
||||
if (it == certificates.end())
|
||||
|
@ -309,14 +306,8 @@ namespace ccf
|
|||
|
||||
kv::TxHistory::Result receive_nonces()
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto nonces_tv = tx.get_view(revealed_nonces);
|
||||
auto nonces = nonces_tv->get(0);
|
||||
if (!nonces.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT("No signatures found in signatures map");
|
||||
return kv::TxHistory::Result::FAIL;
|
||||
}
|
||||
std::optional<aft::RevealedNonces> nonces = store->get_nonces();
|
||||
CCF_ASSERT(nonces.has_value(), "nonces does not have a value");
|
||||
aft::RevealedNonces& nonces_value = nonces.value();
|
||||
|
||||
auto it = certificates.find(CertKey(nonces_value.tx_id));
|
||||
|
@ -462,9 +453,6 @@ namespace ccf
|
|||
|
||||
if (is_primary && should_append_nonces_to_ledger(cert, node_count))
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto nonces_tv = tx.get_view(revealed_nonces);
|
||||
|
||||
aft::RevealedNonces revealed_nonces(tx_id);
|
||||
|
||||
for (auto nonce_node_id : cert.nonce_set)
|
||||
|
@ -478,19 +466,7 @@ namespace ccf
|
|||
aft::RevealedNonce(nonce_node_id, it->second.nonce));
|
||||
}
|
||||
|
||||
nonces_tv->put(0, revealed_nonces);
|
||||
auto r = tx.commit();
|
||||
if (r != kv::CommitSuccess::OK)
|
||||
{
|
||||
LOG_FAIL_FMT(
|
||||
"Failed to write nonces, view:{}, seqno:{}",
|
||||
tx_id.term,
|
||||
tx_id.version);
|
||||
throw ccf::ccf_logic_error(fmt::format(
|
||||
"Failed to write nonces, view:{}, seqno:{}",
|
||||
tx_id.term,
|
||||
tx_id.version));
|
||||
}
|
||||
store->write_nonces(revealed_nonces);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,87 +494,7 @@ namespace ccf
|
|||
id = id_;
|
||||
}
|
||||
|
||||
private:
|
||||
kv::AbstractStore& store;
|
||||
kv::NodeId id;
|
||||
ccf::Nodes& nodes;
|
||||
ccf::BackupSignaturesMap& backup_signatures;
|
||||
aft::RevealedNoncesMap& revealed_nonces;
|
||||
std::shared_ptr<tls::Entropy> entropy;
|
||||
|
||||
struct CertKey
|
||||
{
|
||||
CertKey(kv::TxID tx_id_) : tx_id(tx_id_) {}
|
||||
|
||||
kv::TxID tx_id;
|
||||
|
||||
bool operator<(const CertKey& rhs) const
|
||||
{
|
||||
if (tx_id.version == rhs.tx_id.version)
|
||||
{
|
||||
return tx_id.term < rhs.tx_id.term;
|
||||
}
|
||||
return tx_id.version < rhs.tx_id.version;
|
||||
}
|
||||
};
|
||||
|
||||
struct BftNodeSignature : public ccf::NodeSignature
|
||||
{
|
||||
bool is_primary;
|
||||
Nonce nonce;
|
||||
|
||||
BftNodeSignature(
|
||||
const std::vector<uint8_t>& sig_, NodeId node_, Nonce hashed_nonce_) :
|
||||
NodeSignature(sig_, node_, hashed_nonce_),
|
||||
is_primary(false)
|
||||
{}
|
||||
};
|
||||
|
||||
struct CommitCert
|
||||
{
|
||||
CommitCert(crypto::Sha256Hash& root_, Nonce my_nonce_) :
|
||||
root(root_),
|
||||
my_nonce(my_nonce_),
|
||||
have_primary_signature(true)
|
||||
{}
|
||||
|
||||
CommitCert() = default;
|
||||
|
||||
crypto::Sha256Hash root;
|
||||
std::map<kv::NodeId, BftNodeSignature> sigs;
|
||||
std::set<kv::NodeId> sig_acks;
|
||||
std::set<kv::NodeId> nonce_set;
|
||||
std::map<kv::NodeId, Nonce> unmatched_nonces;
|
||||
Nonce my_nonce;
|
||||
bool have_primary_signature = false;
|
||||
bool ack_sent = false;
|
||||
bool reply_and_nonce_sent = false;
|
||||
bool nonces_committed_to_ledger = false;
|
||||
};
|
||||
std::map<CertKey, CommitCert> certificates;
|
||||
|
||||
bool verify_signature(
|
||||
kv::NodeId node_id,
|
||||
crypto::Sha256Hash& root,
|
||||
uint32_t sig_size,
|
||||
uint8_t* sig)
|
||||
{
|
||||
kv::Tx tx;
|
||||
auto ni_tv = tx.get_view_old(nodes);
|
||||
|
||||
auto ni = ni_tv->get(node_id);
|
||||
if (!ni.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT(
|
||||
"No node info, and therefore no cert for node {}", node_id);
|
||||
return false;
|
||||
}
|
||||
tls::VerifierPtr from_cert = tls::make_verifier(ni.value().cert);
|
||||
return from_cert->verify_hash(
|
||||
root.h.data(), root.h.size(), sig, sig_size);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> hash_data(Nonce data)
|
||||
std::vector<uint8_t> hash_data(Nonce& data)
|
||||
{
|
||||
tls::HashBytes hash;
|
||||
tls::do_hash(
|
||||
|
@ -609,6 +505,12 @@ namespace ccf
|
|||
return hash;
|
||||
}
|
||||
|
||||
private:
|
||||
kv::NodeId id;
|
||||
std::shared_ptr<tls::Entropy> entropy;
|
||||
|
||||
std::map<CertKey, CommitCert> certificates;
|
||||
|
||||
void try_match_unmatched_nonces(
|
||||
CommitCert& cert,
|
||||
BftNodeSignature& bft_node_sig,
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
#include "backup_signatures.h"
|
||||
#include "consensus/aft/revealed_nonces.h"
|
||||
#include "node_signature.h"
|
||||
#include "tls/hash.h"
|
||||
#include "tls/tls.h"
|
||||
#include "tls/verifier.h"
|
||||
|
||||
namespace ccf
|
||||
{
|
||||
struct CertKey
|
||||
{
|
||||
CertKey(kv::TxID tx_id_) : tx_id(tx_id_) {}
|
||||
|
||||
kv::TxID tx_id;
|
||||
|
||||
bool operator<(const CertKey& rhs) const
|
||||
{
|
||||
if (tx_id.version == rhs.tx_id.version)
|
||||
{
|
||||
return tx_id.term < rhs.tx_id.term;
|
||||
}
|
||||
return tx_id.version < rhs.tx_id.version;
|
||||
}
|
||||
};
|
||||
|
||||
struct BftNodeSignature : public ccf::NodeSignature
|
||||
{
|
||||
bool is_primary;
|
||||
Nonce nonce;
|
||||
|
||||
BftNodeSignature(
|
||||
const std::vector<uint8_t>& sig_, NodeId node_, Nonce hashed_nonce_) :
|
||||
NodeSignature(sig_, node_, hashed_nonce_),
|
||||
is_primary(false)
|
||||
{}
|
||||
};
|
||||
|
||||
struct CommitCert
|
||||
{
|
||||
CommitCert(crypto::Sha256Hash& root_, Nonce my_nonce_) :
|
||||
root(root_),
|
||||
my_nonce(my_nonce_),
|
||||
have_primary_signature(true)
|
||||
{}
|
||||
|
||||
CommitCert() = default;
|
||||
|
||||
crypto::Sha256Hash root;
|
||||
std::map<kv::NodeId, BftNodeSignature> sigs;
|
||||
std::set<kv::NodeId> sig_acks;
|
||||
std::set<kv::NodeId> nonce_set;
|
||||
std::map<kv::NodeId, Nonce> unmatched_nonces;
|
||||
Nonce my_nonce;
|
||||
bool have_primary_signature = false;
|
||||
bool ack_sent = false;
|
||||
bool reply_and_nonce_sent = false;
|
||||
bool nonces_committed_to_ledger = false;
|
||||
};
|
||||
|
||||
class ProgressTrackerStore
|
||||
{
|
||||
public:
|
||||
virtual ~ProgressTrackerStore() = default;
|
||||
virtual void write_backup_signatures(ccf::BackupSignatures& sig_value) = 0;
|
||||
virtual std::optional<ccf::BackupSignatures> get_backup_signatures() = 0;
|
||||
virtual void write_nonces(aft::RevealedNonces& nonces) = 0;
|
||||
virtual std::optional<aft::RevealedNonces> get_nonces() = 0;
|
||||
virtual bool verify_signature(
|
||||
kv::NodeId node_id,
|
||||
crypto::Sha256Hash& root,
|
||||
uint32_t sig_size,
|
||||
uint8_t* sig) = 0;
|
||||
};
|
||||
|
||||
class ProgressTrackerStoreAdapter : public ProgressTrackerStore
|
||||
{
|
||||
public:
|
||||
ProgressTrackerStoreAdapter(
|
||||
kv::AbstractStore& store_,
|
||||
ccf::Nodes& nodes_,
|
||||
ccf::BackupSignaturesMap& backup_signatures_,
|
||||
aft::RevealedNoncesMap& revealed_nonces_) :
|
||||
store(store_),
|
||||
nodes(nodes_),
|
||||
backup_signatures(backup_signatures_),
|
||||
revealed_nonces(revealed_nonces_)
|
||||
{}
|
||||
|
||||
void write_backup_signatures(ccf::BackupSignatures& sig_value) override
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto backup_sig_view = tx.get_view(backup_signatures);
|
||||
|
||||
backup_sig_view->put(0, sig_value);
|
||||
auto r = tx.commit();
|
||||
LOG_TRACE_FMT("Adding signatures to ledger, result:{}", r);
|
||||
CCF_ASSERT_FMT(
|
||||
r == kv::CommitSuccess::OK,
|
||||
"Commiting backup signatures failed r:{}",
|
||||
r);
|
||||
}
|
||||
|
||||
std::optional<ccf::BackupSignatures> get_backup_signatures() override
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto sigs_tv = tx.get_view(backup_signatures);
|
||||
auto sigs = sigs_tv->get(0);
|
||||
if (!sigs.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT("No signatures found in signatures map");
|
||||
throw ccf::ccf_logic_error("No signatures found in signatures map");
|
||||
}
|
||||
return sigs;
|
||||
}
|
||||
|
||||
void write_nonces(aft::RevealedNonces& nonces) override
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto nonces_tv = tx.get_view(revealed_nonces);
|
||||
|
||||
nonces_tv->put(0, nonces);
|
||||
auto r = tx.commit();
|
||||
if (r != kv::CommitSuccess::OK)
|
||||
{
|
||||
LOG_FAIL_FMT(
|
||||
"Failed to write nonces, view:{}, seqno:{}",
|
||||
nonces.tx_id.term,
|
||||
nonces.tx_id.version);
|
||||
throw ccf::ccf_logic_error(fmt::format(
|
||||
"Failed to write nonces, view:{}, seqno:{}",
|
||||
nonces.tx_id.term,
|
||||
nonces.tx_id.version));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<aft::RevealedNonces> get_nonces() override
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto nonces_tv = tx.get_view(revealed_nonces);
|
||||
auto nonces = nonces_tv->get(0);
|
||||
if (!nonces.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT("No signatures found in signatures map");
|
||||
throw ccf::ccf_logic_error("No signatures found in signatures map");
|
||||
}
|
||||
return nonces;
|
||||
}
|
||||
|
||||
bool verify_signature(
|
||||
kv::NodeId node_id,
|
||||
crypto::Sha256Hash& root,
|
||||
uint32_t sig_size,
|
||||
uint8_t* sig) override
|
||||
{
|
||||
kv::Tx tx(&store);
|
||||
auto ni_tv = tx.get_view_old(nodes);
|
||||
|
||||
auto ni = ni_tv->get(node_id);
|
||||
if (!ni.has_value())
|
||||
{
|
||||
LOG_FAIL_FMT(
|
||||
"No node info, and therefore no cert for node {}", node_id);
|
||||
return false;
|
||||
}
|
||||
tls::VerifierPtr from_cert = tls::make_verifier(ni.value().cert);
|
||||
return from_cert->verify_hash(
|
||||
root.h.data(), root.h.size(), sig, sig_size);
|
||||
}
|
||||
|
||||
private:
|
||||
kv::AbstractStore& store;
|
||||
ccf::Nodes& nodes;
|
||||
ccf::BackupSignaturesMap& backup_signatures;
|
||||
aft::RevealedNoncesMap& revealed_nonces;
|
||||
};
|
||||
}
|
|
@ -9,44 +9,116 @@
|
|||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include <doctest/doctest.h>
|
||||
#include <string>
|
||||
#include <trompeloeil/include/trompeloeil.hpp>
|
||||
|
||||
TEST_CASE("Ordered Execution")
|
||||
class StoreMock : public ccf::ProgressTrackerStore
|
||||
{
|
||||
kv::Store store;
|
||||
auto& nodes =
|
||||
store.create<ccf::Nodes>(ccf::Tables::NODES, kv::SecurityDomain::PUBLIC);
|
||||
auto& backup_signatures_map = store.create<ccf::BackupSignaturesMap>(
|
||||
ccf::Tables::BACKUP_SIGNATURES, kv::SecurityDomain::PUBLIC);
|
||||
auto& revealed_nonces_map = store.create<aft::RevealedNoncesMap>(
|
||||
ccf::Tables::NONCES, kv::SecurityDomain::PUBLIC);
|
||||
public:
|
||||
MAKE_MOCK1(write_backup_signatures, void(ccf::BackupSignatures&), override);
|
||||
MAKE_MOCK0(
|
||||
get_backup_signatures, std::optional<ccf::BackupSignatures>(), override);
|
||||
MAKE_MOCK1(write_nonces, void(aft::RevealedNonces&), override);
|
||||
MAKE_MOCK0(get_nonces, std::optional<aft::RevealedNonces>(), override);
|
||||
MAKE_MOCK4(
|
||||
verify_signature,
|
||||
bool(kv::NodeId, crypto::Sha256Hash&, uint32_t, uint8_t*),
|
||||
override);
|
||||
};
|
||||
|
||||
void run_ordered_execution(uint32_t my_node_id)
|
||||
{
|
||||
using trompeloeil::_;
|
||||
|
||||
auto store = std::make_unique<StoreMock>();
|
||||
StoreMock& store_mock = *store.get();
|
||||
auto pt =
|
||||
std::make_unique<ccf::ProgressTracker>(std::move(store), my_node_id);
|
||||
|
||||
kv::Consensus::View view = 0;
|
||||
kv::Consensus::SeqNo seqno = 0;
|
||||
uint32_t node_count = 4;
|
||||
uint32_t node_count_quorum =
|
||||
2; // Takes into account that counting starts at 0
|
||||
|
||||
crypto::Sha256Hash root;
|
||||
std::array<uint8_t, MBEDTLS_ECDSA_MAX_LEN> sig;
|
||||
ccf::Nonce nonce;
|
||||
auto h = pt->hash_data(nonce);
|
||||
ccf::Nonce hashed_nonce;
|
||||
std::copy(h.begin(), h.end(), hashed_nonce.begin());
|
||||
|
||||
INFO("Adding signature");
|
||||
REQUIRE_CALL(store_mock, verify_signature(_, _, _, _))
|
||||
.RETURN(true)
|
||||
.TIMES(AT_LEAST(2));
|
||||
REQUIRE_CALL(store_mock, write_backup_signatures(_)).TIMES(1);
|
||||
REQUIRE_CALL(store_mock, write_nonces(_)).TIMES(1);
|
||||
|
||||
INFO("Adding signatures");
|
||||
{
|
||||
auto pt = std::make_unique<ccf::ProgressTracker>(
|
||||
store, 0, nodes, backup_signatures_map, revealed_nonces_map);
|
||||
auto result = pt->add_signature(
|
||||
{view, seqno}, 1, MBEDTLS_ECDSA_MAX_LEN, sig, nonce, node_count, true);
|
||||
auto result =
|
||||
pt->record_primary({view, seqno}, 0, root, hashed_nonce, node_count);
|
||||
REQUIRE(result == kv::TxHistory::Result::OK);
|
||||
REQUIRE_THROWS(
|
||||
pt->record_primary({view, seqno}, 0, root, nonce, node_count));
|
||||
|
||||
for (uint32_t i = 1; i < node_count; ++i)
|
||||
{
|
||||
if (i == my_node_id)
|
||||
{
|
||||
auto h = pt->get_my_hashed_nonce({view, seqno});
|
||||
std::copy(h.begin(), h.end(), hashed_nonce.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(h.begin(), h.end(), hashed_nonce.begin());
|
||||
}
|
||||
|
||||
auto result = pt->add_signature(
|
||||
{view, seqno},
|
||||
i,
|
||||
MBEDTLS_ECDSA_MAX_LEN,
|
||||
sig,
|
||||
hashed_nonce,
|
||||
node_count,
|
||||
true);
|
||||
REQUIRE(
|
||||
((result == kv::TxHistory::Result::OK && i != node_count_quorum) ||
|
||||
(result == kv::TxHistory::Result::SEND_SIG_RECEIPT_ACK &&
|
||||
i == node_count_quorum)));
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Waits for signature tx");
|
||||
INFO("Add signature acks");
|
||||
{
|
||||
auto pt = std::make_unique<ccf::ProgressTracker>(
|
||||
store, 0, nodes, backup_signatures_map, revealed_nonces_map);
|
||||
for (size_t i = 0; i < node_count; ++i)
|
||||
for (uint32_t i = 0; i < node_count; ++i)
|
||||
{
|
||||
auto result = pt->add_signature_ack({view, seqno}, i, node_count);
|
||||
REQUIRE(result == kv::TxHistory::Result::OK);
|
||||
REQUIRE(
|
||||
((result == kv::TxHistory::Result::OK && i != node_count_quorum) ||
|
||||
(result == kv::TxHistory::Result::SEND_REPLY_AND_NONCE &&
|
||||
i == node_count_quorum)));
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Add nonces here");
|
||||
{
|
||||
for (uint32_t i = 0; i < node_count; ++i)
|
||||
{
|
||||
if (my_node_id == i)
|
||||
{
|
||||
pt->add_nonce_reveal(
|
||||
{view, seqno}, pt->get_my_nonce({view, seqno}), i, node_count, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
pt->add_nonce_reveal({view, seqno}, nonce, i, node_count, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Ordered Execution")
|
||||
{
|
||||
for (uint32_t i = 0; i < 4; ++i)
|
||||
{
|
||||
run_ordered_execution(i);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче