Aft: refactor progress tracker and introduce mock framework (#1697)

This commit is contained in:
Alex 2020-10-05 16:24:41 +01:00 коммит произвёл GitHub
Родитель 21bad27af8
Коммит 09faf8e234
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 5455 добавлений и 172 удалений

57
3rdparty/trompeloeil/include/trompeloeil.hpp поставляемый Normal file
Просмотреть файл

@ -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_

5033
3rdparty/trompeloeil/trompeloeil.hpp поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -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);
}
}