20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/AmendmentTable.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/core/DatabaseCon.h>
24 #include <ripple/protocol/Feature.h>
25 #include <ripple/protocol/STValidation.h>
26 #include <ripple/protocol/TxFlags.h>
27 #include <ripple/protocol/jss.h>
28 #include <boost/format.hpp>
29 #include <boost/regex.hpp>
38 static boost::regex
const re1(
41 "([abcdefABCDEF0-9]{64})"
45 boost::regex_constants::optimize);
49 for (
auto const& line : section.
lines())
53 if (!boost::regex_match(line, match, re1))
54 Throw<std::runtime_error>(
55 "Invalid entry '" + line +
"' in [" + section.
name() +
"]");
59 if (!
id.parseHex(match[1]))
60 Throw<std::runtime_error>(
61 "Invalid amendment ID '" + match[1] +
"' in [" +
62 section.
name() +
"]");
114 for (
auto const& val : valSet)
116 if (val->isTrusted())
124 [&](
auto const& amendment) { ++votes_[amendment]; });
149 auto const& it =
votes_.find(amendment);
169 auto const& it =
votes_.find(amendment);
249 bool vote_to_veto)
const;
279 boost::optional<NetClock::time_point>
321 , majorityTime_(majorityTime)
322 , unsupportedEnabled_(false)
324 , db_(app.getWalletDB())
329 bool const featureVotesExist = [
this]() {
331 soci::transaction tr(*db);
333 "SELECT count(*) FROM sqlite_master "
334 "WHERE type='table' AND name='FeatureVotes'";
335 boost::optional<int> featureVotesCount;
336 *db << sql, soci::into(featureVotesCount);
337 bool exists =
static_cast<bool>(*featureVotesCount);
342 *db <<
"CREATE TABLE FeatureVotes ( "
343 "AmendmentHash CHARACTER(64) NOT NULL, "
344 "AmendmentName TEXT, "
345 "Veto INTEGER NOT NULL );";
354 if (
auto s =
add(a.first, sl))
356 JLOG(
j_.
debug()) <<
"Amendment " << a.first <<
" is supported.";
358 if (!a.second.empty())
369 if (featureVotesExist)
371 JLOG(
j_.
warn()) <<
"[amendments] section in config file ignored"
372 " in favor of data in db/wallet.db.";
377 detect_conflict.
insert(a.first);
385 if (featureVotesExist)
388 <<
"[veto_amendments] section in config file ignored"
389 " in favor of data in db/wallet.db.";
394 if (detect_conflict.
count(a.first) == 0)
401 <<
"[veto_amendments] section in config has amendment "
402 <<
'(' << a.first <<
", " << a.second
403 <<
") both [veto_amendments] and [amendments].";
410 soci::transaction tr(*db);
412 "SELECT AmendmentHash, AmendmentName, Veto FROM FeatureVotes";
413 boost::optional<std::string> amendment_hash;
414 boost::optional<std::string> amendment_name;
415 boost::optional<int> vote_to_veto;
418 soci::into(amendment_hash),
419 soci::into(amendment_name),
420 soci::into(vote_to_veto));
425 if (!amend_hash.
parseHex(*amendment_hash))
427 Throw<std::runtime_error>(
428 "Invalid amendment ID '" + *amendment_hash +
" in wallet.db");
433 if (
auto s =
get(amend_hash, sl))
435 JLOG(
j_.
info()) <<
"Amendment {" << *amendment_name <<
", "
436 << amend_hash <<
"} is vetoed.";
437 if (!amendment_name->empty())
438 s->name = *amendment_name;
444 if (
auto s =
add(amend_hash, sl))
446 JLOG(
j_.
debug()) <<
"Amendment {" << *amendment_name <<
", "
447 << amend_hash <<
"} is un-vetoed.";
448 if (!amendment_name->empty())
449 s->name = *amendment_name;
496 if (name == e.second.name)
507 bool vote_to_veto)
const
510 soci::transaction tr(*db);
512 "INSERT INTO FeatureVotes (AmendmentHash, AmendmentName, Veto) VALUES "
515 sql +=
"', '" + name;
525 auto s =
add(amendment, sl);
538 auto s =
get(amendment, sl);
540 if (!s || !s->vetoed)
551 auto s =
add(amendment, sl);
560 JLOG(
j_.
error()) <<
"Unsupported amendment " << amendment
572 auto s =
get(amendment, sl);
573 return s && s->enabled;
580 auto s =
get(amendment, sl);
581 return s && s->supported;
591 boost::optional<NetClock::time_point>
610 if (e.second.supported && !e.second.vetoed &&
611 (enabled.
count(e.first) == 0))
613 amendments.push_back(e.first);
618 if (!amendments.empty())
619 std::sort(amendments.begin(), amendments.end());
640 <<
": " << enabledAmendments.
size() <<
", "
641 << majorityAmendments.
size() <<
", " << valSet.size();
643 auto vote = std::make_unique<AmendmentSet>(rules, valSet);
645 JLOG(
j_.
debug()) <<
"Received " << vote->trustedValidations()
646 <<
" trusted validations, threshold is: "
647 << vote->threshold();
660 bool const hasValMajority = vote->passes(entry.first);
663 auto const it = majorityAmendments.
find(entry.first);
664 if (it != majorityAmendments.
end())
665 majorityTime = it->second;
668 if (enabledAmendments.
count(entry.first) != 0)
670 JLOG(
j_.
debug()) << entry.first <<
": amendment already enabled";
674 !entry.second.vetoed)
677 JLOG(
j_.
debug()) << entry.first <<
": amendment got majority";
683 JLOG(
j_.
debug()) << entry.first <<
": amendment lost majority";
689 !entry.second.vetoed)
692 JLOG(
j_.
debug()) << entry.first <<
": amendment majority held";
693 actions[entry.first] = 0;
719 for (
auto& e : enabled)
731 for (
auto const& [hash, time] : majority)
733 auto s =
add(hash, sl);
740 JLOG(
j_.
info()) <<
"Unsupported amendment " << hash
741 <<
" reached majority at " <<
to_string(time);
758 v[jss::name] = fs.
name;
761 v[jss::vetoed] = fs.
vetoed;
766 auto const votesTotal =
lastVote_->trustedValidations();
767 auto const votesNeeded =
lastVote_->threshold();
768 auto const votesFor =
lastVote_->votes(
id);
770 v[jss::count] = votesFor;
771 v[jss::validations] = votesTotal;
774 v[jss::threshold] = votesNeeded;
804 auto a =
get(amendmentID, sl);
821 return std::make_unique<AmendmentTableImpl>(
822 app, majorityTime, supported, enabled, vetoed, journal);
Holds a collection of configuration values.
bool supported
Indicates an amendment that this server has code support for.
std::uint32_t lastUpdateSeq_
Current state of an amendment.
boost::optional< NetClock::time_point > firstUnsupportedExpected_
Stream trace() const
Severity stream access functions.
std::vector< uint256 > getDesired() const override
std::vector< uint256 > doValidation(std::set< uint256 > const &enabledAmendments) const override
uint256 find(std::string const &name) const override
bool vetoed
If an amendment is vetoed, a server will not support it.
hash_map< uint256, int > votes_
bool unVeto(uint256 const &amendment) override
boost::optional< NetClock::time_point > firstUnsupportedExpected() const override
std::string to_string(ListDisposition disposition)
The status of all amendments requested in a given window.
const std::uint32_t tfLostMajority
const std::uint32_t tfGotMajority
Track the list of "amendments".
static std::vector< std::pair< uint256, std::string > > parseSection(Section const §ion)
bool passes(uint256 const &amendment) const
Integers of any length that is a multiple of 32-bits.
std::string const & name() const
Returns the name of this section.
T time_since_epoch(T... args)
void persistVote(uint256 const &amendment, std::string const &name, bool vote_to_veto) const
LockedSociSession checkoutDb()
@ objectValue
object value (collection of name/value pairs).
constexpr std::ratio< 204, 256 > preFixAmendmentMajorityCalcThreshold
The minimum amount of support an amendment should have.
const uint256 fixAmendmentMajorityCalc
std::map< uint256, std::uint32_t > doVoting(Rules const &rules, NetClock::time_point closeTime, std::set< uint256 > const &enabledAmendments, majorityAmendments_t const &majorityAmendments, std::vector< std::shared_ptr< STValidation >> const &validations) override
bool isSupported(uint256 const &amendment) const override
AmendmentTableImpl(Application &app, std::chrono::seconds majorityTime, Section const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, Section const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
std::vector< std::string > const & lines() const
Returns all the lines in the section.
A generic endpoint for log messages.
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
bool veto(uint256 const &amendment) override
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
hash_map< uint256, AmendmentState > amendmentMap_
std::unique_ptr< AmendmentSet > lastVote_
const std::chrono::seconds majorityTime_
bool enabled
Indicates that the amendment has been enabled.
AmendmentSet(Rules const &rules, std::vector< std::shared_ptr< STValidation >> const &valSet)
Json::Value getJson() const override
std::string name
The name of this amendment, possibly empty.
Rules controlling protocol behavior.
int trustedValidations() const
bool isEnabled(uint256 const &amendment) const override
void injectJson(Json::Value &v, uint256 const &amendment, AmendmentState const &state, std::lock_guard< std::mutex > const &sl) const
AmendmentState * add(uint256 const &amendment, std::lock_guard< std::mutex > const &sl)
The amendment table stores the list of enabled and potential amendments.
bool needValidatedLedger(LedgerIndex seq) const override
Called to determine whether the amendment logic needs to process a new validated ledger.
int votes(uint256 const &amendment) const
constexpr std::ratio< 80, 100 > postFixAmendmentMajorityCalcThreshold
void doValidatedLedger(LedgerIndex seq, std::set< uint256 > const &enabled, majorityAmendments_t const &majority) override
bool enable(uint256 const &amendment) override
const SF_VECTOR256 sfAmendments
AmendmentState * get(uint256 const &amendment, std::lock_guard< std::mutex > const &sl)
bool hasUnsupportedEnabled() const override
returns true if one or more amendments on the network have been enabled that this server does not sup...