mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-05 16:57:56 +00:00
Enable Amendments from config file or static data (RIPD-746):
* The rippled.cfg file has a new section called "amendments" * Each line in this section contains two white-space separated items ** The first item is the ID of the amendment (a 256-bit hash) ** The second item is the friendly name * Replaces config section name macros with variables * Make addKnown arguments safer * Added lock to addKnown
This commit is contained in:
committed by
Nik Bougalis
parent
312aec79ca
commit
44450bf644
3
Builds/VisualStudio2013/RippleD.vcxproj
Normal file → Executable file
3
Builds/VisualStudio2013/RippleD.vcxproj
Normal file → Executable file
@@ -1990,6 +1990,9 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\misc\tests\AmendmentTable.test.cpp">
|
||||||
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\misc\Validations.cpp">
|
<ClCompile Include="..\..\src\ripple\app\misc\Validations.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
6
Builds/VisualStudio2013/RippleD.vcxproj.filters
Normal file → Executable file
6
Builds/VisualStudio2013/RippleD.vcxproj.filters
Normal file → Executable file
@@ -325,6 +325,9 @@
|
|||||||
<Filter Include="ripple\app\misc">
|
<Filter Include="ripple\app\misc">
|
||||||
<UniqueIdentifier>{5A1509B2-871B-A7AC-1E60-544D3F398741}</UniqueIdentifier>
|
<UniqueIdentifier>{5A1509B2-871B-A7AC-1E60-544D3F398741}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="ripple\app\misc\tests">
|
||||||
|
<UniqueIdentifier>{815DC1A2-E2EF-E6E3-D979-19AD1476A28B}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="ripple\app\node">
|
<Filter Include="ripple\app\node">
|
||||||
<UniqueIdentifier>{0FCD3973-E9A6-7172-C8A3-C3401E1A03DD}</UniqueIdentifier>
|
<UniqueIdentifier>{0FCD3973-E9A6-7172-C8A3-C3401E1A03DD}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
@@ -2964,6 +2967,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
||||||
<Filter>ripple\app\misc</Filter>
|
<Filter>ripple\app\misc</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\misc\tests\AmendmentTable.test.cpp">
|
||||||
|
<Filter>ripple\app\misc\tests</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\misc\Validations.cpp">
|
<ClCompile Include="..\..\src\ripple\app\misc\Validations.cpp">
|
||||||
<Filter>ripple\app\misc</Filter>
|
<Filter>ripple\app\misc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include <ripple/json/json_reader.h>
|
#include <ripple/json/json_reader.h>
|
||||||
#include <ripple/json/to_string.h>
|
#include <ripple/json/to_string.h>
|
||||||
#include <ripple/core/LoadFeeTrack.h>
|
#include <ripple/core/LoadFeeTrack.h>
|
||||||
|
#include <ripple/core/ConfigSections.h>
|
||||||
#include <ripple/net/SNTPClient.h>
|
#include <ripple/net/SNTPClient.h>
|
||||||
#include <ripple/nodestore/Database.h>
|
#include <ripple/nodestore/Database.h>
|
||||||
#include <ripple/nodestore/DummyScheduler.h>
|
#include <ripple/nodestore/DummyScheduler.h>
|
||||||
@@ -317,8 +318,9 @@ public:
|
|||||||
, m_validators (Validators::make_Manager(*this, get_io_service(),
|
, m_validators (Validators::make_Manager(*this, get_io_service(),
|
||||||
getConfig ().getModuleDatabasePath (), m_logs.journal("UVL")))
|
getConfig ().getModuleDatabasePath (), m_logs.journal("UVL")))
|
||||||
|
|
||||||
, m_amendmentTable (make_AmendmentTable (weeks(2), MAJORITY_FRACTION,
|
, m_amendmentTable (make_AmendmentTable
|
||||||
m_logs.journal("AmendmentTable")))
|
(weeks(2), MAJORITY_FRACTION,
|
||||||
|
m_logs.journal("AmendmentTable")))
|
||||||
|
|
||||||
, mFeeTrack (LoadFeeTrack::New (m_logs.journal("LoadManager")))
|
, mFeeTrack (LoadFeeTrack::New (m_logs.journal("LoadManager")))
|
||||||
|
|
||||||
@@ -650,7 +652,8 @@ public:
|
|||||||
if (!getConfig ().RUN_STANDALONE)
|
if (!getConfig ().RUN_STANDALONE)
|
||||||
updateTables ();
|
updateTables ();
|
||||||
|
|
||||||
m_amendmentTable->addInitial();
|
m_amendmentTable->addInitial (
|
||||||
|
getConfig ().section (SECTION_AMENDMENTS));
|
||||||
initializePathfinding ();
|
initializePathfinding ();
|
||||||
|
|
||||||
m_ledgerMaster->setMinValidations (getConfig ().VALIDATION_QUORUM);
|
m_ledgerMaster->setMinValidations (getConfig ().VALIDATION_QUORUM);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define RIPPLE_AMENDMENT_TABLE_H
|
#define RIPPLE_AMENDMENT_TABLE_H
|
||||||
|
|
||||||
#include <ripple/app/book/Types.h>
|
#include <ripple/app/book/Types.h>
|
||||||
|
#include <ripple/app/misc/Validations.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -46,6 +47,48 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 256-bit Id and human friendly name of an amendment.
|
||||||
|
*/
|
||||||
|
class AmendmentName final
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint256 mId;
|
||||||
|
// Keep the hex string around for error reporting
|
||||||
|
std::string mHexString;
|
||||||
|
std::string mFriendlyName;
|
||||||
|
bool mValid{false};
|
||||||
|
|
||||||
|
public:
|
||||||
|
AmendmentName () = default;
|
||||||
|
AmendmentName (AmendmentName const& rhs) = default;
|
||||||
|
// AmendmentName (AmendmentName&& rhs) = default; // MSVS not supported
|
||||||
|
AmendmentName (uint256 const& id, std::string friendlyName)
|
||||||
|
: mId (id), mFriendlyName (std::move (friendlyName)), mValid (true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
AmendmentName (std::string id, std::string friendlyName)
|
||||||
|
: mHexString (std::move (id)), mFriendlyName (std::move (friendlyName))
|
||||||
|
{
|
||||||
|
mValid = mId.SetHex (mHexString);
|
||||||
|
}
|
||||||
|
bool valid () const
|
||||||
|
{
|
||||||
|
return mValid;
|
||||||
|
}
|
||||||
|
uint256 const& id () const
|
||||||
|
{
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
std::string const& hexString () const
|
||||||
|
{
|
||||||
|
return mHexString;
|
||||||
|
}
|
||||||
|
std::string const& friendlyName () const
|
||||||
|
{
|
||||||
|
return mFriendlyName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Current state of an amendment.
|
/** Current state of an amendment.
|
||||||
Tells if a amendment is supported, enabled or vetoed. A vetoed amendment
|
Tells if a amendment is supported, enabled or vetoed. A vetoed amendment
|
||||||
means the node will never announce its support.
|
means the node will never announce its support.
|
||||||
@@ -53,22 +96,19 @@ public:
|
|||||||
class AmendmentState
|
class AmendmentState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool mVetoed; // We don't want this amendment enabled
|
bool mVetoed{false}; // We don't want this amendment enabled
|
||||||
bool mEnabled;
|
bool mEnabled{false};
|
||||||
bool mSupported;
|
bool mSupported{false};
|
||||||
bool mDefault; // Include in genesis ledger
|
bool mDefault{false}; // Include in genesis ledger
|
||||||
|
|
||||||
core::Clock::time_point m_firstMajority; // First time we saw a majority (close time)
|
core::Clock::time_point
|
||||||
core::Clock::time_point m_lastMajority; // Most recent time we saw a majority (close time)
|
m_firstMajority{0}; // First time we saw a majority (close time)
|
||||||
|
core::Clock::time_point
|
||||||
|
m_lastMajority{0}; // Most recent time we saw a majority (close time)
|
||||||
|
|
||||||
std::string mFriendlyName;
|
std::string mFriendlyName;
|
||||||
|
|
||||||
AmendmentState ()
|
AmendmentState () = default;
|
||||||
: mVetoed (false), mEnabled (false), mSupported (false), mDefault (false),
|
|
||||||
m_firstMajority (0), m_lastMajority (0)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVeto ()
|
void setVeto ()
|
||||||
{
|
{
|
||||||
@@ -104,6 +144,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Section;
|
||||||
|
|
||||||
/** The amendment table stores the list of enabled and potential amendments.
|
/** The amendment table stores the list of enabled and potential amendments.
|
||||||
Individuals amendments are voted on by validators during the consensus
|
Individuals amendments are voted on by validators during the consensus
|
||||||
process.
|
process.
|
||||||
@@ -123,10 +165,17 @@ public:
|
|||||||
|
|
||||||
virtual ~AmendmentTable() { }
|
virtual ~AmendmentTable() { }
|
||||||
|
|
||||||
virtual void addInitial () = 0;
|
/**
|
||||||
|
@param section the config section of initial amendments
|
||||||
|
*/
|
||||||
|
virtual void addInitial (Section const& section) = 0;
|
||||||
|
|
||||||
|
/** Add an amendment to the AmendmentTable
|
||||||
|
|
||||||
|
@throw will throw if the name parameter is not valid
|
||||||
|
*/
|
||||||
|
virtual void addKnown (AmendmentName const& name) = 0;
|
||||||
|
|
||||||
virtual AmendmentState* addKnown (const char* amendmentID,
|
|
||||||
const char* friendlyName, bool veto) = 0;
|
|
||||||
virtual uint256 get (std::string const& name) = 0;
|
virtual uint256 get (std::string const& name) = 0;
|
||||||
|
|
||||||
virtual bool veto (uint256 const& amendment) = 0;
|
virtual bool veto (uint256 const& amendment) = 0;
|
||||||
@@ -138,9 +187,17 @@ public:
|
|||||||
virtual bool isEnabled (uint256 const& amendment) = 0;
|
virtual bool isEnabled (uint256 const& amendment) = 0;
|
||||||
virtual bool isSupported (uint256 const& amendment) = 0;
|
virtual bool isSupported (uint256 const& amendment) = 0;
|
||||||
|
|
||||||
|
/** Enable only the specified amendments.
|
||||||
|
Other amendments in the table will be set to disabled.
|
||||||
|
*/
|
||||||
virtual void setEnabled (const std::vector<uint256>& amendments) = 0;
|
virtual void setEnabled (const std::vector<uint256>& amendments) = 0;
|
||||||
|
/** Support only the specified amendments.
|
||||||
|
Other amendments in the table will be set to unsupported.
|
||||||
|
*/
|
||||||
virtual void setSupported (const std::vector<uint256>& amendments) = 0;
|
virtual void setSupported (const std::vector<uint256>& amendments) = 0;
|
||||||
|
|
||||||
|
/** Update the walletDB with the majority times.
|
||||||
|
*/
|
||||||
virtual void reportValidations (const AmendmentSet&) = 0;
|
virtual void reportValidations (const AmendmentSet&) = 0;
|
||||||
|
|
||||||
virtual Json::Value getJson (int) = 0;
|
virtual Json::Value getJson (int) = 0;
|
||||||
@@ -154,10 +211,12 @@ public:
|
|||||||
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
|
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<AmendmentTable>
|
std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||||
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
|
std::chrono::seconds majorityTime,
|
||||||
beast::Journal journal);
|
int majorityFraction,
|
||||||
|
beast::Journal journal,
|
||||||
|
bool useMockFacade = false);
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,24 +19,24 @@
|
|||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/misc/AmendmentTable.h>
|
#include <ripple/app/misc/AmendmentTable.h>
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/misc/Validations.h>
|
#include <ripple/app/misc/Validations.h>
|
||||||
#include <ripple/app/data/DatabaseCon.h>
|
#include <ripple/app/data/DatabaseCon.h>
|
||||||
|
#include <ripple/core/ConfigSections.h>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
#include <boost/tokenizer.hpp>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
/** Track the list of "amendments"
|
/** Track the list of "amendments"
|
||||||
|
|
||||||
An "amendment" is an option that can affect transaction processing
|
An "amendment" is an option that can affect transaction processing rules.
|
||||||
rules that is identified by a 256-bit amendment identifier
|
Amendments are proposed and then adopted or rejected by the network. An
|
||||||
and adopted, or rejected, by the network.
|
Amendment is uniquely identified by its AmendmentID, a 256-bit key.
|
||||||
*/
|
*/
|
||||||
class AmendmentTableImpl : public AmendmentTable
|
template<class AppApiFacade>
|
||||||
|
class AmendmentTableImpl final : public AmendmentTable
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef hash_map<uint256, AmendmentState> amendmentMap_t;
|
typedef hash_map<uint256, AmendmentState> amendmentMap_t;
|
||||||
typedef std::pair<const uint256, AmendmentState> amendmentIt_t;
|
|
||||||
typedef hash_set<uint256> amendmentList_t;
|
typedef hash_set<uint256> amendmentList_t;
|
||||||
|
|
||||||
typedef RippleMutex LockType;
|
typedef RippleMutex LockType;
|
||||||
@@ -49,14 +49,18 @@ protected:
|
|||||||
core::Clock::time_point m_firstReport; // close time of first majority report
|
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
|
core::Clock::time_point m_lastReport; // close time of most recent majority report
|
||||||
beast::Journal m_journal;
|
beast::Journal m_journal;
|
||||||
|
AppApiFacade m_appApiFacade;
|
||||||
|
|
||||||
AmendmentState* getCreate (uint256 const& amendment, bool create);
|
AmendmentState& getCreate (uint256 const& amendment);
|
||||||
|
AmendmentState* getExisting (uint256 const& amendment);
|
||||||
bool shouldEnable (std::uint32_t closeTime, const AmendmentState& fs);
|
bool shouldEnable (std::uint32_t closeTime, const AmendmentState& fs);
|
||||||
void setJson (Json::Value& v, const AmendmentState&);
|
void setJson (Json::Value& v, const AmendmentState&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AmendmentTableImpl (std::chrono::seconds majorityTime, int majorityFraction,
|
AmendmentTableImpl (
|
||||||
beast::Journal journal)
|
std::chrono::seconds majorityTime,
|
||||||
|
int majorityFraction,
|
||||||
|
beast::Journal journal)
|
||||||
: m_majorityTime (majorityTime)
|
: m_majorityTime (majorityTime)
|
||||||
, mMajorityFraction (majorityFraction)
|
, mMajorityFraction (majorityFraction)
|
||||||
, m_firstReport (0)
|
, m_firstReport (0)
|
||||||
@@ -65,10 +69,10 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInitial () override;
|
void addInitial (Section const& section) override;
|
||||||
|
|
||||||
|
void addKnown (AmendmentName const& name) override;
|
||||||
|
|
||||||
AmendmentState* addKnown (const char* amendmentID, const char* friendlyName,
|
|
||||||
bool veto) override;
|
|
||||||
uint256 get (std::string const& name) override;
|
uint256 get (std::string const& name) override;
|
||||||
|
|
||||||
bool veto (uint256 const& amendment) override;
|
bool veto (uint256 const& amendment) override;
|
||||||
@@ -97,51 +101,114 @@ public:
|
|||||||
amendmentList_t getDesired(); // amendments we support, do not veto, are not enabled
|
amendmentList_t getDesired(); // amendments we support, do not veto, are not enabled
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
namespace detail
|
||||||
AmendmentTableImpl::addInitial ()
|
|
||||||
{
|
{
|
||||||
// For each amendment this version supports, construct the AmendmentState object by calling
|
/** preEnabledAmendments is a static collection of amendments that are are
|
||||||
// addKnown. Set any vetoes or defaults. A pointer to the AmendmentState can be stashed
|
enabled at build time.
|
||||||
|
|
||||||
|
Add amendments to this collection at build time to enable them on this
|
||||||
|
server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::vector<AmendmentName> const preEnabledAmendments;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentState*
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::getCreate (uint256 const& amendmentHash, bool create)
|
void
|
||||||
|
AmendmentTableImpl<AppApiFacade>::addInitial (Section const& section)
|
||||||
|
{
|
||||||
|
for (auto const& a : detail::preEnabledAmendments)
|
||||||
|
{
|
||||||
|
if (!a.valid ())
|
||||||
|
{
|
||||||
|
std::string const errorMsg =
|
||||||
|
(boost::format (
|
||||||
|
"preEnabledAmendments contains an invalid hash (expected "
|
||||||
|
"a hex number). Value was: %1%") %
|
||||||
|
a.hexString ()).str ();
|
||||||
|
throw std::runtime_error (errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AmendmentName> toAdd (detail::preEnabledAmendments);
|
||||||
|
|
||||||
|
{
|
||||||
|
// add the amendments from the config file
|
||||||
|
int const numExpectedToks = 2;
|
||||||
|
for (auto const& line : section.lines ())
|
||||||
|
{
|
||||||
|
boost::tokenizer<> tokenizer (line);
|
||||||
|
std::vector<std::string> tokens (tokenizer.begin (),
|
||||||
|
tokenizer.end ());
|
||||||
|
if (tokens.size () != numExpectedToks)
|
||||||
|
{
|
||||||
|
std::string const errorMsg =
|
||||||
|
(boost::format (
|
||||||
|
"The %1% section in the config file expects %2% "
|
||||||
|
"items. Found %3%. Line was: %4%") %
|
||||||
|
SECTION_AMENDMENTS % numExpectedToks % tokens.size () %
|
||||||
|
line).str ();
|
||||||
|
throw std::runtime_error (errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
toAdd.emplace_back (std::move (tokens[0]), std::move (tokens[1]));
|
||||||
|
if (!toAdd.back ().valid ())
|
||||||
|
{
|
||||||
|
std::string const errorMsg =
|
||||||
|
(boost::format (
|
||||||
|
"%1% is not a valid hash. Expected a hex "
|
||||||
|
"number. In config setcion: %2%. Line was: "
|
||||||
|
"%3%") %
|
||||||
|
toAdd.back ().hexString () % SECTION_AMENDMENTS %
|
||||||
|
line).str ();
|
||||||
|
throw std::runtime_error (errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& a : toAdd)
|
||||||
|
{
|
||||||
|
addKnown (a);
|
||||||
|
enable (a.id ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
|
AmendmentState&
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getCreate (uint256 const& amendmentHash)
|
||||||
{
|
{
|
||||||
// call with the mutex held
|
// call with the mutex held
|
||||||
auto iter (m_amendmentMap.find (amendmentHash));
|
auto iter (m_amendmentMap.find (amendmentHash));
|
||||||
|
|
||||||
if (iter == m_amendmentMap.end())
|
if (iter == m_amendmentMap.end())
|
||||||
{
|
{
|
||||||
if (!create)
|
AmendmentState& amendment = m_amendmentMap[amendmentHash];
|
||||||
return nullptr;
|
m_appApiFacade.setMajorityTimesFromDBToState (amendment, amendmentHash);
|
||||||
|
|
||||||
AmendmentState* amendment = & (m_amendmentMap[amendmentHash]);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::string query = "SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
|
|
||||||
query.append (to_string (amendmentHash));
|
|
||||||
query.append ("';");
|
|
||||||
|
|
||||||
auto sl (getApp().getWalletDB ().lock ());
|
|
||||||
auto db = getApp().getWalletDB ().getDB ();
|
|
||||||
|
|
||||||
if (db->executeSQL (query) && db->startIterRows ())
|
|
||||||
{
|
|
||||||
amendment->m_firstMajority = db->getBigInt("FirstMajority");
|
|
||||||
amendment->m_lastMajority = db->getBigInt("LastMajority");
|
|
||||||
db->endIterRows ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return amendment;
|
return amendment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
|
AmendmentState*
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getExisting (uint256 const& amendmentHash)
|
||||||
|
{
|
||||||
|
// call with the mutex held
|
||||||
|
auto iter (m_amendmentMap.find (amendmentHash));
|
||||||
|
|
||||||
|
if (iter == m_amendmentMap.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return & (iter->second);
|
return & (iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
uint256
|
uint256
|
||||||
AmendmentTableImpl::get (std::string const& name)
|
AmendmentTableImpl<AppApiFacade>::get (std::string const& name)
|
||||||
{
|
{
|
||||||
|
ScopedLockType sl (mLock);
|
||||||
|
|
||||||
for (auto const& e : m_amendmentMap)
|
for (auto const& e : m_amendmentMap)
|
||||||
{
|
{
|
||||||
if (name == e.second.mFriendlyName)
|
if (name == e.second.mFriendlyName)
|
||||||
@@ -151,48 +218,50 @@ AmendmentTableImpl::get (std::string const& name)
|
|||||||
return uint256 ();
|
return uint256 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentState*
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::addKnown (const char* amendmentID, const char* friendlyName,
|
void
|
||||||
bool veto)
|
AmendmentTableImpl<AppApiFacade>::addKnown (AmendmentName const& name)
|
||||||
{
|
{
|
||||||
uint256 hash;
|
if (!name.valid ())
|
||||||
hash.SetHex (amendmentID);
|
|
||||||
|
|
||||||
if (hash.isZero ())
|
|
||||||
{
|
{
|
||||||
assert (false);
|
std::string const errorMsg =
|
||||||
return nullptr;
|
(boost::format (
|
||||||
|
"addKnown was given an invalid hash (expected a hex number). "
|
||||||
|
"Value was: %1%") %
|
||||||
|
name.hexString ()).str ();
|
||||||
|
throw std::runtime_error (errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentState* f = getCreate (hash, true);
|
ScopedLockType sl (mLock);
|
||||||
|
AmendmentState& amendment = getCreate (name.id ());
|
||||||
|
|
||||||
if (friendlyName != nullptr)
|
if (!name.friendlyName ().empty ())
|
||||||
f->setFriendlyName (friendlyName);
|
amendment.setFriendlyName (name.friendlyName ());
|
||||||
|
|
||||||
f->mVetoed = veto;
|
amendment.mVetoed = false;
|
||||||
f->mSupported = true;
|
amendment.mSupported = true;
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::veto (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::veto (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, true);
|
AmendmentState& s = getCreate (amendment);
|
||||||
|
|
||||||
if (s->mVetoed)
|
if (s.mVetoed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s->mVetoed = true;
|
s.mVetoed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::unVeto (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::unVeto (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, false);
|
AmendmentState* s = getExisting (amendment);
|
||||||
|
|
||||||
if (!s || !s->mVetoed)
|
if (!s || !s->mVetoed)
|
||||||
return false;
|
return false;
|
||||||
@@ -201,24 +270,26 @@ AmendmentTableImpl::unVeto (uint256 const& amendment)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::enable (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::enable (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, true);
|
AmendmentState& s = getCreate (amendment);
|
||||||
|
|
||||||
if (s->mEnabled)
|
if (s.mEnabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s->mEnabled = true;
|
s.mEnabled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::disable (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::disable (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, false);
|
AmendmentState* s = getExisting (amendment);
|
||||||
|
|
||||||
if (!s || !s->mEnabled)
|
if (!s || !s->mEnabled)
|
||||||
return false;
|
return false;
|
||||||
@@ -227,24 +298,27 @@ AmendmentTableImpl::disable (uint256 const& amendment)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::isEnabled (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::isEnabled (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, false);
|
AmendmentState* s = getExisting (amendment);
|
||||||
return s && s->mEnabled;
|
return s && s->mEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::isSupported (uint256 const& amendment)
|
AmendmentTableImpl<AppApiFacade>::isSupported (uint256 const& amendment)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
AmendmentState* s = getCreate (amendment, false);
|
AmendmentState* s = getExisting (amendment);
|
||||||
return s && s->mSupported;
|
return s && s->mSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentTableImpl::amendmentList_t
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::getVetoed ()
|
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getVetoed ()
|
||||||
{
|
{
|
||||||
amendmentList_t ret;
|
amendmentList_t ret;
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
@@ -256,8 +330,9 @@ AmendmentTableImpl::getVetoed ()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentTableImpl::amendmentList_t
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::getEnabled ()
|
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getEnabled ()
|
||||||
{
|
{
|
||||||
amendmentList_t ret;
|
amendmentList_t ret;
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
@@ -269,8 +344,9 @@ AmendmentTableImpl::getEnabled ()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
bool
|
bool
|
||||||
AmendmentTableImpl::shouldEnable (std::uint32_t closeTime,
|
AmendmentTableImpl<AppApiFacade>::shouldEnable (std::uint32_t closeTime,
|
||||||
const AmendmentState& fs)
|
const AmendmentState& fs)
|
||||||
{
|
{
|
||||||
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.m_lastMajority != m_lastReport))
|
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.m_lastMajority != m_lastReport))
|
||||||
@@ -286,8 +362,9 @@ AmendmentTableImpl::shouldEnable (std::uint32_t closeTime,
|
|||||||
return (fs.m_lastMajority - fs.m_firstMajority) > m_majorityTime.count();
|
return (fs.m_lastMajority - fs.m_firstMajority) > m_majorityTime.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentTableImpl::amendmentList_t
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::getToEnable (core::Clock::time_point closeTime)
|
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getToEnable (core::Clock::time_point closeTime)
|
||||||
{
|
{
|
||||||
amendmentList_t ret;
|
amendmentList_t ret;
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
@@ -304,8 +381,9 @@ AmendmentTableImpl::getToEnable (core::Clock::time_point closeTime)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmendmentTableImpl::amendmentList_t
|
template<class AppApiFacade>
|
||||||
AmendmentTableImpl::getDesired ()
|
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||||
|
AmendmentTableImpl<AppApiFacade>::getDesired ()
|
||||||
{
|
{
|
||||||
amendmentList_t ret;
|
amendmentList_t ret;
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
@@ -319,8 +397,9 @@ AmendmentTableImpl::getDesired ()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
AmendmentTableImpl<AppApiFacade>::reportValidations (const AmendmentSet& set)
|
||||||
{
|
{
|
||||||
if (set.mTrustedValidations == 0)
|
if (set.mTrustedValidations == 0)
|
||||||
return;
|
return;
|
||||||
@@ -335,7 +414,7 @@ AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
|||||||
m_firstReport = set.mCloseTime;
|
m_firstReport = set.mCloseTime;
|
||||||
|
|
||||||
std::vector<uint256> changedAmendments;
|
std::vector<uint256> changedAmendments;
|
||||||
changedAmendments.resize(set.mVotes.size());
|
changedAmendments.reserve (set.mVotes.size());
|
||||||
|
|
||||||
for (auto const& e : set.mVotes)
|
for (auto const& e : set.mVotes)
|
||||||
{
|
{
|
||||||
@@ -378,27 +457,15 @@ AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
|||||||
|
|
||||||
if (!changedAmendments.empty())
|
if (!changedAmendments.empty())
|
||||||
{
|
{
|
||||||
auto sl (getApp().getWalletDB ().lock ());
|
m_appApiFacade.setMajorityTimesFromStateToDB (changedAmendments,
|
||||||
auto db = getApp().getWalletDB ().getDB ();
|
m_amendmentMap);
|
||||||
|
changedAmendments.clear ();
|
||||||
db->executeSQL ("BEGIN TRANSACTION;");
|
|
||||||
for (auto const& hash : changedAmendments)
|
|
||||||
{
|
|
||||||
AmendmentState& fState = m_amendmentMap[hash];
|
|
||||||
db->executeSQL (boost::str (boost::format (
|
|
||||||
"UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';") %
|
|
||||||
fState.m_firstMajority % to_string (hash)));
|
|
||||||
db->executeSQL (boost::str (boost::format (
|
|
||||||
"UPDATE Features SET LastMajority = %d WHERE Hash = '%s';") %
|
|
||||||
fState.m_lastMajority % to_string(hash)));
|
|
||||||
}
|
|
||||||
db->executeSQL ("END TRANSACTION;");
|
|
||||||
changedAmendments.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::setEnabled (const std::vector<uint256>& amendments)
|
AmendmentTableImpl<AppApiFacade>::setEnabled (const std::vector<uint256>& amendments)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
for (auto& e : m_amendmentMap)
|
for (auto& e : m_amendmentMap)
|
||||||
@@ -411,8 +478,9 @@ AmendmentTableImpl::setEnabled (const std::vector<uint256>& amendments)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::setSupported (const std::vector<uint256>& amendments)
|
AmendmentTableImpl<AppApiFacade>::setSupported (const std::vector<uint256>& amendments)
|
||||||
{
|
{
|
||||||
ScopedLockType sl (mLock);
|
ScopedLockType sl (mLock);
|
||||||
for (auto &e : m_amendmentMap)
|
for (auto &e : m_amendmentMap)
|
||||||
@@ -425,8 +493,9 @@ AmendmentTableImpl::setSupported (const std::vector<uint256>& amendments)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger,
|
AmendmentTableImpl<AppApiFacade>::doValidation (Ledger::ref lastClosedLedger,
|
||||||
STObject& baseValidation)
|
STObject& baseValidation)
|
||||||
{
|
{
|
||||||
amendmentList_t lAmendments = getDesired();
|
amendmentList_t lAmendments = getDesired();
|
||||||
@@ -441,8 +510,9 @@ AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger,
|
|||||||
baseValidation.setFieldV256 (sfAmendments, vAmendments);
|
baseValidation.setFieldV256 (sfAmendments, vAmendments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
AmendmentTableImpl<AppApiFacade>::doVoting (Ledger::ref lastClosedLedger,
|
||||||
SHAMap::ref initialPosition)
|
SHAMap::ref initialPosition)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -452,7 +522,8 @@ AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
|||||||
AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ());
|
AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ());
|
||||||
|
|
||||||
// get validations for ledger before flag ledger
|
// get validations for ledger before flag ledger
|
||||||
ValidationSet valSet = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
|
ValidationSet valSet = m_appApiFacade.getValidations (
|
||||||
|
lastClosedLedger->getParentHash ());
|
||||||
for (auto const& entry : valSet)
|
for (auto const& entry : valSet)
|
||||||
{
|
{
|
||||||
auto const& val = *entry.second;
|
auto const& val = *entry.second;
|
||||||
@@ -500,8 +571,9 @@ AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
Json::Value
|
Json::Value
|
||||||
AmendmentTableImpl::getJson (int)
|
AmendmentTableImpl<AppApiFacade>::getJson (int)
|
||||||
{
|
{
|
||||||
Json::Value ret(Json::objectValue);
|
Json::Value ret(Json::objectValue);
|
||||||
{
|
{
|
||||||
@@ -514,8 +586,9 @@ AmendmentTableImpl::getJson (int)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::setJson (Json::Value& v, const AmendmentState& fs)
|
AmendmentTableImpl<AppApiFacade>::setJson (Json::Value& v, const AmendmentState& fs)
|
||||||
{
|
{
|
||||||
if (!fs.mFriendlyName.empty())
|
if (!fs.mFriendlyName.empty())
|
||||||
v["name"] = fs.mFriendlyName;
|
v["name"] = fs.mFriendlyName;
|
||||||
@@ -560,8 +633,9 @@ AmendmentTableImpl::setJson (Json::Value& v, const AmendmentState& fs)
|
|||||||
v["veto"] = true;
|
v["veto"] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class AppApiFacade>
|
||||||
Json::Value
|
Json::Value
|
||||||
AmendmentTableImpl::getJson (uint256 const& amendmentID)
|
AmendmentTableImpl<AppApiFacade>::getJson (uint256 const& amendmentID)
|
||||||
{
|
{
|
||||||
Json::Value ret = Json::objectValue;
|
Json::Value ret = Json::objectValue;
|
||||||
Json::Value& jAmendment = (ret[to_string (amendmentID)] = Json::objectValue);
|
Json::Value& jAmendment = (ret[to_string (amendmentID)] = Json::objectValue);
|
||||||
@@ -569,19 +643,108 @@ AmendmentTableImpl::getJson (uint256 const& amendmentID)
|
|||||||
{
|
{
|
||||||
ScopedLockType sl(mLock);
|
ScopedLockType sl(mLock);
|
||||||
|
|
||||||
AmendmentState *amendmentState = getCreate (amendmentID, true);
|
AmendmentState& amendmentState = getCreate (amendmentID);
|
||||||
setJson (jAmendment, *amendmentState);
|
setJson (jAmendment, amendmentState);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AmendmentTable>
|
namespace detail
|
||||||
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
|
|
||||||
beast::Journal journal)
|
|
||||||
{
|
{
|
||||||
return std::make_unique<AmendmentTableImpl> (majorityTime, majorityFraction,
|
class AppApiFacadeImpl final
|
||||||
journal);
|
{
|
||||||
|
public:
|
||||||
|
void setMajorityTimesFromDBToState (AmendmentState& toUpdate,
|
||||||
|
uint256 const& amendmentHash) const;
|
||||||
|
void setMajorityTimesFromStateToDB (
|
||||||
|
std::vector<uint256> const& changedAmendments,
|
||||||
|
hash_map<uint256, AmendmentState>& amendmentMap) const;
|
||||||
|
ValidationSet getValidations (uint256 const& hash) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AppApiFacadeMock final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setMajorityTimesFromDBToState (AmendmentState& toUpdate,
|
||||||
|
uint256 const& amendmentHash) const {};
|
||||||
|
void setMajorityTimesFromStateToDB (
|
||||||
|
std::vector<uint256> const& changedAmendments,
|
||||||
|
hash_map<uint256, AmendmentState>& amendmentMap) const {};
|
||||||
|
ValidationSet getValidations (uint256 const& hash) const
|
||||||
|
{
|
||||||
|
return ValidationSet ();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AppApiFacadeImpl::setMajorityTimesFromDBToState (
|
||||||
|
AmendmentState& toUpdate,
|
||||||
|
uint256 const& amendmentHash) const
|
||||||
|
{
|
||||||
|
std::string query =
|
||||||
|
"SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
|
||||||
|
query.append (to_string (amendmentHash));
|
||||||
|
query.append ("';");
|
||||||
|
|
||||||
|
auto& walletDB (getApp ().getWalletDB ());
|
||||||
|
auto sl (walletDB.lock ());
|
||||||
|
auto db (walletDB.getDB ());
|
||||||
|
|
||||||
|
if (db->executeSQL (query) && db->startIterRows ())
|
||||||
|
{
|
||||||
|
toUpdate.m_firstMajority = db->getBigInt ("FirstMajority");
|
||||||
|
toUpdate.m_lastMajority = db->getBigInt ("LastMajority");
|
||||||
|
db->endIterRows ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
void AppApiFacadeImpl::setMajorityTimesFromStateToDB (
|
||||||
|
std::vector<uint256> const& changedAmendments,
|
||||||
|
hash_map<uint256, AmendmentState>& amendmentMap) const
|
||||||
|
{
|
||||||
|
if (changedAmendments.empty ())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& walletDB (getApp ().getWalletDB ());
|
||||||
|
auto sl (walletDB.lock ());
|
||||||
|
auto db (walletDB.getDB ());
|
||||||
|
|
||||||
|
db->executeSQL ("BEGIN TRANSACTION;");
|
||||||
|
for (auto const& hash : changedAmendments)
|
||||||
|
{
|
||||||
|
AmendmentState const& fState = amendmentMap[hash];
|
||||||
|
db->executeSQL (boost::str (boost::format (
|
||||||
|
"UPDATE Features SET FirstMajority "
|
||||||
|
"= %d WHERE Hash = '%s';") %
|
||||||
|
fState.m_firstMajority % to_string (hash)));
|
||||||
|
db->executeSQL (boost::str (boost::format (
|
||||||
|
"UPDATE Features SET LastMajority "
|
||||||
|
"= %d WHERE Hash = '%s';") %
|
||||||
|
fState.m_lastMajority % to_string (hash)));
|
||||||
|
}
|
||||||
|
db->executeSQL ("END TRANSACTION;");
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationSet AppApiFacadeImpl::getValidations (uint256 const& hash) const
|
||||||
|
{
|
||||||
|
return getApp ().getValidations ().getValidations (hash);
|
||||||
|
}
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||||
|
std::chrono::seconds majorityTime,
|
||||||
|
int majorityFraction,
|
||||||
|
beast::Journal journal,
|
||||||
|
bool useMockFacade)
|
||||||
|
{
|
||||||
|
if (useMockFacade)
|
||||||
|
{
|
||||||
|
return std::make_unique<AmendmentTableImpl<detail::AppApiFacadeMock>>(
|
||||||
|
majorityTime, majorityFraction, std::move (journal));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<AmendmentTableImpl<detail::AppApiFacadeImpl>>(
|
||||||
|
majorityTime, majorityFraction, std::move (journal));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ripple
|
||||||
|
|||||||
391
src/ripple/app/misc/tests/AmendmentTable.test.cpp
Normal file
391
src/ripple/app/misc/tests/AmendmentTable.test.cpp
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
|
||||||
|
#include <ripple/app/misc/AmendmentTable.h>
|
||||||
|
#include <ripple/core/ConfigSections.h>
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
|
||||||
|
namespace ripple
|
||||||
|
{
|
||||||
|
class AmendmentTable_test final : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using StringPairVec = std::vector<std::pair<std::string, std::string>>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class TablePopulationAlgo
|
||||||
|
{
|
||||||
|
addInitial,
|
||||||
|
addKnown
|
||||||
|
};
|
||||||
|
|
||||||
|
// 204/256 about 80%
|
||||||
|
static int const majorityFraction{204};
|
||||||
|
|
||||||
|
static void populateTable (AmendmentTable& table,
|
||||||
|
std::vector<std::string> const& configLines)
|
||||||
|
{
|
||||||
|
Section section (SECTION_AMENDMENTS);
|
||||||
|
section.append (configLines);
|
||||||
|
table.addInitial (section);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<AmendmentName> getAmendmentNames (
|
||||||
|
StringPairVec const& amendmentPairs)
|
||||||
|
{
|
||||||
|
std::vector<AmendmentName> amendmentNames;
|
||||||
|
amendmentNames.reserve (amendmentPairs.size ());
|
||||||
|
for (auto const& i : amendmentPairs)
|
||||||
|
{
|
||||||
|
amendmentNames.emplace_back (i.first, i.second);
|
||||||
|
}
|
||||||
|
return amendmentNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AmendmentName> populateTable (
|
||||||
|
AmendmentTable& table,
|
||||||
|
StringPairVec const& amendmentPairs,
|
||||||
|
TablePopulationAlgo populationAlgo = TablePopulationAlgo::addKnown)
|
||||||
|
{
|
||||||
|
std::vector<AmendmentName> const amendmentNames (
|
||||||
|
getAmendmentNames (amendmentPairs));
|
||||||
|
switch (populationAlgo)
|
||||||
|
{
|
||||||
|
case TablePopulationAlgo::addKnown:
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
table.addKnown (i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TablePopulationAlgo::addInitial:
|
||||||
|
{
|
||||||
|
std::vector<std::string> configLines;
|
||||||
|
configLines.reserve (amendmentPairs.size ());
|
||||||
|
for (auto const& i : amendmentPairs)
|
||||||
|
{
|
||||||
|
configLines.emplace_back (i.first + " " + i.second);
|
||||||
|
}
|
||||||
|
populateTable (table, configLines);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail ("Error in test case logic");
|
||||||
|
}
|
||||||
|
|
||||||
|
return amendmentNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<AmendmentTable> makeTable ()
|
||||||
|
{
|
||||||
|
beast::Journal journal;
|
||||||
|
return make_AmendmentTable (
|
||||||
|
weeks (2),
|
||||||
|
majorityFraction,
|
||||||
|
journal,
|
||||||
|
/*useMock*/ true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the amendments by string pairs instead of AmendmentNames
|
||||||
|
// as this helps test the AmendmentNames class
|
||||||
|
StringPairVec const m_validAmendmentPairs;
|
||||||
|
StringPairVec const m_notAddedAmendmentPairs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AmendmentTable_test ()
|
||||||
|
: m_validAmendmentPairs (
|
||||||
|
{{"a49f90e7cddbcadfed8fc89ec4d02011", "Added1"},
|
||||||
|
{"ca956ccabf25151a16d773171c485423", "Added2"},
|
||||||
|
{"60dcd528f057711c5d26b57be28e23df", "Added3"},
|
||||||
|
{"da956ccabf25151a16d773171c485423", "Added4"},
|
||||||
|
{"70dcd528f057711c5d26b57be28e23df", "Added5"},
|
||||||
|
{"70dcd528f057711c5d26b57be28e23d0", "Added6"}})
|
||||||
|
, m_notAddedAmendmentPairs (
|
||||||
|
{{"a9f90e7cddbcadfed8fc89ec4d02011c", "NotAdded1"},
|
||||||
|
{"c956ccabf25151a16d773171c485423b", "NotAdded2"},
|
||||||
|
{"6dcd528f057711c5d26b57be28e23dfa", "NotAdded3"}})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void testGet ()
|
||||||
|
{
|
||||||
|
testcase ("get");
|
||||||
|
auto table (makeTable ());
|
||||||
|
std::vector<AmendmentName> const amendmentNames (
|
||||||
|
populateTable (*table, m_validAmendmentPairs));
|
||||||
|
std::vector<AmendmentName> const notAddedAmendmentNames (
|
||||||
|
getAmendmentNames (m_notAddedAmendmentPairs));
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
expect (table->get (i.friendlyName ()) == i.id ());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& i : notAddedAmendmentNames)
|
||||||
|
{
|
||||||
|
expect (table->get (i.friendlyName ()) == uint256 ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAddInitialAddKnown ()
|
||||||
|
{
|
||||||
|
testcase ("addInitialAddKnown");
|
||||||
|
|
||||||
|
for (auto tablePopulationAlgo :
|
||||||
|
{TablePopulationAlgo::addInitial, TablePopulationAlgo::addKnown})
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// test that the amendments we add are enabled and amendments we
|
||||||
|
// didn't add are not enabled
|
||||||
|
|
||||||
|
auto table (makeTable ());
|
||||||
|
std::vector<AmendmentName> const amendmentNames (populateTable (
|
||||||
|
*table, m_validAmendmentPairs, tablePopulationAlgo));
|
||||||
|
std::vector<AmendmentName> const notAddedAmendmentNames (
|
||||||
|
getAmendmentNames (m_notAddedAmendmentPairs));
|
||||||
|
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
expect (table->isSupported (i.id ()));
|
||||||
|
if (tablePopulationAlgo == TablePopulationAlgo::addInitial)
|
||||||
|
expect (table->isEnabled (i.id ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& i : notAddedAmendmentNames)
|
||||||
|
{
|
||||||
|
expect (!table->isSupported (i.id ()));
|
||||||
|
expect (!table->isEnabled (i.id ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// check that we throw an exception on bad hex pairs
|
||||||
|
StringPairVec const badHexPairs (
|
||||||
|
{{"a9f90e7cddbcadfedm8fc89ec4d02011c", "BadHex1"},
|
||||||
|
{"c956ccabf25151a16d77T3171c485423b", "BadHex2"},
|
||||||
|
{"6dcd528f057711c5d2Z6b57be28e23dfa", "BadHex3"}});
|
||||||
|
|
||||||
|
// make sure each element throws
|
||||||
|
for (auto const& i : badHexPairs)
|
||||||
|
{
|
||||||
|
StringPairVec v ({i});
|
||||||
|
auto table (makeTable ());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
populateTable (*table, v, tablePopulationAlgo);
|
||||||
|
// line above should throw
|
||||||
|
fail ("didn't throw");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pass ();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
populateTable (
|
||||||
|
*table, badHexPairs, tablePopulationAlgo);
|
||||||
|
// line above should throw
|
||||||
|
fail ("didn't throw");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pass ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// check that we thow on bad num tokens
|
||||||
|
std::vector<std::string> const badNumTokensConfigLines (
|
||||||
|
{"19f6d",
|
||||||
|
"19fd6 bad friendly name"
|
||||||
|
"9876 one two"});
|
||||||
|
|
||||||
|
// make sure each element throws
|
||||||
|
for (auto const& i : badNumTokensConfigLines)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v ({i});
|
||||||
|
auto table (makeTable ());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
populateTable (*table, v);
|
||||||
|
// line above should throw
|
||||||
|
fail ("didn't throw");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pass ();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
populateTable (*table, badNumTokensConfigLines);
|
||||||
|
// line above should throw
|
||||||
|
fail ("didn't throw");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pass ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testEnable ()
|
||||||
|
{
|
||||||
|
testcase ("enable");
|
||||||
|
auto table (makeTable ());
|
||||||
|
std::vector<AmendmentName> const amendmentNames (
|
||||||
|
populateTable (*table, m_validAmendmentPairs));
|
||||||
|
{
|
||||||
|
// enable/disable tests
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
auto id (i.id ());
|
||||||
|
table->enable (id);
|
||||||
|
expect (table->isEnabled (id));
|
||||||
|
table->disable (id);
|
||||||
|
expect (!table->isEnabled (id));
|
||||||
|
table->enable (id);
|
||||||
|
expect (table->isEnabled (id));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint256> toEnable;
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
auto id (i.id ());
|
||||||
|
toEnable.emplace_back (id);
|
||||||
|
table->disable (id);
|
||||||
|
expect (!table->isEnabled (id));
|
||||||
|
}
|
||||||
|
table->setEnabled (toEnable);
|
||||||
|
for (auto const& i : toEnable)
|
||||||
|
{
|
||||||
|
expect (table->isEnabled (i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using ATSetter =
|
||||||
|
void (AmendmentTable::*)(const std::vector<uint256>& amendments);
|
||||||
|
using ATGetter = bool (AmendmentTable::*)(uint256 const& amendment);
|
||||||
|
void testVectorSetUnset (ATSetter setter, ATGetter getter)
|
||||||
|
{
|
||||||
|
auto table (makeTable ());
|
||||||
|
// make pointer to ref syntax a little nicer
|
||||||
|
auto& tableRef (*table);
|
||||||
|
std::vector<AmendmentName> const amendmentNames (
|
||||||
|
populateTable (tableRef, m_validAmendmentPairs));
|
||||||
|
|
||||||
|
// they should all be set
|
||||||
|
for (auto const& i : amendmentNames)
|
||||||
|
{
|
||||||
|
expect ((tableRef.*getter)(i.id ())); // i.e. "isSupported"
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// only set every other amendment
|
||||||
|
std::vector<uint256> toSet;
|
||||||
|
toSet.reserve (amendmentNames.size ());
|
||||||
|
for (int i = 0; i < amendmentNames.size (); ++i)
|
||||||
|
{
|
||||||
|
if (i % 2)
|
||||||
|
{
|
||||||
|
toSet.emplace_back (amendmentNames[i].id ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(tableRef.*setter)(toSet);
|
||||||
|
for (int i = 0; i < amendmentNames.size (); ++i)
|
||||||
|
{
|
||||||
|
bool const shouldBeSet = i % 2;
|
||||||
|
expect (shouldBeSet ==
|
||||||
|
(tableRef.*getter)(
|
||||||
|
amendmentNames[i].id ())); // i.e. "isSupported"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void testSupported ()
|
||||||
|
{
|
||||||
|
testcase ("supported");
|
||||||
|
testVectorSetUnset (&AmendmentTable::setSupported,
|
||||||
|
&AmendmentTable::isSupported);
|
||||||
|
}
|
||||||
|
void testEnabled ()
|
||||||
|
{
|
||||||
|
testcase ("enabled");
|
||||||
|
testVectorSetUnset (&AmendmentTable::setEnabled,
|
||||||
|
&AmendmentTable::isEnabled);
|
||||||
|
}
|
||||||
|
void testSupportedEnabled ()
|
||||||
|
{
|
||||||
|
// Check that supported/enabled aren't the same thing
|
||||||
|
testcase ("supportedEnabled");
|
||||||
|
auto table (makeTable ());
|
||||||
|
|
||||||
|
std::vector<AmendmentName> const amendmentNames (
|
||||||
|
populateTable (*table, m_validAmendmentPairs));
|
||||||
|
|
||||||
|
{
|
||||||
|
// support every even amendment
|
||||||
|
// enable every odd amendment
|
||||||
|
std::vector<uint256> toSupport;
|
||||||
|
toSupport.reserve (amendmentNames.size ());
|
||||||
|
std::vector<uint256> toEnable;
|
||||||
|
toEnable.reserve (amendmentNames.size ());
|
||||||
|
for (int i = 0; i < amendmentNames.size (); ++i)
|
||||||
|
{
|
||||||
|
if (i % 2)
|
||||||
|
{
|
||||||
|
toSupport.emplace_back (amendmentNames[i].id ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toEnable.emplace_back (amendmentNames[i].id ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table->setEnabled (toEnable);
|
||||||
|
table->setSupported (toSupport);
|
||||||
|
for (int i = 0; i < amendmentNames.size (); ++i)
|
||||||
|
{
|
||||||
|
bool const shouldBeSupported = i % 2;
|
||||||
|
bool const shouldBeEnabled = !(i % 2);
|
||||||
|
expect (shouldBeEnabled ==
|
||||||
|
(table->isEnabled (amendmentNames[i].id ())));
|
||||||
|
expect (shouldBeSupported ==
|
||||||
|
(table->isSupported (amendmentNames[i].id ())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBD: veto/reportValidations/getJson/doValidation/doVoting
|
||||||
|
// Threading test?
|
||||||
|
|
||||||
|
void run ()
|
||||||
|
{
|
||||||
|
testGet ();
|
||||||
|
testAddInitialAddKnown ();
|
||||||
|
testEnable ();
|
||||||
|
testSupported ();
|
||||||
|
testSupportedEnabled ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE (AmendmentTable, app, ripple);
|
||||||
|
|
||||||
|
} // ripple
|
||||||
@@ -32,6 +32,7 @@ struct ConfigSection
|
|||||||
|
|
||||||
// VFALCO TODO Rename and replace these macros with variables.
|
// VFALCO TODO Rename and replace these macros with variables.
|
||||||
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
|
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
|
||||||
|
#define SECTION_AMENDMENTS "amendments"
|
||||||
#define SECTION_CLUSTER_NODES "cluster_nodes"
|
#define SECTION_CLUSTER_NODES "cluster_nodes"
|
||||||
#define SECTION_DATABASE_PATH "database_path"
|
#define SECTION_DATABASE_PATH "database_path"
|
||||||
#define SECTION_DEBUG_LOGFILE "debug_logfile"
|
#define SECTION_DEBUG_LOGFILE "debug_logfile"
|
||||||
|
|||||||
@@ -30,3 +30,4 @@
|
|||||||
#include <ripple/app/paths/FindPaths.cpp>
|
#include <ripple/app/paths/FindPaths.cpp>
|
||||||
#include <ripple/app/paths/Pathfinder.cpp>
|
#include <ripple/app/paths/Pathfinder.cpp>
|
||||||
#include <ripple/app/misc/AmendmentTableImpl.cpp>
|
#include <ripple/app/misc/AmendmentTableImpl.cpp>
|
||||||
|
#include <ripple/app/misc/tests/AmendmentTable.test.cpp>
|
||||||
|
|||||||
Reference in New Issue
Block a user