Finish implementation of Ledger process/Features logic:

* Defining RIPPLE_PROPOSE_FEATURES enables ledger features
* Reduce dependence on getApp via dependency injection
* Converted uint32 members to use Clock::time_point
* Inject Journal, tidy up classes:
    - Features
    - FeaturesImpl
    - FeeVote
    - FeeVoteImpl
This commit is contained in:
miguelportilla
2014-04-22 16:48:53 -07:00
committed by Vinnie Falco
parent ebae927a3e
commit b8162884d9
19 changed files with 785 additions and 647 deletions

View File

@@ -1072,13 +1072,13 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\Features.cpp">
<ClCompile Include="..\..\src\ripple_app\misc\FeaturesImpl.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\FeeVote.cpp">
<ClCompile Include="..\..\src\ripple_app\misc\FeeVoteImpl.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -2951,8 +2951,8 @@
<ClInclude Include="..\..\src\ripple_app\misc\AccountItems.h" />
<ClInclude Include="..\..\src\ripple_app\misc\AccountState.h" />
<ClInclude Include="..\..\src\ripple_app\misc\CanonicalTXSet.h" />
<ClInclude Include="..\..\src\ripple_app\misc\IFeatures.h" />
<ClInclude Include="..\..\src\ripple_app\misc\IFeeVote.h" />
<ClInclude Include="..\..\src\ripple_app\misc\FeatureTable.h" />
<ClInclude Include="..\..\src\ripple_app\misc\FeeVote.h" />
<ClInclude Include="..\..\src\ripple_app\misc\IHashRouter.h" />
<ClInclude Include="..\..\src\ripple_app\misc\ProofOfWorkFactory.h" />
<ClInclude Include="..\..\src\ripple_app\misc\NicknameState.h" />

View File

@@ -678,12 +678,6 @@
<ClCompile Include="..\..\src\ripple_app\misc\CanonicalTXSet.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\Features.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\FeeVote.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\HashRouter.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
@@ -1722,6 +1716,12 @@
<ClCompile Include="..\..\src\ripple_rpc\impl\LookupLedger.cpp">
<Filter>[2] Old Ripple\ripple_rpc\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\FeaturesImpl.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\FeeVoteImpl.cpp">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ripple_basics\containers\RangeSet.h">
@@ -2126,12 +2126,6 @@
<ClInclude Include="..\..\src\ripple_app\misc\CanonicalTXSet.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\misc\IFeatures.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\misc\IFeeVote.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\misc\IHashRouter.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
@@ -3345,6 +3339,12 @@
<ClInclude Include="..\..\src\ripple_rpc\impl\LegacyPathFind.h">
<Filter>[2] Old Ripple\ripple_rpc\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\misc\FeeVote.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\misc\FeatureTable.h">
<Filter>[2] Old Ripple\ripple_app\misc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">

View File

@@ -199,4 +199,20 @@
#define RIPPLE_USE_VALIDATORS 0
#endif
/** Config: BEAST_USE_BOOST_FEATURES
This activates boost specific features and improvements. If this is
turned on, the include paths for your build environment must be set
correctly to find the boost headers.
*/
#ifndef BEAST_USE_BOOST_FEATURES
//#define BEAST_USE_BOOST_FEATURES 1
#endif
/** Config: RIPPLE_PROPOSE_FEATURES
This determines whether to add any features to the proposed transaction set.
*/
#ifndef RIPPLE_PROPOSE_FEATURES
#define RIPPLE_PROPOSE_FEATURES 0
#endif
#endif

View File

@@ -27,6 +27,12 @@
namespace ripple {
using days = std::chrono::duration
<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>>;
using weeks = std::chrono::duration
<int, std::ratio_multiply<days::period, std::ratio<7>>>;
/** Returns an abstract_clock optimized for counting seconds. */
inline beast::abstract_clock <std::chrono::seconds>& get_seconds_clock ()
{

View File

@@ -36,10 +36,11 @@ public:
static char const* getCountedObjectName () { return "LedgerConsensus"; }
LedgerConsensusImp (clock_type& clock, LocalTxs& localtx,
LedgerHash const & prevLCLHash,
Ledger::ref previousLedger, std::uint32_t closeTime)
LedgerHash const & prevLCLHash, Ledger::ref previousLedger,
std::uint32_t closeTime, FeeVote& feeVote)
: m_clock (clock)
, m_localTX (localtx)
, m_feeVote (feeVote)
, mState (lcsPRE_CLOSE)
, mCloseTime (closeTime)
, mPrevLedgerHash (prevLCLHash)
@@ -950,7 +951,7 @@ private:
if (((newLCL->getLedgerSeq () + 1) % 256) == 0)
// next ledger is flag ledger
{
getApp().getFeeVote ().doValidation (newLCL, *v);
m_feeVote.doValidation (newLCL, *v);
getApp().getFeatureTable ().doValidation (newLCL, *v);
}
@@ -1477,7 +1478,7 @@ private:
// previous ledger was flag ledger
SHAMap::pointer preSet
= initialLedger.peekTransactionMap ()->snapShot (true);
getApp().getFeeVote ().doVoting (mPreviousLedger, preSet);
m_feeVote.doVoting (mPreviousLedger, preSet);
getApp().getFeatureTable ().doVoting (mPreviousLedger, preSet);
initialSet = preSet->snapShot (false);
}
@@ -1859,7 +1860,7 @@ private:
getApp().getOPs ().endConsensus (mHaveCorrectLCL);
}
/** Add our fee to our validation
/** Add our load fee to our validation
*/
void addLoad(SerializedValidation::ref val)
{
@@ -1873,6 +1874,7 @@ private:
private:
clock_type& m_clock;
LocalTxs& m_localTX;
FeeVote& m_feeVote;
// VFALCO TODO Rename these to look pretty
enum LCState
@@ -1928,12 +1930,13 @@ LedgerConsensus::~LedgerConsensus ()
{
}
boost::shared_ptr <LedgerConsensus> LedgerConsensus::New (
clock_type& clock, LocalTxs& localtx,
LedgerHash const &prevLCLHash, Ledger::ref previousLedger, std::uint32_t closeTime)
boost::shared_ptr <LedgerConsensus>
make_LedgerConsensus (LedgerConsensus::clock_type& clock, LocalTxs& localtx,
LedgerHash const &prevLCLHash, Ledger::ref previousLedger,
std::uint32_t closeTime, FeeVote& feeVote)
{
return boost::make_shared <LedgerConsensusImp> (
clock, localtx, prevLCLHash, previousLedger,closeTime);
return boost::make_shared <LedgerConsensusImp> (clock, localtx,
prevLCLHash, previousLedger, closeTime, feeVote);
}
} // ripple

View File

@@ -21,7 +21,7 @@
#define RIPPLE_LEDGERCONSENSUS_H
namespace ripple {
/** Manager for achieving consensus on the next ledger.
This object is created when the consensus process starts, and
@@ -32,12 +32,7 @@ class LedgerConsensus
public:
typedef beast::abstract_clock <std::chrono::seconds> clock_type;
static boost::shared_ptr <LedgerConsensus> New (
clock_type& clock, LocalTxs& localtx,
LedgerHash const & prevLCLHash, Ledger::ref previousLedger,
std::uint32_t closeTime);
virtual ~LedgerConsensus () = 0;
virtual ~LedgerConsensus() = 0;
virtual int startup () = 0;
@@ -85,6 +80,11 @@ public:
virtual void simulate () = 0;
};
boost::shared_ptr <LedgerConsensus>
make_LedgerConsensus (LedgerConsensus::clock_type& clock, LocalTxs& localtx,
LedgerHash const & prevLCLHash, Ledger::ref previousLedger,
std::uint32_t closeTime, FeeVote& feeVote);
} // ripple
#endif

View File

@@ -24,10 +24,12 @@
#include "Tuning.h"
namespace ripple {
// VFALCO TODO Clean this global up
static bool volatile doShutdown = false;
static int const MAJORITY_FRACTION (200);
//------------------------------------------------------------------------------
//
// Specializations for LogPartition names
@@ -57,6 +59,8 @@ class PathRequestLog;
template <> char const* LogPartition::getPartitionName <PathRequestLog> () { return "PathRequest"; }
class RPCManagerLog;
template <> char const* LogPartition::getPartitionName <RPCManagerLog> () { return "RPCManager"; }
class FeaturesLog;
template <> char const* LogPartition::getPartitionName <FeaturesLog>() { return "FeatureTable"; }
template <> char const* LogPartition::getPartitionName <CollectorManager> () { return "Collector"; }
@@ -137,8 +141,7 @@ public:
std::unique_ptr <SNTPClient> m_sntpClient;
std::unique_ptr <TxQueue> m_txQueue;
std::unique_ptr <Validators::Manager> m_validators;
std::unique_ptr <IFeatures> mFeatures;
std::unique_ptr <IFeeVote> mFeeVote;
std::unique_ptr <FeatureTable> m_featureTable;
std::unique_ptr <LoadFeeTrack> mFeeTrack;
std::unique_ptr <IHashRouter> mHashRouter;
std::unique_ptr <Validations> mValidations;
@@ -293,9 +296,8 @@ public:
getConfig ().getModuleDatabasePath (),
LogPartition::getJournal <ValidatorsLog> ())))
, mFeatures (IFeatures::New (2 * 7 * 24 * 60 * 60, 200)) // two weeks, 200/256
, mFeeVote (IFeeVote::New (10, 20 * SYSTEM_CURRENCY_PARTS, 5 * SYSTEM_CURRENCY_PARTS))
, m_featureTable (make_FeatureTable (weeks(2), MAJORITY_FRACTION, // 200/256
LogPartition::getJournal <FeaturesLog> ()))
, mFeeTrack (LoadFeeTrack::New (LogPartition::getJournal <LoadManagerLog> ()))
@@ -448,9 +450,9 @@ public:
return *m_validators;
}
IFeatures& getFeatureTable ()
FeatureTable& getFeatureTable ()
{
return *mFeatures;
return *m_featureTable;
}
LoadFeeTrack& getFeeTrack ()
@@ -458,11 +460,6 @@ public:
return *mFeeTrack;
}
IFeeVote& getFeeVote ()
{
return *mFeeVote;
}
IHashRouter& getHashRouter ()
{
return *mHashRouter;
@@ -612,7 +609,7 @@ public:
if (!getConfig ().RUN_STANDALONE)
updateTables ();
mFeatures->addInitialFeatures ();
m_featureTable->addInitial ();
Pathfinder::initPathTable ();
m_ledgerMaster->setMinValidations (getConfig ().VALIDATION_QUORUM);

View File

@@ -32,8 +32,7 @@ namespace RPC { class Manager; }
// VFALCO TODO Fix forward declares required for header dependency loops
class CollectorManager;
class IFeatures;
class IFeeVote;
class FeatureTable;
class IHashRouter;
class LoadFeeTrack;
class Overlay;
@@ -89,8 +88,7 @@ public:
virtual NodeCache& getTempNodeCache () = 0;
virtual SLECache& getSLECache () = 0;
virtual Validators::Manager& getValidators () = 0;
virtual IFeatures& getFeatureTable () = 0;
virtual IFeeVote& getFeeVote () = 0;
virtual FeatureTable& getFeatureTable () = 0;
virtual IHashRouter& getHashRouter () = 0;
virtual LoadFeeTrack& getFeeTrack () = 0;
virtual LoadManager& getLoadManager () = 0;

View File

@@ -17,8 +17,10 @@
*/
//==============================================================================
#ifndef RIPPLE_IFEATURES_H
#define RIPPLE_IFEATURES_H
#ifndef RIPPLE_FEATURES_H
#define RIPPLE_FEATURES_H
#include "../book/Types.h"
namespace ripple {
@@ -26,14 +28,18 @@ class FeatureSet
{
// the status of all features requested in a given window
public:
std::uint32_t mCloseTime;
int mTrustedValidations; // number of trusted validations
ripple::unordered_map<uint256, int> mVotes; // yes votes by feature
std::uint32_t mCloseTime;
int mTrustedValidations; // number of trusted validations
ripple::unordered_map<uint256, int> mVotes; // yes votes by feature
FeatureSet (std::uint32_t ct, int tv) : mCloseTime (ct), mTrustedValidations (tv)
FeatureSet (std::uint32_t ct) : mCloseTime (ct), mTrustedValidations (0)
{
;
}
void addVoter ()
{
++mTrustedValidations;
}
void addVote (uint256 const& feature)
{
++mVotes[feature];
@@ -43,19 +49,19 @@ public:
class FeatureState
{
public:
bool mVetoed; // We don't want this feature enabled
bool mEnabled;
bool mSupported;
bool mDefault; // Include in genesis ledger
bool mVetoed; // We don't want this feature enabled
bool mEnabled;
bool mSupported;
bool mDefault; // Include in genesis ledger
std::uint32_t mFirstMajority; // First time we saw a majority (close time)
std::uint32_t mLastMajority; // Most recent time we saw a majority (close time)
core::Clock::time_point m_firstMajority; // First time we saw a majority (close time)
core::Clock::time_point m_lastMajority; // Most recent time we saw a majority (close time)
std::string mFriendlyName;
FeatureState ()
: mVetoed (false), mEnabled (false), mSupported (false), mDefault (false),
mFirstMajority (0), mLastMajority (0)
m_firstMajority (0), m_lastMajority (0)
{
;
}
@@ -100,48 +106,54 @@ public:
Individuals features are voted on by validators during the consensus
process.
*/
class IFeatures
class FeatureTable
{
public:
static IFeatures* New (std::uint32_t majorityTime, int majorityFraction);
/** Create a new FeatureTable.
virtual ~IFeatures () { }
virtual void addInitialFeatures () = 0;
virtual FeatureState* addKnownFeature (const char* featureID, const char* friendlyName, bool veto) = 0;
virtual uint256 getFeature (const std::string& name) = 0;
virtual bool vetoFeature (uint256 const& feature) = 0;
virtual bool unVetoFeature (uint256 const& feature) = 0;
virtual bool enableFeature (uint256 const& feature) = 0;
virtual bool disableFeature (uint256 const& feature) = 0;
virtual bool isFeatureEnabled (uint256 const& feature) = 0;
virtual bool isFeatureSupported (uint256 const& feature) = 0;
virtual void setEnabledFeatures (const std::vector<uint256>& features) = 0;
virtual void setSupportedFeatures (const std::vector<uint256>& features) = 0;
// VFALCO NOTE these can't possibly be used since featureList_t was/is private.
/*
featureList_t getVetoedFeatures() = 0;
featureList_t getEnabledFeatures() = 0;
featureList_t getFeaturesToEnable(std::uint32_t closeTime) = 0; // gets features we would vote to enable
featureList_t getDesiredFeatures() = 0; // features we support, do not veto, are not enabled
@param majorityTime the number of seconds a feature must hold a majority
before we're willing to vote yes on it.
@param majorityFraction ratio, out of 256, of servers that must say
they want a feature before we consider it to
have a majority.
@param journal
*/
virtual ~FeatureTable() { }
virtual void addInitial () = 0;
virtual FeatureState* addKnown (const char* featureID,
const char* friendlyName, bool veto) = 0;
virtual uint256 get (const std::string& name) = 0;
virtual bool veto (uint256 const& feature) = 0;
virtual bool unVeto (uint256 const& feature) = 0;
virtual bool enable (uint256 const& feature) = 0;
virtual bool disable (uint256 const& feature) = 0;
virtual bool isEnabled (uint256 const& feature) = 0;
virtual bool isSupported (uint256 const& feature) = 0;
virtual void setEnabled (const std::vector<uint256>& features) = 0;
virtual void setSupported (const std::vector<uint256>& features) = 0;
virtual void reportValidations (const FeatureSet&) = 0;
virtual Json::Value getJson (int) = 0;
virtual Json::Value getJson (uint256 const& ) = 0;
virtual void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) = 0;
virtual void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
virtual void
doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) = 0;
virtual void
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
};
std::unique_ptr<FeatureTable>
make_FeatureTable (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal);
} // ripple
#endif

View File

@@ -1,507 +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.
*/
//==============================================================================
namespace ripple {
class Features;
SETUP_LOG (Features)
FeatureState* testFeature = nullptr;
// VFALCO TODO Rename this to Features
class Features : public IFeatures
{
protected:
typedef ripple::unordered_map<uint256, FeatureState> featureMap_t;
typedef std::pair<const uint256, FeatureState> featureIt_t;
typedef boost::unordered_set<uint256> featureList_t;
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
featureMap_t mFeatureMap;
int mMajorityTime; // Seconds a feature must hold a majority
int mMajorityFraction; // 256 = 100%
std::uint32_t mFirstReport; // close time of first majority report
std::uint32_t mLastReport; // close time of most recent majority report
FeatureState* getCreateFeature (uint256 const& feature, bool create);
bool shouldEnable (std::uint32_t closeTime, const FeatureState& fs);
void setJson (Json::Value& v, const FeatureState&);
public:
Features (std::uint32_t majorityTime, int majorityFraction)
: mMajorityTime (majorityTime), mMajorityFraction (majorityFraction), mFirstReport (0), mLastReport (0)
{
}
void addInitialFeatures ();
FeatureState* addKnownFeature (const char* featureID, const char* friendlyName, bool veto);
uint256 getFeature (const std::string& name);
bool vetoFeature (uint256 const& feature);
bool unVetoFeature (uint256 const& feature);
bool enableFeature (uint256 const& feature);
bool disableFeature (uint256 const& feature);
bool isFeatureEnabled (uint256 const& feature);
bool isFeatureSupported (uint256 const& feature);
void setEnabledFeatures (const std::vector<uint256>& features);
void setSupportedFeatures (const std::vector<uint256>& features);
featureList_t getVetoedFeatures ();
featureList_t getEnabledFeatures ();
featureList_t getFeaturesToEnable (std::uint32_t closeTime); // gets features we would vote to enable
featureList_t getDesiredFeatures (); // features we support, do not veto, are not enabled
void reportValidations (const FeatureSet&);
Json::Value getJson (int);
Json::Value getJson (uint256 const& );
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation);
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition);
};
void Features::addInitialFeatures ()
{
// For each feature this version supports, construct the FeatureState object by calling
// getCreateFeature. Set any vetoes or defaults. A pointer to the FeatureState can be stashed
testFeature = addKnownFeature ("1234", "testFeature", false);
}
FeatureState* Features::getCreateFeature (uint256 const& featureHash, bool create)
{
// call with the mutex held
featureMap_t::iterator it = mFeatureMap.find (featureHash);
if (it == mFeatureMap.end ())
{
if (!create)
return nullptr;
FeatureState* feature = & (mFeatureMap[featureHash]);
{
std::string query = "SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
query.append (featureHash.GetHex ());
query.append ("';");
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
if (db->executeSQL (query) && db->startIterRows ())
{
feature->mFirstMajority = db->getBigInt ("FirstMajority");
feature->mLastMajority = db->getBigInt ("LastMajority");
db->endIterRows ();
}
}
return feature;
}
return & (it->second);
}
uint256 Features::getFeature (const std::string& name)
{
if (!name.empty ())
{
BOOST_FOREACH (featureMap_t::value_type & it, mFeatureMap)
{
if (name == it.second.mFriendlyName)
return it.first;
}
}
return uint256 ();
}
FeatureState* Features::addKnownFeature (const char* featureID, const char* friendlyName, bool veto)
{
uint256 hash;
hash.SetHex (featureID);
if (hash.isZero ())
{
assert (false);
return nullptr;
}
FeatureState* f = getCreateFeature (hash, true);
if (friendlyName != nullptr)
f->setFriendlyName (friendlyName);
f->mVetoed = veto;
f->mSupported = true;
return f;
}
bool Features::vetoFeature (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, true);
if (s->mVetoed)
return false;
s->mVetoed = true;
return true;
}
bool Features::unVetoFeature (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, false);
if (!s || !s->mVetoed)
return false;
s->mVetoed = false;
return true;
}
bool Features::enableFeature (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, true);
if (s->mEnabled)
return false;
s->mEnabled = true;
return true;
}
bool Features::disableFeature (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, false);
if (!s || !s->mEnabled)
return false;
s->mEnabled = false;
return true;
}
bool Features::isFeatureEnabled (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, false);
return s && s->mEnabled;
}
bool Features::isFeatureSupported (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreateFeature (feature, false);
return s && s->mSupported;
}
Features::featureList_t Features::getVetoedFeatures ()
{
featureList_t ret;
ScopedLockType sl (mLock);
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
{
if (it.second.mVetoed)
ret.insert (it.first);
}
return ret;
}
Features::featureList_t Features::getEnabledFeatures ()
{
featureList_t ret;
ScopedLockType sl (mLock);
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
{
if (it.second.mEnabled)
ret.insert (it.first);
}
return ret;
}
bool Features::shouldEnable (std::uint32_t closeTime, const FeatureState& fs)
{
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.mLastMajority != mLastReport))
return false;
if (fs.mFirstMajority == mFirstReport)
{
// had a majority when we first started the server, relaxed check
// WRITEME
}
// didn't have a majority when we first started the server, normal check
return (fs.mLastMajority - fs.mFirstMajority) > mMajorityTime;
}
Features::featureList_t Features::getFeaturesToEnable (std::uint32_t closeTime)
{
featureList_t ret;
ScopedLockType sl (mLock);
if (mLastReport != 0)
{
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
{
if (shouldEnable (closeTime, it.second))
ret.insert (it.first);
}
}
return ret;
}
Features::featureList_t Features::getDesiredFeatures ()
{
featureList_t ret;
ScopedLockType sl (mLock);
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
{
if (it.second.mSupported && !it.second.mEnabled && !it.second.mVetoed)
ret.insert (it.first);
}
return ret;
}
void Features::reportValidations (const FeatureSet& set)
{
if (set.mTrustedValidations == 0)
return;
int threshold = (set.mTrustedValidations * mMajorityFraction) / 256;
typedef std::map<uint256, int>::value_type u256_int_pair;
ScopedLockType sl (mLock);
if (mFirstReport == 0)
mFirstReport = set.mCloseTime;
std::vector<uint256> changedFeatures;
changedFeatures.resize (set.mVotes.size ());
BOOST_FOREACH (const u256_int_pair & it, set.mVotes)
{
FeatureState& state = mFeatureMap[it.first];
WriteLog (lsDEBUG, Features) << "Feature " << it.first.GetHex () << " has " << it.second << " votes, needs " << threshold;
if (it.second >= threshold)
{
// we have a majority
state.mLastMajority = set.mCloseTime;
if (state.mFirstMajority == 0)
{
WriteLog (lsWARNING, Features) << "Feature " << it.first << " attains a majority vote";
state.mFirstMajority = set.mCloseTime;
changedFeatures.push_back (it.first);
}
}
else // we have no majority
{
if (state.mFirstMajority != 0)
{
WriteLog (lsWARNING, Features) << "Feature " << it.first << " loses majority vote";
state.mFirstMajority = 0;
state.mLastMajority = 0;
changedFeatures.push_back (it.first);
}
}
}
mLastReport = set.mCloseTime;
if (!changedFeatures.empty ())
{
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
db->executeSQL ("BEGIN TRANSACTION;");
BOOST_FOREACH (uint256 const & hash, changedFeatures)
{
FeatureState& fState = mFeatureMap[hash];
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';"
) % fState.mFirstMajority % hash.GetHex ()));
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET LastMajority = %d WHERE Hash = '%s';"
) % fState.mLastMajority % hash.GetHex ()));
}
db->executeSQL ("END TRANSACTION;");
changedFeatures.clear ();
}
}
void Features::setEnabledFeatures (const std::vector<uint256>& features)
{
ScopedLockType sl (mLock);
BOOST_FOREACH (featureIt_t & it, mFeatureMap)
{
it.second.mEnabled = false;
}
BOOST_FOREACH (uint256 const & it, features)
{
mFeatureMap[it].mEnabled = true;
}
}
void Features::setSupportedFeatures (const std::vector<uint256>& features)
{
ScopedLockType sl (mLock);
BOOST_FOREACH (featureIt_t & it, mFeatureMap)
{
it.second.mSupported = false;
}
BOOST_FOREACH (uint256 const & it, features)
{
mFeatureMap[it].mSupported = true;
}
}
void Features::doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation)
{
featureList_t lFeatures = getDesiredFeatures ();
if (lFeatures.empty ())
return;
STVector256 vFeatures (sfFeatures);
BOOST_FOREACH (uint256 const & uFeature, lFeatures)
{
vFeatures.addValue (uFeature);
}
vFeatures.sort ();
baseValidation.setFieldV256 (sfFeatures, vFeatures);
}
void Features::doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition)
{
featureList_t lFeatures = getFeaturesToEnable (lastClosedLedger->getCloseTimeNC ());
if (lFeatures.empty ())
return;
BOOST_FOREACH (uint256 const & uFeature, lFeatures)
{
WriteLog (lsWARNING, Features) << "Voting for feature: " << uFeature;
SerializedTransaction trans (ttFEATURE);
trans.setFieldAccount (sfAccount, uint160 ());
trans.setFieldH256 (sfFeature, uFeature);
uint256 txID = trans.getTransactionID ();
WriteLog (lsWARNING, Features) << "Vote ID: " << txID;
Serializer s;
trans.add (s, true);
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
if (!initialPosition->addGiveItem (tItem, true, false))
{
WriteLog (lsWARNING, Features) << "Ledger already had feature transaction";
}
}
}
Json::Value Features::getJson (int)
{
Json::Value ret (Json::objectValue);
{
ScopedLockType sl (mLock);
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
{
setJson (ret[it.first.GetHex ()] = Json::objectValue, it.second);
}
}
return ret;
}
void Features::setJson (Json::Value& v, const FeatureState& fs)
{
if (!fs.mFriendlyName.empty ())
v["name"] = fs.mFriendlyName;
v["supported"] = fs.mSupported;
v["vetoed"] = fs.mVetoed;
if (fs.mEnabled)
v["enabled"] = true;
else
{
v["enabled"] = false;
if (mLastReport != 0)
{
if (fs.mLastMajority == 0)
{
v["majority"] = false;
}
else
{
if (fs.mFirstMajority != 0)
{
if (fs.mFirstMajority == mFirstReport)
v["majority_start"] = "start";
else
v["majority_start"] = fs.mFirstMajority;
}
if (fs.mLastMajority != 0)
{
if (fs.mLastMajority == mLastReport)
v["majority_until"] = "now";
else
v["majority_until"] = fs.mLastMajority;
}
}
}
}
if (fs.mVetoed)
v["veto"] = true;
}
Json::Value Features::getJson (uint256 const& feature)
{
Json::Value ret = Json::objectValue;
ScopedLockType sl (mLock);
setJson (ret[feature.GetHex ()] = Json::objectValue, *getCreateFeature (feature, true));
return ret;
}
IFeatures* IFeatures::New (std::uint32_t majorityTime, int majorityFraction)
{
return new Features (majorityTime, majorityFraction);
}
} // ripple

View File

@@ -0,0 +1,582 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
namespace ripple {
/** Track the list of "features"
A "feature" is an option that can affect transaction processing
rules that is identified by a 256-bit feature identifier
and adopted, or rejected, by the network.
*/
class FeaturesImpl : public FeatureTable
{
protected:
typedef ripple::unordered_map<uint256, FeatureState> featureMap_t;
typedef std::pair<const uint256, FeatureState> featureIt_t;
typedef boost::unordered_set<uint256> featureList_t;
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
featureMap_t mFeatureMap;
std::chrono::seconds m_majorityTime; // Seconds a feature must hold a majority
int mMajorityFraction; // 256 = 100%
core::Clock::time_point m_firstReport; // close time of first majority report
core::Clock::time_point m_lastReport; // close time of most recent majority report
beast::Journal m_journal;
FeatureState* getCreate (uint256 const& feature, bool create);
bool shouldEnable (std::uint32_t closeTime, const FeatureState& fs);
void setJson (Json::Value& v, const FeatureState&);
public:
FeaturesImpl (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal)
: m_majorityTime (majorityTime)
, mMajorityFraction (majorityFraction)
, m_firstReport (0)
, m_lastReport (0)
, m_journal (journal)
{
}
void addInitial () override;
FeatureState* addKnown (const char* featureID, const char* friendlyName,
bool veto) override;
uint256 get (const std::string& name) override;
bool veto (uint256 const& feature) override;
bool unVeto (uint256 const& feature) override;
bool enable (uint256 const& feature) override;
bool disable (uint256 const& feature) override;
bool isEnabled (uint256 const& feature) override;
bool isSupported (uint256 const& feature) override;
void setEnabled (const std::vector<uint256>& features) override;
void setSupported (const std::vector<uint256>& features) override;
void reportValidations (const FeatureSet&) override;
Json::Value getJson (int) override;
Json::Value getJson (uint256 const&) override;
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) override;
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) override;
featureList_t getVetoed ();
featureList_t getEnabled ();
featureList_t getToEnable (core::Clock::time_point closeTime); // gets features we would vote to enable
featureList_t getDesired (); // features we support, do not veto, are not enabled
};
void
FeaturesImpl::addInitial ()
{
// For each feature this version supports, construct the FeatureState object by calling
// addKnown. Set any vetoes or defaults. A pointer to the FeatureState can be stashed
}
FeatureState*
FeaturesImpl::getCreate (uint256 const& featureHash, bool create)
{
// call with the mutex held
auto iter (mFeatureMap.find (featureHash));
if (iter == mFeatureMap.end ())
{
if (!create)
return nullptr;
FeatureState* feature = & (mFeatureMap[featureHash]);
{
std::string query = "SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
query.append (featureHash.GetHex ());
query.append ("';");
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
if (db->executeSQL (query) && db->startIterRows ())
{
feature->m_firstMajority = db->getBigInt("FirstMajority");
feature->m_lastMajority = db->getBigInt("LastMajority");
db->endIterRows ();
}
}
return feature;
}
return & (iter->second);
}
uint256
FeaturesImpl::get (const std::string& name)
{
for (auto const& e : mFeatureMap)
{
if (name == e.second.mFriendlyName)
return e.first;
}
return uint256 ();
}
FeatureState*
FeaturesImpl::addKnown (const char* featureID, const char* friendlyName,
bool veto)
{
uint256 hash;
hash.SetHex (featureID);
if (hash.isZero ())
{
assert (false);
return nullptr;
}
FeatureState* f = getCreate (hash, true);
if (friendlyName != nullptr)
f->setFriendlyName (friendlyName);
f->mVetoed = veto;
f->mSupported = true;
return f;
}
bool
FeaturesImpl::veto (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, true);
if (s->mVetoed)
return false;
s->mVetoed = true;
return true;
}
bool
FeaturesImpl::unVeto (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, false);
if (!s || !s->mVetoed)
return false;
s->mVetoed = false;
return true;
}
bool
FeaturesImpl::enable (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, true);
if (s->mEnabled)
return false;
s->mEnabled = true;
return true;
}
bool
FeaturesImpl::disable (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, false);
if (!s || !s->mEnabled)
return false;
s->mEnabled = false;
return true;
}
bool
FeaturesImpl::isEnabled (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, false);
return s && s->mEnabled;
}
bool
FeaturesImpl::isSupported (uint256 const& feature)
{
ScopedLockType sl (mLock);
FeatureState* s = getCreate (feature, false);
return s && s->mSupported;
}
FeaturesImpl::featureList_t
FeaturesImpl::getVetoed ()
{
featureList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : mFeatureMap)
{
if (e.second.mVetoed)
ret.insert (e.first);
}
return ret;
}
FeaturesImpl::featureList_t
FeaturesImpl::getEnabled ()
{
featureList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : mFeatureMap)
{
if (e.second.mEnabled)
ret.insert (e.first);
}
return ret;
}
bool
FeaturesImpl::shouldEnable (std::uint32_t closeTime, const FeatureState& fs)
{
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.m_lastMajority != m_lastReport))
return false;
if (fs.m_firstMajority == m_firstReport)
{
// had a majority when we first started the server, relaxed check
// WRITEME
}
// didn't have a majority when we first started the server, normal check
return (fs.m_lastMajority - fs.m_firstMajority) > m_majorityTime.count();
}
FeaturesImpl::featureList_t
FeaturesImpl::getToEnable (core::Clock::time_point closeTime)
{
featureList_t ret;
ScopedLockType sl (mLock);
if (m_lastReport != 0)
{
for (auto const& e : mFeatureMap)
{
if (shouldEnable (closeTime, e.second))
ret.insert (e.first);
}
}
return ret;
}
FeaturesImpl::featureList_t
FeaturesImpl::getDesired ()
{
featureList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : mFeatureMap)
{
if (e.second.mSupported && !e.second.mEnabled && !e.second.mVetoed)
ret.insert (e.first);
}
return ret;
}
void
FeaturesImpl::reportValidations (const FeatureSet& set)
{
if (set.mTrustedValidations == 0)
return;
int threshold = (set.mTrustedValidations * mMajorityFraction) / 256;
typedef std::map<uint256, int>::value_type u256_int_pair;
ScopedLockType sl (mLock);
if (m_firstReport == 0)
m_firstReport = set.mCloseTime;
std::vector<uint256> changedFeatures;
changedFeatures.resize (set.mVotes.size ());
for (auto const& e : set.mVotes)
{
FeatureState& state = mFeatureMap[e.first];
if (m_journal.debug) m_journal.debug <<
"Feature " << e.first.GetHex () <<
" has " << e.second <<
" votes, needs " << threshold;
if (e.second >= threshold)
{
// we have a majority
state.m_lastMajority = set.mCloseTime;
if (state.m_firstMajority == 0)
{
if (m_journal.warning) m_journal.warning <<
"Feature " << e.first <<
" attains a majority vote";
state.m_firstMajority = set.mCloseTime;
changedFeatures.push_back (e.first);
}
}
else // we have no majority
{
if (state.m_firstMajority != 0)
{
if (m_journal.warning) m_journal.warning <<
"Feature " << e.first <<
" loses majority vote";
state.m_firstMajority = 0;
state.m_lastMajority = 0;
changedFeatures.push_back (e.first);
}
}
}
m_lastReport = set.mCloseTime;
if (!changedFeatures.empty ())
{
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
db->executeSQL ("BEGIN TRANSACTION;");
for (auto const& hash : changedFeatures)
{
FeatureState& fState = mFeatureMap[hash];
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';"
) % fState.m_firstMajority % hash.GetHex ()));
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET LastMajority = %d WHERE Hash = '%s';"
) % fState.m_lastMajority % hash.GetHex()));
}
db->executeSQL ("END TRANSACTION;");
changedFeatures.clear ();
}
}
void
FeaturesImpl::setEnabled (const std::vector<uint256>& features)
{
ScopedLockType sl (mLock);
for (auto& e : mFeatureMap)
{
e.second.mEnabled = false;
}
for (auto const& e : features)
{
mFeatureMap[e].mEnabled = true;
}
}
void
FeaturesImpl::setSupported (const std::vector<uint256>& features)
{
ScopedLockType sl (mLock);
for (auto &e : mFeatureMap)
{
e.second.mSupported = false;
}
for (auto const& e : features)
{
mFeatureMap[e].mSupported = true;
}
}
void
FeaturesImpl::doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation)
{
featureList_t lFeatures = getDesired ();
if (lFeatures.empty ())
return;
STVector256 vFeatures (sfFeatures);
for (auto const& uFeature : lFeatures)
{
vFeatures.addValue (uFeature);
}
vFeatures.sort ();
baseValidation.setFieldV256 (sfFeatures, vFeatures);
}
void
FeaturesImpl::doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition)
{
// LCL must be flag ledger
assert((lastClosedLedger->getLedgerSeq () % 256) == 0);
FeatureSet featureSet (lastClosedLedger->getParentCloseTimeNC ());
// get validations for ledger before flag ledger
ValidationSet valSet = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
for (auto const& entry : valSet)
{
auto const& val = *entry.second;
if (val.isTrusted ())
{
featureSet.addVoter ();
if (val.isFieldPresent (sfFeatures))
{
for (auto const& feature : val.getFieldV256 (sfFeatures))
{
featureSet.addVote (feature);
}
}
}
}
reportValidations (featureSet);
featureList_t lFeatures = getToEnable (lastClosedLedger->getCloseTimeNC ());
for (auto const& uFeature : lFeatures)
{
if (m_journal.warning) m_journal.warning <<
"Voting for feature: " << uFeature;
// Create the transaction to enable the feature
SerializedTransaction trans (ttFEATURE);
trans.setFieldAccount (sfAccount, uint160 ());
trans.setFieldH256 (sfFeature, uFeature);
uint256 txID = trans.getTransactionID ();
if (m_journal.warning) m_journal.warning <<
"Vote ID: " << txID;
// Inject the transaction into our initial proposal
Serializer s;
trans.add (s, true);
#if RIPPLE_PROPOSE_FEATURES
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
if (!initialPosition->addGiveItem (tItem, true, false))
{
if (m_journal.warning) m_journal.warning <<
"Ledger already had feature transaction";
}
#endif
}
}
Json::Value
FeaturesImpl::getJson (int)
{
Json::Value ret(Json::objectValue);
{
ScopedLockType sl(mLock);
for (auto const& e : mFeatureMap)
{
setJson (ret[e.first.GetHex ()] = Json::objectValue, e.second);
}
}
return ret;
}
void
FeaturesImpl::setJson (Json::Value& v, const FeatureState& fs)
{
if (!fs.mFriendlyName.empty())
v["name"] = fs.mFriendlyName;
v["supported"] = fs.mSupported;
v["vetoed"] = fs.mVetoed;
if (fs.mEnabled)
v["enabled"] = true;
else
{
v["enabled"] = false;
if (m_lastReport != 0)
{
if (fs.m_lastMajority == 0)
{
v["majority"] = false;
}
else
{
if (fs.m_firstMajority != 0)
{
if (fs.m_firstMajority == m_firstReport)
v["majority_start"] = "start";
else
v["majority_start"] = fs.m_firstMajority;
}
if (fs.m_lastMajority != 0)
{
if (fs.m_lastMajority == m_lastReport)
v["majority_until"] = "now";
else
v["majority_until"] = fs.m_lastMajority;
}
}
}
}
if (fs.mVetoed)
v["veto"] = true;
}
Json::Value
FeaturesImpl::getJson (uint256 const& featureID)
{
Json::Value ret = Json::objectValue;
Json::Value& jFeature = (ret[featureID.GetHex()] = Json::objectValue);
{
ScopedLockType sl(mLock);
FeatureState *featureState = getCreate (featureID, true);
setJson (jFeature, *featureState);
}
return ret;
}
std::unique_ptr<FeatureTable>
make_FeatureTable (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal)
{
return std::make_unique<FeaturesImpl> (majorityTime, majorityFraction,
journal);
}
} // ripple

View File

@@ -23,7 +23,7 @@
namespace ripple {
/** Manager to process fee votes. */
class IFeeVote
class FeeVote
{
public:
/** Create a new fee vote manager.
@@ -31,12 +31,10 @@ public:
@param targetBaseFee
@param targetReserveBase
@param targetReserveIncrement
@param journal
*/
static IFeeVote* New (std::uint64_t targetBaseFee,
std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement);
virtual ~IFeeVote () { }
virtual ~FeeVote () { }
/** Add local fee preference to validation.
@@ -55,6 +53,10 @@ public:
SHAMap::ref initialPosition) = 0;
};
std::unique_ptr<FeeVote>
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal);
} // ripple
#endif

View File

@@ -19,9 +19,9 @@
namespace ripple {
class Features;
class FeaturesImpl;
class FeeVote : public IFeeVote
class FeeVoteImpl : public FeeVote
{
private:
@@ -37,37 +37,41 @@ private:
++mVoteMap[mTarget];
}
bool mayVote () const
bool
mayVote () const
{
// If we love the current setting, we will not vote
return mCurrent != mTarget;
}
void addVote (Integer vote)
void
addVote (Integer vote)
{
++mVoteMap[vote];
}
void noVote ()
void
noVote ()
{
addVote (mCurrent);
}
Integer getVotes ()
Integer
getVotes ()
{
Integer ourVote = mCurrent;
int weight = 0;
typedef typename std::map<Integer, int>::value_type mapVType;
BOOST_FOREACH (const mapVType & value, mVoteMap)
for (auto const& e : mVoteMap)
{
// Take most voted value between current and target, inclusive
if ((value.first <= std::max (mTarget, mCurrent)) &&
(value.first >= std::min (mTarget, mCurrent)) &&
(value.second > weight))
if ((e.first <= std::max (mTarget, mCurrent)) &&
(e.first >= std::min (mTarget, mCurrent)) &&
(e.second > weight))
{
ourVote = value.first;
weight = value.second;
ourVote = e.first;
weight = e.second;
}
}
@@ -75,46 +79,55 @@ private:
}
private:
Integer mCurrent; // The current setting
Integer mTarget; // The setting we want
Integer mCurrent; // The current setting
Integer mTarget; // The setting we want
std::map<Integer, int> mVoteMap;
};
public:
FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement)
FeeVoteImpl (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal)
: mTargetBaseFee (targetBaseFee)
, mTargetReserveBase (targetReserveBase)
, mTargetReserveIncrement (targetReserveIncrement)
, m_journal (journal)
{
}
//--------------------------------------------------------------------------
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation)
void
doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) override
{
if (lastClosedLedger->getBaseFee () != mTargetBaseFee)
{
WriteLog (lsINFO, Features) << "Voting for base fee of " << mTargetBaseFee;
if (m_journal.info) m_journal.info <<
"Voting for base fee of " << mTargetBaseFee;
baseValidation.setFieldU64 (sfBaseFee, mTargetBaseFee);
}
if (lastClosedLedger->getReserve (0) != mTargetReserveBase)
{
WriteLog (lsINFO, Features) << "Voting for base resrve of " << mTargetReserveBase;
baseValidation.setFieldU32 (sfReserveBase, mTargetReserveBase);
if (m_journal.info) m_journal.info <<
"Voting for base resrve of " << mTargetReserveBase;
baseValidation.setFieldU32(sfReserveBase, mTargetReserveBase);
}
if (lastClosedLedger->getReserveInc () != mTargetReserveIncrement)
{
WriteLog (lsINFO, Features) << "Voting for reserve increment of " << mTargetReserveIncrement;
if (m_journal.info) m_journal.info <<
"Voting for reserve increment of " << mTargetReserveIncrement;
baseValidation.setFieldU32 (sfReserveIncrement, mTargetReserveIncrement);
}
}
//--------------------------------------------------------------------------
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition)
void
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) override
{
// LCL must be flag ledger
assert ((lastClosedLedger->getLedgerSeq () % 256) == 0);
@@ -125,9 +138,9 @@ public:
// get validations for ledger before flag
ValidationSet set = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
BOOST_FOREACH (ValidationSet::value_type const & value, set)
for (auto const& e : set)
{
SerializedValidation const& val = *value.second;
SerializedValidation const& val = *e.second;
if (val.isTrusted ())
{
@@ -170,7 +183,10 @@ public:
(baseReserve != lastClosedLedger->getReserve (0)) ||
(incReserve != lastClosedLedger->getReserveInc ()))
{
WriteLog (lsWARNING, Features) << "We are voting for a fee change: " << baseFee << "/" << baseReserve << "/" << incReserve;
if (m_journal.warning) m_journal.warning <<
"We are voting for a fee change: " << baseFee <<
"/" << baseReserve <<
"/" << incReserve;
SerializedTransaction trans (ttFEE);
trans.setFieldAccount (sfAccount, uint160 ());
@@ -181,7 +197,8 @@ public:
uint256 txID = trans.getTransactionID ();
WriteLog (lsWARNING, Features) << "Vote: " << txID;
if (m_journal.warning) m_journal.warning <<
"Vote: " << txID;
Serializer s;
trans.add (s, true);
@@ -190,7 +207,8 @@ public:
if (!initialPosition->addGiveItem (tItem, true, false))
{
WriteLog (lsWARNING, Features) << "Ledger already had fee change";
if (m_journal.warning) m_journal.warning <<
"Ledger already had fee change";
}
}
}
@@ -199,15 +217,17 @@ private:
std::uint64_t mTargetBaseFee;
std::uint32_t mTargetReserveBase;
std::uint32_t mTargetReserveIncrement;
beast::Journal m_journal;
};
//------------------------------------------------------------------------------
IFeeVote* IFeeVote::New (std::uint64_t targetBaseFee,
std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement)
std::unique_ptr<FeeVote>
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal)
{
return new FeeVote (targetBaseFee, targetReserveBase, targetReserveIncrement);
return std::make_unique<FeeVoteImpl> (targetBaseFee, targetReserveBase,
targetReserveIncrement, journal);
}
} // ripple

View File

@@ -25,6 +25,11 @@
namespace ripple {
class FeeVoteLog;
template <>
char const*
LogPartition::getPartitionName <FeeVoteLog>() { return "FeeVote"; }
class NetworkOPsImp
: public NetworkOPs
, public beast::DeadlineTimer::Listener
@@ -46,6 +51,8 @@ public:
: NetworkOPs (parent)
, m_clock (clock)
, m_journal (journal)
, m_feeVote (make_FeeVote(10, 20 * SYSTEM_CURRENCY_PARTS,
5 * SYSTEM_CURRENCY_PARTS, LogPartition::getJournal <FeeVoteLog>()))
, m_localTX (LocalTxs::New ())
, mMode (omDISCONNECTED)
, mNeedNetworkLedger (false)
@@ -455,6 +462,8 @@ private:
std::unique_ptr <LocalTxs> m_localTX;
std::unique_ptr <FeeVote> m_feeVote;
LockType mLock;
OperatingMode mMode;
@@ -1463,9 +1472,9 @@ int NetworkOPsImp::beginConsensus (uint256 const& networkClosed, Ledger::pointer
assert (!mConsensus);
prevLedger->setImmutable ();
mConsensus = LedgerConsensus::New (m_clock, *m_localTX,
networkClosed, prevLedger,
m_ledgerMaster.getCurrentLedger ()->getCloseTimeNC ());
mConsensus = make_LedgerConsensus (m_clock, *m_localTX, networkClosed,
prevLedger, m_ledgerMaster.getCurrentLedger ()->getCloseTimeNC (),
*m_feeVote);
m_journal.debug << "Initiating consensus engine";
return mConsensus->startup ();

View File

@@ -83,8 +83,8 @@
#include "main/LoadManager.h"
#include "misc/OrderBook.h"
#include "shamap/SHAMapSyncFilters.h"
#include "misc/IFeatures.h"
#include "misc/IFeeVote.h"
#include "misc/FeatureTable.h"
#include "misc/FeeVote.h"
#include "misc/IHashRouter.h"
#include "peers/ClusterNodeStatus.h"
#include "peers/UniqueNodeList.h"

View File

@@ -36,4 +36,4 @@
#include "ledger/AcceptedLedgerTx.cpp"
#include "main/LocalCredentials.cpp"
#include "misc/Validations.cpp"
#include "misc/FeeVote.cpp"
#include "misc/FeeVoteImpl.cpp"

View File

@@ -31,4 +31,4 @@
#include "misc/HashRouter.cpp"
#include "misc/Offer.cpp"
#include "paths/Pathfinder.cpp"
#include "misc/Features.cpp"
#include "misc/FeaturesImpl.cpp"

View File

@@ -109,9 +109,9 @@ TER ChangeTransactor::applyFeature ()
featureObject->setFieldV256 (sfFeatures, features);
mEngine->entryModify (featureObject);
getApp().getFeatureTable ().enableFeature (feature);
getApp().getFeatureTable ().enable (feature);
if (!getApp().getFeatureTable ().isFeatureSupported (feature))
if (!getApp().getFeatureTable ().isSupported (feature))
getApp().getOPs ().setFeatureBlocked ();
return tesSUCCESS;

View File

@@ -49,7 +49,7 @@ Json::Value RPCHandler::doFeature (Json::Value params, Resource::Charge& loadTyp
return jvReply;
}
uint256 uFeature = getApp().getFeatureTable ().getFeature (params["feature"].asString ());
uint256 uFeature = getApp().getFeatureTable ().get (params["feature"].asString ());
if (uFeature.isZero ())
{