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