mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +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>
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\tests\AmendmentTable.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\misc\Validations.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</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">
|
||||
<UniqueIdentifier>{5A1509B2-871B-A7AC-1E60-544D3F398741}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\app\misc\tests">
|
||||
<UniqueIdentifier>{815DC1A2-E2EF-E6E3-D979-19AD1476A28B}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\app\node">
|
||||
<UniqueIdentifier>{0FCD3973-E9A6-7172-C8A3-C3401E1A03DD}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -2964,6 +2967,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\app\misc\SHAMapStoreImp.h">
|
||||
<Filter>ripple\app\misc</Filter>
|
||||
</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">
|
||||
<Filter>ripple\app\misc</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <ripple/json/json_reader.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/core/LoadFeeTrack.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/net/SNTPClient.h>
|
||||
#include <ripple/nodestore/Database.h>
|
||||
#include <ripple/nodestore/DummyScheduler.h>
|
||||
@@ -317,8 +318,9 @@ public:
|
||||
, m_validators (Validators::make_Manager(*this, get_io_service(),
|
||||
getConfig ().getModuleDatabasePath (), m_logs.journal("UVL")))
|
||||
|
||||
, m_amendmentTable (make_AmendmentTable (weeks(2), MAJORITY_FRACTION,
|
||||
m_logs.journal("AmendmentTable")))
|
||||
, m_amendmentTable (make_AmendmentTable
|
||||
(weeks(2), MAJORITY_FRACTION,
|
||||
m_logs.journal("AmendmentTable")))
|
||||
|
||||
, mFeeTrack (LoadFeeTrack::New (m_logs.journal("LoadManager")))
|
||||
|
||||
@@ -650,7 +652,8 @@ public:
|
||||
if (!getConfig ().RUN_STANDALONE)
|
||||
updateTables ();
|
||||
|
||||
m_amendmentTable->addInitial();
|
||||
m_amendmentTable->addInitial (
|
||||
getConfig ().section (SECTION_AMENDMENTS));
|
||||
initializePathfinding ();
|
||||
|
||||
m_ledgerMaster->setMinValidations (getConfig ().VALIDATION_QUORUM);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define RIPPLE_AMENDMENT_TABLE_H
|
||||
|
||||
#include <ripple/app/book/Types.h>
|
||||
#include <ripple/app/misc/Validations.h>
|
||||
|
||||
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.
|
||||
Tells if a amendment is supported, enabled or vetoed. A vetoed amendment
|
||||
means the node will never announce its support.
|
||||
@@ -53,22 +96,19 @@ public:
|
||||
class AmendmentState
|
||||
{
|
||||
public:
|
||||
bool mVetoed; // We don't want this amendment enabled
|
||||
bool mEnabled;
|
||||
bool mSupported;
|
||||
bool mDefault; // Include in genesis ledger
|
||||
bool mVetoed{false}; // We don't want this amendment enabled
|
||||
bool mEnabled{false};
|
||||
bool mSupported{false};
|
||||
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 m_lastMajority; // Most recent time we saw a majority (close time)
|
||||
core::Clock::time_point
|
||||
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;
|
||||
|
||||
AmendmentState ()
|
||||
: mVetoed (false), mEnabled (false), mSupported (false), mDefault (false),
|
||||
m_firstMajority (0), m_lastMajority (0)
|
||||
{
|
||||
;
|
||||
}
|
||||
AmendmentState () = default;
|
||||
|
||||
void setVeto ()
|
||||
{
|
||||
@@ -104,6 +144,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class Section;
|
||||
|
||||
/** The amendment table stores the list of enabled and potential amendments.
|
||||
Individuals amendments are voted on by validators during the consensus
|
||||
process.
|
||||
@@ -123,10 +165,17 @@ public:
|
||||
|
||||
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 bool veto (uint256 const& amendment) = 0;
|
||||
@@ -138,9 +187,17 @@ public:
|
||||
virtual bool isEnabled (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;
|
||||
/** Support only the specified amendments.
|
||||
Other amendments in the table will be set to unsupported.
|
||||
*/
|
||||
virtual void setSupported (const std::vector<uint256>& amendments) = 0;
|
||||
|
||||
/** Update the walletDB with the majority times.
|
||||
*/
|
||||
virtual void reportValidations (const AmendmentSet&) = 0;
|
||||
|
||||
virtual Json::Value getJson (int) = 0;
|
||||
@@ -154,10 +211,12 @@ public:
|
||||
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<AmendmentTable>
|
||||
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
|
||||
beast::Journal journal);
|
||||
std::unique_ptr<AmendmentTable> make_AmendmentTable (
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
beast::Journal journal,
|
||||
bool useMockFacade = false);
|
||||
|
||||
} // ripple
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,24 +19,24 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/misc/AmendmentTable.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/Validations.h>
|
||||
#include <ripple/app/data/DatabaseCon.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Track the list of "amendments"
|
||||
|
||||
An "amendment" is an option that can affect transaction processing
|
||||
rules that is identified by a 256-bit amendment identifier
|
||||
and adopted, or rejected, by the network.
|
||||
An "amendment" is an option that can affect transaction processing rules.
|
||||
Amendments are proposed and then adopted or rejected by the network. An
|
||||
Amendment is uniquely identified by its AmendmentID, a 256-bit key.
|
||||
*/
|
||||
class AmendmentTableImpl : public AmendmentTable
|
||||
template<class AppApiFacade>
|
||||
class AmendmentTableImpl final : public AmendmentTable
|
||||
{
|
||||
protected:
|
||||
typedef hash_map<uint256, AmendmentState> amendmentMap_t;
|
||||
typedef std::pair<const uint256, AmendmentState> amendmentIt_t;
|
||||
typedef hash_set<uint256> amendmentList_t;
|
||||
|
||||
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_lastReport; // close time of most recent majority report
|
||||
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);
|
||||
void setJson (Json::Value& v, const AmendmentState&);
|
||||
|
||||
public:
|
||||
AmendmentTableImpl (std::chrono::seconds majorityTime, int majorityFraction,
|
||||
beast::Journal journal)
|
||||
AmendmentTableImpl (
|
||||
std::chrono::seconds majorityTime,
|
||||
int majorityFraction,
|
||||
beast::Journal journal)
|
||||
: m_majorityTime (majorityTime)
|
||||
, mMajorityFraction (majorityFraction)
|
||||
, 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;
|
||||
|
||||
bool veto (uint256 const& amendment) override;
|
||||
@@ -97,51 +101,114 @@ public:
|
||||
amendmentList_t getDesired(); // amendments we support, do not veto, are not enabled
|
||||
};
|
||||
|
||||
void
|
||||
AmendmentTableImpl::addInitial ()
|
||||
namespace detail
|
||||
{
|
||||
// For each amendment this version supports, construct the AmendmentState object by calling
|
||||
// addKnown. Set any vetoes or defaults. A pointer to the AmendmentState can be stashed
|
||||
/** preEnabledAmendments is a static collection of amendments that are are
|
||||
enabled at build time.
|
||||
|
||||
Add amendments to this collection at build time to enable them on this
|
||||
server.
|
||||
*/
|
||||
|
||||
std::vector<AmendmentName> const preEnabledAmendments;
|
||||
}
|
||||
|
||||
AmendmentState*
|
||||
AmendmentTableImpl::getCreate (uint256 const& amendmentHash, bool create)
|
||||
template<class AppApiFacade>
|
||||
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
|
||||
auto iter (m_amendmentMap.find (amendmentHash));
|
||||
|
||||
if (iter == m_amendmentMap.end())
|
||||
{
|
||||
if (!create)
|
||||
return nullptr;
|
||||
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
|
||||
AmendmentState& amendment = m_amendmentMap[amendmentHash];
|
||||
m_appApiFacade.setMajorityTimesFromDBToState (amendment, amendmentHash);
|
||||
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);
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
uint256
|
||||
AmendmentTableImpl::get (std::string const& name)
|
||||
AmendmentTableImpl<AppApiFacade>::get (std::string const& name)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
for (auto const& e : m_amendmentMap)
|
||||
{
|
||||
if (name == e.second.mFriendlyName)
|
||||
@@ -151,48 +218,50 @@ AmendmentTableImpl::get (std::string const& name)
|
||||
return uint256 ();
|
||||
}
|
||||
|
||||
AmendmentState*
|
||||
AmendmentTableImpl::addKnown (const char* amendmentID, const char* friendlyName,
|
||||
bool veto)
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl<AppApiFacade>::addKnown (AmendmentName const& name)
|
||||
{
|
||||
uint256 hash;
|
||||
hash.SetHex (amendmentID);
|
||||
|
||||
if (hash.isZero ())
|
||||
if (!name.valid ())
|
||||
{
|
||||
assert (false);
|
||||
return nullptr;
|
||||
std::string const errorMsg =
|
||||
(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)
|
||||
f->setFriendlyName (friendlyName);
|
||||
if (!name.friendlyName ().empty ())
|
||||
amendment.setFriendlyName (name.friendlyName ());
|
||||
|
||||
f->mVetoed = veto;
|
||||
f->mSupported = true;
|
||||
|
||||
return f;
|
||||
amendment.mVetoed = false;
|
||||
amendment.mSupported = true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::veto (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::veto (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, true);
|
||||
AmendmentState& s = getCreate (amendment);
|
||||
|
||||
if (s->mVetoed)
|
||||
if (s.mVetoed)
|
||||
return false;
|
||||
|
||||
s->mVetoed = true;
|
||||
s.mVetoed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::unVeto (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::unVeto (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, false);
|
||||
AmendmentState* s = getExisting (amendment);
|
||||
|
||||
if (!s || !s->mVetoed)
|
||||
return false;
|
||||
@@ -201,24 +270,26 @@ AmendmentTableImpl::unVeto (uint256 const& amendment)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::enable (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::enable (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, true);
|
||||
AmendmentState& s = getCreate (amendment);
|
||||
|
||||
if (s->mEnabled)
|
||||
if (s.mEnabled)
|
||||
return false;
|
||||
|
||||
s->mEnabled = true;
|
||||
s.mEnabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::disable (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::disable (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, false);
|
||||
AmendmentState* s = getExisting (amendment);
|
||||
|
||||
if (!s || !s->mEnabled)
|
||||
return false;
|
||||
@@ -227,24 +298,27 @@ AmendmentTableImpl::disable (uint256 const& amendment)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::isEnabled (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::isEnabled (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, false);
|
||||
AmendmentState* s = getExisting (amendment);
|
||||
return s && s->mEnabled;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::isSupported (uint256 const& amendment)
|
||||
AmendmentTableImpl<AppApiFacade>::isSupported (uint256 const& amendment)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
AmendmentState* s = getCreate (amendment, false);
|
||||
AmendmentState* s = getExisting (amendment);
|
||||
return s && s->mSupported;
|
||||
}
|
||||
|
||||
AmendmentTableImpl::amendmentList_t
|
||||
AmendmentTableImpl::getVetoed ()
|
||||
template<class AppApiFacade>
|
||||
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||
AmendmentTableImpl<AppApiFacade>::getVetoed ()
|
||||
{
|
||||
amendmentList_t ret;
|
||||
ScopedLockType sl (mLock);
|
||||
@@ -256,8 +330,9 @@ AmendmentTableImpl::getVetoed ()
|
||||
return ret;
|
||||
}
|
||||
|
||||
AmendmentTableImpl::amendmentList_t
|
||||
AmendmentTableImpl::getEnabled ()
|
||||
template<class AppApiFacade>
|
||||
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||
AmendmentTableImpl<AppApiFacade>::getEnabled ()
|
||||
{
|
||||
amendmentList_t ret;
|
||||
ScopedLockType sl (mLock);
|
||||
@@ -269,8 +344,9 @@ AmendmentTableImpl::getEnabled ()
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
bool
|
||||
AmendmentTableImpl::shouldEnable (std::uint32_t closeTime,
|
||||
AmendmentTableImpl<AppApiFacade>::shouldEnable (std::uint32_t closeTime,
|
||||
const AmendmentState& fs)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
AmendmentTableImpl::amendmentList_t
|
||||
AmendmentTableImpl::getToEnable (core::Clock::time_point closeTime)
|
||||
template<class AppApiFacade>
|
||||
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||
AmendmentTableImpl<AppApiFacade>::getToEnable (core::Clock::time_point closeTime)
|
||||
{
|
||||
amendmentList_t ret;
|
||||
ScopedLockType sl (mLock);
|
||||
@@ -304,8 +381,9 @@ AmendmentTableImpl::getToEnable (core::Clock::time_point closeTime)
|
||||
return ret;
|
||||
}
|
||||
|
||||
AmendmentTableImpl::amendmentList_t
|
||||
AmendmentTableImpl::getDesired ()
|
||||
template<class AppApiFacade>
|
||||
typename AmendmentTableImpl<AppApiFacade>::amendmentList_t
|
||||
AmendmentTableImpl<AppApiFacade>::getDesired ()
|
||||
{
|
||||
amendmentList_t ret;
|
||||
ScopedLockType sl (mLock);
|
||||
@@ -319,8 +397,9 @@ AmendmentTableImpl::getDesired ()
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
||||
AmendmentTableImpl<AppApiFacade>::reportValidations (const AmendmentSet& set)
|
||||
{
|
||||
if (set.mTrustedValidations == 0)
|
||||
return;
|
||||
@@ -335,7 +414,7 @@ AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
||||
m_firstReport = set.mCloseTime;
|
||||
|
||||
std::vector<uint256> changedAmendments;
|
||||
changedAmendments.resize(set.mVotes.size());
|
||||
changedAmendments.reserve (set.mVotes.size());
|
||||
|
||||
for (auto const& e : set.mVotes)
|
||||
{
|
||||
@@ -378,27 +457,15 @@ AmendmentTableImpl::reportValidations (const AmendmentSet& set)
|
||||
|
||||
if (!changedAmendments.empty())
|
||||
{
|
||||
auto sl (getApp().getWalletDB ().lock ());
|
||||
auto db = getApp().getWalletDB ().getDB ();
|
||||
|
||||
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();
|
||||
m_appApiFacade.setMajorityTimesFromStateToDB (changedAmendments,
|
||||
m_amendmentMap);
|
||||
changedAmendments.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::setEnabled (const std::vector<uint256>& amendments)
|
||||
AmendmentTableImpl<AppApiFacade>::setEnabled (const std::vector<uint256>& amendments)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
for (auto& e : m_amendmentMap)
|
||||
@@ -411,8 +478,9 @@ AmendmentTableImpl::setEnabled (const std::vector<uint256>& amendments)
|
||||
}
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::setSupported (const std::vector<uint256>& amendments)
|
||||
AmendmentTableImpl<AppApiFacade>::setSupported (const std::vector<uint256>& amendments)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
for (auto &e : m_amendmentMap)
|
||||
@@ -425,8 +493,9 @@ AmendmentTableImpl::setSupported (const std::vector<uint256>& amendments)
|
||||
}
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger,
|
||||
AmendmentTableImpl<AppApiFacade>::doValidation (Ledger::ref lastClosedLedger,
|
||||
STObject& baseValidation)
|
||||
{
|
||||
amendmentList_t lAmendments = getDesired();
|
||||
@@ -441,8 +510,9 @@ AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger,
|
||||
baseValidation.setFieldV256 (sfAmendments, vAmendments);
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
||||
AmendmentTableImpl<AppApiFacade>::doVoting (Ledger::ref lastClosedLedger,
|
||||
SHAMap::ref initialPosition)
|
||||
{
|
||||
|
||||
@@ -452,7 +522,8 @@ AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
||||
AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ());
|
||||
|
||||
// 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)
|
||||
{
|
||||
auto const& val = *entry.second;
|
||||
@@ -500,8 +571,9 @@ AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
|
||||
}
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
Json::Value
|
||||
AmendmentTableImpl::getJson (int)
|
||||
AmendmentTableImpl<AppApiFacade>::getJson (int)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
{
|
||||
@@ -514,8 +586,9 @@ AmendmentTableImpl::getJson (int)
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
void
|
||||
AmendmentTableImpl::setJson (Json::Value& v, const AmendmentState& fs)
|
||||
AmendmentTableImpl<AppApiFacade>::setJson (Json::Value& v, const AmendmentState& fs)
|
||||
{
|
||||
if (!fs.mFriendlyName.empty())
|
||||
v["name"] = fs.mFriendlyName;
|
||||
@@ -560,8 +633,9 @@ AmendmentTableImpl::setJson (Json::Value& v, const AmendmentState& fs)
|
||||
v["veto"] = true;
|
||||
}
|
||||
|
||||
template<class AppApiFacade>
|
||||
Json::Value
|
||||
AmendmentTableImpl::getJson (uint256 const& amendmentID)
|
||||
AmendmentTableImpl<AppApiFacade>::getJson (uint256 const& amendmentID)
|
||||
{
|
||||
Json::Value ret = Json::objectValue;
|
||||
Json::Value& jAmendment = (ret[to_string (amendmentID)] = Json::objectValue);
|
||||
@@ -569,19 +643,108 @@ AmendmentTableImpl::getJson (uint256 const& amendmentID)
|
||||
{
|
||||
ScopedLockType sl(mLock);
|
||||
|
||||
AmendmentState *amendmentState = getCreate (amendmentID, true);
|
||||
setJson (jAmendment, *amendmentState);
|
||||
AmendmentState& amendmentState = getCreate (amendmentID);
|
||||
setJson (jAmendment, amendmentState);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<AmendmentTable>
|
||||
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
|
||||
beast::Journal journal)
|
||||
namespace detail
|
||||
{
|
||||
return std::make_unique<AmendmentTableImpl> (majorityTime, majorityFraction,
|
||||
journal);
|
||||
class AppApiFacadeImpl 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;
|
||||
};
|
||||
|
||||
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.
|
||||
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
|
||||
#define SECTION_AMENDMENTS "amendments"
|
||||
#define SECTION_CLUSTER_NODES "cluster_nodes"
|
||||
#define SECTION_DATABASE_PATH "database_path"
|
||||
#define SECTION_DEBUG_LOGFILE "debug_logfile"
|
||||
|
||||
@@ -30,3 +30,4 @@
|
||||
#include <ripple/app/paths/FindPaths.cpp>
|
||||
#include <ripple/app/paths/Pathfinder.cpp>
|
||||
#include <ripple/app/misc/AmendmentTableImpl.cpp>
|
||||
#include <ripple/app/misc/tests/AmendmentTable.test.cpp>
|
||||
|
||||
Reference in New Issue
Block a user