rippled
Loading...
Searching...
No Matches
AmendmentTable.cpp
1#include <xrpl/core/ServiceRegistry.h>
2#include <xrpl/ledger/AmendmentTable.h>
3#include <xrpl/protocol/Feature.h>
4#include <xrpl/protocol/STValidation.h>
5#include <xrpl/protocol/TxFlags.h>
6#include <xrpl/protocol/jss.h>
7#include <xrpl/server/Wallet.h>
8
9#include <boost/algorithm/string.hpp>
10#include <boost/format.hpp>
11#include <boost/range/adaptor/transformed.hpp>
12#include <boost/regex.hpp>
13
14#include <algorithm>
15#include <mutex>
16
17namespace xrpl {
18
20parseSection(Section const& section)
21{
22 static boost::regex const re1(
23 "^" // start of line
24 "(?:\\s*)" // whitespace (optional)
25 "([abcdefABCDEF0-9]{64})" // <hexadecimal amendment ID>
26 "(?:\\s+)" // whitespace
27 "(\\S+)" // <description>
28 ,
29 boost::regex_constants::optimize);
30
32
33 for (auto const& line : section.lines())
34 {
35 boost::smatch match;
36
37 if (!boost::regex_match(line, match, re1))
38 Throw<std::runtime_error>("Invalid entry '" + line + "' in [" + section.name() + "]");
39
40 uint256 id;
41
42 if (!id.parseHex(match[1]))
43 Throw<std::runtime_error>(
44 "Invalid amendment ID '" + match[1] + "' in [" + section.name() + "]");
45
46 names.push_back(std::make_pair(id, match[2]));
47 }
48
49 return names;
50}
51
71{
72private:
73 // Associates each trusted validator with the last votes we saw from them
74 // and an expiration for that record.
86
87public:
88 TrustedVotes() = default;
89 TrustedVotes(TrustedVotes const& rhs) = delete;
91 operator=(TrustedVotes const& rhs) = delete;
92
93 // Called when the list of trusted validators changes.
94 //
95 // Call with AmendmentTable::mutex_ locked.
96 void
98 {
99 decltype(recordedVotes_) newRecordedVotes;
100 newRecordedVotes.reserve(allTrusted.size());
101
102 // Make sure every PublicKey in allTrusted is represented in
103 // recordedVotes_. Also make sure recordedVotes_ contains
104 // no additional PublicKeys.
105 for (auto& trusted : allTrusted)
106 {
107 if (recordedVotes_.contains(trusted))
108 {
109 // Preserve this validator's previously saved voting state.
110 newRecordedVotes.insert(recordedVotes_.extract(trusted));
111 }
112 else
113 {
114 // New validators have a starting position of no on everything.
115 // Add the entry with an empty vector and unseated timeout.
116 newRecordedVotes[trusted];
117 }
118 }
119 // The votes of any no-longer-trusted validators will be destroyed
120 // when changedTrustedVotes goes out of scope.
121 recordedVotes_.swap(newRecordedVotes);
122 }
123
124 // Called when we receive the latest votes.
125 //
126 // Call with AmendmentTable::mutex_ locked.
127 void
129 Rules const& rules,
131 NetClock::time_point const closeTime,
133 std::lock_guard<std::mutex> const& lock)
134 {
135 // When we get an STValidation we save the upVotes it contains, but
136 // we also set an expiration for those upVotes. The following constant
137 // controls the timeout.
138 //
139 // There really is no "best" timeout to choose for when we finally
140 // lose confidence that we know how a validator is voting. But part
141 // of the point of recording validator votes is to avoid flapping of
142 // amendment votes. A 24h timeout says that we will change the local
143 // record of a validator's vote to "no" 24h after the last vote seen
144 // from that validator. So flapping due to that validator being off
145 // line will happen less frequently than every 24 hours.
146 using namespace std::chrono_literals;
147 static constexpr NetClock::duration expiresAfter = 24h;
148
149 auto const newTimeout = closeTime + expiresAfter;
150
151 // Walk all validations and replace previous votes from trusted
152 // validators with these newest votes.
153 for (auto const& val : valSet)
154 {
155 auto const pkHuman = toBase58(TokenType::NodePublic, val->getSignerPublic());
156 // If this validation comes from one of our trusted validators...
157 if (auto const iter = recordedVotes_.find(val->getSignerPublic());
158 iter != recordedVotes_.end())
159 {
160 iter->second.timeout = newTimeout;
161 if (val->isFieldPresent(sfAmendments))
162 {
163 auto const& choices = val->getFieldV256(sfAmendments);
164 iter->second.upVotes.assign(choices.begin(), choices.end());
165 JLOG(j.debug()) << "recordVotes: Validation from trusted " << pkHuman << " has "
166 << choices.size() << " amendment votes: "
167 << boost::algorithm::join(
168 iter->second.upVotes |
169 boost::adaptors::transformed(to_string<256, void>),
170 ", ");
171 // TODO: Maybe transform using to_short_string once #5126 is
172 // merged
173 //
174 // iter->second.upVotes |
175 // boost::adaptors::transformed(to_short_string<256, void>)
176 }
177 else
178 {
179 // This validator does not upVote any amendments right now.
180 iter->second.upVotes.clear();
181 JLOG(j.debug()) << "recordVotes: Validation from trusted " << pkHuman
182 << " has no amendment votes.";
183 }
184 }
185 else
186 {
187 JLOG(j.debug()) << "recordVotes: Ignoring validation from untrusted " << pkHuman;
188 }
189 }
190
191 // Now remove any expired records from recordedVotes_.
193 recordedVotes_.begin(),
194 recordedVotes_.end(),
195 [&closeTime, newTimeout, &j](decltype(recordedVotes_)::value_type& votes) {
196 auto const pkHuman = toBase58(TokenType::NodePublic, votes.first);
197 if (!votes.second.timeout)
198 {
199 XRPL_ASSERT(
200 votes.second.upVotes.empty(),
201 "xrpl::TrustedVotes::recordVotes : received no "
202 "upvotes");
203 JLOG(j.debug()) << "recordVotes: Have not received any "
204 "amendment votes from "
205 << pkHuman << " since last timeout or startup";
206 }
207 else if (closeTime > votes.second.timeout)
208 {
209 JLOG(j.debug()) << "recordVotes: Timeout: Clearing votes from " << pkHuman;
210 votes.second.timeout.reset();
211 votes.second.upVotes.clear();
212 }
213 else if (votes.second.timeout != newTimeout)
214 {
215 XRPL_ASSERT(
216 votes.second.timeout < newTimeout,
217 "xrpl::TrustedVotes::recordVotes : votes not "
218 "expired");
219 using namespace std::chrono;
220 auto const age = duration_cast<minutes>(newTimeout - *votes.second.timeout);
221 JLOG(j.debug()) << "recordVotes: Using " << age.count()
222 << "min old cached votes from " << pkHuman;
223 }
224 });
225 }
226
227 // Return the information needed by AmendmentSet to determine votes.
228 //
229 // Call with AmendmentTable::mutex_ locked.
231 getVotes(Rules const& rules, std::lock_guard<std::mutex> const& lock) const
232 {
234 int available = 0;
235 for (auto& validatorVotes : recordedVotes_)
236 {
237 XRPL_ASSERT(
238 validatorVotes.second.timeout || validatorVotes.second.upVotes.empty(),
239 "xrpl::TrustedVotes::getVotes : valid votes");
240 if (validatorVotes.second.timeout)
241 ++available;
242 for (uint256 const& amendment : validatorVotes.second.upVotes)
243 {
244 ret[amendment] += 1;
245 }
246 }
247 return {available, ret};
248 }
249};
250
256{
258 AmendmentVote vote = AmendmentVote::down;
259
265 bool enabled = false;
266
268 bool supported = false;
269
272
273 explicit AmendmentState() = default;
274};
275
278{
279private:
280 // How many yes votes each amendment received
282 // number of trusted validations
283 int trustedValidations_ = 0;
284 // number of votes needed
285 int threshold_ = 0;
286
287public:
289 Rules const& rules,
290 TrustedVotes const& trustedVotes,
291 std::lock_guard<std::mutex> const& lock)
292 {
293 // process validations for ledger before flag ledger.
294 auto [trustedCount, newVotes] = trustedVotes.getVotes(rules, lock);
295
296 trustedValidations_ = trustedCount;
297 votes_.swap(newVotes);
298
299 threshold_ = std::max(
300 1L,
301 static_cast<long>(
302 (trustedValidations_ * amendmentMajorityCalcThreshold.num) /
304 }
305
306 bool
307 passes(uint256 const& amendment) const
308 {
309 auto const& it = votes_.find(amendment);
310
311 if (it == votes_.end())
312 return false;
313
314 // One validator is an exception, otherwise it is not possible
315 // to gain majority.
316 if (trustedValidations_ == 1)
317 return it->second >= threshold_;
318
319 return it->second > threshold_;
320 }
321
322 int
323 votes(uint256 const& amendment) const
324 {
325 auto const& it = votes_.find(amendment);
326
327 if (it == votes_.end())
328 return 0;
329
330 return it->second;
331 }
332
333 int
335 {
336 return trustedValidations_;
337 }
338
339 int
340 threshold() const
341 {
342 return threshold_;
343 }
344};
345
346//------------------------------------------------------------------------------
347
355{
356private:
358
361
362 // Record of the last votes seen from trusted validators.
364
365 // Time that an amendment must hold a majority for
367
368 // The results of the last voting round - may be empty if
369 // we haven't participated in one yet.
371
372 // True if an unsupported amendment is enabled
374
375 // Unset if no unsupported amendments reach majority,
376 // else set to the earliest time an unsupported amendment
377 // will be enabled.
379
381
382 // Database which persists veto/unveto vote
384
385 // Finds or creates state. Must be called with mutex_ locked.
387 add(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
388
389 // Finds existing state. Must be called with mutex_ locked.
391 get(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
392
393 AmendmentState const*
394 get(uint256 const& amendment, std::lock_guard<std::mutex> const& lock) const;
395
396 // Injects amendment json into v. Must be called with mutex_ locked.
397 void
398 injectJson(
399 Json::Value& v,
400 uint256 const& amendment,
401 AmendmentState const& state,
402 bool isAdmin,
403 std::lock_guard<std::mutex> const& lock) const;
404
405 void
406 persistVote(uint256 const& amendment, std::string const& name, AmendmentVote vote) const;
407
408public:
410 ServiceRegistry& registry,
411 std::chrono::seconds majorityTime,
412 std::vector<FeatureInfo> const& supported,
413 Section const& enabled,
414 Section const& vetoed,
415 beast::Journal journal);
416
417 uint256
418 find(std::string const& name) const override;
419
420 bool
421 veto(uint256 const& amendment) override;
422 bool
423 unVeto(uint256 const& amendment) override;
424
425 bool
426 enable(uint256 const& amendment) override;
427
428 bool
429 isEnabled(uint256 const& amendment) const override;
430 bool
431 isSupported(uint256 const& amendment) const override;
432
433 bool
434 hasUnsupportedEnabled() const override;
435
437 firstUnsupportedExpected() const override;
438
440 getJson(bool isAdmin) const override;
442 getJson(uint256 const&, bool isAdmin) const override;
443
444 bool
445 needValidatedLedger(LedgerIndex seq) const override;
446
447 void
448 doValidatedLedger(
449 LedgerIndex seq,
450 std::set<uint256> const& enabled,
451 majorityAmendments_t const& majority) override;
452
453 void
454 trustChanged(hash_set<PublicKey> const& allTrusted) override;
455
457 doValidation(std::set<uint256> const& enabledAmendments) const override;
458
460 getDesired() const override;
461
463 doVoting(
464 Rules const& rules,
465 NetClock::time_point closeTime,
466 std::set<uint256> const& enabledAmendments,
467 majorityAmendments_t const& majorityAmendments,
468 std::vector<std::shared_ptr<STValidation>> const& validations) override;
469};
470
471//------------------------------------------------------------------------------
472
473AmendmentTableImpl::AmendmentTableImpl(
474 ServiceRegistry& registry,
475 std::chrono::seconds majorityTime,
476 std::vector<FeatureInfo> const& supported,
477 Section const& enabled,
478 Section const& vetoed,
479 beast::Journal journal)
480 : lastUpdateSeq_(0)
481 , majorityTime_(majorityTime)
482 , unsupportedEnabled_(false)
483 , j_(journal)
484 , db_(registry.getWalletDB())
485{
487
488 // Find out if the FeatureVotes table exists in WalletDB
489 bool const featureVotesExist = [this]() {
490 auto db = db_.checkoutDb();
491 return createFeatureVotes(*db);
492 }();
493
494 // Parse supported amendments
495 for (auto const& [name, amendment, votebehavior] : supported)
496 {
497 AmendmentState& s = add(amendment, lock);
498
499 s.name = name;
500 s.supported = true;
501 switch (votebehavior)
502 {
505 break;
506
509 break;
510
513 break;
514 }
515
516 JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name
517 << ") is supported and will be "
518 << (s.vote == AmendmentVote::up ? "up" : "down")
519 << " voted by default if not enabled on the ledger.";
520 }
521
522 hash_set<uint256> detect_conflict;
523 // Parse enabled amendments from config
524 for (std::pair<uint256, std::string> const& a : parseSection(enabled))
525 {
526 if (featureVotesExist)
527 { // If the table existed, warn about duplicate config info
528 JLOG(j_.warn()) << "[amendments] section in config file ignored"
529 " in favor of data in db/wallet.db.";
530 break;
531 }
532 else
533 { // Otherwise transfer config data into the table
534 detect_conflict.insert(a.first);
535 persistVote(a.first, a.second, AmendmentVote::up);
536 }
537 }
538
539 // Parse vetoed amendments from config
540 for (auto const& a : parseSection(vetoed))
541 {
542 if (featureVotesExist)
543 { // If the table existed, warn about duplicate config info
544 JLOG(j_.warn()) << "[veto_amendments] section in config file ignored"
545 " in favor of data in db/wallet.db.";
546 break;
547 }
548 else
549 { // Otherwise transfer config data into the table
550 if (detect_conflict.count(a.first) == 0)
551 {
552 persistVote(a.first, a.second, AmendmentVote::down);
553 }
554 else
555 {
556 JLOG(j_.warn()) << "[veto_amendments] section in config has amendment " << '('
557 << a.first << ", " << a.second
558 << ") both [veto_amendments] and [amendments].";
559 }
560 }
561 }
562
563 // Read amendment votes from wallet.db
564 auto db = db_.checkoutDb();
566 *db,
567 [&](boost::optional<std::string> amendment_hash,
568 boost::optional<std::string> amendment_name,
569 boost::optional<AmendmentVote> vote) {
570 uint256 amend_hash;
571 if (!amendment_hash || !amendment_name || !vote)
572 {
573 // These fields should never have nulls, but check
574 Throw<std::runtime_error>("Invalid FeatureVotes row in wallet.db");
575 }
576 if (!amend_hash.parseHex(*amendment_hash))
577 {
578 Throw<std::runtime_error>(
579 "Invalid amendment ID '" + *amendment_hash + " in wallet.db");
580 }
581 if (*vote == AmendmentVote::down)
582 {
583 // Unknown amendments are effectively vetoed already
584 if (auto s = get(amend_hash, lock))
585 {
586 JLOG(j_.info()) << "Amendment {" << *amendment_name << ", " << amend_hash
587 << "} is downvoted.";
588 if (!amendment_name->empty())
589 s->name = *amendment_name;
590 // An obsolete amendment's vote can never be changed
591 if (s->vote != AmendmentVote::obsolete)
592 s->vote = *vote;
593 }
594 }
595 else // up-vote
596 {
597 AmendmentState& s = add(amend_hash, lock);
598
599 JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", " << amend_hash
600 << "} is upvoted.";
601 if (!amendment_name->empty())
602 s.name = *amendment_name;
603 // An obsolete amendment's vote can never be changed
605 s.vote = *vote;
606 }
607 });
608}
609
612{
613 // call with the mutex held
614 return amendmentMap_[amendmentHash];
615}
616
619{
620 // Forward to the const version of get.
621 return const_cast<AmendmentState*>(std::as_const(*this).get(amendmentHash, lock));
622}
623
624AmendmentState const*
626{
627 // call with the mutex held
628 auto ret = amendmentMap_.find(amendmentHash);
629
630 if (ret == amendmentMap_.end())
631 return nullptr;
632
633 return &ret->second;
634}
635
638{
640
641 for (auto const& e : amendmentMap_)
642 {
643 if (name == e.second.name)
644 return e.first;
645 }
646
647 return {};
648}
649
650void
652 uint256 const& amendment,
653 std::string const& name,
654 AmendmentVote vote) const
655{
656 XRPL_ASSERT(
658 "xrpl::AmendmentTableImpl::persistVote : valid vote input");
659 auto db = db_.checkoutDb();
660 voteAmendment(*db, amendment, name, vote);
661}
662
663bool
665{
667 AmendmentState& s = add(amendment, lock);
668
669 if (s.vote != AmendmentVote::up)
670 return false;
672 persistVote(amendment, s.name, s.vote);
673 return true;
674}
675
676bool
678{
680 AmendmentState* const s = get(amendment, lock);
681
682 if (!s || s->vote != AmendmentVote::down)
683 return false;
685 persistVote(amendment, s->name, s->vote);
686 return true;
687}
688
689bool
691{
693 AmendmentState& s = add(amendment, lock);
694
695 if (s.enabled)
696 return false;
697
698 s.enabled = true;
699
700 if (!s.supported)
701 {
702 JLOG(j_.error()) << "Unsupported amendment " << amendment << " activated.";
703 unsupportedEnabled_ = true;
704 }
705
706 return true;
707}
708
709bool
711{
713 AmendmentState const* s = get(amendment, lock);
714 return s && s->enabled;
715}
716
717bool
719{
721 AmendmentState const* s = get(amendment, lock);
722 return s && s->supported;
723}
724
725bool
731
738
741{
742 // Get the list of amendments we support and do not
743 // veto, but that are not already enabled
744 std::vector<uint256> amendments;
745
746 {
748 amendments.reserve(amendmentMap_.size());
749 for (auto const& e : amendmentMap_)
750 {
751 if (e.second.supported && e.second.vote == AmendmentVote::up &&
752 (enabled.count(e.first) == 0))
753 {
754 amendments.push_back(e.first);
755 JLOG(j_.info()) << "Voting for amendment " << e.second.name;
756 }
757 }
758 }
759
760 if (!amendments.empty())
761 std::sort(amendments.begin(), amendments.end());
762
763 return amendments;
764}
765
768{
769 // Get the list of amendments we support and do not veto
770 return doValidation({});
771}
772
775 Rules const& rules,
776 NetClock::time_point closeTime,
777 std::set<uint256> const& enabledAmendments,
778 majorityAmendments_t const& majorityAmendments,
780{
781 JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count() << ": "
782 << enabledAmendments.size() << ", " << majorityAmendments.size() << ", "
783 << valSet.size();
784
786
787 // Keep a record of the votes we received.
788 previousTrustedVotes_.recordVotes(rules, valSet, closeTime, j_, lock);
789
790 // Tally the most recent votes.
792 JLOG(j_.debug()) << "Counted votes from " << vote->trustedValidations()
793 << " valid trusted validations, threshold is: " << vote->threshold();
794
795 // Map of amendments to the action to be taken for each one. The action is
796 // the value of the flags in the pseudo-transaction
798
799 // process all amendments we know of
800 for (auto const& entry : amendmentMap_)
801 {
802 if (enabledAmendments.contains(entry.first))
803 {
804 JLOG(j_.trace()) << entry.first << ": amendment already enabled";
805
806 continue;
807 }
808
809 bool const hasValMajority = vote->passes(entry.first);
810
811 auto const majorityTime = [&]() -> std::optional<NetClock::time_point> {
812 auto const it = majorityAmendments.find(entry.first);
813 if (it != majorityAmendments.end())
814 return it->second;
815 return std::nullopt;
816 }();
817
818 bool const hasLedgerMajority = majorityTime.has_value();
819
820 auto const logStr = [&entry, &vote]() {
822 ss << entry.first << " (" << entry.second.name << ") has " << vote->votes(entry.first)
823 << " votes";
824 return ss.str();
825 }();
826
827 if (hasValMajority && !hasLedgerMajority && entry.second.vote == AmendmentVote::up)
828 {
829 // Ledger says no majority, validators say yes, and voting yes
830 // locally
831 JLOG(j_.debug()) << logStr << ": amendment got majority";
832 actions[entry.first] = tfGotMajority;
833 }
834 else if (!hasValMajority && hasLedgerMajority)
835 {
836 // Ledger says majority, validators say no
837 JLOG(j_.debug()) << logStr << ": amendment lost majority";
838 actions[entry.first] = tfLostMajority;
839 }
840 else if (
841 hasLedgerMajority && ((*majorityTime + majorityTime_) <= closeTime) &&
842 entry.second.vote == AmendmentVote::up)
843 {
844 // Ledger says majority held
845 JLOG(j_.debug()) << logStr << ": amendment majority held";
846 actions[entry.first] = 0;
847 }
848 // Logging only below this point
849 else if (hasValMajority && hasLedgerMajority)
850 {
851 JLOG(j_.debug()) << logStr << ": amendment holding majority, waiting to be enabled";
852 }
853 else if (!hasValMajority)
854 {
855 JLOG(j_.debug()) << logStr << ": amendment does not have majority";
856 }
857 }
858
859 // Stash for reporting
860 lastVote_ = std::move(vote);
861 return actions;
862}
863
864bool
866{
868
869 // Is there a ledger in which an amendment could have been enabled
870 // between these two ledger sequences?
871
872 return ((ledgerSeq - 1) / 256) != ((lastUpdateSeq_ - 1) / 256);
873}
874
875void
877 LedgerIndex ledgerSeq,
878 std::set<uint256> const& enabled,
879 majorityAmendments_t const& majority)
880{
881 for (auto& e : enabled)
882 enable(e);
883
885
886 // Remember the ledger sequence of this update.
887 lastUpdateSeq_ = ledgerSeq;
888
889 // Since we have the whole list in `majority`, reset the time flag, even
890 // if it's currently set. If it's not set when the loop is done, then any
891 // prior unknown amendments have lost majority.
893 for (auto const& [hash, time] : majority)
894 {
895 AmendmentState& s = add(hash, lock);
896
897 if (s.enabled)
898 continue;
899
900 if (!s.supported)
901 {
902 JLOG(j_.info()) << "Unsupported amendment " << hash << " reached majority at "
903 << to_string(time);
906 }
907 }
910}
911
912void
918
919void
921 Json::Value& v,
922 uint256 const& id,
923 AmendmentState const& fs,
924 bool isAdmin,
925 std::lock_guard<std::mutex> const&) const
926{
927 if (!fs.name.empty())
928 v[jss::name] = fs.name;
929
930 v[jss::supported] = fs.supported;
931 if (!fs.enabled && isAdmin)
932 {
934 v[jss::vetoed] = "Obsolete";
935 else
936 v[jss::vetoed] = fs.vote == AmendmentVote::down;
937 }
938 v[jss::enabled] = fs.enabled;
939
940 if (!fs.enabled && lastVote_ && isAdmin)
941 {
942 auto const votesTotal = lastVote_->trustedValidations();
943 auto const votesNeeded = lastVote_->threshold();
944 auto const votesFor = lastVote_->votes(id);
945
946 v[jss::count] = votesFor;
947 v[jss::validations] = votesTotal;
948
949 if (votesNeeded)
950 v[jss::threshold] = votesNeeded;
951 }
952}
953
956{
958 {
960 for (auto const& e : amendmentMap_)
961 {
963 ret[to_string(e.first)] = Json::objectValue, e.first, e.second, isAdmin, lock);
964 }
965 }
966 return ret;
967}
968
970AmendmentTableImpl::getJson(uint256 const& amendmentID, bool isAdmin) const
971{
973
974 {
976 AmendmentState const* a = get(amendmentID, lock);
977 if (a)
978 {
979 Json::Value& jAmendment = (ret[to_string(amendmentID)] = Json::objectValue);
980 injectJson(jAmendment, amendmentID, *a, isAdmin, lock);
981 }
982 }
983
984 return ret;
985}
986
989 ServiceRegistry& registry,
990 std::chrono::seconds majorityTime,
992 Section const& enabled,
993 Section const& vetoed,
994 beast::Journal journal)
995{
997 registry, majorityTime, supported, enabled, vetoed, journal);
998}
999
1000} // namespace xrpl
T as_const(T... args)
Represents a JSON value.
Definition json_value.h:130
A generic endpoint for log messages.
Definition Journal.h:40
Stream error() const
Definition Journal.h:319
Stream debug() const
Definition Journal.h:301
Stream info() const
Definition Journal.h:307
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
The status of all amendments requested in a given window.
int trustedValidations() const
int votes(uint256 const &amendment) const
hash_map< uint256, int > votes_
AmendmentSet(Rules const &rules, TrustedVotes const &trustedVotes, std::lock_guard< std::mutex > const &lock)
bool passes(uint256 const &amendment) const
Track the list of "amendments".
Json::Value getJson(bool isAdmin) const override
bool isSupported(uint256 const &amendment) const override
std::optional< NetClock::time_point > firstUnsupportedExpected() const override
std::optional< NetClock::time_point > firstUnsupportedExpected_
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_
std::vector< uint256 > doValidation(std::set< uint256 > const &enabledAmendments) const override
bool veto(uint256 const &amendment) override
bool hasUnsupportedEnabled() const override
returns true if one or more amendments on the network have been enabled that this server does not sup...
void persistVote(uint256 const &amendment, std::string const &name, AmendmentVote vote) const
AmendmentState & add(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
std::unique_ptr< AmendmentSet > lastVote_
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 isEnabled(uint256 const &amendment) const override
std::chrono::seconds const majorityTime_
AmendmentState * get(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
bool enable(uint256 const &amendment) override
bool unVeto(uint256 const &amendment) override
uint256 find(std::string const &name) const override
std::vector< uint256 > getDesired() const override
void trustChanged(hash_set< PublicKey > const &allTrusted) override
void doValidatedLedger(LedgerIndex seq, std::set< uint256 > const &enabled, majorityAmendments_t const &majority) override
bool needValidatedLedger(LedgerIndex seq) const override
Called to determine whether the amendment logic needs to process a new validated ledger.
hash_map< uint256, AmendmentState > amendmentMap_
The amendment table stores the list of enabled and potential amendments.
LockedSociSession checkoutDb()
Rules controlling protocol behavior.
Definition Rules.h:18
Holds a collection of configuration values.
Definition BasicConfig.h:24
std::string const & name() const
Returns the name of this section.
Definition BasicConfig.h:40
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition BasicConfig.h:49
Service registry for dependency injection.
TrustedVotes records the most recent votes from trusted validators.
TrustedVotes & operator=(TrustedVotes const &rhs)=delete
hash_map< PublicKey, UpvotesAndTimeout > recordedVotes_
std::pair< int, hash_map< uint256, int > > getVotes(Rules const &rules, std::lock_guard< std::mutex > const &lock) const
void trustChanged(hash_set< PublicKey > const &allTrusted, std::lock_guard< std::mutex > const &lock)
void recordVotes(Rules const &rules, std::vector< std::shared_ptr< STValidation > > const &valSet, NetClock::time_point const closeTime, beast::Journal j, std::lock_guard< std::mutex > const &lock)
TrustedVotes(TrustedVotes const &rhs)=delete
TrustedVotes()=default
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:474
T contains(T... args)
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 is_same_v
T make_pair(T... args)
T max(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:600
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
std::unique_ptr< AmendmentTable > make_AmendmentTable(ServiceRegistry &registry, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition Role.cpp:64
constexpr std::uint32_t tfLostMajority
Definition TxFlags.h:109
constexpr std::uint32_t tfGotMajority
Definition TxFlags.h:108
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:223
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition Wallet.cpp:199
AmendmentVote
Definition Wallet.h:126
constexpr std::ratio< 80, 100 > amendmentMajorityCalcThreshold
The minimum amount of support an amendment should have.
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:258
static std::vector< std::pair< uint256, std::string > > parseSection(Section const &section)
T push_back(T... args)
T size(T... args)
T sort(T... args)
T str(T... args)
Current state of an amendment.
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.
bool supported
Indicates an amendment that this server has code support for.
AmendmentState()=default
bool enabled
Indicates that the amendment has been enabled.
std::optional< NetClock::time_point > timeout
An unseated timeout indicates that either.
T swap(T... args)
T time_since_epoch(T... args)