rippled
Loading...
Searching...
No Matches
AmendmentTable.cpp
1#include <xrpld/app/misc/AmendmentTable.h>
2#include <xrpld/core/ConfigSections.h>
3
4#include <xrpl/core/ServiceRegistry.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/STValidation.h>
7#include <xrpl/protocol/TxFlags.h>
8#include <xrpl/protocol/jss.h>
9#include <xrpl/server/Wallet.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 ServiceRegistry& registry,
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 ServiceRegistry& registry,
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)
471 , majorityTime_(majorityTime)
472 , unsupportedEnabled_(false)
473 , j_(journal)
474 , db_(registry.getWalletDB())
475{
477
478 // Find out if the FeatureVotes table exists in WalletDB
479 bool const featureVotesExist = [this]() {
480 auto db = db_.checkoutDb();
481 return createFeatureVotes(*db);
482 }();
483
484 // Parse supported amendments
485 for (auto const& [name, amendment, votebehavior] : supported)
486 {
487 AmendmentState& s = add(amendment, lock);
488
489 s.name = name;
490 s.supported = true;
491 switch (votebehavior)
492 {
495 break;
496
499 break;
500
503 break;
504 }
505
506 JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name << ") is supported and will be "
507 << (s.vote == AmendmentVote::up ? "up" : "down")
508 << " voted by default if not enabled on the ledger.";
509 }
510
511 hash_set<uint256> detect_conflict;
512 // Parse enabled amendments from config
513 for (std::pair<uint256, std::string> const& a : parseSection(enabled))
514 {
515 if (featureVotesExist)
516 { // If the table existed, warn about duplicate config info
517 JLOG(j_.warn()) << "[amendments] section in config file ignored"
518 " in favor of data in db/wallet.db.";
519 break;
520 }
521 else
522 { // Otherwise transfer config data into the table
523 detect_conflict.insert(a.first);
524 persistVote(a.first, a.second, AmendmentVote::up);
525 }
526 }
527
528 // Parse vetoed amendments from config
529 for (auto const& a : parseSection(vetoed))
530 {
531 if (featureVotesExist)
532 { // If the table existed, warn about duplicate config info
533 JLOG(j_.warn()) << "[veto_amendments] section in config file ignored"
534 " in favor of data in db/wallet.db.";
535 break;
536 }
537 else
538 { // Otherwise transfer config data into the table
539 if (detect_conflict.count(a.first) == 0)
540 {
541 persistVote(a.first, a.second, AmendmentVote::down);
542 }
543 else
544 {
545 JLOG(j_.warn()) << "[veto_amendments] section in config has amendment " << '(' << a.first << ", "
546 << a.second << ") both [veto_amendments] and [amendments].";
547 }
548 }
549 }
550
551 // Read amendment votes from wallet.db
552 auto db = db_.checkoutDb();
554 *db,
555 [&](boost::optional<std::string> amendment_hash,
556 boost::optional<std::string> amendment_name,
557 boost::optional<AmendmentVote> vote) {
558 uint256 amend_hash;
559 if (!amendment_hash || !amendment_name || !vote)
560 {
561 // These fields should never have nulls, but check
562 Throw<std::runtime_error>("Invalid FeatureVotes row in wallet.db");
563 }
564 if (!amend_hash.parseHex(*amendment_hash))
565 {
566 Throw<std::runtime_error>("Invalid amendment ID '" + *amendment_hash + " in wallet.db");
567 }
568 if (*vote == AmendmentVote::down)
569 {
570 // Unknown amendments are effectively vetoed already
571 if (auto s = get(amend_hash, lock))
572 {
573 JLOG(j_.info()) << "Amendment {" << *amendment_name << ", " << amend_hash << "} is downvoted.";
574 if (!amendment_name->empty())
575 s->name = *amendment_name;
576 // An obsolete amendment's vote can never be changed
577 if (s->vote != AmendmentVote::obsolete)
578 s->vote = *vote;
579 }
580 }
581 else // up-vote
582 {
583 AmendmentState& s = add(amend_hash, lock);
584
585 JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", " << amend_hash << "} is upvoted.";
586 if (!amendment_name->empty())
587 s.name = *amendment_name;
588 // An obsolete amendment's vote can never be changed
590 s.vote = *vote;
591 }
592 });
593}
594
597{
598 // call with the mutex held
599 return amendmentMap_[amendmentHash];
600}
601
604{
605 // Forward to the const version of get.
606 return const_cast<AmendmentState*>(std::as_const(*this).get(amendmentHash, lock));
607}
608
609AmendmentState const*
611{
612 // call with the mutex held
613 auto ret = amendmentMap_.find(amendmentHash);
614
615 if (ret == amendmentMap_.end())
616 return nullptr;
617
618 return &ret->second;
619}
620
623{
625
626 for (auto const& e : amendmentMap_)
627 {
628 if (name == e.second.name)
629 return e.first;
630 }
631
632 return {};
633}
634
635void
636AmendmentTableImpl::persistVote(uint256 const& amendment, std::string const& name, AmendmentVote vote) const
637{
638 XRPL_ASSERT(vote != AmendmentVote::obsolete, "xrpl::AmendmentTableImpl::persistVote : valid vote input");
639 auto db = db_.checkoutDb();
640 voteAmendment(*db, amendment, name, vote);
641}
642
643bool
645{
647 AmendmentState& s = add(amendment, lock);
648
649 if (s.vote != AmendmentVote::up)
650 return false;
652 persistVote(amendment, s.name, s.vote);
653 return true;
654}
655
656bool
658{
660 AmendmentState* const s = get(amendment, lock);
661
662 if (!s || s->vote != AmendmentVote::down)
663 return false;
665 persistVote(amendment, s->name, s->vote);
666 return true;
667}
668
669bool
671{
673 AmendmentState& s = add(amendment, lock);
674
675 if (s.enabled)
676 return false;
677
678 s.enabled = true;
679
680 if (!s.supported)
681 {
682 JLOG(j_.error()) << "Unsupported amendment " << amendment << " activated.";
683 unsupportedEnabled_ = true;
684 }
685
686 return true;
687}
688
689bool
691{
693 AmendmentState const* s = get(amendment, lock);
694 return s && s->enabled;
695}
696
697bool
699{
701 AmendmentState const* s = get(amendment, lock);
702 return s && s->supported;
703}
704
705bool
711
718
721{
722 // Get the list of amendments we support and do not
723 // veto, but that are not already enabled
724 std::vector<uint256> amendments;
725
726 {
728 amendments.reserve(amendmentMap_.size());
729 for (auto const& e : amendmentMap_)
730 {
731 if (e.second.supported && e.second.vote == AmendmentVote::up && (enabled.count(e.first) == 0))
732 {
733 amendments.push_back(e.first);
734 JLOG(j_.info()) << "Voting for amendment " << e.second.name;
735 }
736 }
737 }
738
739 if (!amendments.empty())
740 std::sort(amendments.begin(), amendments.end());
741
742 return amendments;
743}
744
747{
748 // Get the list of amendments we support and do not veto
749 return doValidation({});
750}
751
754 Rules const& rules,
755 NetClock::time_point closeTime,
756 std::set<uint256> const& enabledAmendments,
757 majorityAmendments_t const& majorityAmendments,
759{
760 JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count() << ": " << enabledAmendments.size() << ", "
761 << majorityAmendments.size() << ", " << valSet.size();
762
764
765 // Keep a record of the votes we received.
766 previousTrustedVotes_.recordVotes(rules, valSet, closeTime, j_, lock);
767
768 // Tally the most recent votes.
770 JLOG(j_.debug()) << "Counted votes from " << vote->trustedValidations()
771 << " valid trusted validations, threshold is: " << vote->threshold();
772
773 // Map of amendments to the action to be taken for each one. The action is
774 // the value of the flags in the pseudo-transaction
776
777 // process all amendments we know of
778 for (auto const& entry : amendmentMap_)
779 {
780 if (enabledAmendments.contains(entry.first))
781 {
782 JLOG(j_.trace()) << entry.first << ": amendment already enabled";
783
784 continue;
785 }
786
787 bool const hasValMajority = vote->passes(entry.first);
788
789 auto const majorityTime = [&]() -> std::optional<NetClock::time_point> {
790 auto const it = majorityAmendments.find(entry.first);
791 if (it != majorityAmendments.end())
792 return it->second;
793 return std::nullopt;
794 }();
795
796 bool const hasLedgerMajority = majorityTime.has_value();
797
798 auto const logStr = [&entry, &vote]() {
800 ss << entry.first << " (" << entry.second.name << ") has " << vote->votes(entry.first) << " votes";
801 return ss.str();
802 }();
803
804 if (hasValMajority && !hasLedgerMajority && entry.second.vote == AmendmentVote::up)
805 {
806 // Ledger says no majority, validators say yes, and voting yes
807 // locally
808 JLOG(j_.debug()) << logStr << ": amendment got majority";
809 actions[entry.first] = tfGotMajority;
810 }
811 else if (!hasValMajority && hasLedgerMajority)
812 {
813 // Ledger says majority, validators say no
814 JLOG(j_.debug()) << logStr << ": amendment lost majority";
815 actions[entry.first] = tfLostMajority;
816 }
817 else if (
818 hasLedgerMajority && ((*majorityTime + majorityTime_) <= closeTime) &&
819 entry.second.vote == AmendmentVote::up)
820 {
821 // Ledger says majority held
822 JLOG(j_.debug()) << logStr << ": amendment majority held";
823 actions[entry.first] = 0;
824 }
825 // Logging only below this point
826 else if (hasValMajority && hasLedgerMajority)
827 {
828 JLOG(j_.debug()) << logStr << ": amendment holding majority, waiting to be enabled";
829 }
830 else if (!hasValMajority)
831 {
832 JLOG(j_.debug()) << logStr << ": amendment does not have majority";
833 }
834 }
835
836 // Stash for reporting
837 lastVote_ = std::move(vote);
838 return actions;
839}
840
841bool
843{
845
846 // Is there a ledger in which an amendment could have been enabled
847 // between these two ledger sequences?
848
849 return ((ledgerSeq - 1) / 256) != ((lastUpdateSeq_ - 1) / 256);
850}
851
852void
854 LedgerIndex ledgerSeq,
855 std::set<uint256> const& enabled,
856 majorityAmendments_t const& majority)
857{
858 for (auto& e : enabled)
859 enable(e);
860
862
863 // Remember the ledger sequence of this update.
864 lastUpdateSeq_ = ledgerSeq;
865
866 // Since we have the whole list in `majority`, reset the time flag, even
867 // if it's currently set. If it's not set when the loop is done, then any
868 // prior unknown amendments have lost majority.
870 for (auto const& [hash, time] : majority)
871 {
872 AmendmentState& s = add(hash, lock);
873
874 if (s.enabled)
875 continue;
876
877 if (!s.supported)
878 {
879 JLOG(j_.info()) << "Unsupported amendment " << hash << " reached majority at " << to_string(time);
882 }
883 }
886}
887
888void
894
895void
897 Json::Value& v,
898 uint256 const& id,
899 AmendmentState const& fs,
900 bool isAdmin,
901 std::lock_guard<std::mutex> const&) const
902{
903 if (!fs.name.empty())
904 v[jss::name] = fs.name;
905
906 v[jss::supported] = fs.supported;
907 if (!fs.enabled && isAdmin)
908 {
910 v[jss::vetoed] = "Obsolete";
911 else
912 v[jss::vetoed] = fs.vote == AmendmentVote::down;
913 }
914 v[jss::enabled] = fs.enabled;
915
916 if (!fs.enabled && lastVote_ && isAdmin)
917 {
918 auto const votesTotal = lastVote_->trustedValidations();
919 auto const votesNeeded = lastVote_->threshold();
920 auto const votesFor = lastVote_->votes(id);
921
922 v[jss::count] = votesFor;
923 v[jss::validations] = votesTotal;
924
925 if (votesNeeded)
926 v[jss::threshold] = votesNeeded;
927 }
928}
929
932{
934 {
936 for (auto const& e : amendmentMap_)
937 {
938 injectJson(ret[to_string(e.first)] = Json::objectValue, e.first, e.second, isAdmin, lock);
939 }
940 }
941 return ret;
942}
943
945AmendmentTableImpl::getJson(uint256 const& amendmentID, bool isAdmin) const
946{
948
949 {
951 AmendmentState const* a = get(amendmentID, lock);
952 if (a)
953 {
954 Json::Value& jAmendment = (ret[to_string(amendmentID)] = Json::objectValue);
955 injectJson(jAmendment, amendmentID, *a, isAdmin, lock);
956 }
957 }
958
959 return ret;
960}
961
964 ServiceRegistry& registry,
965 std::chrono::seconds majorityTime,
967 Section const& enabled,
968 Section const& vetoed,
969 beast::Journal journal)
970{
971 return std::make_unique<AmendmentTableImpl>(registry, majorityTime, supported, enabled, vetoed, journal);
972}
973
974} // 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:318
Stream debug() const
Definition Journal.h:300
Stream info() const
Definition Journal.h:306
Stream trace() const
Severity stream access functions.
Definition Journal.h:294
Stream warn() const
Definition Journal.h:312
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:471
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:597
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:63
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:212
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition Wallet.cpp:188
AmendmentVote
Definition Wallet.h:119
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:244
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)