diff --git a/doc/rippled-example.cfg b/doc/rippled-example.cfg index f315e1964d..4ed747585f 100644 --- a/doc/rippled-example.cfg +++ b/doc/rippled-example.cfg @@ -494,6 +494,20 @@ # # # +# [fetch_depth] +# +# The number of past ledgers to serve to other peers that request historical +# ledger data (or "full" for no limit). +# +# Servers that require low latency and high local performance may wish to +# restrict the historical ledgers they are willing to serve. Setting this +# below 32 can harm network stability as servers require easy access to +# recent history to stay in sync. Values below 128 are not recommended. +# +# The default is: full +# +# +# # [validation_seed] # # To perform validation, this section should contain either a validation seed diff --git a/src/ripple_app/consensus/LedgerConsensus.cpp b/src/ripple_app/consensus/LedgerConsensus.cpp index 5bf093e247..0d496f861d 100644 --- a/src/ripple_app/consensus/LedgerConsensus.cpp +++ b/src/ripple_app/consensus/LedgerConsensus.cpp @@ -1445,6 +1445,13 @@ private: uMin = 0; uMax = 0; } + else + { + // Don't advertise ledgers we're not willing to serve + uint32 early = getApp().getLedgerMaster().getEarliestFetch (); + if (uMin < early) + uMin = early; + } s.set_firstseq (uMin); s.set_lastseq (uMax); getApp ().getPeers ().foreach (send_always ( diff --git a/src/ripple_app/ledger/LedgerMaster.cpp b/src/ripple_app/ledger/LedgerMaster.cpp index 00b6b949c5..8b3b2a720c 100644 --- a/src/ripple_app/ledger/LedgerMaster.cpp +++ b/src/ripple_app/ledger/LedgerMaster.cpp @@ -424,6 +424,14 @@ public: return true; } + uint32 getEarliestFetch () + { + uint32 e = getClosedLedger()->getLedgerSeq(); + if (e > getConfig().FETCH_DEPTH) + e -= getConfig().FETCH_DEPTH; + return e; + } + void tryFill (Job& job, Ledger::pointer ledger) { uint32 seq = ledger->getLedgerSeq (); diff --git a/src/ripple_app/ledger/LedgerMaster.h b/src/ripple_app/ledger/LedgerMaster.h index 8eb423dbb0..4698932af4 100644 --- a/src/ripple_app/ledger/LedgerMaster.h +++ b/src/ripple_app/ledger/LedgerMaster.h @@ -73,6 +73,8 @@ public: virtual void setMinValidations (int v) = 0; + virtual uint32 getEarliestFetch () = 0; + virtual void pushLedger (Ledger::pointer newLedger) = 0; virtual void pushLedger (Ledger::pointer newLCL, Ledger::pointer newOL) = 0; virtual void storeLedger (Ledger::pointer) = 0; diff --git a/src/ripple_core/functional/Config.cpp b/src/ripple_core/functional/Config.cpp index 41a7f3af1b..810a2b93da 100644 --- a/src/ripple_core/functional/Config.cpp +++ b/src/ripple_core/functional/Config.cpp @@ -130,6 +130,7 @@ Config::Config () FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION; LEDGER_HISTORY = 256; + FETCH_DEPTH = 1000000000; PATH_SEARCH_OLD = DEFAULT_PATH_SEARCH_OLD; PATH_SEARCH = DEFAULT_PATH_SEARCH; @@ -533,13 +534,25 @@ void Config::load () { boost::to_lower (strTemp); - if (strTemp == "none") - LEDGER_HISTORY = 0; - else if (strTemp == "full") + if (strTemp == "full") LEDGER_HISTORY = 1000000000u; else LEDGER_HISTORY = lexicalCastThrow (strTemp); } + if (SectionSingleB (secConfig, SECTION_FETCH_DEPTH, strTemp)) + { + boost::to_lower (strTemp); + + if (strTemp == "none") + FETCH_DEPTH = 0; + else if (strTemp == "full") + FETCH_DEPTH = 1000000000u; + else + FETCH_DEPTH = lexicalCastThrow (strTemp); + + if (FETCH_DEPTH < 10) + FETCH_DEPTH = 10; + } if (SectionSingleB (secConfig, SECTION_PATH_SEARCH_OLD, strTemp)) PATH_SEARCH_OLD = lexicalCastThrow (strTemp); diff --git a/src/ripple_core/functional/Config.h b/src/ripple_core/functional/Config.h index f080576942..e87e156d97 100644 --- a/src/ripple_core/functional/Config.h +++ b/src/ripple_core/functional/Config.h @@ -446,6 +446,7 @@ public: // Node storage configuration uint32 LEDGER_HISTORY; + uint32 FETCH_DEPTH; int NODE_SIZE; // Client behavior diff --git a/src/ripple_core/functional/ConfigSections.h b/src/ripple_core/functional/ConfigSections.h index 994615f80a..a87acf8b1c 100644 --- a/src/ripple_core/functional/ConfigSections.h +++ b/src/ripple_core/functional/ConfigSections.h @@ -46,6 +46,7 @@ struct ConfigSection #define SECTION_FEE_OPERATION "fee_operation" #define SECTION_FEE_ACCOUNT_RESERVE "fee_account_reserve" #define SECTION_FEE_OWNER_RESERVE "fee_owner_reserve" +#define SECTION_FETCH_DEPTH "fetch_depth" #define SECTION_LEDGER_HISTORY "ledger_history" #define SECTION_INSIGHT "insight" #define SECTION_IPS "ips" diff --git a/src/ripple_overlay/impl/PeerImp.h b/src/ripple_overlay/impl/PeerImp.h index 84cbfa1556..666a233c93 100644 --- a/src/ripple_overlay/impl/PeerImp.h +++ b/src/ripple_overlay/impl/PeerImp.h @@ -2198,7 +2198,7 @@ private: void getLedger (protocol::TMGetLedger& packet) { - SHAMap::pointer map; + SHAMap::pointer map; protocol::TMLedgerData reply; bool fatLeaves = true, fatRoot = false; @@ -2304,29 +2304,34 @@ private: seq = packet.ledgerseq (); Peers::PeerSequence peerList = m_peers.getActivePeers (); - Peers::PeerSequence usablePeers; - BOOST_FOREACH (Peer::ref peer, peerList) - { - if (peer->hasLedger (ledgerhash, seq) && (peer.get () != this)) - usablePeers.push_back (peer); - } + Peers::PeerSequence usablePeers; + BOOST_FOREACH (Peer::ref peer, peerList) + { + if (peer->hasLedger (ledgerhash, seq) && (peer.get () != this)) + usablePeers.push_back (peer); + } - if (usablePeers.empty ()) - { - m_journal.trace << "Unable to route ledger request"; + if (usablePeers.empty ()) + { + m_journal.trace << "Unable to route ledger request"; + return; + } + + Peer::ref selectedPeer = usablePeers[rand () % usablePeers.size ()]; + packet.set_requestcookie (getShortId ()); + selectedPeer->sendPacket ( + boost::make_shared (packet, protocol::mtGET_LEDGER), false); + m_journal.debug << "Ledger request routed"; return; } - - Peer::ref selectedPeer = usablePeers[rand () % usablePeers.size ()]; - packet.set_requestcookie (getShortId ()); - selectedPeer->sendPacket ( - boost::make_shared (packet, protocol::mtGET_LEDGER), false); - m_journal.debug << "Ledger request routed"; - return; - } } else if (packet.has_ledgerseq ()) { + if (packet.ledgerseq() < getApp().getLedgerMaster().getEarliestFetch()) + { + m_journal.debug << "Peer requests early ledger"; + return; + } ledger = getApp().getLedgerMaster ().getLedgerBySeq (packet.ledgerseq ()); if (m_journal.debug) m_journal.debug << "Don't have ledger " << packet.ledgerseq (); @@ -2359,6 +2364,12 @@ private: return; } + if (!packet.has_ledgerseq() && (ledger->getLedgerSeq() < getApp().getLedgerMaster().getEarliestFetch())) + { + m_journal.debug << "Peer requests early ledger"; + return; + } + // Fill out the reply uint256 lHash = ledger->getHash (); reply.set_ledgerhash (lHash.begin (), lHash.size ()); @@ -2540,7 +2551,14 @@ private: if (!haveLedger->isClosed ()) { - m_journal.warning << "Peer requests fetch pack from open ledger: " << hash; + m_journal.warning << "Peer requests fetch pack from open ledger: " << hash; + charge (Resource::feeInvalidRequest); + return; + } + + if (haveLedger->getLedgerSeq() < getApp().getLedgerMaster().getEarliestFetch()) + { + m_journal.debug << "Peer requests fetch pack that is too early"; charge (Resource::feeInvalidRequest); return; }