rippled
Loading...
Searching...
No Matches
Ledger.cpp
1#include <xrpld/app/ledger/InboundLedgers.h>
2#include <xrpld/app/ledger/Ledger.h>
3#include <xrpld/app/ledger/LedgerToJson.h>
4#include <xrpld/app/ledger/PendingSaves.h>
5#include <xrpld/app/main/Application.h>
6#include <xrpld/app/misc/HashRouter.h>
7#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
8#include <xrpld/consensus/LedgerTiming.h>
9#include <xrpld/core/Config.h>
10#include <xrpld/core/JobQueue.h>
11#include <xrpld/core/SociDB.h>
12
13#include <xrpl/basics/Log.h>
14#include <xrpl/basics/contract.h>
15#include <xrpl/beast/utility/instrumentation.h>
16#include <xrpl/json/to_string.h>
17#include <xrpl/nodestore/Database.h>
18#include <xrpl/nodestore/detail/DatabaseNodeImp.h>
19#include <xrpl/protocol/Feature.h>
20#include <xrpl/protocol/HashPrefix.h>
21#include <xrpl/protocol/Indexes.h>
22#include <xrpl/protocol/PublicKey.h>
23#include <xrpl/protocol/SecretKey.h>
24#include <xrpl/protocol/digest.h>
25#include <xrpl/protocol/jss.h>
26
27#include <utility>
28#include <vector>
29
30namespace ripple {
31
33
36{
37 // VFALCO This has to match addRaw in View.h.
38 return sha512Half(
40 std::uint32_t(info.seq),
42 info.parentHash,
43 info.txHash,
44 info.accountHash,
49}
50
51//------------------------------------------------------------------------------
52
53class Ledger::sles_iter_impl : public sles_type::iter_base
54{
55private:
57
58public:
59 sles_iter_impl() = delete;
61 operator=(sles_iter_impl const&) = delete;
62
63 sles_iter_impl(sles_iter_impl const&) = default;
64
68
70 copy() const override
71 {
73 }
74
75 bool
76 equal(base_type const& impl) const override
77 {
78 if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
79 return iter_ == p->iter_;
80 return false;
81 }
82
83 void
84 increment() override
85 {
86 ++iter_;
87 }
88
89 sles_type::value_type
90 dereference() const override
91 {
92 SerialIter sit(iter_->slice());
93 return std::make_shared<SLE const>(sit, iter_->key());
94 }
95};
96
97//------------------------------------------------------------------------------
98
99class Ledger::txs_iter_impl : public txs_type::iter_base
100{
101private:
104
105public:
106 txs_iter_impl() = delete;
108 operator=(txs_iter_impl const&) = delete;
109
110 txs_iter_impl(txs_iter_impl const&) = default;
111
113 : metadata_(metadata), iter_(std::move(iter))
114 {
115 }
116
118 copy() const override
119 {
121 }
122
123 bool
124 equal(base_type const& impl) const override
125 {
126 if (auto const p = dynamic_cast<txs_iter_impl const*>(&impl))
127 return iter_ == p->iter_;
128 return false;
129 }
130
131 void
132 increment() override
133 {
134 ++iter_;
135 }
136
137 txs_type::value_type
138 dereference() const override
139 {
140 auto const& item = *iter_;
141 if (metadata_)
142 return deserializeTxPlusMeta(item);
143 return {deserializeTx(item), nullptr};
144 }
145};
146
147//------------------------------------------------------------------------------
148
151 Config const& config,
152 std::vector<uint256> const& amendments,
153 Family& family)
154 : mImmutable(false)
155 , txMap_(SHAMapType::TRANSACTION, family)
156 , stateMap_(SHAMapType::STATE, family)
157 , rules_{config.features}
158 , j_(beast::Journal(beast::Journal::getNullSink()))
159{
160 info_.seq = 1;
163
164 static auto const id = calcAccountID(
166 .first);
167 {
168 auto const sle = std::make_shared<SLE>(keylet::account(id));
169 sle->setFieldU32(sfSequence, 1);
170 sle->setAccountID(sfAccount, id);
171 sle->setFieldAmount(sfBalance, info_.drops);
172 rawInsert(sle);
173 }
174
175 if (!amendments.empty())
176 {
177 auto const sle = std::make_shared<SLE>(keylet::amendments());
178 sle->setFieldV256(sfAmendments, STVector256{amendments});
179 rawInsert(sle);
180 }
181
182 {
184 // Whether featureXRPFees is supported will depend on startup options.
185 if (std::find(amendments.begin(), amendments.end(), featureXRPFees) !=
186 amendments.end())
187 {
188 sle->at(sfBaseFeeDrops) = config.FEES.reference_fee;
189 sle->at(sfReserveBaseDrops) = config.FEES.account_reserve;
190 sle->at(sfReserveIncrementDrops) = config.FEES.owner_reserve;
191 }
192 else
193 {
194 if (auto const f =
196 sle->at(sfBaseFee) = *f;
197 if (auto const f =
199 sle->at(sfReserveBase) = *f;
200 if (auto const f =
202 sle->at(sfReserveIncrement) = *f;
203 sle->at(sfReferenceFeeUnits) = Config::FEE_UNITS_DEPRECATED;
204 }
205 rawInsert(sle);
206 }
207
209 setImmutable();
210}
211
213 LedgerInfo const& info,
214 bool& loaded,
215 bool acquire,
216 Config const& config,
217 Family& family,
219 : mImmutable(true)
220 , txMap_(SHAMapType::TRANSACTION, info.txHash, family)
221 , stateMap_(SHAMapType::STATE, info.accountHash, family)
222 , rules_(config.features)
223 , info_(info)
224 , j_(j)
225{
226 loaded = true;
227
228 if (info_.txHash.isNonZero() &&
229 !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr))
230 {
231 loaded = false;
232 JLOG(j.warn()) << "Don't have transaction root for ledger" << info_.seq;
233 }
234
236 !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr))
237 {
238 loaded = false;
239 JLOG(j.warn()) << "Don't have state data root for ledger" << info_.seq;
240 }
241
244
245 defaultFees(config);
246 if (!setup())
247 loaded = false;
248
249 if (!loaded)
250 {
252 if (acquire)
254 }
255}
256
257// Create a new ledger that follows this one
258Ledger::Ledger(Ledger const& prevLedger, NetClock::time_point closeTime)
259 : mImmutable(false)
260 , txMap_(SHAMapType::TRANSACTION, prevLedger.txMap_.family())
261 , stateMap_(prevLedger.stateMap_, true)
262 , fees_(prevLedger.fees_)
263 , rules_(prevLedger.rules_)
264 , j_(beast::Journal(beast::Journal::getNullSink()))
265{
266 info_.seq = prevLedger.info_.seq + 1;
268 info_.hash = prevLedger.info().hash + uint256(1);
269 info_.drops = prevLedger.info().drops;
271 info_.parentHash = prevLedger.info().hash;
273 prevLedger.info_.closeTimeResolution,
274 getCloseAgree(prevLedger.info()),
275 info_.seq);
276
277 if (prevLedger.info_.closeTime == NetClock::time_point{})
278 {
280 }
281 else
282 {
285 }
286}
287
288Ledger::Ledger(LedgerInfo const& info, Config const& config, Family& family)
289 : mImmutable(true)
290 , txMap_(SHAMapType::TRANSACTION, info.txHash, family)
291 , stateMap_(SHAMapType::STATE, info.accountHash, family)
292 , rules_{config.features}
293 , info_(info)
294 , j_(beast::Journal(beast::Journal::getNullSink()))
295{
297}
298
300 std::uint32_t ledgerSeq,
301 NetClock::time_point closeTime,
302 Config const& config,
303 Family& family)
304 : mImmutable(false)
305 , txMap_(SHAMapType::TRANSACTION, family)
306 , stateMap_(SHAMapType::STATE, family)
307 , rules_{config.features}
308 , j_(beast::Journal(beast::Journal::getNullSink()))
309{
310 info_.seq = ledgerSeq;
311 info_.closeTime = closeTime;
313 defaultFees(config);
314 setup();
315}
316
317void
319{
320 // Force update, since this is the only
321 // place the hash transitions to valid
322 if (!mImmutable && rehash)
323 {
326 }
327
328 if (rehash)
330
331 mImmutable = true;
334 setup();
335}
336
337void
339 NetClock::time_point closeTime,
340 NetClock::duration closeResolution,
341 bool correctCloseTime)
342{
343 // Used when we witnessed the consensus.
344 XRPL_ASSERT(!open(), "ripple::Ledger::setAccepted : valid ledger state");
345
346 info_.closeTime = closeTime;
347 info_.closeTimeResolution = closeResolution;
348 info_.closeFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime;
349 setImmutable();
350}
351
352bool
354{
355 auto const s = sle.getSerializer();
356 return stateMap_.addItem(
358}
359
360//------------------------------------------------------------------------------
361
364{
365 SerialIter sit(item.slice());
367}
368
371{
373 result;
374 SerialIter sit(item.slice());
375 {
376 SerialIter s(sit.getSlice(sit.getVLDataLength()));
378 }
379 {
380 SerialIter s(sit.getSlice(sit.getVLDataLength()));
381 result.second = std::make_shared<STObject const>(s, sfMetadata);
382 }
383 return result;
384}
385
386//------------------------------------------------------------------------------
387
388bool
389Ledger::exists(Keylet const& k) const
390{
391 // VFALCO NOTE Perhaps check the type for debug builds?
392 return stateMap_.hasItem(k.key);
393}
394
395bool
396Ledger::exists(uint256 const& key) const
397{
398 return stateMap_.hasItem(key);
399}
400
402Ledger::succ(uint256 const& key, std::optional<uint256> const& last) const
403{
404 auto item = stateMap_.upper_bound(key);
405 if (item == stateMap_.end())
406 return std::nullopt;
407 if (last && item->key() >= last)
408 return std::nullopt;
409 return item->key();
410}
411
413Ledger::read(Keylet const& k) const
414{
415 if (k.key == beast::zero)
416 {
417 // LCOV_EXCL_START
418 UNREACHABLE("ripple::Ledger::read : zero key");
419 return nullptr;
420 // LCOV_EXCL_STOP
421 }
422 auto const& item = stateMap_.peekItem(k.key);
423 if (!item)
424 return nullptr;
425 auto sle = std::make_shared<SLE>(SerialIter{item->slice()}, item->key());
426 if (!k.check(*sle))
427 return nullptr;
428 return sle;
429}
430
431//------------------------------------------------------------------------------
432
433auto
434Ledger::slesBegin() const -> std::unique_ptr<sles_type::iter_base>
435{
437}
438
439auto
440Ledger::slesEnd() const -> std::unique_ptr<sles_type::iter_base>
441{
443}
444
445auto
448{
449 return std::make_unique<sles_iter_impl>(stateMap_.upper_bound(key));
450}
451
452auto
453Ledger::txsBegin() const -> std::unique_ptr<txs_type::iter_base>
454{
456}
457
458auto
459Ledger::txsEnd() const -> std::unique_ptr<txs_type::iter_base>
460{
462}
463
464bool
465Ledger::txExists(uint256 const& key) const
466{
467 return txMap_.hasItem(key);
468}
469
470auto
471Ledger::txRead(key_type const& key) const -> tx_type
472{
473 auto const& item = txMap_.peekItem(key);
474 if (!item)
475 return {};
476 if (!open())
477 {
478 auto result = deserializeTxPlusMeta(*item);
479 return {std::move(result.first), std::move(result.second)};
480 }
481 return {deserializeTx(*item), nullptr};
482}
483
484auto
486{
488 // VFALCO Unfortunately this loads the item
489 // from the NodeStore needlessly.
490 if (!stateMap_.peekItem(key, digest))
491 return std::nullopt;
492 return digest.as_uint256();
493}
494
495//------------------------------------------------------------------------------
496
497void
499{
500 if (!stateMap_.delItem(sle->key()))
501 LogicError("Ledger::rawErase: key not found");
502}
503
504void
506{
507 if (!stateMap_.delItem(key))
508 LogicError("Ledger::rawErase: key not found");
509}
510
511void
513{
514 Serializer ss;
515 sle->add(ss);
518 make_shamapitem(sle->key(), ss.slice())))
519 LogicError("Ledger::rawInsert: key already exists");
520}
521
522void
524{
525 Serializer ss;
526 sle->add(ss);
529 make_shamapitem(sle->key(), ss.slice())))
530 LogicError("Ledger::rawReplace: key not found");
531}
532
533void
535 uint256 const& key,
537 std::shared_ptr<Serializer const> const& metaData)
538{
539 XRPL_ASSERT(
540 metaData, "ripple::Ledger::rawTxInsert : non-null metadata input");
541
542 // low-level - just add to table
543 Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
544 s.addVL(txn->peekData());
545 s.addVL(metaData->peekData());
546 if (!txMap_.addGiveItem(
548 LogicError("duplicate_tx: " + to_string(key));
549}
550
553 uint256 const& key,
555 std::shared_ptr<Serializer const> const& metaData)
556{
557 XRPL_ASSERT(
558 metaData,
559 "ripple::Ledger::rawTxInsertWithHash : non-null metadata input");
560
561 // low-level - just add to table
562 Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
563 s.addVL(txn->peekData());
564 s.addVL(metaData->peekData());
565 auto item = make_shamapitem(key, s.slice());
566 auto hash = sha512Half(HashPrefix::txNode, item->slice(), item->key());
568 LogicError("duplicate_tx: " + to_string(key));
569
570 return hash;
571}
572
573bool
575{
576 bool ret = true;
577
578 try
579 {
581 }
582 catch (SHAMapMissingNode const&)
583 {
584 ret = false;
585 }
586 catch (std::exception const& ex)
587 {
588 JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
589 Rethrow();
590 }
591
592 try
593 {
594 if (auto const sle = read(keylet::fees()))
595 {
596 bool oldFees = false;
597 bool newFees = false;
598 {
599 auto const baseFee = sle->at(~sfBaseFee);
600 auto const reserveBase = sle->at(~sfReserveBase);
601 auto const reserveIncrement = sle->at(~sfReserveIncrement);
602 if (baseFee)
603 fees_.base = *baseFee;
604 if (reserveBase)
605 fees_.reserve = *reserveBase;
606 if (reserveIncrement)
607 fees_.increment = *reserveIncrement;
608 oldFees = baseFee || reserveBase || reserveIncrement;
609 }
610 {
611 auto const baseFeeXRP = sle->at(~sfBaseFeeDrops);
612 auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops);
613 auto const reserveIncrementXRP =
614 sle->at(~sfReserveIncrementDrops);
615 auto assign = [&ret](
616 XRPAmount& dest,
617 std::optional<STAmount> const& src) {
618 if (src)
619 {
620 if (src->native())
621 dest = src->xrp();
622 else
623 ret = false;
624 }
625 };
626 assign(fees_.base, baseFeeXRP);
627 assign(fees_.reserve, reserveBaseXRP);
628 assign(fees_.increment, reserveIncrementXRP);
629 newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
630 }
631 if (oldFees && newFees)
632 // Should be all of one or the other, but not both
633 ret = false;
634 if (!rules_.enabled(featureXRPFees) && newFees)
635 // Can't populate the new fees before the amendment is enabled
636 ret = false;
637 }
638 }
639 catch (SHAMapMissingNode const&)
640 {
641 ret = false;
642 }
643 catch (std::exception const& ex)
644 {
645 JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
646 Rethrow();
647 }
648
649 return ret;
650}
651
652void
654{
655 XRPL_ASSERT(
656 fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0,
657 "ripple::Ledger::defaultFees : zero fees");
658 if (fees_.base == 0)
659 fees_.base = config.FEES.reference_fee;
660 if (fees_.reserve == 0)
662 if (fees_.increment == 0)
664}
665
667Ledger::peek(Keylet const& k) const
668{
669 auto const& value = stateMap_.peekItem(k.key);
670 if (!value)
671 return nullptr;
672 auto sle = std::make_shared<SLE>(SerialIter{value->slice()}, value->key());
673 if (!k.check(*sle))
674 return nullptr;
675 return sle;
676}
677
680{
681 hash_set<PublicKey> negUnl;
682 if (auto sle = read(keylet::negativeUNL());
683 sle && sle->isFieldPresent(sfDisabledValidators))
684 {
685 auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
686 for (auto const& n : nUnlData)
687 {
688 if (n.isFieldPresent(sfPublicKey))
689 {
690 auto d = n.getFieldVL(sfPublicKey);
691 auto s = makeSlice(d);
692 if (!publicKeyType(s))
693 {
694 continue;
695 }
696 negUnl.emplace(s);
697 }
698 }
699 }
700
701 return negUnl;
702}
703
706{
707 if (auto sle = read(keylet::negativeUNL());
708 sle && sle->isFieldPresent(sfValidatorToDisable))
709 {
710 auto d = sle->getFieldVL(sfValidatorToDisable);
711 auto s = makeSlice(d);
712 if (publicKeyType(s))
713 return PublicKey(s);
714 }
715
716 return std::nullopt;
717}
718
721{
722 if (auto sle = read(keylet::negativeUNL());
723 sle && sle->isFieldPresent(sfValidatorToReEnable))
724 {
725 auto d = sle->getFieldVL(sfValidatorToReEnable);
726 auto s = makeSlice(d);
727 if (publicKeyType(s))
728 return PublicKey(s);
729 }
730
731 return std::nullopt;
732}
733
734void
736{
737 auto sle = peek(keylet::negativeUNL());
738 if (!sle)
739 return;
740
741 bool const hasToDisable = sle->isFieldPresent(sfValidatorToDisable);
742 bool const hasToReEnable = sle->isFieldPresent(sfValidatorToReEnable);
743
744 if (!hasToDisable && !hasToReEnable)
745 return;
746
747 STArray newNUnl;
748 if (sle->isFieldPresent(sfDisabledValidators))
749 {
750 auto const& oldNUnl = sle->getFieldArray(sfDisabledValidators);
751 for (auto v : oldNUnl)
752 {
753 if (hasToReEnable && v.isFieldPresent(sfPublicKey) &&
754 v.getFieldVL(sfPublicKey) ==
755 sle->getFieldVL(sfValidatorToReEnable))
756 continue;
757 newNUnl.push_back(v);
758 }
759 }
760
761 if (hasToDisable)
762 {
763 newNUnl.push_back(STObject::makeInnerObject(sfDisabledValidator));
764 newNUnl.back().setFieldVL(
765 sfPublicKey, sle->getFieldVL(sfValidatorToDisable));
766 newNUnl.back().setFieldU32(sfFirstLedgerSequence, seq());
767 }
768
769 if (!newNUnl.empty())
770 {
771 sle->setFieldArray(sfDisabledValidators, newNUnl);
772 if (hasToReEnable)
773 sle->makeFieldAbsent(sfValidatorToReEnable);
774 if (hasToDisable)
775 sle->makeFieldAbsent(sfValidatorToDisable);
776 rawReplace(sle);
777 }
778 else
779 {
780 rawErase(sle);
781 }
782}
783
784//------------------------------------------------------------------------------
785bool
786Ledger::walkLedger(beast::Journal j, bool parallel) const
787{
788 std::vector<SHAMapMissingNode> missingNodes1;
789 std::vector<SHAMapMissingNode> missingNodes2;
790
792 !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr))
793 {
794 missingNodes1.emplace_back(
796 }
797 else
798 {
799 if (parallel)
800 return stateMap_.walkMapParallel(missingNodes1, 32);
801 else
802 stateMap_.walkMap(missingNodes1, 32);
803 }
804
805 if (!missingNodes1.empty())
806 {
807 if (auto stream = j.info())
808 {
809 stream << missingNodes1.size() << " missing account node(s)";
810 stream << "First: " << missingNodes1[0].what();
811 }
812 }
813
814 if (txMap_.getHash().isZero() && info_.txHash.isNonZero() &&
815 !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr))
816 {
817 missingNodes2.emplace_back(
819 }
820 else
821 {
822 txMap_.walkMap(missingNodes2, 32);
823 }
824
825 if (!missingNodes2.empty())
826 {
827 if (auto stream = j.info())
828 {
829 stream << missingNodes2.size() << " missing transaction node(s)";
830 stream << "First: " << missingNodes2[0].what();
831 }
832 }
833 return missingNodes1.empty() && missingNodes2.empty();
834}
835
836bool
838{
842 {
843 return true;
844 }
845
846 // LCOV_EXCL_START
847 Json::Value j = getJson({*this, {}});
848
849 j[jss::accountTreeHash] = to_string(info_.accountHash);
850 j[jss::transTreeHash] = to_string(info_.txHash);
851
852 JLOG(ledgerJ.fatal()) << "ledger is not sensible" << j;
853
854 UNREACHABLE("ripple::Ledger::assertSensible : ledger is not sensible");
855
856 return false;
857 // LCOV_EXCL_STOP
858}
859
860// update the skip list with the information from our previous ledger
861// VFALCO TODO Document this skip list concept
862void
864{
865 if (info_.seq == 0) // genesis ledger has no previous ledger
866 return;
867
868 std::uint32_t prevIndex = info_.seq - 1;
869
870 // update record of every 256th ledger
871 if ((prevIndex & 0xff) == 0)
872 {
873 auto const k = keylet::skip(prevIndex);
874 auto sle = peek(k);
876
877 bool created;
878 if (!sle)
879 {
880 sle = std::make_shared<SLE>(k);
881 created = true;
882 }
883 else
884 {
885 hashes = static_cast<decltype(hashes)>(sle->getFieldV256(sfHashes));
886 created = false;
887 }
888
889 XRPL_ASSERT(
890 hashes.size() <= 256,
891 "ripple::Ledger::updateSkipList : first maximum hashes size");
892 hashes.push_back(info_.parentHash);
893 sle->setFieldV256(sfHashes, STVector256(hashes));
894 sle->setFieldU32(sfLastLedgerSequence, prevIndex);
895 if (created)
896 rawInsert(sle);
897 else
898 rawReplace(sle);
899 }
900
901 // update record of past 256 ledger
902 auto const k = keylet::skip();
903 auto sle = peek(k);
905 bool created;
906 if (!sle)
907 {
908 sle = std::make_shared<SLE>(k);
909 created = true;
910 }
911 else
912 {
913 hashes = static_cast<decltype(hashes)>(sle->getFieldV256(sfHashes));
914 created = false;
915 }
916 XRPL_ASSERT(
917 hashes.size() <= 256,
918 "ripple::Ledger::updateSkipList : second maximum hashes size");
919 if (hashes.size() == 256)
920 hashes.erase(hashes.begin());
921 hashes.push_back(info_.parentHash);
922 sle->setFieldV256(sfHashes, STVector256(hashes));
923 sle->setFieldU32(sfLastLedgerSequence, prevIndex);
924 if (created)
925 rawInsert(sle);
926 else
927 rawReplace(sle);
928}
929
930bool
932{
933 return info_.seq % FLAG_LEDGER_INTERVAL == 0;
934}
935bool
937{
938 return (info_.seq + 1) % FLAG_LEDGER_INTERVAL == 0;
939}
940
941bool
943{
944 return seq % FLAG_LEDGER_INTERVAL == 0;
945}
946
947static bool
949 Application& app,
950 std::shared_ptr<Ledger const> const& ledger,
951 bool current)
952{
953 auto j = app.journal("Ledger");
954 auto seq = ledger->info().seq;
955 if (!app.pendingSaves().startWork(seq))
956 {
957 // The save was completed synchronously
958 JLOG(j.debug()) << "Save aborted";
959 return true;
960 }
961
962 auto const db = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase());
963 if (!db)
964 Throw<std::runtime_error>("Failed to get relational database");
965
966 auto const res = db->saveValidatedLedger(ledger, current);
967
968 // Clients can now trust the database for
969 // information about this ledger sequence.
970 app.pendingSaves().finishWork(seq);
971 return res;
972}
973
977bool
979 Application& app,
980 std::shared_ptr<Ledger const> const& ledger,
981 bool isSynchronous,
982 bool isCurrent)
983{
984 if (!app.getHashRouter().setFlags(
985 ledger->info().hash, HashRouterFlags::SAVED))
986 {
987 // We have tried to save this ledger recently
988 auto stream = app.journal("Ledger").debug();
989 JLOG(stream) << "Double pend save for " << ledger->info().seq;
990
991 if (!isSynchronous || !app.pendingSaves().pending(ledger->info().seq))
992 {
993 // Either we don't need it to be finished
994 // or it is finished
995 return true;
996 }
997 }
998
999 XRPL_ASSERT(
1000 ledger->isImmutable(), "ripple::pendSaveValidated : immutable ledger");
1001
1002 if (!app.pendingSaves().shouldWork(ledger->info().seq, isSynchronous))
1003 {
1004 auto stream = app.journal("Ledger").debug();
1005 JLOG(stream) << "Pend save with seq in pending saves "
1006 << ledger->info().seq;
1007
1008 return true;
1009 }
1010
1011 // See if we can use the JobQueue.
1012 if (!isSynchronous &&
1013 app.getJobQueue().addJob(
1015 std::to_string(ledger->seq()),
1016 [&app, ledger, isCurrent]() {
1017 saveValidatedLedger(app, ledger, isCurrent);
1018 }))
1019 {
1020 return true;
1021 }
1022
1023 // The JobQueue won't do the Job. Do the save synchronously.
1024 return saveValidatedLedger(app, ledger, isCurrent);
1025}
1026
1027void
1029{
1031 txMap_.unshare();
1032}
1033
1034void
1036{
1039}
1040//------------------------------------------------------------------------------
1041
1042/*
1043 * Make ledger using info loaded from database.
1044 *
1045 * @param LedgerInfo: Ledger information.
1046 * @param app: Link to the Application.
1047 * @param acquire: Acquire the ledger if not found locally.
1048 * @return Shared pointer to the ledger.
1049 */
1051loadLedgerHelper(LedgerInfo const& info, Application& app, bool acquire)
1052{
1053 bool loaded;
1054 auto ledger = std::make_shared<Ledger>(
1055 info,
1056 loaded,
1057 acquire,
1058 app.config(),
1059 app.getNodeFamily(),
1060 app.journal("Ledger"));
1061
1062 if (!loaded)
1063 ledger.reset();
1064
1065 return ledger;
1066}
1067
1068static void
1070 std::shared_ptr<Ledger> const& ledger,
1071 Config const& config,
1073{
1074 if (!ledger)
1075 return;
1076
1077 XRPL_ASSERT(
1078 ledger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
1079 ledger->read(keylet::fees()),
1080 "ripple::finishLoadByIndexOrHash : valid ledger fees");
1081 ledger->setImmutable();
1082
1083 JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->info().hash);
1084
1085 ledger->setFull();
1086}
1087
1090{
1091 std::optional<LedgerInfo> const info =
1093 if (!info)
1094 return {std::shared_ptr<Ledger>(), {}, {}};
1095 return {loadLedgerHelper(*info, app, true), info->seq, info->hash};
1096}
1097
1099loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire)
1100{
1101 if (std::optional<LedgerInfo> info =
1103 {
1104 std::shared_ptr<Ledger> ledger = loadLedgerHelper(*info, app, acquire);
1105 finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger"));
1106 return ledger;
1107 }
1108 return {};
1109}
1110
1112loadByHash(uint256 const& ledgerHash, Application& app, bool acquire)
1113{
1114 if (std::optional<LedgerInfo> info =
1116 {
1117 std::shared_ptr<Ledger> ledger = loadLedgerHelper(*info, app, acquire);
1118 finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger"));
1119 XRPL_ASSERT(
1120 !ledger || ledger->info().hash == ledgerHash,
1121 "ripple::loadByHash : ledger hash match if loaded");
1122 return ledger;
1123 }
1124 return {};
1125}
1126
1127} // namespace ripple
T begin(T... args)
Represents a JSON value.
Definition json_value.h:131
A generic endpoint for log messages.
Definition Journal.h:41
Stream fatal() const
Definition Journal.h:333
Stream error() const
Definition Journal.h:327
Stream debug() const
Definition Journal.h:309
Stream info() const
Definition Journal.h:315
Stream trace() const
Severity stream access functions.
Definition Journal.h:303
Stream warn() const
Definition Journal.h:321
virtual Config & config()=0
virtual beast::Journal journal(std::string const &name)=0
virtual JobQueue & getJobQueue()=0
virtual Family & getNodeFamily()=0
virtual RelationalDatabase & getRelationalDatabase()=0
virtual HashRouter & getHashRouter()=0
virtual PendingSaves & pendingSaves()=0
FeeSetup FEES
Definition Config.h:185
static constexpr std::uint32_t FEE_UNITS_DEPRECATED
Definition Config.h:141
virtual void missingNodeAcquireByHash(uint256 const &refHash, std::uint32_t refNum)=0
Acquire ledger that has a missing node by ledger hash.
bool setFlags(uint256 const &key, HashRouterFlags flags)
Set the flags on a hash.
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition JobQueue.h:149
sles_iter_impl(sles_iter_impl const &)=default
std::unique_ptr< base_type > copy() const override
Definition Ledger.cpp:70
sles_type::value_type dereference() const override
Definition Ledger.cpp:90
sles_iter_impl(SHAMap::const_iterator iter)
Definition Ledger.cpp:65
void increment() override
Definition Ledger.cpp:84
bool equal(base_type const &impl) const override
Definition Ledger.cpp:76
SHAMap::const_iterator iter_
Definition Ledger.cpp:56
sles_iter_impl & operator=(sles_iter_impl const &)=delete
txs_iter_impl & operator=(txs_iter_impl const &)=delete
txs_iter_impl(txs_iter_impl const &)=default
SHAMap::const_iterator iter_
Definition Ledger.cpp:103
txs_type::value_type dereference() const override
Definition Ledger.cpp:138
bool equal(base_type const &impl) const override
Definition Ledger.cpp:124
std::unique_ptr< base_type > copy() const override
Definition Ledger.cpp:118
void increment() override
Definition Ledger.cpp:132
txs_iter_impl(bool metadata, SHAMap::const_iterator iter)
Definition Ledger.cpp:112
Holds a ledger.
Definition Ledger.h:61
LedgerInfo const & info() const override
Returns information about the ledger.
Definition Ledger.h:133
void setAccepted(NetClock::time_point closeTime, NetClock::duration closeResolution, bool correctCloseTime)
Definition Ledger.cpp:338
void defaultFees(Config const &config)
Definition Ledger.cpp:653
void rawTxInsert(uint256 const &key, std::shared_ptr< Serializer const > const &txn, std::shared_ptr< Serializer const > const &metaData) override
Definition Ledger.cpp:534
std::unique_ptr< sles_type::iter_base > slesUpperBound(uint256 const &key) const override
Definition Ledger.cpp:446
void unshare() const
Definition Ledger.cpp:1028
bool open() const override
Returns true if this reflects an open ledger.
Definition Ledger.h:127
bool assertSensible(beast::Journal ledgerJ) const
Definition Ledger.cpp:837
void invariants() const
Definition Ledger.cpp:1035
bool exists(Keylet const &k) const override
Determine if a state item exists.
Definition Ledger.cpp:389
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Definition Ledger.cpp:523
std::unique_ptr< sles_type::iter_base > slesEnd() const override
Definition Ledger.cpp:440
void rawErase(std::shared_ptr< SLE > const &sle) override
Delete an existing state item.
Definition Ledger.cpp:498
std::optional< PublicKey > validatorToReEnable() const
get the to be re-enabled validator's master public key if any
Definition Ledger.cpp:720
SHAMap stateMap_
Definition Ledger.h:393
bool isFlagLedger() const
Returns true if the ledger is a flag ledger.
Definition Ledger.cpp:931
hash_set< PublicKey > negativeUNL() const
get Negative UNL validators' master public keys
Definition Ledger.cpp:679
bool txExists(uint256 const &key) const override
Definition Ledger.cpp:465
std::optional< PublicKey > validatorToDisable() const
get the to be disabled validator's master public key if any
Definition Ledger.cpp:705
bool isVotingLedger() const
Returns true if the ledger directly precedes a flag ledger.
Definition Ledger.cpp:936
bool mImmutable
Definition Ledger.h:387
void updateNegativeUNL()
update the Negative UNL ledger component.
Definition Ledger.cpp:735
std::shared_ptr< SLE > peek(Keylet const &k) const
Definition Ledger.cpp:667
std::optional< digest_type > digest(key_type const &key) const override
Return the digest associated with the key.
Definition Ledger.cpp:485
tx_type txRead(key_type const &key) const override
Read a transaction from the tx map.
Definition Ledger.cpp:471
void rawInsert(std::shared_ptr< SLE > const &sle) override
Unconditionally insert a state item.
Definition Ledger.cpp:512
bool walkLedger(beast::Journal j, bool parallel=false) const
Definition Ledger.cpp:786
beast::Journal j_
Definition Ledger.h:401
SHAMap txMap_
Definition Ledger.h:390
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Definition Ledger.cpp:413
uint256 rawTxInsertWithHash(uint256 const &key, std::shared_ptr< Serializer const > const &txn, std::shared_ptr< Serializer const > const &metaData)
Definition Ledger.cpp:552
std::unique_ptr< sles_type::iter_base > slesBegin() const override
Definition Ledger.cpp:434
std::unique_ptr< txs_type::iter_base > txsEnd() const override
Definition Ledger.cpp:459
std::unique_ptr< txs_type::iter_base > txsBegin() const override
Definition Ledger.cpp:453
std::optional< uint256 > succ(uint256 const &key, std::optional< uint256 > const &last=std::nullopt) const override
Definition Ledger.cpp:402
void updateSkipList()
Definition Ledger.cpp:863
LedgerInfo info_
Definition Ledger.h:400
bool addSLE(SLE const &sle)
Definition Ledger.cpp:353
Rules rules_
Definition Ledger.h:399
Ledger(Ledger const &)=delete
void setImmutable(bool rehash=true)
Definition Ledger.cpp:318
void finishWork(LedgerIndex seq)
Finish working on a ledger.
bool startWork(LedgerIndex seq)
Start working on a ledger.
bool shouldWork(LedgerIndex seq, bool isSynchronous)
Check if a ledger should be dispatched.
bool pending(LedgerIndex seq)
Return true if a ledger is in the progress of being saved.
A public key.
Definition PublicKey.h:43
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:99
virtual std::optional< LedgerInfo > getNewestLedgerInfo()=0
getNewestLedgerInfo Returns the info of the newest saved ledger.
virtual std::optional< LedgerInfo > getLedgerInfoByIndex(LedgerIndex ledgerSeq)=0
getLedgerInfoByIndex Returns a ledger by its sequence.
virtual std::optional< LedgerInfo > getLedgerInfoByHash(uint256 const &ledgerHash)=0
getLedgerInfoByHash Returns the info of the ledger with given hash.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:111
uint256 const & as_uint256() const
Definition SHAMapHash.h:25
bool isZero() const
Definition SHAMapHash.h:35
Slice slice() const
Definition SHAMapItem.h:87
bool hasItem(uint256 const &id) const
Does the tree have an item with the given ID?
Definition SHAMap.cpp:696
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition SHAMap.cpp:598
bool addGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:784
void setImmutable()
Definition SHAMap.h:583
const_iterator end() const
Definition SHAMap.h:742
void invariants() const
Definition SHAMap.cpp:1229
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:863
const_iterator upper_bound(uint256 const &id) const
Find the first item after the given item.
Definition SHAMap.cpp:621
SHAMapHash getHash() const
Definition SHAMap.cpp:871
void walkMap(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
bool walkMapParallel(std::vector< SHAMapMissingNode > &missingNodes, int maxMissing) const
bool updateGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:883
const_iterator begin() const
Definition SHAMap.h:736
bool delItem(uint256 const &id)
Definition SHAMap.cpp:702
bool fetchRoot(SHAMapHash const &hash, SHAMapSyncFilter *filter)
Definition SHAMap.cpp:928
int flushDirty(NodeObjectType t)
Flush modified nodes to the nodestore and convert them to shared.
Definition SHAMap.cpp:1021
int unshare()
Convert any modified nodes to shared.
Definition SHAMap.cpp:1014
bool empty() const
Definition STArray.h:235
void push_back(STObject const &object)
Definition STArray.h:193
STObject & back()
Definition STArray.h:174
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
Serializer getSerializer() const
Definition STObject.h:953
static STObject makeInnerObject(SField const &name)
Definition STObject.cpp:76
void setFieldU32(SField const &field, std::uint32_t)
Definition STObject.cpp:738
void setFieldVL(SField const &field, Blob const &)
Definition STObject.cpp:780
Slice getSlice(std::size_t bytes)
Slice slice() const noexcept
Definition Serializer.h:47
int addVL(Blob const &vector)
std::optional< Dest > dropsAs() const
Definition XRPAmount.h:168
constexpr value_type drops() const
Returns the number of drops.
Definition XRPAmount.h:158
bool isZero() const
Definition base_uint.h:521
bool isNonZero() const
Definition base_uint.h:526
T emplace_back(T... args)
T emplace(T... args)
T empty(T... args)
T erase(T... args)
T find(T... args)
T is_same_v
Keylet const & negativeUNL() noexcept
The (fixed) index of the object containing the ledger negativeUNL.
Definition Indexes.cpp:211
Keylet const & amendments() noexcept
The index of the amendment table.
Definition Indexes.cpp:195
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:203
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:177
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
bool getCloseAgree(LedgerHeader const &info)
std::tuple< std::shared_ptr< Ledger >, std::uint32_t, uint256 > getLatestLedger(Application &app)
Definition Ledger.cpp:1089
std::pair< std::shared_ptr< STTx const >, std::shared_ptr< STObject const > > deserializeTxPlusMeta(SHAMapItem const &item)
Deserialize a SHAMapItem containing STTx + STObject metadata.
Definition Ledger.cpp:370
static void finishLoadByIndexOrHash(std::shared_ptr< Ledger > const &ledger, Config const &config, beast::Journal j)
Definition Ledger.cpp:1069
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
Definition Ledger.cpp:1099
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
std::shared_ptr< STTx const > deserializeTx(SHAMapItem const &item)
Deserialize a SHAMapItem containing a single STTx.
Definition Ledger.cpp:363
base_uint< 256 > uint256
Definition base_uint.h:539
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
std::chrono::time_point< Clock, Duration > roundCloseTime(std::chrono::time_point< Clock, Duration > closeTime, std::chrono::duration< Rep, Period > closeResolution)
Calculates the close time for a ledger, given a close time resolution.
static bool saveValidatedLedger(Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
Definition Ledger.cpp:948
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
std::shared_ptr< Ledger > loadLedgerHelper(LedgerInfo const &info, Application &app, bool acquire)
Definition Ledger.cpp:1051
@ hotACCOUNT_NODE
Definition NodeObject.h:16
AccountID calcAccountID(PublicKey const &pk)
@ current
This was a new validation and was added.
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES
The XRP Ledger mainnet's earliest ledger with a FeeSettings object.
auto constexpr ledgerDefaultTimeResolution
Initial resolution of ledger close time.
uint256 calculateLedgerHash(LedgerInfo const &info)
Definition Ledger.cpp:35
std::shared_ptr< Ledger > loadByHash(uint256 const &ledgerHash, Application &app, bool acquire)
Definition Ledger.cpp:1112
@ open
We haven't closed our ledger yet, but others might have.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
bool isFlagLedger(LedgerIndex seq)
Returns true if the given ledgerIndex is a flag ledgerIndex.
Definition Ledger.cpp:942
auto constexpr ledgerGenesisTimeResolution
Close time resolution in genesis ledger.
static std::uint32_t const sLCF_NoConsensusTime
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition tokens.cpp:138
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:225
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:142
Rules makeRulesGivenLedger(DigestAwareReadView const &ledger, Rules const &current)
Definition ReadView.cpp:50
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
create_genesis_t const create_genesis
Definition Ledger.cpp:32
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
@ txNode
transaction plus metadata
@ ledgerMaster
ledger master data for signing
void Rethrow()
Rethrow the exception currently being handled.
Definition contract.h:29
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:57
@ jtPUBLEDGER
Definition Job.h:49
@ jtPUBOLDLEDGER
Definition Job.h:25
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:205
std::uint32_t constexpr FLAG_LEDGER_INTERVAL
Definition Ledger.h:407
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
bool pendSaveValidated(Application &app, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger Returns false on error.
Definition Ledger.cpp:978
std::chrono::duration< Rep, Period > getNextLedgerTimeResolution(std::chrono::duration< Rep, Period > previousResolution, bool previousAgree, Seq ledgerSeq)
Calculates the close time resolution for the specified ledger.
STL namespace.
T push_back(T... args)
T size(T... args)
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition Config.h:49
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
Definition Config.h:55
XRPAmount account_reserve
The account reserve requirement in drops.
Definition Config.h:52
XRPAmount base
XRPAmount increment
XRPAmount reserve
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
bool check(STLedgerEntry const &) const
Returns true if the SLE matches the type.
Definition Keylet.cpp:9
uint256 key
Definition Keylet.h:21
Information about the notional ledger backing the view.
NetClock::time_point closeTime
NetClock::duration closeTimeResolution
NetClock::time_point parentCloseTime
T time_since_epoch(T... args)
T to_string(T... args)
T what(T... args)