diff --git a/src/ripple/nodestore/DatabaseShard.h b/src/ripple/nodestore/DatabaseShard.h index a7fa7de0a..c43f9ccc5 100644 --- a/src/ripple/nodestore/DatabaseShard.h +++ b/src/ripple/nodestore/DatabaseShard.h @@ -211,6 +211,14 @@ public: static constexpr std::uint32_t ledgersPerShardDefault {16384u}; }; +constexpr +std::uint32_t +seqToShardIndex(std::uint32_t seq, + std::uint32_t ledgersPerShard = DatabaseShard::ledgersPerShardDefault) +{ + return (seq - 1) / ledgersPerShard; +} + } } diff --git a/src/ripple/nodestore/impl/DatabaseShardImp.h b/src/ripple/nodestore/impl/DatabaseShardImp.h index 34bf296ec..e6246843a 100644 --- a/src/ripple/nodestore/impl/DatabaseShardImp.h +++ b/src/ripple/nodestore/impl/DatabaseShardImp.h @@ -89,7 +89,7 @@ public: seqToShardIndex(std::uint32_t seq) const override { assert(seq >= earliestSeq()); - return (seq - 1) / ledgersPerShard_; + return NodeStore::seqToShardIndex(seq, ledgersPerShard_); } std::uint32_t diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp index 40d34d1b7..a3492cdd0 100644 --- a/src/ripple/overlay/impl/PeerImp.cpp +++ b/src/ripple/overlay/impl/PeerImp.cpp @@ -1119,36 +1119,78 @@ PeerImp::onMessage(std::shared_ptr const& m) // Parse the shard indexes received in the shard info RangeSet shardIndexes; { - std::vector tokens; - boost::split(tokens, m->shardindexes(), boost::algorithm::is_any_of(",")); - for (auto const& t : tokens) + std::uint32_t earliestShard; + boost::optional latestShard; { - std::vector seqs; - boost::split(seqs, t, boost::algorithm::is_any_of("-")); - if (seqs.empty() || seqs.size() > 2) + auto const curLedgerSeq { + app_.getLedgerMaster().getCurrentLedgerIndex()}; + if (auto shardStore = app_.getShardStore()) { - fee_ = Resource::feeBadData; - return; + earliestShard = shardStore->earliestShardIndex(); + if (curLedgerSeq >= shardStore->earliestSeq()) + latestShard = shardStore->seqToShardIndex(curLedgerSeq); } - - std::uint32_t first; - if (!beast::lexicalCastChecked(first, seqs.front())) - { - fee_ = Resource::feeBadData; - return; - } - - if (seqs.size() == 1) - shardIndexes.insert(first); else { - std::uint32_t second; - if (!beast::lexicalCastChecked(second, seqs.back())) - { - fee_ = Resource::feeBadData; + auto const earliestSeq {app_.getNodeStore().earliestSeq()}; + earliestShard = NodeStore::seqToShardIndex(earliestSeq); + if (curLedgerSeq >= earliestSeq) + latestShard = NodeStore::seqToShardIndex(curLedgerSeq); + } + } + + auto getIndex = [this, &earliestShard, &latestShard] + (std::string const& s) -> boost::optional + { + std::uint32_t shardIndex; + if (!beast::lexicalCastChecked(shardIndex, s)) + { + fee_ = Resource::feeBadData; + return boost::none; + } + if (shardIndex < earliestShard || + (latestShard && shardIndex > latestShard)) + { + fee_ = Resource::feeBadData; + JLOG(p_journal_.error()) << + "Invalid shard index " << shardIndex; + return boost::none; + } + return shardIndex; + }; + + std::vector tokens; + boost::split(tokens, m->shardindexes(), + boost::algorithm::is_any_of(",")); + std::vector indexes; + for (auto const& t : tokens) + { + indexes.clear(); + boost::split(indexes, t, boost::algorithm::is_any_of("-")); + switch (indexes.size()) + { + case 1: + { + auto const first {getIndex(indexes.front())}; + if (!first) return; - } - shardIndexes.insert(range(first, second)); + shardIndexes.insert(*first); + break; + } + case 2: + { + auto const first {getIndex(indexes.front())}; + if (!first) + return; + auto const second {getIndex(indexes.back())}; + if (!second) + return; + shardIndexes.insert(range(*first, *second)); + break; + } + default: + fee_ = Resource::feeBadData; + return; } } }