rippled
Loading...
Searching...
No Matches
AmendmentTable.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/misc/AmendmentTable.h>
22#include <xrpld/app/rdb/Wallet.h>
23#include <xrpld/core/ConfigSections.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/STValidation.h>
26#include <xrpl/protocol/TxFlags.h>
27#include <xrpl/protocol/jss.h>
28#include <boost/format.hpp>
29#include <boost/regex.hpp>
30#include <algorithm>
31#include <mutex>
32
33namespace ripple {
34
36parseSection(Section const& section)
37{
38 static boost::regex const re1(
39 "^" // start of line
40 "(?:\\s*)" // whitespace (optional)
41 "([abcdefABCDEF0-9]{64})" // <hexadecimal amendment ID>
42 "(?:\\s+)" // whitespace
43 "(\\S+)" // <description>
44 ,
45 boost::regex_constants::optimize);
46
48
49 for (auto const& line : section.lines())
50 {
51 boost::smatch match;
52
53 if (!boost::regex_match(line, match, re1))
54 Throw<std::runtime_error>(
55 "Invalid entry '" + line + "' in [" + section.name() + "]");
56
57 uint256 id;
58
59 if (!id.parseHex(match[1]))
60 Throw<std::runtime_error>(
61 "Invalid amendment ID '" + match[1] + "' in [" +
62 section.name() + "]");
63
64 names.push_back(std::make_pair(id, match[2]));
65 }
66
67 return names;
68}
69
89{
90private:
93
94 // Associates each trusted validator with the last votes we saw from them
95 // and an expiration for that record.
97 {
100 };
102
103public:
104 TrustedVotes() = default;
105 TrustedVotes(TrustedVotes const& rhs) = delete;
107 operator=(TrustedVotes const& rhs) = delete;
108
109 // Called when the list of trusted validators changes.
110 //
111 // Call with AmendmentTable::mutex_ locked.
112 void
114 hash_set<PublicKey> const& allTrusted,
115 std::lock_guard<std::mutex> const& lock)
116 {
117 decltype(recordedVotes_) newRecordedVotes;
118 newRecordedVotes.reserve(allTrusted.size());
119
120 // Make sure every PublicKey in allTrusted is represented in
121 // recordedVotes_. Also make sure recordedVotes_ contains
122 // no additional PublicKeys.
123 for (auto& trusted : allTrusted)
124 {
125 if (recordedVotes_.contains(trusted))
126 {
127 // Preserve this validator's previously saved voting state.
128 newRecordedVotes.insert(recordedVotes_.extract(trusted));
129 }
130 else
131 {
132 // New validators have a starting position of no on everything.
133 // Add the entry with an empty vector and maxTimeout.
134 newRecordedVotes[trusted];
135 }
136 }
137 // The votes of any no-longer-trusted validators will be destroyed
138 // when changedTrustedVotes goes out of scope.
139 recordedVotes_.swap(newRecordedVotes);
140 }
141
142 // Called when we receive the latest votes.
143 //
144 // Call with AmendmentTable::mutex_ locked.
145 void
147 Rules const& rules,
149 NetClock::time_point const closeTime,
150 std::lock_guard<std::mutex> const& lock)
151 {
152 // When we get an STValidation we save the upVotes it contains, but
153 // we also set an expiration for those upVotes. The following constant
154 // controls the timeout.
155 //
156 // There really is no "best" timeout to choose for when we finally
157 // lose confidence that we know how a validator is voting. But part
158 // of the point of recording validator votes is to avoid flapping of
159 // amendment votes. A 24h timeout says that we will change the local
160 // record of a validator's vote to "no" 24h after the last vote seen
161 // from that validator. So flapping due to that validator being off
162 // line will happen less frequently than every 24 hours.
163 using namespace std::chrono_literals;
164 static constexpr NetClock::duration expiresAfter = 24h;
165
166 // Walk all validations and replace previous votes from trusted
167 // validators with these newest votes.
168 for (auto const& val : valSet)
169 {
170 // If this validation comes from one of our trusted validators...
171 if (auto const iter = recordedVotes_.find(val->getSignerPublic());
172 iter != recordedVotes_.end())
173 {
174 iter->second.timeout = closeTime + expiresAfter;
175 if (val->isFieldPresent(sfAmendments))
176 {
177 auto const& choices = val->getFieldV256(sfAmendments);
178 iter->second.upVotes.assign(choices.begin(), choices.end());
179 }
180 else
181 {
182 // This validator does not upVote any amendments right now.
183 iter->second.upVotes.clear();
184 }
185 }
186 }
187
188 // Now remove any expired records from recordedVotes_.
190 recordedVotes_.begin(),
191 recordedVotes_.end(),
192 [&closeTime](decltype(recordedVotes_)::value_type& votes) {
193 if (closeTime > votes.second.timeout)
194 {
195 votes.second.timeout = maxTimeout;
196 votes.second.upVotes.clear();
197 }
198 });
199 }
200
201 // Return the information needed by AmendmentSet to determine votes.
202 //
203 // Call with AmendmentTable::mutex_ locked.
205 getVotes(Rules const& rules, std::lock_guard<std::mutex> const& lock) const
206 {
208 for (auto& validatorVotes : recordedVotes_)
209 {
210 for (uint256 const& amendment : validatorVotes.second.upVotes)
211 {
212 ret[amendment] += 1;
213 }
214 }
215 return {recordedVotes_.size(), ret};
216 }
217};
218
224{
226 AmendmentVote vote = AmendmentVote::down;
227
233 bool enabled = false;
234
236 bool supported = false;
237
240
241 explicit AmendmentState() = default;
242};
243
246{
247private:
248 // How many yes votes each amendment received
250 Rules const& rules_;
251 // number of trusted validations
252 int trustedValidations_ = 0;
253 // number of votes needed
254 int threshold_ = 0;
255
256 void
257 computeThreshold(int trustedValidations, Rules const& rules)
258 {
259 threshold_ = !rules_.enabled(fixAmendmentMajorityCalc)
260 ? std::max(
261 1L,
262 static_cast<long>(
263 (trustedValidations_ *
266 : std::max(
267 1L,
268 static_cast<long>(
269 (trustedValidations_ *
272 }
273
274public:
276 Rules const& rules,
277 TrustedVotes const& trustedVotes,
278 std::lock_guard<std::mutex> const& lock)
279 : rules_(rules)
280 {
281 // process validations for ledger before flag ledger.
282 auto [trustedCount, newVotes] = trustedVotes.getVotes(rules, lock);
283
284 trustedValidations_ = trustedCount;
285 votes_.swap(newVotes);
286
287 computeThreshold(trustedValidations_, rules);
288 }
289
290 bool
291 passes(uint256 const& amendment) const
292 {
293 auto const& it = votes_.find(amendment);
294
295 if (it == votes_.end())
296 return false;
297
298 // Before this fix, it was possible for an amendment to activate with a
299 // percentage slightly less than 80% because we compared for "greater
300 // than or equal to" instead of strictly "greater than".
301 // One validator is an exception, otherwise it is not possible
302 // to gain majority.
303 if (!rules_.enabled(fixAmendmentMajorityCalc) ||
304 trustedValidations_ == 1)
305 return it->second >= threshold_;
306
307 return it->second > threshold_;
308 }
309
310 int
311 votes(uint256 const& amendment) const
312 {
313 auto const& it = votes_.find(amendment);
314
315 if (it == votes_.end())
316 return 0;
317
318 return it->second;
319 }
320
321 int
323 {
324 return trustedValidations_;
325 }
326
327 int
328 threshold() const
329 {
330 return threshold_;
331 }
332};
333
334//------------------------------------------------------------------------------
335
343{
344private:
346
349
350 // Record of the last votes seen from trusted validators.
352
353 // Time that an amendment must hold a majority for
355
356 // The results of the last voting round - may be empty if
357 // we haven't participated in one yet.
359
360 // True if an unsupported amendment is enabled
362
363 // Unset if no unsupported amendments reach majority,
364 // else set to the earliest time an unsupported amendment
365 // will be enabled.
367
369
370 // Database which persists veto/unveto vote
372
373 // Finds or creates state. Must be called with mutex_ locked.
375 add(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
376
377 // Finds existing state. Must be called with mutex_ locked.
379 get(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
380
381 AmendmentState const*
382 get(uint256 const& amendment,
383 std::lock_guard<std::mutex> const& lock) const;
384
385 // Injects amendment json into v. Must be called with mutex_ locked.
386 void
387 injectJson(
388 Json::Value& v,
389 uint256 const& amendment,
390 AmendmentState const& state,
391 bool isAdmin,
392 std::lock_guard<std::mutex> const& lock) const;
393
394 void
395 persistVote(
396 uint256 const& amendment,
397 std::string const& name,
398 AmendmentVote vote) const;
399
400public:
402 Application& app,
403 std::chrono::seconds majorityTime,
404 std::vector<FeatureInfo> const& supported,
405 Section const& enabled,
406 Section const& vetoed,
407 beast::Journal journal);
408
409 uint256
410 find(std::string const& name) const override;
411
412 bool
413 veto(uint256 const& amendment) override;
414 bool
415 unVeto(uint256 const& amendment) override;
416
417 bool
418 enable(uint256 const& amendment) override;
419
420 bool
421 isEnabled(uint256 const& amendment) const override;
422 bool
423 isSupported(uint256 const& amendment) const override;
424
425 bool
426 hasUnsupportedEnabled() const override;
427
429 firstUnsupportedExpected() const override;
430
432 getJson(bool isAdmin) const override;
434 getJson(uint256 const&, bool isAdmin) const override;
435
436 bool
437 needValidatedLedger(LedgerIndex seq) const override;
438
439 void
440 doValidatedLedger(
441 LedgerIndex seq,
442 std::set<uint256> const& enabled,
443 majorityAmendments_t const& majority) override;
444
445 void
446 trustChanged(hash_set<PublicKey> const& allTrusted) override;
447
449 doValidation(std::set<uint256> const& enabledAmendments) const override;
450
452 getDesired() const override;
453
455 doVoting(
456 Rules const& rules,
457 NetClock::time_point closeTime,
458 std::set<uint256> const& enabledAmendments,
459 majorityAmendments_t const& majorityAmendments,
460 std::vector<std::shared_ptr<STValidation>> const& validations) override;
461};
462
463//------------------------------------------------------------------------------
464
465AmendmentTableImpl::AmendmentTableImpl(
466 Application& app,
467 std::chrono::seconds majorityTime,
468 std::vector<FeatureInfo> const& supported,
469 Section const& enabled,
470 Section const& vetoed,
471 beast::Journal journal)
472 : lastUpdateSeq_(0)
473 , majorityTime_(majorityTime)
474 , unsupportedEnabled_(false)
475 , j_(journal)
476 , db_(app.getWalletDB())
477{
479
480 // Find out if the FeatureVotes table exists in WalletDB
481 bool const featureVotesExist = [this]() {
482 auto db = db_.checkoutDb();
483 return createFeatureVotes(*db);
484 }();
485
486 // Parse supported amendments
487 for (auto const& [name, amendment, votebehavior] : supported)
488 {
489 AmendmentState& s = add(amendment, lock);
490
491 s.name = name;
492 s.supported = true;
493 switch (votebehavior)
494 {
497 break;
498
501 break;
502
505 break;
506 }
507
508 JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name
509 << ") is supported and will be "
510 << (s.vote == AmendmentVote::up ? "up" : "down")
511 << " voted by default if not enabled on the ledger.";
512 }
513
514 hash_set<uint256> detect_conflict;
515 // Parse enabled amendments from config
516 for (std::pair<uint256, std::string> const& a : parseSection(enabled))
517 {
518 if (featureVotesExist)
519 { // If the table existed, warn about duplicate config info
520 JLOG(j_.warn()) << "[amendments] section in config file ignored"
521 " in favor of data in db/wallet.db.";
522 break;
523 }
524 else
525 { // Otherwise transfer config data into the table
526 detect_conflict.insert(a.first);
527 persistVote(a.first, a.second, AmendmentVote::up);
528 }
529 }
530
531 // Parse vetoed amendments from config
532 for (auto const& a : parseSection(vetoed))
533 {
534 if (featureVotesExist)
535 { // If the table existed, warn about duplicate config info
536 JLOG(j_.warn())
537 << "[veto_amendments] section in config file ignored"
538 " in favor of data in db/wallet.db.";
539 break;
540 }
541 else
542 { // Otherwise transfer config data into the table
543 if (detect_conflict.count(a.first) == 0)
544 {
545 persistVote(a.first, a.second, AmendmentVote::down);
546 }
547 else
548 {
549 JLOG(j_.warn())
550 << "[veto_amendments] section in config has amendment "
551 << '(' << a.first << ", " << a.second
552 << ") both [veto_amendments] and [amendments].";
553 }
554 }
555 }
556
557 // Read amendment votes from wallet.db
558 auto db = db_.checkoutDb();
560 *db,
561 [&](boost::optional<std::string> amendment_hash,
562 boost::optional<std::string> amendment_name,
563 boost::optional<AmendmentVote> vote) {
564 uint256 amend_hash;
565 if (!amendment_hash || !amendment_name || !vote)
566 {
567 // These fields should never have nulls, but check
568 Throw<std::runtime_error>(
569 "Invalid FeatureVotes row in wallet.db");
570 }
571 if (!amend_hash.parseHex(*amendment_hash))
572 {
573 Throw<std::runtime_error>(
574 "Invalid amendment ID '" + *amendment_hash +
575 " in wallet.db");
576 }
577 if (*vote == AmendmentVote::down)
578 {
579 // Unknown amendments are effectively vetoed already
580 if (auto s = get(amend_hash, lock))
581 {
582 JLOG(j_.info()) << "Amendment {" << *amendment_name << ", "
583 << amend_hash << "} is downvoted.";
584 if (!amendment_name->empty())
585 s->name = *amendment_name;
586 // An obsolete amendment's vote can never be changed
587 if (s->vote != AmendmentVote::obsolete)
588 s->vote = *vote;
589 }
590 }
591 else // up-vote
592 {
593 AmendmentState& s = add(amend_hash, lock);
594
595 JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", "
596 << amend_hash << "} is upvoted.";
597 if (!amendment_name->empty())
598 s.name = *amendment_name;
599 // An obsolete amendment's vote can never be changed
601 s.vote = *vote;
602 }
603 });
604}
605
608 uint256 const& amendmentHash,
610{
611 // call with the mutex held
612 return amendmentMap_[amendmentHash];
613}
614
617 uint256 const& amendmentHash,
618 std::lock_guard<std::mutex> const& lock)
619{
620 // Forward to the const version of get.
621 return const_cast<AmendmentState*>(
622 std::as_const(*this).get(amendmentHash, lock));
623}
624
625AmendmentState const*
627 uint256 const& amendmentHash,
628 std::lock_guard<std::mutex> const&) const
629{
630 // call with the mutex held
631 auto ret = amendmentMap_.find(amendmentHash);
632
633 if (ret == amendmentMap_.end())
634 return nullptr;
635
636 return &ret->second;
637}
638
641{
643
644 for (auto const& e : amendmentMap_)
645 {
646 if (name == e.second.name)
647 return e.first;
648 }
649
650 return {};
651}
652
653void
655 uint256 const& amendment,
656 std::string const& name,
657 AmendmentVote vote) const
658{
659 XRPL_ASSERT(
661 "ripple::AmendmentTableImpl::persistVote : valid vote input");
662 auto db = db_.checkoutDb();
663 voteAmendment(*db, amendment, name, vote);
664}
665
666bool
668{
670 AmendmentState& s = add(amendment, lock);
671
672 if (s.vote != AmendmentVote::up)
673 return false;
675 persistVote(amendment, s.name, s.vote);
676 return true;
677}
678
679bool
681{
683 AmendmentState* const s = get(amendment, lock);
684
685 if (!s || s->vote != AmendmentVote::down)
686 return false;
688 persistVote(amendment, s->name, s->vote);
689 return true;
690}
691
692bool
694{
696 AmendmentState& s = add(amendment, lock);
697
698 if (s.enabled)
699 return false;
700
701 s.enabled = true;
702
703 if (!s.supported)
704 {
705 JLOG(j_.error()) << "Unsupported amendment " << amendment
706 << " activated.";
707 unsupportedEnabled_ = true;
708 }
709
710 return true;
711}
712
713bool
715{
717 AmendmentState const* s = get(amendment, lock);
718 return s && s->enabled;
719}
720
721bool
723{
725 AmendmentState const* s = get(amendment, lock);
726 return s && s->supported;
727}
728
729bool
731{
733 return unsupportedEnabled_;
734}
735
738{
741}
742
745{
746 // Get the list of amendments we support and do not
747 // veto, but that are not already enabled
748 std::vector<uint256> amendments;
749
750 {
752 amendments.reserve(amendmentMap_.size());
753 for (auto const& e : amendmentMap_)
754 {
755 if (e.second.supported && e.second.vote == AmendmentVote::up &&
756 (enabled.count(e.first) == 0))
757 {
758 amendments.push_back(e.first);
759 JLOG(j_.info()) << "Voting for amendment " << e.second.name;
760 }
761 }
762 }
763
764 if (!amendments.empty())
765 std::sort(amendments.begin(), amendments.end());
766
767 return amendments;
768}
769
772{
773 // Get the list of amendments we support and do not veto
774 return doValidation({});
775}
776
779 Rules const& rules,
780 NetClock::time_point closeTime,
781 std::set<uint256> const& enabledAmendments,
782 majorityAmendments_t const& majorityAmendments,
784{
785 JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count()
786 << ": " << enabledAmendments.size() << ", "
787 << majorityAmendments.size() << ", " << valSet.size();
788
790
791 // Keep a record of the votes we received.
792 previousTrustedVotes_.recordVotes(rules, valSet, closeTime, lock);
793
794 // Tally the most recent votes.
795 auto vote =
796 std::make_unique<AmendmentSet>(rules, previousTrustedVotes_, lock);
797 JLOG(j_.debug()) << "Received " << vote->trustedValidations()
798 << " trusted validations, threshold is: "
799 << vote->threshold();
800
801 // Map of amendments to the action to be taken for each one. The action is
802 // the value of the flags in the pseudo-transaction
804
805 // process all amendments we know of
806 for (auto const& entry : amendmentMap_)
807 {
808 NetClock::time_point majorityTime = {};
809
810 bool const hasValMajority = vote->passes(entry.first);
811
812 {
813 auto const it = majorityAmendments.find(entry.first);
814 if (it != majorityAmendments.end())
815 majorityTime = it->second;
816 }
817
818 if (enabledAmendments.count(entry.first) != 0)
819 {
820 JLOG(j_.debug()) << entry.first << ": amendment already enabled";
821 }
822 else if (
823 hasValMajority && (majorityTime == NetClock::time_point{}) &&
824 entry.second.vote == AmendmentVote::up)
825 {
826 // Ledger says no majority, validators say yes
827 JLOG(j_.debug()) << entry.first << ": amendment got majority";
828 actions[entry.first] = tfGotMajority;
829 }
830 else if (!hasValMajority && (majorityTime != NetClock::time_point{}))
831 {
832 // Ledger says majority, validators say no
833 JLOG(j_.debug()) << entry.first << ": amendment lost majority";
834 actions[entry.first] = tfLostMajority;
835 }
836 else if (
837 (majorityTime != NetClock::time_point{}) &&
838 ((majorityTime + majorityTime_) <= closeTime) &&
839 entry.second.vote == AmendmentVote::up)
840 {
841 // Ledger says majority held
842 JLOG(j_.debug()) << entry.first << ": amendment majority held";
843 actions[entry.first] = 0;
844 }
845 }
846
847 // Stash for reporting
848 lastVote_ = std::move(vote);
849 return actions;
850}
851
852bool
854{
856
857 // Is there a ledger in which an amendment could have been enabled
858 // between these two ledger sequences?
859
860 return ((ledgerSeq - 1) / 256) != ((lastUpdateSeq_ - 1) / 256);
861}
862
863void
865 LedgerIndex ledgerSeq,
866 std::set<uint256> const& enabled,
867 majorityAmendments_t const& majority)
868{
869 for (auto& e : enabled)
870 enable(e);
871
873
874 // Remember the ledger sequence of this update.
875 lastUpdateSeq_ = ledgerSeq;
876
877 // Since we have the whole list in `majority`, reset the time flag, even
878 // if it's currently set. If it's not set when the loop is done, then any
879 // prior unknown amendments have lost majority.
881 for (auto const& [hash, time] : majority)
882 {
883 AmendmentState& s = add(hash, lock);
884
885 if (s.enabled)
886 continue;
887
888 if (!s.supported)
889 {
890 JLOG(j_.info()) << "Unsupported amendment " << hash
891 << " reached majority at " << to_string(time);
894 }
895 }
898}
899
900void
902{
904 previousTrustedVotes_.trustChanged(allTrusted, lock);
905}
906
907void
909 Json::Value& v,
910 const uint256& id,
911 const AmendmentState& fs,
912 bool isAdmin,
913 std::lock_guard<std::mutex> const&) const
914{
915 if (!fs.name.empty())
916 v[jss::name] = fs.name;
917
918 v[jss::supported] = fs.supported;
919 if (!fs.enabled && isAdmin)
920 {
922 v[jss::vetoed] = "Obsolete";
923 else
924 v[jss::vetoed] = fs.vote == AmendmentVote::down;
925 }
926 v[jss::enabled] = fs.enabled;
927
928 if (!fs.enabled && lastVote_ && isAdmin)
929 {
930 auto const votesTotal = lastVote_->trustedValidations();
931 auto const votesNeeded = lastVote_->threshold();
932 auto const votesFor = lastVote_->votes(id);
933
934 v[jss::count] = votesFor;
935 v[jss::validations] = votesTotal;
936
937 if (votesNeeded)
938 v[jss::threshold] = votesNeeded;
939 }
940}
941
944{
946 {
948 for (auto const& e : amendmentMap_)
949 {
951 ret[to_string(e.first)] = Json::objectValue,
952 e.first,
953 e.second,
954 isAdmin,
955 lock);
956 }
957 }
958 return ret;
959}
960
962AmendmentTableImpl::getJson(uint256 const& amendmentID, bool isAdmin) const
963{
965
966 {
968 AmendmentState const* a = get(amendmentID, lock);
969 if (a)
970 {
971 Json::Value& jAmendment =
972 (ret[to_string(amendmentID)] = Json::objectValue);
973 injectJson(jAmendment, amendmentID, *a, isAdmin, lock);
974 }
975 }
976
977 return ret;
978}
979
982 Application& app,
983 std::chrono::seconds majorityTime,
985 Section const& enabled,
986 Section const& vetoed,
987 beast::Journal journal)
988{
989 return std::make_unique<AmendmentTableImpl>(
990 app, majorityTime, supported, enabled, vetoed, journal);
991}
992
993} // namespace ripple
T as_const(T... args)
Represents a JSON value.
Definition: json_value.h:147
A generic endpoint for log messages.
Definition: Journal.h:59
Stream error() const
Definition: Journal.h:335
Stream debug() const
Definition: Journal.h:317
Stream info() const
Definition: Journal.h:323
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Stream warn() const
Definition: Journal.h:329
The status of all amendments requested in a given window.
int votes(uint256 const &amendment) const
int trustedValidations() const
void computeThreshold(int trustedValidations, Rules const &rules)
bool passes(uint256 const &amendment) const
hash_map< uint256, int > votes_
AmendmentSet(Rules const &rules, TrustedVotes const &trustedVotes, std::lock_guard< std::mutex > const &lock)
Track the list of "amendments".
uint256 find(std::string const &name) const override
bool unVeto(uint256 const &amendment) override
bool enable(uint256 const &amendment) override
bool needValidatedLedger(LedgerIndex seq) const override
Called to determine whether the amendment logic needs to process a new validated ledger.
std::optional< NetClock::time_point > firstUnsupportedExpected_
std::vector< uint256 > getDesired() const override
bool veto(uint256 const &amendment) override
std::unique_ptr< AmendmentSet > lastVote_
std::chrono::seconds const majorityTime_
void doValidatedLedger(LedgerIndex seq, std::set< uint256 > const &enabled, majorityAmendments_t const &majority) override
bool isEnabled(uint256 const &amendment) const override
AmendmentState & add(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
hash_map< uint256, AmendmentState > amendmentMap_
void injectJson(Json::Value &v, uint256 const &amendment, AmendmentState const &state, bool isAdmin, std::lock_guard< std::mutex > const &lock) const
beast::Journal const j_
Json::Value getJson(bool isAdmin) const override
void trustChanged(hash_set< PublicKey > const &allTrusted) override
std::vector< uint256 > doValidation(std::set< uint256 > const &enabledAmendments) const override
AmendmentState * get(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
void persistVote(uint256 const &amendment, std::string const &name, AmendmentVote vote) const
bool hasUnsupportedEnabled() const override
returns true if one or more amendments on the network have been enabled that this server does not sup...
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
std::optional< NetClock::time_point > firstUnsupportedExpected() const override
The amendment table stores the list of enabled and potential amendments.
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:188
Rules controlling protocol behavior.
Definition: Rules.h:35
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:122
Holds a collection of configuration values.
Definition: BasicConfig.h:46
std::string const & name() const
Returns the name of this section.
Definition: BasicConfig.h:62
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition: BasicConfig.h:71
TrustedVotes records the most recent votes from trusted validators.
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)
std::pair< int, hash_map< uint256, int > > getVotes(Rules const &rules, std::lock_guard< std::mutex > const &lock) const
hash_map< PublicKey, UpvotesAndTimeout > recordedVotes_
TrustedVotes & operator=(TrustedVotes const &rhs)=delete
static constexpr NetClock::time_point maxTimeout
void trustChanged(hash_set< PublicKey > const &allTrusted, std::lock_guard< std::mutex > const &lock)
TrustedVotes(TrustedVotes const &rhs)=delete
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:502
T count(T... args)
T empty(T... args)
T end(T... args)
T find(T... args)
T for_each(T... args)
T insert(T... args)
T make_pair(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
static std::vector< std::pair< uint256, std::string > > parseSection(Section const &section)
AmendmentVote
Definition: Wallet.h:152
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:124
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition: Wallet.cpp:228
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.
Definition: Wallet.cpp:252
constexpr std::ratio< 80, 100 > postFixAmendmentMajorityCalcThreshold
constexpr std::ratio< 204, 256 > preFixAmendmentMajorityCalcThreshold
The minimum amount of support an amendment should have.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Definition: BasicConfig.h:356
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
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)
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:125
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set the veto value for a particular amendment.
Definition: Wallet.cpp:288
T push_back(T... args)
T size(T... args)
T sort(T... args)
Current state of an amendment.
bool supported
Indicates an amendment that this server has code support for.
bool enabled
Indicates that the amendment has been enabled.
std::string name
The name of this amendment, possibly empty.
AmendmentVote vote
If an amendment is down-voted, a server will not vote to enable it.
T swap(T... args)
T time_since_epoch(T... args)