mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-18 09:35:49 +00:00
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:
committed by
Vinnie Falco
parent
ebae927a3e
commit
b8162884d9
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
582
src/ripple_app/misc/FeaturesImpl.cpp
Normal file
582
src/ripple_app/misc/FeaturesImpl.cpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
#include "ledger/AcceptedLedgerTx.cpp"
|
||||
#include "main/LocalCredentials.cpp"
|
||||
#include "misc/Validations.cpp"
|
||||
#include "misc/FeeVote.cpp"
|
||||
#include "misc/FeeVoteImpl.cpp"
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
#include "misc/HashRouter.cpp"
|
||||
#include "misc/Offer.cpp"
|
||||
#include "paths/Pathfinder.cpp"
|
||||
#include "misc/Features.cpp"
|
||||
#include "misc/FeaturesImpl.cpp"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user