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#include <xrpld/nodestore/Database.h>
32#include <xrpld/nodestore/detail/DatabaseNodeImp.h>
33
34#include <xrpl/basics/Log.h>
35#include <xrpl/basics/contract.h>
36#include <xrpl/beast/utility/instrumentation.h>
37#include <xrpl/json/to_string.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 UNREACHABLE("ripple::Ledger::read : zero key");
437 return nullptr;
438 }
439 auto const& item = stateMap_.peekItem(k.key);
440 if (!item)
441 return nullptr;
442 auto sle = std::make_shared<SLE>(SerialIter{item->slice()}, item->key());
443 if (!k.check(*sle))
444 return nullptr;
445 return sle;
446}
447
448//------------------------------------------------------------------------------
449
450auto
451Ledger::slesBegin() const -> std::unique_ptr<sles_type::iter_base>
452{
454}
455
456auto
457Ledger::slesEnd() const -> std::unique_ptr<sles_type::iter_base>
458{
460}
461
462auto
465{
466 return std::make_unique<sles_iter_impl>(stateMap_.upper_bound(key));
467}
468
469auto
470Ledger::txsBegin() const -> std::unique_ptr<txs_type::iter_base>
471{
473}
474
475auto
476Ledger::txsEnd() const -> std::unique_ptr<txs_type::iter_base>
477{
479}
480
481bool
482Ledger::txExists(uint256 const& key) const
483{
484 return txMap_.hasItem(key);
485}
486
487auto
488Ledger::txRead(key_type const& key) const -> tx_type
489{
490 auto const& item = txMap_.peekItem(key);
491 if (!item)
492 return {};
493 if (!open())
494 {
495 auto result = deserializeTxPlusMeta(*item);
496 return {std::move(result.first), std::move(result.second)};
497 }
498 return {deserializeTx(*item), nullptr};
499}
500
501auto
503{
505 // VFALCO Unfortunately this loads the item
506 // from the NodeStore needlessly.
507 if (!stateMap_.peekItem(key, digest))
508 return std::nullopt;
509 return digest.as_uint256();
510}
511
512//------------------------------------------------------------------------------
513
514void
516{
517 if (!stateMap_.delItem(sle->key()))
518 LogicError("Ledger::rawErase: key not found");
519}
520
521void
523{
524 if (!stateMap_.delItem(key))
525 LogicError("Ledger::rawErase: key not found");
526}
527
528void
530{
531 Serializer ss;
532 sle->add(ss);
535 make_shamapitem(sle->key(), ss.slice())))
536 LogicError("Ledger::rawInsert: key already exists");
537}
538
539void
541{
542 Serializer ss;
543 sle->add(ss);
546 make_shamapitem(sle->key(), ss.slice())))
547 LogicError("Ledger::rawReplace: key not found");
548}
549
550void
552 uint256 const& key,
554 std::shared_ptr<Serializer const> const& metaData)
555{
556 XRPL_ASSERT(
557 metaData, "ripple::Ledger::rawTxInsert : non-null metadata input");
558
559 // low-level - just add to table
560 Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
561 s.addVL(txn->peekData());
562 s.addVL(metaData->peekData());
563 if (!txMap_.addGiveItem(
565 LogicError("duplicate_tx: " + to_string(key));
566}
567
570 uint256 const& key,
572 std::shared_ptr<Serializer const> const& metaData)
573{
574 XRPL_ASSERT(
575 metaData,
576 "ripple::Ledger::rawTxInsertWithHash : non-null metadata input");
577
578 // low-level - just add to table
579 Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
580 s.addVL(txn->peekData());
581 s.addVL(metaData->peekData());
582 auto item = make_shamapitem(key, s.slice());
583 auto hash = sha512Half(HashPrefix::txNode, item->slice(), item->key());
585 LogicError("duplicate_tx: " + to_string(key));
586
587 return hash;
588}
589
590bool
592{
593 bool ret = true;
594
595 try
596 {
598 }
599 catch (SHAMapMissingNode const&)
600 {
601 ret = false;
602 }
603 catch (std::exception const& ex)
604 {
605 JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
606 Rethrow();
607 }
608
609 try
610 {
611 if (auto const sle = read(keylet::fees()))
612 {
613 bool oldFees = false;
614 bool newFees = false;
615 {
616 auto const baseFee = sle->at(~sfBaseFee);
617 auto const reserveBase = sle->at(~sfReserveBase);
618 auto const reserveIncrement = sle->at(~sfReserveIncrement);
619 if (baseFee)
620 fees_.base = *baseFee;
621 if (reserveBase)
622 fees_.reserve = *reserveBase;
623 if (reserveIncrement)
624 fees_.increment = *reserveIncrement;
625 oldFees = baseFee || reserveBase || reserveIncrement;
626 }
627 {
628 auto const baseFeeXRP = sle->at(~sfBaseFeeDrops);
629 auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops);
630 auto const reserveIncrementXRP =
631 sle->at(~sfReserveIncrementDrops);
632 auto assign = [&ret](
633 XRPAmount& dest,
634 std::optional<STAmount> const& src) {
635 if (src)
636 {
637 if (src->native())
638 dest = src->xrp();
639 else
640 ret = false;
641 }
642 };
643 assign(fees_.base, baseFeeXRP);
644 assign(fees_.reserve, reserveBaseXRP);
645 assign(fees_.increment, reserveIncrementXRP);
646 newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
647 }
648 if (oldFees && newFees)
649 // Should be all of one or the other, but not both
650 ret = false;
651 if (!rules_.enabled(featureXRPFees) && newFees)
652 // Can't populate the new fees before the amendment is enabled
653 ret = false;
654 }
655 }
656 catch (SHAMapMissingNode const&)
657 {
658 ret = false;
659 }
660 catch (std::exception const& ex)
661 {
662 JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
663 Rethrow();
664 }
665
666 return ret;
667}
668
669void
671{
672 XRPL_ASSERT(
673 fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0,
674 "ripple::Ledger::defaultFees : zero fees");
675 if (fees_.base == 0)
676 fees_.base = config.FEES.reference_fee;
677 if (fees_.reserve == 0)
679 if (fees_.increment == 0)
681}
682
684Ledger::peek(Keylet const& k) const
685{
686 auto const& value = stateMap_.peekItem(k.key);
687 if (!value)
688 return nullptr;
689 auto sle = std::make_shared<SLE>(SerialIter{value->slice()}, value->key());
690 if (!k.check(*sle))
691 return nullptr;
692 return sle;
693}
694
697{
698 hash_set<PublicKey> negUnl;
699 if (auto sle = read(keylet::negativeUNL());
700 sle && sle->isFieldPresent(sfDisabledValidators))
701 {
702 auto const& nUnlData = sle->getFieldArray(sfDisabledValidators);
703 for (auto const& n : nUnlData)
704 {
705 if (n.isFieldPresent(sfPublicKey))
706 {
707 auto d = n.getFieldVL(sfPublicKey);
708 auto s = makeSlice(d);
709 if (!publicKeyType(s))
710 {
711 continue;
712 }
713 negUnl.emplace(s);
714 }
715 }
716 }
717
718 return negUnl;
719}
720
723{
724 if (auto sle = read(keylet::negativeUNL());
725 sle && sle->isFieldPresent(sfValidatorToDisable))
726 {
727 auto d = sle->getFieldVL(sfValidatorToDisable);
728 auto s = makeSlice(d);
729 if (publicKeyType(s))
730 return PublicKey(s);
731 }
732
733 return std::nullopt;
734}
735
738{
739 if (auto sle = read(keylet::negativeUNL());
740 sle && sle->isFieldPresent(sfValidatorToReEnable))
741 {
742 auto d = sle->getFieldVL(sfValidatorToReEnable);
743 auto s = makeSlice(d);
744 if (publicKeyType(s))
745 return PublicKey(s);
746 }
747
748 return std::nullopt;
749}
750
751void
753{
754 auto sle = peek(keylet::negativeUNL());
755 if (!sle)
756 return;
757
758 bool const hasToDisable = sle->isFieldPresent(sfValidatorToDisable);
759 bool const hasToReEnable = sle->isFieldPresent(sfValidatorToReEnable);
760
761 if (!hasToDisable && !hasToReEnable)
762 return;
763
764 STArray newNUnl;
765 if (sle->isFieldPresent(sfDisabledValidators))
766 {
767 auto const& oldNUnl = sle->getFieldArray(sfDisabledValidators);
768 for (auto v : oldNUnl)
769 {
770 if (hasToReEnable && v.isFieldPresent(sfPublicKey) &&
771 v.getFieldVL(sfPublicKey) ==
772 sle->getFieldVL(sfValidatorToReEnable))
773 continue;
774 newNUnl.push_back(v);
775 }
776 }
777
778 if (hasToDisable)
779 {
780 newNUnl.push_back(STObject::makeInnerObject(sfDisabledValidator));
781 newNUnl.back().setFieldVL(
782 sfPublicKey, sle->getFieldVL(sfValidatorToDisable));
783 newNUnl.back().setFieldU32(sfFirstLedgerSequence, seq());
784 }
785
786 if (!newNUnl.empty())
787 {
788 sle->setFieldArray(sfDisabledValidators, newNUnl);
789 if (hasToReEnable)
790 sle->makeFieldAbsent(sfValidatorToReEnable);
791 if (hasToDisable)
792 sle->makeFieldAbsent(sfValidatorToDisable);
793 rawReplace(sle);
794 }
795 else
796 {
797 rawErase(sle);
798 }
799}
800
801//------------------------------------------------------------------------------
802bool
803Ledger::walkLedger(beast::Journal j, bool parallel) const
804{
805 std::vector<SHAMapMissingNode> missingNodes1;
806 std::vector<SHAMapMissingNode> missingNodes2;
807
809 !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr))
810 {
811 missingNodes1.emplace_back(
813 }
814 else
815 {
816 if (parallel)
817 return stateMap_.walkMapParallel(missingNodes1, 32);
818 else
819 stateMap_.walkMap(missingNodes1, 32);
820 }
821
822 if (!missingNodes1.empty())
823 {
824 if (auto stream = j.info())
825 {
826 stream << missingNodes1.size() << " missing account node(s)";
827 stream << "First: " << missingNodes1[0].what();
828 }
829 }
830
831 if (txMap_.getHash().isZero() && info_.txHash.isNonZero() &&
832 !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr))
833 {
834 missingNodes2.emplace_back(
836 }
837 else
838 {
839 txMap_.walkMap(missingNodes2, 32);
840 }
841
842 if (!missingNodes2.empty())
843 {
844 if (auto stream = j.info())
845 {
846 stream << missingNodes2.size() << " missing transaction node(s)";
847 stream << "First: " << missingNodes2[0].what();
848 }
849 }
850 return missingNodes1.empty() && missingNodes2.empty();
851}
852
853bool
855{
859 {
860 return true;
861 }
862
863 Json::Value j = getJson({*this, {}});
864
865 j[jss::accountTreeHash] = to_string(info_.accountHash);
866 j[jss::transTreeHash] = to_string(info_.txHash);
867
868 JLOG(ledgerJ.fatal()) << "ledger is not sensible" << j;
869
870 UNREACHABLE("ripple::Ledger::assertSensible : ledger is not sensible");
871
872 return false;
873}
874
875// update the skip list with the information from our previous ledger
876// VFALCO TODO Document this skip list concept
877void
879{
880 if (info_.seq == 0) // genesis ledger has no previous ledger
881 return;
882
883 std::uint32_t prevIndex = info_.seq - 1;
884
885 // update record of every 256th ledger
886 if ((prevIndex & 0xff) == 0)
887 {
888 auto const k = keylet::skip(prevIndex);
889 auto sle = peek(k);
891
892 bool created;
893 if (!sle)
894 {
895 sle = std::make_shared<SLE>(k);
896 created = true;
897 }
898 else
899 {
900 hashes = static_cast<decltype(hashes)>(sle->getFieldV256(sfHashes));
901 created = false;
902 }
903
904 XRPL_ASSERT(
905 hashes.size() <= 256,
906 "ripple::Ledger::updateSkipList : first maximum hashes size");
907 hashes.push_back(info_.parentHash);
908 sle->setFieldV256(sfHashes, STVector256(hashes));
909 sle->setFieldU32(sfLastLedgerSequence, prevIndex);
910 if (created)
911 rawInsert(sle);
912 else
913 rawReplace(sle);
914 }
915
916 // update record of past 256 ledger
917 auto const k = keylet::skip();
918 auto sle = peek(k);
920 bool created;
921 if (!sle)
922 {
923 sle = std::make_shared<SLE>(k);
924 created = true;
925 }
926 else
927 {
928 hashes = static_cast<decltype(hashes)>(sle->getFieldV256(sfHashes));
929 created = false;
930 }
931 XRPL_ASSERT(
932 hashes.size() <= 256,
933 "ripple::Ledger::updateSkipList : second maximum hashes size");
934 if (hashes.size() == 256)
935 hashes.erase(hashes.begin());
936 hashes.push_back(info_.parentHash);
937 sle->setFieldV256(sfHashes, STVector256(hashes));
938 sle->setFieldU32(sfLastLedgerSequence, prevIndex);
939 if (created)
940 rawInsert(sle);
941 else
942 rawReplace(sle);
943}
944
945bool
947{
948 return info_.seq % FLAG_LEDGER_INTERVAL == 0;
949}
950bool
952{
953 return (info_.seq + 1) % FLAG_LEDGER_INTERVAL == 0;
954}
955
956bool
958{
959 return seq % FLAG_LEDGER_INTERVAL == 0;
960}
961
962static bool
964 Application& app,
965 std::shared_ptr<Ledger const> const& ledger,
966 bool current)
967{
968 auto j = app.journal("Ledger");
969 auto seq = ledger->info().seq;
970 if (!app.pendingSaves().startWork(seq))
971 {
972 // The save was completed synchronously
973 JLOG(j.debug()) << "Save aborted";
974 return true;
975 }
976
977 auto const db = dynamic_cast<SQLiteDatabase*>(&app.getRelationalDatabase());
978 if (!db)
979 Throw<std::runtime_error>("Failed to get relational database");
980
981 auto const res = db->saveValidatedLedger(ledger, current);
982
983 // Clients can now trust the database for
984 // information about this ledger sequence.
985 app.pendingSaves().finishWork(seq);
986 return res;
987}
988
992bool
994 Application& app,
995 std::shared_ptr<Ledger const> const& ledger,
996 bool isSynchronous,
997 bool isCurrent)
998{
999 if (!app.getHashRouter().setFlags(
1000 ledger->info().hash, HashRouterFlags::SAVED))
1001 {
1002 // We have tried to save this ledger recently
1003 auto stream = app.journal("Ledger").debug();
1004 JLOG(stream) << "Double pend save for " << ledger->info().seq;
1005
1006 if (!isSynchronous || !app.pendingSaves().pending(ledger->info().seq))
1007 {
1008 // Either we don't need it to be finished
1009 // or it is finished
1010 return true;
1011 }
1012 }
1013
1014 XRPL_ASSERT(
1015 ledger->isImmutable(), "ripple::pendSaveValidated : immutable ledger");
1016
1017 if (!app.pendingSaves().shouldWork(ledger->info().seq, isSynchronous))
1018 {
1019 auto stream = app.journal("Ledger").debug();
1020 JLOG(stream) << "Pend save with seq in pending saves "
1021 << ledger->info().seq;
1022
1023 return true;
1024 }
1025
1026 // See if we can use the JobQueue.
1027 if (!isSynchronous &&
1028 app.getJobQueue().addJob(
1030 std::to_string(ledger->seq()),
1031 [&app, ledger, isCurrent]() {
1032 saveValidatedLedger(app, ledger, isCurrent);
1033 }))
1034 {
1035 return true;
1036 }
1037
1038 // The JobQueue won't do the Job. Do the save synchronously.
1039 return saveValidatedLedger(app, ledger, isCurrent);
1040}
1041
1042void
1044{
1046 txMap_.unshare();
1047}
1048
1049void
1051{
1054}
1055//------------------------------------------------------------------------------
1056
1057/*
1058 * Make ledger using info loaded from database.
1059 *
1060 * @param LedgerInfo: Ledger information.
1061 * @param app: Link to the Application.
1062 * @param acquire: Acquire the ledger if not found locally.
1063 * @return Shared pointer to the ledger.
1064 */
1066loadLedgerHelper(LedgerInfo const& info, Application& app, bool acquire)
1067{
1068 bool loaded;
1069 auto ledger = std::make_shared<Ledger>(
1070 info,
1071 loaded,
1072 acquire,
1073 app.config(),
1074 app.getNodeFamily(),
1075 app.journal("Ledger"));
1076
1077 if (!loaded)
1078 ledger.reset();
1079
1080 return ledger;
1081}
1082
1083static void
1085 std::shared_ptr<Ledger> const& ledger,
1086 Config const& config,
1088{
1089 if (!ledger)
1090 return;
1091
1092 XRPL_ASSERT(
1093 ledger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
1094 ledger->read(keylet::fees()),
1095 "ripple::finishLoadByIndexOrHash : valid ledger fees");
1096 ledger->setImmutable();
1097
1098 JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->info().hash);
1099
1100 ledger->setFull();
1101}
1102
1105{
1106 std::optional<LedgerInfo> const info =
1108 if (!info)
1109 return {std::shared_ptr<Ledger>(), {}, {}};
1110 return {loadLedgerHelper(*info, app, true), info->seq, info->hash};
1111}
1112
1114loadByIndex(std::uint32_t ledgerIndex, Application& app, bool acquire)
1115{
1116 if (std::optional<LedgerInfo> info =
1118 {
1119 std::shared_ptr<Ledger> ledger = loadLedgerHelper(*info, app, acquire);
1120 finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger"));
1121 return ledger;
1122 }
1123 return {};
1124}
1125
1127loadByHash(uint256 const& ledgerHash, Application& app, bool acquire)
1128{
1129 if (std::optional<LedgerInfo> info =
1131 {
1132 std::shared_ptr<Ledger> ledger = loadLedgerHelper(*info, app, acquire);
1133 finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger"));
1134 XRPL_ASSERT(
1135 !ledger || ledger->info().hash == ledgerHash,
1136 "ripple::loadByHash : ledger hash match if loaded");
1137 return ledger;
1138 }
1139 return {};
1140}
1141
1142} // 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:670
void rawTxInsert(uint256 const &key, std::shared_ptr< Serializer const > const &txn, std::shared_ptr< Serializer const > const &metaData) override
Definition Ledger.cpp:551
std::unique_ptr< sles_type::iter_base > slesUpperBound(uint256 const &key) const override
Definition Ledger.cpp:463
void unshare() const
Definition Ledger.cpp:1043
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:854
void invariants() const
Definition Ledger.cpp:1050
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:540
std::unique_ptr< sles_type::iter_base > slesEnd() const override
Definition Ledger.cpp:457
void rawErase(std::shared_ptr< SLE > const &sle) override
Delete an existing state item.
Definition Ledger.cpp:515
std::optional< PublicKey > validatorToReEnable() const
get the to be re-enabled validator's master public key if any
Definition Ledger.cpp:737
SHAMap stateMap_
Definition Ledger.h:412
bool isFlagLedger() const
Returns true if the ledger is a flag ledger.
Definition Ledger.cpp:946
hash_set< PublicKey > negativeUNL() const
get Negative UNL validators' master public keys
Definition Ledger.cpp:696
bool txExists(uint256 const &key) const override
Definition Ledger.cpp:482
std::optional< PublicKey > validatorToDisable() const
get the to be disabled validator's master public key if any
Definition Ledger.cpp:722
bool isVotingLedger() const
Returns true if the ledger directly precedes a flag ledger.
Definition Ledger.cpp:951
bool mImmutable
Definition Ledger.h:406
void updateNegativeUNL()
update the Negative UNL ledger component.
Definition Ledger.cpp:752
std::shared_ptr< SLE > peek(Keylet const &k) const
Definition Ledger.cpp:684
std::optional< digest_type > digest(key_type const &key) const override
Return the digest associated with the key.
Definition Ledger.cpp:502
tx_type txRead(key_type const &key) const override
Read a transaction from the tx map.
Definition Ledger.cpp:488
void rawInsert(std::shared_ptr< SLE > const &sle) override
Unconditionally insert a state item.
Definition Ledger.cpp:529
bool walkLedger(beast::Journal j, bool parallel=false) const
Definition Ledger.cpp:803
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:569
std::unique_ptr< sles_type::iter_base > slesBegin() const override
Definition Ledger.cpp:451
std::unique_ptr< txs_type::iter_base > txsEnd() const override
Definition Ledger.cpp:476
std::unique_ptr< txs_type::iter_base > txsBegin() const override
Definition Ledger.cpp:470
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:878
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:61
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:119
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:714
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition SHAMap.cpp:616
bool addGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:802
void setImmutable()
Definition SHAMap.h:604
const_iterator end() const
Definition SHAMap.h:763
void invariants() const
Definition SHAMap.cpp:1245
bool addItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:881
const_iterator upper_bound(uint256 const &id) const
Find the first item after the given item.
Definition SHAMap.cpp:639
SHAMapHash getHash() const
Definition SHAMap.cpp:889
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:901
const_iterator begin() const
Definition SHAMap.h:757
bool delItem(uint256 const &id)
Definition SHAMap.cpp:720
bool fetchRoot(SHAMapHash const &hash, SHAMapSyncFilter *filter)
Definition SHAMap.cpp:944
int flushDirty(NodeObjectType t)
Flush modified nodes to the nodestore and convert them to shared.
Definition SHAMap.cpp:1037
int unshare()
Convert any modified nodes to shared.
Definition SHAMap.cpp:1030
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:963
static STObject makeInnerObject(SField const &name)
Definition STObject.cpp:95
void setFieldU32(SField const &field, std::uint32_t)
Definition STObject.cpp:741
void setFieldVL(SField const &field, Blob const &)
Definition STObject.cpp:777
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:1104
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:1084
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
Definition Ledger.cpp:1114
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:963
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
std::shared_ptr< Ledger > loadLedgerHelper(LedgerInfo const &info, Application &app, bool acquire)
Definition Ledger.cpp:1066
@ 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:1127
@ 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:957
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:993
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)