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