Migrate thread safety to RCLConsensus (RIPD-1389):

Moves thread safety from generic Consensus to RCLConsensus and switch generic
Consensus to adaptor design.
This commit is contained in:
Brad Chase
2017-04-26 11:13:30 -04:00
committed by seelabs
parent 8c155dd875
commit 01b4d5cdd4
23 changed files with 1729 additions and 1135 deletions

View File

@@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright 2017 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/misc/ValidatorKeys.h>
#include <ripple/beast/unit_test.h>
#include <ripple/core/Config.h>
#include <ripple/core/ConfigSections.h>
#include <string>
namespace ripple {
namespace test {
class ValidatorKeys_test : public beast::unit_test::suite
{
// Used with [validation_seed]
const std::string seed = "shUwVw52ofnCUX5m7kPTKzJdr4HEH";
// Used with [validation_token]
const std::string tokenSecretStr =
"paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi";
const std::vector<std::string> tokenBlob = {
" "
"eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
" \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl "
" \n",
"\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE"
"\n",
"\t "
"hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t "
"\t\n",
"bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
"hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
"NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
"VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"};
const std::string tokenManifest =
"JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwD"
"wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+sAOkVB"
"+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
"gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFOr7C0kw"
"2AiTzSCjIzditQ8=";
public:
void
run() override
{
beast::Journal j;
// Keys when using [validation_seed]
auto const seedSecretKey =
generateSecretKey(KeyType::secp256k1, *parseBase58<Seed>(seed));
auto const seedPublicKey =
derivePublicKey(KeyType::secp256k1, seedSecretKey);
// Keys when using [validation_token]
auto const tokenSecretKey = *parseBase58<SecretKey>(
TokenType::TOKEN_NODE_PRIVATE, tokenSecretStr);
auto const tokenPublicKey =
derivePublicKey(KeyType::secp256k1, tokenSecretKey);
{
// No config -> no key but valid
Config c;
ValidatorKeys k{c, j};
BEAST_EXPECT(k.publicKey.size() == 0);
BEAST_EXPECT(k.manifest.empty());
BEAST_EXPECT(!k.configInvalid());
}
{
// validation seed section -> empty manifest and valid seeds
Config c;
c.section(SECTION_VALIDATION_SEED).append(seed);
ValidatorKeys k{c, j};
BEAST_EXPECT(k.publicKey == seedPublicKey);
BEAST_EXPECT(k.secretKey == seedSecretKey);
BEAST_EXPECT(k.manifest.empty());
BEAST_EXPECT(!k.configInvalid());
}
{
// validation seed bad seed -> invalid
Config c;
c.section(SECTION_VALIDATION_SEED).append("badseed");
ValidatorKeys k{c, j};
BEAST_EXPECT(k.configInvalid());
BEAST_EXPECT(k.publicKey.size() == 0);
BEAST_EXPECT(k.manifest.empty());
}
{
// validator token
Config c;
c.section(SECTION_VALIDATOR_TOKEN).append(tokenBlob);
ValidatorKeys k{c, j};
BEAST_EXPECT(k.publicKey == tokenPublicKey);
BEAST_EXPECT(k.secretKey == tokenSecretKey);
BEAST_EXPECT(k.manifest == tokenManifest);
BEAST_EXPECT(!k.configInvalid());
}
{
// invalid validator token
Config c;
c.section(SECTION_VALIDATOR_TOKEN).append("badtoken");
ValidatorKeys k{c, j};
BEAST_EXPECT(k.configInvalid());
BEAST_EXPECT(k.publicKey.size() == 0);
BEAST_EXPECT(k.manifest.empty());
}
{
// Cannot specify both
Config c;
c.section(SECTION_VALIDATION_SEED).append(seed);
c.section(SECTION_VALIDATOR_TOKEN).append(tokenBlob);
ValidatorKeys k{c, j};
BEAST_EXPECT(k.configInvalid());
BEAST_EXPECT(k.publicKey.size() == 0);
BEAST_EXPECT(k.manifest.empty());
}
}
}; // namespace test
BEAST_DEFINE_TESTSUITE(ValidatorKeys, app, ripple);
} // namespace test
} // namespace ripple

View File

@@ -21,7 +21,8 @@
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include <ripple/consensus/Consensus.h>
#include <ripple/consensus/ConsensusProposal.h>
#include <test/csf/Ledger.h>
#include <test/csf/Tx.h>
#include <test/csf/UNL.h>
@@ -115,20 +116,43 @@ public:
directly from the generic types.
*/
using Proposal = ConsensusProposal<PeerID, Ledger::ID, TxSetType>;
class PeerPosition
{
public:
PeerPosition(Proposal const & p)
: proposal_(p)
{
}
struct Traits
Proposal const&
proposal() const
{
return proposal_;
}
Json::Value
getJson() const
{
return proposal_.getJson();
}
private:
Proposal proposal_;
};
/** Represents a single node participating in the consensus process.
It implements the Adaptor requirements of generic Consensus.
*/
struct Peer
{
using Ledger_t = Ledger;
using NodeID_t = PeerID;
using TxSet_t = TxSet;
};
using PeerPosition_t = PeerPosition;
using Result = ConsensusResult<Peer>;
/** Represents a single node participating in the consensus process.
It implements the Callbacks required by Consensus.
*/
struct Peer : public Consensus<Peer, Traits>
{
using Base = Consensus<Peer, Traits>;
Consensus<Peer> consensus;
//! Our unique ID
PeerID id;
@@ -172,12 +196,17 @@ struct Peer : public Consensus<Peer, Traits>
bool validating_ = true;
bool proposing_ = true;
ConsensusParms parms_;
std::size_t prevProposers_ = 0;
std::chrono::milliseconds prevRoundTime_;
//! All peers start from the default constructed ledger
Peer(PeerID i, BasicNetwork<Peer*>& n, UNL const& u, ConsensusParms p)
: Consensus<Peer, Traits>(n.clock(), p, beast::Journal{})
: consensus(n.clock(), *this, beast::Journal{})
, id{i}
, net{n}
, unl(u)
, parms_(p)
{
ledgers[lastClosedLedger.id()] = lastClosedLedger;
}
@@ -210,12 +239,6 @@ struct Peer : public Consensus<Peer, Traits>
return nullptr;
}
auto const&
proposals(Ledger::ID const& ledgerHash)
{
return peerPositions_[ledgerHash];
}
TxSet const*
acquireTxSet(TxSet::ID const& setId)
{
@@ -245,17 +268,17 @@ struct Peer : public Consensus<Peer, Traits>
}
Result
onClose(Ledger const& prevLedger, NetClock::time_point closeTime, Mode mode)
onClose(Ledger const& prevLedger, NetClock::time_point closeTime, ConsensusMode mode)
{
TxSet res{openTxs};
return Result{TxSet{openTxs},
Proposal{prevLedger.id(),
return Result(TxSet{openTxs},
Proposal(prevLedger.id(),
Proposal::seqJoin,
res.id(),
closeTime,
now(),
id}};
id));
}
void
@@ -263,10 +286,17 @@ struct Peer : public Consensus<Peer, Traits>
Result const& result,
Ledger const& prevLedger,
NetClock::duration const& closeResolution,
CloseTimes const& rawCloseTimes,
Mode const& mode)
ConsensusCloseTimes const& rawCloseTimes,
ConsensusMode const& mode,
Json::Value && consensusJson)
{
onAccept(result, prevLedger, closeResolution, rawCloseTimes, mode);
onAccept(
result,
prevLedger,
closeResolution,
rawCloseTimes,
mode,
std::move(consensusJson));
}
void
@@ -274,8 +304,9 @@ struct Peer : public Consensus<Peer, Traits>
Result const& result,
Ledger const& prevLedger,
NetClock::duration const& closeResolution,
CloseTimes const& rawCloseTimes,
Mode const& mode)
ConsensusCloseTimes const& rawCloseTimes,
ConsensusMode const& mode,
Json::Value && consensusJson)
{
auto newLedger = prevLedger.close(
result.set.txs_,
@@ -283,7 +314,8 @@ struct Peer : public Consensus<Peer, Traits>
rawCloseTimes.self,
result.position.closeTime() != NetClock::time_point{});
ledgers[newLedger.id()] = newLedger;
prevProposers_ = result.proposers;
prevRoundTime_ = result.roundTime.read();
lastClosedLedger = newLedger;
auto it =
@@ -304,16 +336,16 @@ struct Peer : public Consensus<Peer, Traits>
// TODO: reconsider this and instead just save LCL generated here?
if (completedLedgers <= targetLedgers)
{
startRound(
consensus.startRound(
now(), lastClosedLedger.id(), lastClosedLedger, proposing_);
}
}
Ledger::ID
getPrevLedger(Ledger::ID const& ledgerID, Ledger const& ledger, Mode mode)
getPrevLedger(Ledger::ID const& ledgerID, Ledger const& ledger, ConsensusMode mode)
{
// TODO: Use generic validation code
if (mode != Mode::wrongLedger && ledgerID.seq > 0 &&
if (mode != ConsensusMode::wrongLedger && ledgerID.seq > 0 &&
ledger.id().seq > 0)
return peerValidations.getBestLCL(ledgerID, ledger.parentID());
return ledgerID;
@@ -323,24 +355,31 @@ struct Peer : public Consensus<Peer, Traits>
propose(Proposal const& pos)
{
if (proposing_)
relay(pos);
relay(PeerPosition(pos));
}
ConsensusParms const &
parms() const
{
return parms_;
}
//-------------------------------------------------------------------------
// non-callback helpers
void
receive(Proposal const& p)
receive(PeerPosition const& peerPos)
{
Proposal const & p = peerPos.proposal();
if (unl.find(p.nodeID()) == unl.end())
return;
// TODO: Be sure this is a new proposal!!!!!
// TODO: Supress repeats more efficiently
auto& dest = peerPositions_[p.prevLedger()];
if (std::find(dest.begin(), dest.end(), p) != dest.end())
return;
dest.push_back(p);
peerProposal(now(), p);
consensus.peerProposal(now(), peerPos);
}
void
@@ -349,7 +388,7 @@ struct Peer : public Consensus<Peer, Traits>
// save and map complete?
auto it = txSets.insert(std::make_pair(txs.id(), txs));
if (it.second)
gotTxSet(now(), txs);
consensus.gotTxSet(now(), txs);
}
void
@@ -392,7 +431,7 @@ struct Peer : public Consensus<Peer, Traits>
void
timerEntry()
{
Base::timerEntry(now());
consensus.timerEntry(now());
// only reschedule if not completed
if (completedLedgers < targetLedgers)
net.timer(parms().ledgerGRANULARITY, [&]() { timerEntry(); });
@@ -406,7 +445,7 @@ struct Peer : public Consensus<Peer, Traits>
// so there is no gaurantee that bestLCL == lastClosedLedger.id()
auto bestLCL = peerValidations.getBestLCL(
lastClosedLedger.id(), lastClosedLedger.parentID());
startRound(now(), bestLCL, lastClosedLedger, proposing_);
consensus.startRound(now(), bestLCL, lastClosedLedger, proposing_);
}
NetClock::time_point
@@ -435,6 +474,28 @@ struct Peer : public Consensus<Peer, Traits>
else
net.timer(when, std::forward<T>(what));
}
Ledger::ID
prevLedgerID()
{
return consensus.prevLedgerID();
}
std::size_t
prevProposers()
{
return prevProposers_;
}
std::chrono::milliseconds
prevRoundTime()
{
return prevRoundTime_;
}
// Not interested in tracking consensus mode
void
onModeChange(ConsensusMode, ConsensusMode) {}
};
} // csf

View File

@@ -45,6 +45,7 @@
#include <test/app/Transaction_ordering_test.cpp>
#include <test/app/TrustAndBalance_test.cpp>
#include <test/app/TxQ_test.cpp>
#include <test/app/ValidatorKeys_test.cpp>
#include <test/app/ValidatorList_test.cpp>
#include <test/app/ValidatorSite_test.cpp>
#include <test/app/SetTrust_test.cpp>