Begin consensus refactor (RIPD-1011):

* New RCLCx* classes
* Refactor consensus positions
* Refactor proposed transaction sets
* Refactor disputed transactions
* Refactor position broadcast/replay
This commit is contained in:
David Schwartz
2016-07-13 13:21:51 -07:00
committed by Edward Hennis
parent 97806b42c4
commit f456355da2
20 changed files with 1128 additions and 632 deletions

View File

@@ -783,6 +783,12 @@
</ClInclude>
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPos.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTraits.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\AcceptedLedger.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -821,10 +827,6 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\DisputedTx.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\impl\DisputedTx.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\InboundLedger.cpp">

View File

@@ -94,6 +94,9 @@
<Filter Include="ripple\app">
<UniqueIdentifier>{83B96C00-A786-6597-826D-E12FA6187AA8}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\app\consensus">
<UniqueIdentifier>{0E8BC18A-9853-B13E-1A9D-C55FA29DA60F}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\app\ledger">
<UniqueIdentifier>{CE126498-A44D-30A2-345B-0F672BCDF947}</UniqueIdentifier>
</Filter>
@@ -1299,6 +1302,15 @@
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
<Filter>protobuf\vsprojects</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPos.h">
<Filter>ripple\app\consensus</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTraits.h">
<Filter>ripple\app\consensus</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
<Filter>ripple\app\consensus</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\AcceptedLedger.cpp">
<Filter>ripple\app\ledger</Filter>
</ClCompile>
@@ -1338,9 +1350,6 @@
<ClInclude Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.h">
<Filter>ripple\app\ledger\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\DisputedTx.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\impl\DisputedTx.h">
<Filter>ripple\app\ledger\impl</Filter>
</ClInclude>

View File

@@ -0,0 +1,143 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012-2016 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.
*/
//==============================================================================
#ifndef RIPPLE_APP_CONSENSUS_RCLCXPOSITION_H_INCLUDED
#define RIPPLE_APP_CONSENSUS_RCLCXPOSITION_H_INCLUDED
#include <ripple/app/ledger/LedgerProposal.h>
#include <ripple/json/json_value.h>
#include <ripple/basics/chrono.h>
#include <ripple/protocol/UintTypes.h>
namespace ripple {
// A position taken during a consensus round
// As seen by the RCL consensus process
class RCLCxPos
{
public:
static std::uint32_t constexpr seqInitial = 0;
static std::uint32_t constexpr seqLeave = 0xffffffff;
RCLCxPos (LedgerProposal const& prop) :
proposal_ (prop)
{ }
std::uint32_t getSequence() const
{
return proposal_.getProposeSeq();
}
NetClock::time_point getCloseTime () const
{
return proposal_.getCloseTime();
}
NetClock::time_point getSeenTime() const
{
return proposal_.getSeenTime();
}
bool isStale (NetClock::time_point lastValid) const
{
return getSeenTime() < lastValid;
}
NodeID const& getNodeID() const
{
return proposal_.getPeerID();
}
LedgerHash const& getPosition() const
{
return proposal_.getCurrentHash();
}
LedgerHash const& getPrevLedger() const
{
return proposal_.getPrevLedger();
}
bool changePosition (
LedgerHash const& position,
NetClock::time_point closeTime,
NetClock::time_point now)
{
return proposal_.changePosition (position, closeTime, now);
}
bool bowOut (NetClock::time_point now)
{
if (isBowOut ())
return false;
proposal_.bowOut (now);
return true;
}
Json::Value getJson() const
{
return proposal_.getJson();
}
bool isInitial () const
{
return getSequence() == seqInitial;
}
bool isBowOut() const
{
return getSequence() == seqLeave;
}
// These three functions will be removed. New code
// should use getPosition, getSequence and getNodeID
LedgerHash const& getCurrentHash() const
{
return getPosition();
}
NodeID const& getPeerID() const
{
return getNodeID();
}
std::uint32_t getProposeSeq() const
{
return getSequence();
}
LedgerProposal const& peek() const
{
return proposal_;
}
LedgerProposal& peek()
{
return proposal_;
}
protected:
LedgerProposal proposal_;
};
}
#endif

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012-2016 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.
*/
//==============================================================================
#ifndef RIPPLE_APP_CONSENSUS_RCLCXTRAITS_H_INCLUDED
#define RIPPLE_APP_CONSENSUS_RCLCXTRAITS_H_INCLUDED
#include <ripple/basics/chrono.h>
#include <ripple/basics/base_uint.h>
#include <ripple/protocol/UintTypes.h>
#include <ripple/protocol/RippleLedgerHash.h>
#include <ripple/app/consensus/RCLCxPos.h>
#include <ripple/app/consensus/RCLCxTx.h>
namespace ripple {
// Consensus traits class
// For adapting consensus to RCL
class RCLCxTraits
{
public:
using Time_t = NetClock::time_point;
using Pos_t = RCLCxPos;
using TxSet_t = RCLTxSet;
using Tx_t = RCLCxTx;
using LgrID_t = LedgerHash;
using TxID_t = uint256;
using TxSetID_t = uint256;
using NodeID_t = NodeID;
};
}
#endif

View File

@@ -0,0 +1,156 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012-2016 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.
*/
//==============================================================================
#ifndef RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED
#define RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED
#include <ripple/basics/chrono.h>
#include <ripple/protocol/UintTypes.h>
#include <ripple/shamap/SHAMap.h>
namespace ripple {
// Transactions, as seen by the consensus code in the rippled app
class RCLCxTx
{
public:
RCLCxTx (SHAMapItem const& txn) : txn_ (txn)
{ }
uint256 const& getID() const
{
return txn_.key ();
}
SHAMapItem const& txn() const
{
return txn_;
}
protected:
SHAMapItem const txn_;
};
class RCLTxSet;
class MutableRCLTxSet
{
public:
MutableRCLTxSet (RCLTxSet const&);
bool
addEntry (RCLCxTx const& p)
{
return map_->addItem (
SHAMapItem {p.getID(), p.txn().peekData()},
true, false);
}
bool
removeEntry (uint256 const& entry)
{
return map_->delItem (entry);
}
std::shared_ptr <SHAMap> const& map() const
{
return map_;
}
protected:
std::shared_ptr <SHAMap> map_;
};
// Sets of transactions
// as seen by the consensus code in the rippled app
class RCLTxSet
{
public:
using mutable_t = MutableRCLTxSet;
RCLTxSet (std::shared_ptr<SHAMap> map) :
map_ (std::move(map))
{
assert (map_);
}
RCLTxSet (MutableRCLTxSet const& set) :
map_ (set.map()->snapShot (false))
{ }
bool hasEntry (uint256 const& entry) const
{
return map_->hasItem (entry);
}
boost::optional <RCLCxTx const>
getEntry (uint256 const& entry) const
{
auto item = map_->peekItem (entry);
if (item)
return RCLCxTx(*item);
return boost::none;
}
uint256 getID() const
{
return map_->getHash().as_uint256();
}
std::map <uint256, bool>
getDifferences (RCLTxSet const& j) const
{
SHAMap::Delta delta;
// Bound the work we do in case of a malicious
// map from a trusted validator
map_->compare (*(j.map_), delta, 65536);
std::map <uint256, bool> ret;
for (auto const& item : delta)
{
assert ( (item.second.first && ! item.second.second) ||
(item.second.second && ! item.second.first) );
ret[item.first] = static_cast<bool> (item.second.first);
}
return ret;
}
std::shared_ptr<SHAMap> const& map() const
{
return map_;
}
protected:
std::shared_ptr <SHAMap> map_;
};
inline MutableRCLTxSet::MutableRCLTxSet (RCLTxSet const& set)
: map_ (set.map()->snapShot (true))
{ }
}
#endif

View File

@@ -0,0 +1,115 @@
# Consensus Algorithm
This directory holds the types and classes needed
to connect consensus to rippled.
## Types
All types must be copy constructible and assignable.
* `LgrID_t`
Represents a ledger identifier.
Typically a 256-bit hash of the ledger header.
* `TxID_t`
Represents a transaction identifier.
Typically a 256-bit hash of the transaction data.
* `TxSetID_t`
Represents an identifier of a set of transactions.
Typically a 256-bit hash of the set's root tree node.
* `NodeID_t`
Represents an identifier for a node that can take positions during
the consenus process.
* `Time_t`
Encodes absolute times. Used for the close times of ledgers and the
expiration times of positions.
* `Pos_t`
Represents a position on a consensus taken by a participant.
Typically it encodes the previous ledger identifier, the transaction
set identifier, the participant, and a sequence number. It also includes
either the time it was signed or the time it was first seen. It may also
include additional information such as the participant's public key or
signature
* `Tx_t`
Represent a transaction. Has an identifier and also whatever information
is needed to add it to a set.
* `TxSet_t`
Represents a set of transactions. It has an identifier and can report
which transactions it has and provide the actual transaction data.
If non-const, it can be modified.
## `Pos_t`
Represents a position taken by a validator during a consensus round.
Must provide:
static std::uint32_t seqInitial;
static std::uint32_t seqLeave;
std::uint32_t getSequence() const;
Time_t getCloseTime() const;
Time_t getSeenTime() const;
bool isStale (Time_t) const;
NodeID_t getNodeID() const;
TxSetID_t getPosition() const;
LgrID_t getPrevLedger() const;
bool isInitial() const;
bool isBowOut() const;
Json::Value getJson() const;
bool changePosition (TxSetID_t const& position, Time_t closeTime, Time_t now);
bool bowOut (Time_t now);
### `Tx_t`
Represents a transaction.
Must provide:
TxID_t getID() const;
### TxSet_t
Represents a set of transactions.
Must provide:
TxSet_t (TxSet_t::mutable_t const&);
TxSetID_t getID() const;
bool hasEntry (TxID_t const&) const;
bool hasEntry (Tx_t const&) const;
boost::optional <Tx_t const> const getEntry (TxID_t const&) const;
std::map <TxID_t, bool> getDifferences(TxSet_t const&) const;
## TxSet_t::mutable_t
Represents a set of transactions that can be modified.
Must provide:
TxSet_t::mutable_t (TxSet_t const &);
bool addEntry (Tx_t const&);
bool removeEntry (TxID_t const&);

View File

@@ -23,6 +23,7 @@
#include <ripple/app/ledger/LedgerConsensus.h>
#include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/InboundTransactions.h>
#include <ripple/app/consensus/RCLCxTraits.h>
#include <ripple/app/main/Application.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
@@ -64,7 +65,7 @@ public:
/** Called to create a LedgerConsensus instance */
virtual
std::shared_ptr<LedgerConsensus>
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
makeLedgerConsensus (
Application& app,
InboundTransactions& inboundTransactions,
@@ -75,7 +76,7 @@ public:
virtual
void
startRound (
LedgerConsensus& consensus,
LedgerConsensus<RCLCxTraits>& consensus,
LedgerHash const &prevLCLHash,
std::shared_ptr<Ledger const> const& previousLedger,
NetClock::time_point closeTime) = 0;

View File

@@ -23,6 +23,7 @@
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/LedgerProposal.h>
#include <ripple/app/ledger/InboundTransactions.h>
#include <ripple/app/consensus/RCLCxTraits.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/CanonicalTXSet.h>
#include <ripple/app/misc/FeeVote.h>
@@ -34,30 +35,37 @@
namespace ripple {
/** Manager for achieving consensus on the next ledger.
This object is created when the consensus process starts, and
is destroyed when the process is complete.
*/
class LedgerConsensus
template <class Traits>
class LedgerConsensus : public Traits
{
public:
using typename Traits::Time_t;
using typename Traits::Pos_t;
using typename Traits::TxSet_t;
using typename Traits::Tx_t;
using typename Traits::LgrID_t;
using typename Traits::TxID_t;
using typename Traits::TxSetID_t;
using typename Traits::NodeID_t;
virtual ~LedgerConsensus() = default;
virtual Json::Value getJson (bool full) = 0;
virtual uint256 getLCL () = 0;
virtual LgrID_t getLCL () = 0;
virtual void gotMap (
std::shared_ptr<SHAMap> const& map) = 0;
virtual void gotMap (TxSet_t const& map) = 0;
virtual void timerEntry () = 0;
virtual bool peerPosition (LedgerProposal::ref) = 0;
virtual bool peerPosition (Pos_t const& position) = 0;
virtual void startRound (
LedgerHash const& prevLCLHash,
LgrID_t const& prevLCLHash,
std::shared_ptr<Ledger const> const& prevLedger,
NetClock::time_point closeTime,
Time_t closeTime,
int previousProposers,
std::chrono::milliseconds previousConvergeTime) = 0;

View File

@@ -33,8 +33,10 @@ LedgerProposal::LedgerProposal (
std::uint32_t seq,
uint256 const& tx,
NetClock::time_point closeTime,
NetClock::time_point now,
PublicKey const& publicKey,
NodeID const& nodeID,
Slice const& signature,
uint256 const& suppression)
: mPreviousLedger (pLgr)
, mCurrentHash (tx)
@@ -43,8 +45,11 @@ LedgerProposal::LedgerProposal (
, mProposeSeq (seq)
, publicKey_ (publicKey)
, mPeerID (nodeID)
, mTime (std::chrono::steady_clock::now ())
, mTime (now)
{
signature_.resize (signature.size());
std::memcpy(signature_.data(),
signature.data(), signature.size());
}
// Used to construct local proposals
@@ -52,12 +57,13 @@ LedgerProposal::LedgerProposal (
LedgerProposal::LedgerProposal (
uint256 const& prevLgr,
uint256 const& position,
NetClock::time_point closeTime)
NetClock::time_point closeTime,
NetClock::time_point now)
: mPreviousLedger (prevLgr)
, mCurrentHash (position)
, mCloseTime (closeTime)
, mProposeSeq (seqJoin)
, mTime (std::chrono::steady_clock::now ())
, mTime (now)
{
}
@@ -76,27 +82,28 @@ bool LedgerProposal::checkSign () const
return verifyDigest (
publicKey_,
getSigningHash(),
signature_,
makeSlice (signature_),
false);
}
bool LedgerProposal::changePosition (
uint256 const& newPosition,
NetClock::time_point closeTime)
NetClock::time_point closeTime,
NetClock::time_point now)
{
if (mProposeSeq == seqLeave)
return false;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = std::chrono::steady_clock::now ();
mTime = now;
++mProposeSeq;
return true;
}
void LedgerProposal::bowOut ()
void LedgerProposal::bowOut (NetClock::time_point now)
{
mTime = std::chrono::steady_clock::now ();
mTime = now;
mProposeSeq = seqLeave;
}

View File

@@ -55,15 +55,18 @@ public:
std::uint32_t proposeSeq,
uint256 const& propose,
NetClock::time_point closeTime,
NetClock::time_point now,
PublicKey const& publicKey,
NodeID const& nodeID,
Slice const& signature,
uint256 const& suppress);
// Our own proposal:
LedgerProposal (
uint256 const& prevLedger,
uint256 const& position,
NetClock::time_point closeTime);
NetClock::time_point closeTime,
NetClock::time_point now);
uint256 getSigningHash () const;
bool checkSign () const;
@@ -96,17 +99,14 @@ public:
{
return mCloseTime;
}
void setSignature (Buffer&& sig)
NetClock::time_point getSeenTime () const
{
signature_ = std::move(sig);
return mTime;
}
Slice getSignature () const
Blob const& getSignature () const
{
return signature_;
}
bool isInitial () const
{
return mProposeSeq == seqJoin;
@@ -116,14 +116,16 @@ public:
return mProposeSeq == seqLeave;
}
bool isStale (std::chrono::steady_clock::time_point cutoff) const
bool isStale (NetClock::time_point cutoff) const
{
return mTime <= cutoff;
}
bool changePosition (
uint256 const& newPosition, NetClock::time_point newCloseTime);
void bowOut ();
uint256 const& newPosition,
NetClock::time_point newCloseTime,
NetClock::time_point now);
void bowOut (NetClock::time_point now);
Json::Value getJson () const;
private:
@@ -145,9 +147,9 @@ private:
PublicKey publicKey_;
NodeID mPeerID;
Buffer signature_;
Blob signature_;
std::chrono::steady_clock::time_point mTime;
NetClock::time_point mTime;
};
/** Calculate a unique identifier for a signed proposal.

View File

@@ -63,7 +63,7 @@ ConsensusImp::getLastCloseDuration () const
return lastCloseConvergeTook_;
}
std::shared_ptr<LedgerConsensus>
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
ConsensusImp::makeLedgerConsensus (
Application& app,
InboundTransactions& inboundTransactions,
@@ -76,7 +76,7 @@ ConsensusImp::makeLedgerConsensus (
void
ConsensusImp::startRound (
LedgerConsensus& consensus,
LedgerConsensus<RCLCxTraits>& consensus,
LedgerHash const &prevLCLHash,
std::shared_ptr<Ledger const> const& previousLedger,
NetClock::time_point closeTime)
@@ -154,11 +154,11 @@ ConsensusImp::storeProposal (
props.push_back (proposal);
}
std::vector <std::shared_ptr <LedgerProposal>>
std::vector <RCLCxPos>
ConsensusImp::getStoredProposals (uint256 const& prevLedger)
{
std::vector <std::shared_ptr <LedgerProposal>> ret;
std::vector <RCLCxPos> ret;
{
std::lock_guard <std::mutex> _(lock_);
@@ -166,15 +166,13 @@ ConsensusImp::getStoredProposals (uint256 const& prevLedger)
for (auto const& it : storedProposals_)
for (auto const& prop : it.second)
if (prop->getPrevLedger() == prevLedger)
ret.push_back (prop);
ret.emplace_back (*prop);
}
return ret;
}
//==============================================================================
std::unique_ptr<Consensus>
std::unique_ptr <Consensus>
make_Consensus (Config const& config, Logs& logs)
{
return std::make_unique<ConsensusImp> (

View File

@@ -1,4 +1,4 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
@@ -52,7 +52,7 @@ public:
std::chrono::milliseconds
getLastCloseDuration () const override;
std::shared_ptr<LedgerConsensus>
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
makeLedgerConsensus (
Application& app,
InboundTransactions& inboundTransactions,
@@ -61,7 +61,7 @@ public:
void
startRound (
LedgerConsensus& ledgerConsensus,
LedgerConsensus<RCLCxTraits>& ledgerConsensus,
LedgerHash const& prevLCLHash,
std::shared_ptr<Ledger const> const& previousLedger,
NetClock::time_point closeTime) override;
@@ -94,7 +94,7 @@ public:
NetClock::time_point
getLastCloseTime () const;
std::vector <std::shared_ptr <LedgerProposal>>
std::vector <RCLCxPos>
getStoredProposals (uint256 const& previousLedger);
private:

View File

@@ -1,161 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 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 <BeastConfig.h>
#include <ripple/app/ledger/impl/DisputedTx.h>
#include <ripple/app/ledger/LedgerTiming.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
namespace ripple {
// Track a peer's yes/no vote on a particular disputed transaction
void DisputedTx::setVote (NodeID const& peer, bool votesYes)
{
auto res = mVotes.insert (std::make_pair (peer, votesYes));
// new vote
if (res.second)
{
if (votesYes)
{
JLOG (j_.debug())
<< "Peer " << peer << " votes YES on " << mTransactionID;
++mYays;
}
else
{
JLOG (j_.debug())
<< "Peer " << peer << " votes NO on " << mTransactionID;
++mNays;
}
}
// changes vote to yes
else if (votesYes && !res.first->second)
{
JLOG (j_.debug())
<< "Peer " << peer << " now votes YES on " << mTransactionID;
--mNays;
++mYays;
res.first->second = true;
}
// changes vote to no
else if (!votesYes && res.first->second)
{
JLOG (j_.debug())
<< "Peer " << peer << " now votes NO on " << mTransactionID;
++mNays;
--mYays;
res.first->second = false;
}
}
// Remove a peer's vote on this disputed transasction
void DisputedTx::unVote (NodeID const& peer)
{
auto it = mVotes.find (peer);
if (it != mVotes.end ())
{
if (it->second)
--mYays;
else
--mNays;
mVotes.erase (it);
}
}
bool DisputedTx::updateVote (int percentTime, bool proposing)
{
// VFALCO TODO Give the return value a descriptive local variable name
// and don't return from the middle.
if (mOurVote && (mNays == 0))
return false;
if (!mOurVote && (mYays == 0))
return false;
bool newPosition;
int weight;
if (proposing) // give ourselves full weight
{
// This is basically the percentage of nodes voting 'yes' (including us)
weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1);
// VFALCO TODO Rename these macros and turn them into language
// constructs. consolidate them into a class that collects
// all these related values.
//
// To prevent avalanche stalls, we increase the needed weight slightly
// over time.
if (percentTime < AV_MID_CONSENSUS_TIME)
newPosition = weight > AV_INIT_CONSENSUS_PCT;
else if (percentTime < AV_LATE_CONSENSUS_TIME)
newPosition = weight > AV_MID_CONSENSUS_PCT;
else if (percentTime < AV_STUCK_CONSENSUS_TIME)
newPosition = weight > AV_LATE_CONSENSUS_PCT;
else
newPosition = weight > AV_STUCK_CONSENSUS_PCT;
}
else // don't let us outweigh a proposing node, just recognize consensus
{
weight = -1;
newPosition = mYays > mNays;
}
if (newPosition == mOurVote)
{
JLOG (j_.info())
<< "No change (" << (mOurVote ? "YES" : "NO") << ") : weight "
<< weight << ", percent " << percentTime;
JLOG (j_.debug()) << getJson ();
return false;
}
mOurVote = newPosition;
JLOG (j_.debug())
<< "We now vote " << (mOurVote ? "YES" : "NO")
<< " on " << mTransactionID;
JLOG (j_.debug()) << getJson ();
return true;
}
Json::Value DisputedTx::getJson ()
{
Json::Value ret (Json::objectValue);
ret["yays"] = mYays;
ret["nays"] = mNays;
ret["our_vote"] = mOurVote;
if (!mVotes.empty ())
{
Json::Value votesj (Json::objectValue);
for (auto& vote : mVotes)
votesj[to_string (vote.first)] = vote.second;
ret["votes"] = votesj;
}
return ret;
}
} // ripple

View File

@@ -36,22 +36,28 @@ namespace ripple {
Undisputed transactions have no corresponding @ref DisputedTx object.
*/
template <class Traits>
class DisputedTx
{
public:
// VFALCO `Blob` is a poor choice of parameter
DisputedTx (uint256 const& txID,
Blob const& tx, bool ourVote, beast::Journal j)
: mTransactionID (txID)
using Tx_t = typename Traits::Tx_t;
using TxID_t = typename Traits::TxID_t;
using NodeID_t = typename Traits::NodeID_t;
DisputedTx (Tx_t const& tx,
bool ourVote, beast::Journal j)
: mTransactionID (tx.getID())
, mYays (0)
, mNays (0)
, mOurVote (ourVote)
, transaction (tx.data(), tx.size())
, transaction (tx)
, j_ (j)
{
}
uint256 const& getTransactionID () const
TxID_t const& getID () const
{
return mTransactionID;
}
@@ -61,9 +67,7 @@ public:
return mOurVote;
}
// VFALCO TODO make this const
// VFALCO TODO Don't return a Serializer (doh)
Serializer& peekTransaction ()
Tx_t const& tx () const
{
return transaction;
}
@@ -73,26 +77,158 @@ public:
mOurVote = o;
}
// VFALCO NOTE its not really a peer, its the 160 bit hash of the
// validator's public key.
void setVote (NodeID const& peer, bool votesYes);
void unVote (NodeID const& peer);
void setVote (NodeID_t const& peer, bool votesYes);
void unVote (NodeID_t const& peer);
bool updateVote (int percentTime, bool proposing);
Json::Value getJson ();
private:
uint256 mTransactionID;
TxID_t mTransactionID;
int mYays;
int mNays;
bool mOurVote;
// VFALCO Why is this being stored as a Serializer?
Serializer transaction;
Tx_t transaction;
hash_map <NodeID, bool> mVotes;
hash_map <NodeID_t, bool> mVotes;
beast::Journal j_;
};
// Track a peer's yes/no vote on a particular disputed transaction
template <class Traits>
void DisputedTx<Traits>::setVote (NodeID_t const& peer, bool votesYes)
{
auto res = mVotes.insert (std::make_pair (peer, votesYes));
// new vote
if (res.second)
{
if (votesYes)
{
JLOG (j_.debug())
<< "Peer " << peer << " votes YES on " << mTransactionID;
++mYays;
}
else
{
JLOG (j_.debug())
<< "Peer " << peer << " votes NO on " << mTransactionID;
++mNays;
}
}
// changes vote to yes
else if (votesYes && !res.first->second)
{
JLOG (j_.debug())
<< "Peer " << peer << " now votes YES on " << mTransactionID;
--mNays;
++mYays;
res.first->second = true;
}
// changes vote to no
else if (!votesYes && res.first->second)
{
JLOG (j_.debug())
<< "Peer " << peer << " now votes NO on " << mTransactionID;
++mNays;
--mYays;
res.first->second = false;
}
}
// Remove a peer's vote on this disputed transasction
template <class Traits>
void DisputedTx<Traits>::unVote (NodeID_t const& peer)
{
auto it = mVotes.find (peer);
if (it != mVotes.end ())
{
if (it->second)
--mYays;
else
--mNays;
mVotes.erase (it);
}
}
template <class Traits>
bool DisputedTx<Traits>::updateVote (int percentTime, bool proposing)
{
if (mOurVote && (mNays == 0))
return false;
if (!mOurVote && (mYays == 0))
return false;
bool newPosition;
int weight;
if (proposing) // give ourselves full weight
{
// This is basically the percentage of nodes voting 'yes' (including us)
weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1);
// VFALCO TODO Rename these macros and turn them into language
// constructs. consolidate them into a class that collects
// all these related values.
//
// To prevent avalanche stalls, we increase the needed weight slightly
// over time.
if (percentTime < AV_MID_CONSENSUS_TIME)
newPosition = weight > AV_INIT_CONSENSUS_PCT;
else if (percentTime < AV_LATE_CONSENSUS_TIME)
newPosition = weight > AV_MID_CONSENSUS_PCT;
else if (percentTime < AV_STUCK_CONSENSUS_TIME)
newPosition = weight > AV_LATE_CONSENSUS_PCT;
else
newPosition = weight > AV_STUCK_CONSENSUS_PCT;
}
else
{
// don't let us outweigh a proposing node, just recognize consensus
weight = -1;
newPosition = mYays > mNays;
}
if (newPosition == mOurVote)
{
JLOG (j_.info())
<< "No change (" << (mOurVote ? "YES" : "NO") << ") : weight "
<< weight << ", percent " << percentTime;
JLOG (j_.debug()) << getJson ();
return false;
}
mOurVote = newPosition;
JLOG (j_.debug())
<< "We now vote " << (mOurVote ? "YES" : "NO")
<< " on " << mTransactionID;
JLOG (j_.debug()) << getJson ();
return true;
}
template <class Traits>
Json::Value DisputedTx<Traits>::getJson ()
{
Json::Value ret (Json::objectValue);
ret["yays"] = mYays;
ret["nays"] = mNays;
ret["our_vote"] = mOurVote;
if (!mVotes.empty ())
{
Json::Value votesj (Json::objectValue);
for (auto& vote : mVotes)
votesj[to_string (vote.first)] = vote.second;
ret["votes"] = std::move (votesj);
}
return ret;
}
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -37,19 +37,16 @@ namespace ripple {
Provides the implementation for LedgerConsensus.
Achieves consensus on the next ledger.
This object is created when the consensus process starts, and
is destroyed when the process is complete.
Nearly everything herein is invoked with the master lock.
Two things need consensus:
1. The set of transactions.
2. The close time for the ledger.
*/
template <class Traits>
class LedgerConsensusImp
: public LedgerConsensus
, public std::enable_shared_from_this <LedgerConsensusImp>
, public CountedObject <LedgerConsensusImp>
: public LedgerConsensus<Traits>
, public std::enable_shared_from_this <LedgerConsensusImp<Traits>>
, public CountedObject <LedgerConsensusImp<Traits>>
{
private:
enum class State
@@ -70,6 +67,17 @@ private:
};
public:
using typename Traits::Time_t;
using typename Traits::Pos_t;
using typename Traits::TxSet_t;
using typename Traits::Tx_t;
using typename Traits::LgrID_t;
using typename Traits::TxID_t;
using typename Traits::TxSetID_t;
using typename Traits::NodeID_t;
using Dispute_t = DisputedTx <Traits>;
/**
* The result of applying a transaction to a ledger.
*/
@@ -82,6 +90,7 @@ public:
~LedgerConsensusImp () = default;
/**
@param localtx transactions issued by local clients
@param inboundTransactions set of inbound transaction sets
@@ -104,9 +113,9 @@ public:
@param previousConvergeTime how long the last round took (ms)
*/
void startRound (
LedgerHash const& prevLCLHash,
LgrID_t const& prevLCLHash,
std::shared_ptr<Ledger const> const& prevLedger,
NetClock::time_point closeTime,
Time_t closeTime,
int previousProposers,
std::chrono::milliseconds previousConvergeTime) override;
@@ -120,24 +129,20 @@ public:
Json::Value getJson (bool full) override;
/* The hash of the last closed ledger */
uint256 getLCL () override;
LgrID_t getLCL () override;
/**
We have a complete transaction set, typically acquired from the network
@param map the transaction set.
@param acquired true if we have acquired the transaction set.
*/
void gotMap (
std::shared_ptr<SHAMap> const& map) override;
void gotMap (TxSet_t const& map) override;
/**
On timer call the correct handler for each state.
*/
void timerEntry () override;
std::shared_ptr<SHAMap> getTransactionTree (uint256 const& hash);
/**
A server has taken a new position, adjust our tracking
Called when a peer takes a new postion.
@@ -145,11 +150,16 @@ public:
@param newPosition the new position
@return true if we should do delayed relay of this position.
*/
bool peerPosition (LedgerProposal::ref newPosition) override;
bool peerPosition (Pos_t const& newPosition) override;
void simulate(
boost::optional<std::chrono::milliseconds> consensusDelay) override;
/**
Put a transaction set where peers can find it
*/
void shareSet (TxSet_t const&);
private:
/**
Handle pre-close state.
@@ -179,7 +189,7 @@ private:
@param lclHash Hash of the last closed ledger.
*/
void handleLCL (uint256 const& lclHash);
void handleLCL (LgrID_t const& lclHash);
/**
We have a complete transaction set, typically acquired from the network
@@ -188,14 +198,14 @@ private:
@param acquired true if we have acquired the transaction set.
*/
void mapCompleteInternal (
std::shared_ptr<SHAMap> const& map,
TxSet_t const& map,
bool acquired);
/** We have a new last closed ledger, process it. Final accept logic
@param set Our consensus set
*/
void accept (std::shared_ptr<SHAMap> set);
void accept (TxSet_t const& set);
/**
Compare two proposed transaction sets and create disputed
@@ -204,17 +214,16 @@ private:
@param m1 One transaction set
@param m2 The other transaction set
*/
void createDisputes (std::shared_ptr<SHAMap> const& m1,
std::shared_ptr<SHAMap> const& m2);
void createDisputes (TxSet_t const& m1,
TxSet_t const& m2);
/**
Add a disputed transaction (one that at least one node wants
in the consensus set and at least one node does not) to our tracking
@param txID The ID of the disputed transaction
@param tx The data of the disputed transaction
@param tx The disputed transaction
*/
void addDisputedTransaction (uint256 const& txID, Blob const& tx);
void addDisputedTransaction (Tx_t const& tx);
/**
Adjust the votes on all disputed transactions based
@@ -223,8 +232,8 @@ private:
@param map A disputed position
@param peers peers which are taking the position map
*/
void adjustCount (std::shared_ptr<SHAMap> const& map,
const std::vector<NodeID>& peers);
void adjustCount (TxSet_t const& map,
std::vector<NodeID_t> const& peers);
/**
Revoke our outstanding proposal, if any, and
@@ -247,7 +256,7 @@ private:
/** Determine our initial proposed transaction set based on
our open ledger
*/
std::shared_ptr<SHAMap> makeInitialPosition();
std::pair <TxSet_t, Pos_t> makeInitialPosition();
/** Take an initial position on what we think the consensus set should be
*/
@@ -296,16 +305,18 @@ private:
FeeVote& feeVote_;
std::recursive_mutex lock_;
NodeID_t ourID_;
State state_;
// The wall time this ledger closed
NetClock::time_point closeTime_;
Time_t closeTime_;
uint256 prevLedgerHash_;
uint256 acquiringLedger_;
LgrID_t prevLedgerHash_;
LgrID_t acquiringLedger_;
std::shared_ptr<Ledger const> previousLedger_;
LedgerProposal::pointer ourPosition_;
boost::optional<Pos_t> ourPosition_;
boost::optional<TxSet_t> ourSet_;
PublicKey valPublic_;
SecretKey valSecret_;
bool proposing_, validating_, haveCorrectLCL_, consensusFail_;
@@ -328,26 +339,26 @@ private:
std::chrono::milliseconds previousRoundTime_;
// Convergence tracking, trusted peers indexed by hash of public key
hash_map<NodeID, LedgerProposal::pointer> peerPositions_;
hash_map<NodeID_t, Pos_t> peerPositions_;
// Transaction Sets, indexed by hash of transaction tree
hash_map<uint256, std::shared_ptr<SHAMap>> acquired_;
hash_map<TxSetID_t, const TxSet_t> acquired_;
// Disputed transactions
hash_map<uint256, std::shared_ptr <DisputedTx>> disputes_;
hash_set<uint256> compares_;
hash_map<TxID_t, Dispute_t> disputes_;
hash_set<TxSetID_t> compares_;
// Close time estimates, keep ordered for predictable traverse
std::map<NetClock::time_point, int> closeTimes_;
std::map <Time_t, int> closeTimes_;
// nodes that have bowed out of this consensus process
hash_set<NodeID> deadNodes_;
hash_set<NodeID_t> deadNodes_;
beast::Journal j_;
};
//------------------------------------------------------------------------------
std::shared_ptr <LedgerConsensus>
std::shared_ptr <LedgerConsensus <RCLCxTraits>>
make_LedgerConsensus (
Application& app,
ConsensusImp& consensus,
@@ -370,10 +381,12 @@ make_LedgerConsensus (
CanonicalTXSet
applyTransactions (
Application& app,
SHAMap const& set,
RCLTxSet const& set,
OpenView& view,
std::function<bool(uint256 const&)> txFilter);
extern template class LedgerConsensusImp <RCLCxTraits>;
} // ripple
#endif

View File

@@ -459,8 +459,7 @@ public:
, [this](std::shared_ptr <SHAMap> const& set,
bool fromAcquire)
{
if (set)
gotTXSet (set, fromAcquire);
gotTXSet (set, fromAcquire);
}))
, m_acceptedLedgerCache ("AcceptedLedger", 4, 60, stopwatch(),

View File

@@ -22,6 +22,7 @@
#include <ripple/protocol/Quality.h>
#include <ripple/core/DatabaseCon.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/consensus/RCLCxTraits.h>
#include <ripple/app/ledger/Consensus.h>
#include <ripple/app/ledger/LedgerConsensus.h>
#include <ripple/app/ledger/AcceptedLedger.h>
@@ -529,7 +530,7 @@ private:
DeadlineTimer m_clusterTimer;
std::unique_ptr<Consensus> mConsensus;
std::shared_ptr<LedgerConsensus> mLedgerConsensus;
std::shared_ptr<LedgerConsensus<RCLCxTraits>> mLedgerConsensus;
LedgerMaster& m_ledgerMaster;
std::shared_ptr<InboundLedger> mAcquiringLedger;
@@ -1503,14 +1504,12 @@ void NetworkOPsImp::processTrustedProposal (
std::shared_ptr<protocol::TMProposeSet> set,
NodeID const& node)
{
{
mConsensus->storeProposal (proposal, node);
mConsensus->storeProposal (proposal, node);
if (mLedgerConsensus->peerPosition (proposal))
app_.overlay().relay(*set, proposal->getSuppressionID());
else
JLOG(m_journal.info()) << "Not relaying trusted proposal";
}
if (mLedgerConsensus->peerPosition (*proposal))
app_.overlay().relay(*set, proposal->getSuppressionID());
else
JLOG(m_journal.info()) << "Not relaying trusted proposal";
}
void
@@ -1531,7 +1530,7 @@ NetworkOPsImp::mapComplete (
// We acquired it because consensus asked us to
if (fromAcquire)
mLedgerConsensus->gotMap (map);
mLedgerConsensus->gotMap (RCLTxSet{map});
}
void NetworkOPsImp::endConsensus (bool correctLCL)

View File

@@ -1233,7 +1233,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
PublicKey const publicKey (makeSlice(set.nodepubkey()));
NetClock::time_point const closeTime { NetClock::duration{set.closetime()} };
Buffer signature (set.signature().data(), set.signature ().size());
Slice signature (set.signature().data(), set.signature ().size());
uint256 proposeHash, prevLedger;
memcpy (proposeHash.begin (), set.currenttxhash ().data (), 32);
@@ -1278,8 +1278,8 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
auto proposal = std::make_shared<LedgerProposal> (
prevLedger, set.proposeseq (), proposeHash, closeTime,
publicKey, calcNodeID(publicKey), suppression);
proposal->setSignature (std::move(signature));
app_.timeKeeper().closeTime(), publicKey, calcNodeID(publicKey),
signature, suppression);
std::weak_ptr<PeerImp> weak = shared_from_this();
app_.getJobQueue ().addJob (

View File

@@ -31,7 +31,6 @@
#include <ripple/app/ledger/TransactionStateSF.cpp>
#include <ripple/app/ledger/impl/ConsensusImp.cpp>
#include <ripple/app/ledger/impl/DisputedTx.cpp>
#include <ripple/app/ledger/impl/InboundLedger.cpp>
#include <ripple/app/ledger/impl/InboundLedgers.cpp>
#include <ripple/app/ledger/impl/InboundTransactions.cpp>