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