1#include <xrpld/app/misc/NegativeUNLVote.h>
3#include <xrpld/app/consensus/RCLValidations.h>
5#include <xrpl/basics/Log.h>
6#include <xrpl/basics/UnorderedContainers.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/beast/utility/Journal.h>
9#include <xrpl/beast/utility/instrumentation.h>
10#include <xrpl/ledger/Ledger.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/Protocol.h>
13#include <xrpl/protocol/PublicKey.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STTx.h>
16#include <xrpl/protocol/Serializer.h>
17#include <xrpl/protocol/TxFormats.h>
18#include <xrpl/protocol/UintTypes.h>
19#include <xrpl/shamap/SHAMapItem.h>
20#include <xrpl/shamap/SHAMapTreeNode.h>
53 for (
auto const& k : unlKeys)
65 auto negUnlKeys = prevLedger->negativeUNL();
66 auto negUnlToDisable = prevLedger->validatorToDisable();
67 auto negUnlToReEnable = prevLedger->validatorToReEnable();
69 negUnlKeys.insert(*negUnlToDisable);
71 negUnlKeys.erase(*negUnlToReEnable);
74 for (
auto const& k : negUnlKeys)
84 auto const seq = prevLedger->header().seq + 1;
88 auto const candidates =
findAllCandidates(unlNodeIDs, negUnlNodeIDs, *scoreTable);
91 if (!candidates.toDisableCandidates.empty())
93 auto n =
choose(prevLedger->header().hash, candidates.toDisableCandidates);
95 nidToKeyMap.
contains(n),
"xrpl::NegativeUNLVote::doVoting : found node to disable");
99 if (!candidates.toReEnableCandidates.empty())
101 auto n =
choose(prevLedger->header().hash, candidates.toReEnableCandidates);
103 nidToKeyMap.
contains(n),
"xrpl::NegativeUNLVote::doVoting : found node to enable");
116 STTx const negUnlTx(ttUNL_MODIFY, [&](
auto& obj) {
118 obj.setFieldU32(sfLedgerSequence, seq);
119 obj.setFieldVL(sfUNLModifyValidator, vp.
slice());
124 if (!initialSet->addGiveItem(
128 JLOG(
j_.warn()) <<
"N-UNL: ledger seq=" << seq <<
", add ttUNL_MODIFY tx failed";
132 JLOG(
j_.debug()) <<
"N-UNL: ledger seq=" << seq
133 <<
", add a ttUNL_MODIFY Tx with txID: " << negUnlTx.getTransactionID()
134 <<
", the validator to "
143 XRPL_ASSERT(!candidates.
empty(),
"xrpl::NegativeUNLVote::choose : non-empty input");
146 NodeID txNodeID = candidates[0];
147 for (
int j = 1; j < candidates.
size(); ++j)
149 if ((candidates[j] ^ randomPad) < (txNodeID ^ randomPad))
151 txNodeID = candidates[j];
169 auto const seq = prevLedger->header().seq + 1;
173 auto const hashIndex = prevLedger->read(
keylet::skip());
174 if (!hashIndex || !hashIndex->isFieldPresent(sfHashes))
176 JLOG(
j_.debug()) <<
"N-UNL: ledger " << seq <<
" no history.";
179 auto const ledgerAncestors = hashIndex->getFieldV256(sfHashes).value();
180 auto const numAncestors = ledgerAncestors.size();
183 JLOG(
j_.debug()) <<
"N-UNL: ledger " << seq <<
" not enough history. Can trace back only "
184 << numAncestors <<
" ledgers.";
190 for (
auto const& k : unl)
202 if (scoreTable.
contains(v->getNodeID()))
203 ++scoreTable[v->getNodeID()];
210 if (
auto const it = scoreTable.
find(
myId_); it != scoreTable.
end())
216 JLOG(
j_.debug()) <<
"N-UNL: ledger " << seq <<
". Local node only issued "
219 <<
" The reliability measurement could be wrong.";
230 JLOG(
j_.error()) <<
"N-UNL: ledger " << seq <<
". Local node issued " << myValidationCount
242 auto const canAdd = [&]() ->
bool {
243 auto const maxNegativeListed =
246 for (
auto const& n : unl)
251 bool const result = negativeListed < maxNegativeListed;
252 JLOG(
j_.trace()) <<
"N-UNL: nodeId " <<
myId_ <<
" lowWaterMark "
255 << negativeListed <<
" maxNegativeListed " << maxNegativeListed;
260 for (
auto const& [nodeId, score] : scoreTable)
262 JLOG(
j_.trace()) <<
"N-UNL: node " << nodeId <<
" score " << score;
272 JLOG(
j_.trace()) <<
"N-UNL: toDisable candidate " << nodeId;
281 JLOG(
j_.trace()) <<
"N-UNL: toReEnable candidate " << nodeId;
298 for (
auto const& n : negUnl)
313 for (
auto const& n : nowTrusted)
317 JLOG(
j_.trace()) <<
"N-UNL: add a new validator " << n <<
" at ledger seq=" << seq;
A generic endpoint for log messages.
static BaseUInt fromVoid(void const *data)
static constexpr std::size_t kBytes
void newValidators(LedgerIndex seq, hash_set< NodeID > const &nowTrusted)
Notify NegativeUNLVote that new validators are added.
static constexpr size_t kNegativeUnlHighWaterMark
An unreliable validator must have more than negativeUNLHighWaterMark validations in the last flag led...
static constexpr size_t kNegativeUnlMinLocalValsToVote
The minimum number of validations of the local node for it to participate in the voting.
Candidates findAllCandidates(hash_set< NodeID > const &unl, hash_set< NodeID > const &negUnl, hash_map< NodeID, std::uint32_t > const &scoreTable)
Process the score table and find all disabling and re-enabling candidates.
static NodeID choose(uint256 const &randomPadData, std::vector< NodeID > const &candidates)
Pick one candidate from a vector of candidates.
static constexpr size_t kNewValidatorDisableSkip
We don't want to disable new validators immediately after adding them.
NegativeUNLVote(NodeID const &myId, beast::Journal j)
Constructor.
void purgeNewValidators(LedgerIndex seq)
Purge validators that are not new anymore.
NegativeUNLModify
A flag indicating whether a UNLModify Tx is to disable or to re-enable a validator.
static constexpr float kNegativeUnlMaxListed
We only want to put 25% of the UNL on the NegativeUNL.
std::optional< hash_map< NodeID, std::uint32_t > > buildScoreTable(std::shared_ptr< Ledger const > const &prevLedger, hash_set< NodeID > const &unl, RCLValidations &validations)
Build a reliability measurement score table of validators' validation messages in the last flag ledge...
static constexpr size_t kNegativeUnlLowWaterMark
A validator is considered unreliable if its validations is less than negativeUNLLowWaterMark in the l...
void doVoting(std::shared_ptr< Ledger const > const &prevLedger, hash_set< PublicKey > const &unlKeys, RCLValidations &validations, std::shared_ptr< SHAMap > const &initialSet)
Cast our local vote on the NegativeUNL candidates.
hash_map< NodeID, LedgerIndex > newValidators_
void addTx(LedgerIndex seq, PublicKey const &vp, NegativeUNLModify modify, std::shared_ptr< SHAMap > const &initialSet)
Add a ttUNL_MODIFY Tx to the transaction set.
Slice slice() const noexcept
std::vector< WrappedValidationType > getTrustedForLedger(ID const &ledgerID, Seq const &seq)
Get trusted full validations for a specific ledger.
void setSeqToKeep(Seq const &low, Seq const &high)
Set the range [low, high) of validations to keep from expire.
Keylet const & skip() noexcept
The index of the "short" skip list.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::uint32_t LedgerIndex
A ledger index.
std::unordered_set< Value, Hash, Pred, Allocator > hash_set
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
Validations< RCLValidationsAdaptor > RCLValidations
Alias for RCL-specific instantiation of generic Validations.
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
BaseUInt< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
constexpr std::uint32_t kFlagLedgerInterval
std::vector< NodeID > toDisableCandidates
std::vector< NodeID > toReEnableCandidates