20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/AmendmentTable.h>
22 #include <ripple/app/rdb/Wallet.h>
23 #include <ripple/core/ConfigSections.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() +
"]");
118 newRecordedVotes.reserve(allTrusted.
size());
123 for (
auto& trusted : allTrusted)
134 newRecordedVotes[trusted];
163 using namespace std::chrono_literals;
168 for (
auto const& val : valSet)
171 if (
auto const iter =
recordedVotes_.find(val->getSignerPublic());
174 iter->second.timeout = closeTime + expiresAfter;
178 iter->second.upVotes.assign(choices.begin(), choices.end());
183 iter->second.upVotes.clear();
193 if (closeTime > votes.second.timeout)
195 votes.second.timeout = maxTimeout;
196 votes.second.upVotes.clear();
210 for (
uint256 const& amendment : validatorVotes.second.upVotes)
233 bool enabled =
false;
236 bool supported =
false;
252 int trustedValidations_ = 0;
263 (trustedValidations_ *
269 (trustedValidations_ *
282 auto [trustedCount, newVotes] = trustedVotes.
getVotes(rules, lock);
284 trustedValidations_ = trustedCount;
285 votes_.
swap(newVotes);
287 computeThreshold(trustedValidations_, rules);
293 auto const& it = votes_.
find(amendment);
295 if (it == votes_.
end())
304 trustedValidations_ == 1)
305 return it->second >= threshold_;
307 return it->second > threshold_;
313 auto const& it = votes_.
find(amendment);
315 if (it == votes_.
end())
324 return trustedValidations_;
413 veto(
uint256 const& amendment)
override;
415 unVeto(
uint256 const& amendment)
override;
418 enable(
uint256 const& amendment)
override;
421 isEnabled(
uint256 const& amendment)
const override;
423 isSupported(
uint256 const& amendment)
const override;
426 hasUnsupportedEnabled()
const override;
429 firstUnsupportedExpected()
const override;
437 needValidatedLedger(
LedgerIndex seq)
const override;
452 getDesired()
const override;
473 , majorityTime_(majorityTime)
474 , unsupportedEnabled_(false)
476 , db_(app.getWalletDB())
481 bool const featureVotesExist = [
this]() {
487 for (
auto const& [name, amendment, votebehavior] : supported)
493 switch (votebehavior)
508 JLOG(
j_.
debug()) <<
"Amendment " << amendment <<
" (" << s.
name
509 <<
") is supported and will be "
511 <<
" voted by default if not enabled on the ledger.";
518 if (featureVotesExist)
520 JLOG(
j_.
warn()) <<
"[amendments] section in config file ignored"
521 " in favor of data in db/wallet.db.";
526 detect_conflict.
insert(a.first);
534 if (featureVotesExist)
537 <<
"[veto_amendments] section in config file ignored"
538 " in favor of data in db/wallet.db.";
543 if (detect_conflict.
count(a.first) == 0)
550 <<
"[veto_amendments] section in config has amendment "
551 <<
'(' << a.first <<
", " << a.second
552 <<
") both [veto_amendments] and [amendments].";
561 [&](boost::optional<std::string> amendment_hash,
562 boost::optional<std::string> amendment_name,
563 boost::optional<AmendmentVote> vote) {
565 if (!amendment_hash || !amendment_name || !vote)
568 Throw<std::runtime_error>(
569 "Invalid FeatureVotes row in wallet.db");
571 if (!amend_hash.
parseHex(*amendment_hash))
573 Throw<std::runtime_error>(
574 "Invalid amendment ID '" + *amendment_hash +
580 if (
auto s =
get(amend_hash, lock))
582 JLOG(
j_.
info()) <<
"Amendment {" << *amendment_name <<
", "
583 << amend_hash <<
"} is downvoted.";
584 if (!amendment_name->empty())
585 s->name = *amendment_name;
595 JLOG(
j_.
debug()) <<
"Amendment {" << *amendment_name <<
", "
596 << amend_hash <<
"} is upvoted.";
597 if (!amendment_name->empty())
598 s.
name = *amendment_name;
646 if (name == e.second.name)
703 JLOG(
j_.
error()) <<
"Unsupported amendment " << amendment
754 (enabled.
count(e.first) == 0))
756 amendments.push_back(e.first);
757 JLOG(
j_.
info()) <<
"Voting for amendment " << e.second.name;
762 if (!amendments.empty())
763 std::sort(amendments.begin(), amendments.end());
784 <<
": " << enabledAmendments.
size() <<
", "
785 << majorityAmendments.
size() <<
", " << valSet.size();
795 JLOG(
j_.
debug()) <<
"Received " << vote->trustedValidations()
796 <<
" trusted validations, threshold is: "
797 << vote->threshold();
808 bool const hasValMajority = vote->passes(entry.first);
811 auto const it = majorityAmendments.
find(entry.first);
812 if (it != majorityAmendments.
end())
813 majorityTime = it->second;
816 if (enabledAmendments.
count(entry.first) != 0)
818 JLOG(
j_.
debug()) << entry.first <<
": amendment already enabled";
825 JLOG(
j_.
debug()) << entry.first <<
": amendment got majority";
831 JLOG(
j_.
debug()) << entry.first <<
": amendment lost majority";
840 JLOG(
j_.
debug()) << entry.first <<
": amendment majority held";
841 actions[entry.first] = 0;
867 for (
auto& e : enabled)
879 for (
auto const& [hash, time] : majority)
888 JLOG(
j_.
info()) <<
"Unsupported amendment " << hash
889 <<
" reached majority at " <<
to_string(time);
914 v[jss::name] = fs.
name;
920 v[jss::vetoed] =
"Obsolete";
928 auto const votesTotal =
lastVote_->trustedValidations();
929 auto const votesNeeded =
lastVote_->threshold();
930 auto const votesFor =
lastVote_->votes(
id);
932 v[jss::count] = votesFor;
933 v[jss::validations] = votesTotal;
936 v[jss::threshold] = votesNeeded;
987 return std::make_unique<AmendmentTableImpl>(
988 app, majorityTime, supported, enabled, vetoed, journal);
bool isAdmin(Port const &port, Json::Value const ¶ms, beast::IP::Address const &remoteIp)
constexpr std::uint32_t tfGotMajority
Holds a collection of configuration values.
bool supported
Indicates an amendment that this server has code support for.
constexpr std::uint32_t tfLostMajority
std::uint32_t lastUpdateSeq_
Current state of an amendment.
AmendmentSet(Rules const &rules, TrustedVotes const &trustedVotes, std::lock_guard< std::mutex > const &lock)
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Stream trace() const
Severity stream access functions.
std::optional< NetClock::time_point > firstUnsupportedExpected_
std::vector< uint256 > getDesired() const override
std::vector< uint256 > doValidation(std::set< uint256 > const &enabledAmendments) const override
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
uint256 find(std::string const &name) const override
hash_map< uint256, int > votes_
bool unVeto(uint256 const &amendment) override
AmendmentVote vote
If an amendment is down-voted, a server will not vote to enable it.
The status of all amendments requested in a given window.
Json::Value getJson(bool isAdmin) const override
hash_map< PublicKey, UpvotesAndTimeout > recordedVotes_
Track the list of "amendments".
static std::vector< std::pair< uint256, std::string > > parseSection(Section const §ion)
bool passes(uint256 const &amendment) const
std::string const & name() const
Returns the name of this section.
void injectJson(Json::Value &v, uint256 const &amendment, AmendmentState const &state, bool isAdmin, std::lock_guard< std::mutex > const &lock) const
T time_since_epoch(T... args)
LockedSociSession checkoutDb()
@ objectValue
object value (collection of name/value pairs).
std::optional< NetClock::time_point > firstUnsupportedExpected() const override
constexpr std::ratio< 204, 256 > preFixAmendmentMajorityCalcThreshold
The minimum amount of support an amendment should have.
const uint256 fixAmendmentMajorityCalc
AmendmentTableImpl(Application &app, std::chrono::seconds majorityTime, std::vector< FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
static constexpr NetClock::time_point maxTimeout
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
void readAmendments(soci::session &session, std::function< void(boost::optional< std::string > amendment_hash, boost::optional< std::string > amendment_name, boost::optional< AmendmentVote > vote)> const &callback)
readAmendments Reads all amendments from the FeatureVotes table.
AmendmentState * get(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
bool isSupported(uint256 const &amendment) const override
std::vector< std::string > const & lines() const
Returns all the lines in the section.
std::pair< int, hash_map< uint256, int > > getVotes(Rules const &rules, std::lock_guard< std::mutex > const &lock) const
A generic endpoint for log messages.
void trustChanged(hash_set< PublicKey > const &allTrusted, std::lock_guard< std::mutex > const &lock)
TrustedVotes & operator=(TrustedVotes const &rhs)=delete
TrustedVotes previousTrustedVotes_
bool veto(uint256 const &amendment) override
std::vector< uint256 > upVotes
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
void recordVotes(Rules const &rules, std::vector< std::shared_ptr< STValidation >> const &valSet, NetClock::time_point const closeTime, std::lock_guard< std::mutex > const &lock)
NetClock::time_point timeout
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void computeThreshold(int trustedValidations, Rules const &rules)
hash_map< uint256, AmendmentState > amendmentMap_
std::unique_ptr< AmendmentSet > lastVote_
const std::chrono::seconds majorityTime_
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set the veto value for a particular amendment.
bool enabled
Indicates that the amendment has been enabled.
std::string name
The name of this amendment, possibly empty.
Rules controlling protocol behavior.
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
AmendmentState & add(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
int trustedValidations() const
bool isEnabled(uint256 const &amendment) const override
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
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
TrustedVotes records the most recent votes from trusted validators.
void trustChanged(hash_set< PublicKey > const &allTrusted) override
void persistVote(uint256 const &amendment, std::string const &name, AmendmentVote vote) 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
T & get(EitherAmount &amt)
bool hasUnsupportedEnabled() const override
returns true if one or more amendments on the network have been enabled that this server does not sup...