From d70ec5d2e49d52c23756cc889e01965d7626259a Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Mon, 19 Jun 2023 13:09:14 +0000 Subject: [PATCH] change UNLReport to also run consensus on import_vl_keys, change gensisMint to also allow Governance flags and marks to be set on account root, compiling, not tested --- src/ripple/app/consensus/RCLConsensus.cpp | 2 +- src/ripple/app/main/Application.cpp | 7 +- src/ripple/app/misc/NegativeUNLVote.cpp | 51 +++++++++-- src/ripple/app/misc/NegativeUNLVote.h | 3 +- src/ripple/app/tx/impl/Change.cpp | 88 +++++++++++++------ src/ripple/app/tx/impl/GenesisMint.cpp | 68 ++++++++++---- src/ripple/app/tx/impl/Import.cpp | 61 +++++++++++-- src/ripple/core/Config.h | 3 +- src/ripple/core/impl/Config.cpp | 25 ++++-- src/ripple/protocol/SField.h | 4 + .../protocol/impl/InnerObjectFormats.cpp | 4 +- src/ripple/protocol/impl/LedgerFormats.cpp | 3 + src/ripple/protocol/impl/SField.cpp | 4 + src/ripple/protocol/impl/TxFormats.cpp | 6 +- src/test/consensus/NegativeUNL_test.cpp | 24 ++--- 15 files changed, 268 insertions(+), 85 deletions(-) diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index e0a350a2b..1af9f6a4f 100644 --- a/src/ripple/app/consensus/RCLConsensus.cpp +++ b/src/ripple/app/consensus/RCLConsensus.cpp @@ -92,7 +92,7 @@ RCLConsensus::Adaptor::Adaptor( rand_int( crypto_prng(), std::numeric_limits::max() - 1)) - , nUnlVote_(validatorKeys_.nodeID, j_) + , nUnlVote_(validatorKeys_.nodeID, j_, app) { assert(valCookie_ != 0); diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 76d623a8b..c2ffae013 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -1327,8 +1327,11 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) if (config_->IMPORT_VL_KEYS.empty()) { - JLOG(m_journal.fatal()) << "IMPORT_VL_KEYS section must be specified in validators file."; - return false; + JLOG(m_journal.warn()) << "[import_vl_keys] section not specified validators file. " + << "Will attempt to use keys from ledger."; + } + else + { } //---------------------------------------------------------------------- diff --git a/src/ripple/app/misc/NegativeUNLVote.cpp b/src/ripple/app/misc/NegativeUNLVote.cpp index a9dd477a4..87e563117 100644 --- a/src/ripple/app/misc/NegativeUNLVote.cpp +++ b/src/ripple/app/misc/NegativeUNLVote.cpp @@ -23,8 +23,8 @@ namespace ripple { -NegativeUNLVote::NegativeUNLVote(NodeID const& myId, beast::Journal j) - : myId_(myId), j_(j) +NegativeUNLVote::NegativeUNLVote(NodeID const& myId, beast::Journal j, Application& app) + : myId_(myId), j_(j), app_(app) { } @@ -122,11 +122,16 @@ NegativeUNLVote::addReportingTx( ordered.emplace(nidToKeyMap.at(n)); } - for (auto const& k : ordered) + for (auto const& pk : ordered) { STTx repUnlTx(ttUNL_REPORT, [&](auto& obj) { - obj.setFieldVL(sfPublicKey, k); + obj.set(([&]() + { + auto inner = std::make_unique(sfActiveValidator); + inner->setFieldVL(sfPublicKey, pk); + return inner; + })()); obj.setFieldU32(sfLedgerSequence, seq); }); @@ -143,11 +148,47 @@ NegativeUNLVote::addReportingTx( else { JLOG(j_.debug()) << "R-UNL: ledger seq=" << seq - << ", add a ttUNL_REPORT Tx with txID: " << txID + << ", add a ttUNL_REPORT (active_val) Tx with txID: " << txID << ", size=" << s.size() << ", " << repUnlTx.getJson(JsonOptions::none); } } + + + // do import VL key voting + auto const& keyMap = app_.config().IMPORT_VL_KEYS; + for (auto const& [_, pk] : keyMap) + { + STTx repUnlTx(ttUNL_REPORT, [&](auto& obj) + { + obj.set(([&]() + { + auto inner = std::make_unique(sfImportVLKey); + inner->setFieldVL(sfPublicKey, pk); + return inner; + })()); + obj.setFieldU32(sfLedgerSequence, seq); + }); + + uint256 txID = repUnlTx.getTransactionID(); + Serializer s; + repUnlTx.add(s); + if (!initalSet->addGiveItem( + SHAMapNodeType::tnTRANSACTION_NM, + std::make_shared(txID, s.slice()))) + { + JLOG(j_.warn()) << "R-UNL: ledger seq=" << seq + << ", add ttUNL_REPORT tx failed (import_vl_key)"; + } + else + { + JLOG(j_.debug()) << "R-UNL: ledger seq=" << seq + << ", add a ttUNL_REPORT (import_vl) Tx with txID: " << txID + << ", size=" << s.size() + << ", " << repUnlTx.getJson(JsonOptions::none); + } + } + } void diff --git a/src/ripple/app/misc/NegativeUNLVote.h b/src/ripple/app/misc/NegativeUNLVote.h index ed496d37b..0298640f3 100644 --- a/src/ripple/app/misc/NegativeUNLVote.h +++ b/src/ripple/app/misc/NegativeUNLVote.h @@ -91,7 +91,7 @@ public: * @param myId the NodeID of the local node * @param j log */ - NegativeUNLVote(NodeID const& myId, beast::Journal j); + NegativeUNLVote(NodeID const& myId, beast::Journal j, Application& app); ~NegativeUNLVote() = default; /** @@ -128,6 +128,7 @@ private: beast::Journal j_; mutable std::mutex mutex_; hash_map newValidators_; + Application& app_; /** * UNLModify Tx candidates diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index 36c5dcbb4..a1f4f62a7 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -77,11 +77,19 @@ Change::preflight(PreflightContext const& ctx) return temDISABLED; } - if (ctx.tx.getTxnType() == ttUNL_REPORT && - !ctx.rules.enabled(featureXahauGenesis)) + if (ctx.tx.getTxnType() == ttUNL_REPORT) { - JLOG(ctx.j.warn()) << "Change: UNLReport is not enabled."; - return temDISABLED; + if (!ctx.rules.enabled(featureXahauGenesis)) + { + JLOG(ctx.j.warn()) << "Change: UNLReport is not enabled."; + return temDISABLED; + } + + if (!ctx.tx.isFieldPresent(sfActiveValidator) && !ctx.tx.isFieldPresent(sfImportVLKey)) + { + JLOG(ctx.j.warn()) << "Change: UNLReport must specify at least one of sfImportVLKey, sfActiveValidator"; + return temMALFORMED; + } } return tesSUCCESS; @@ -182,37 +190,63 @@ Change::applyUNLReport() if (created) sle = std::make_shared(keylet::UNLReport()); - auto const avExisting = - (sle->isFieldPresent(sfPreviousTxnLgrSeq) && - sle->getFieldU32(sfPreviousTxnLgrSeq) < seq) - ? STArray(sfActiveValidators) - : sle->getFieldArray(sfActiveValidators); + bool const reset = + sle->isFieldPresent(sfPreviousTxnLgrSeq) && + sle->getFieldU32(sfPreviousTxnLgrSeq) < seq; - // canonically order using std::set - std::set ordered; - for (auto const& obj: avExisting) + auto canonicalize = [&](SField const& arrayType, SField const& objType) -> std::vector { - auto pk = obj.getFieldVL(sfPublicKey); - if (!publicKeyType(makeSlice(pk))) - continue; + auto const existing = + reset + ? STArray(arrayType) + : sle->getFieldArray(arrayType); - ordered.emplace(PublicKey(makeSlice(pk))); + // canonically order using std::set + std::set ordered; + for (auto const& obj: existing) + { + auto pk = obj.getFieldVL(sfPublicKey); + if (!publicKeyType(makeSlice(pk))) + continue; + + ordered.emplace(PublicKey(makeSlice(pk))); + }; + + if (ctx_.tx.isFieldPresent(objType)) + { + auto pk = + const_cast(ctx_.tx) + .getField(arrayType) + .downcast() + .getFieldVL(sfPublicKey); + + if (publicKeyType(makeSlice(pk))) + ordered.emplace(PublicKey(makeSlice(pk))); + } + + std::vector out; + out.reserve(ordered.size()); + for (auto const& k: ordered) + { + out.emplace_back(sfActiveValidator); + out.back().setFieldVL(sfPublicKey, k); + } + + return out; }; - auto pk = ctx_.tx.getFieldVL(sfPublicKey); - if (publicKeyType(makeSlice(pk))) - ordered.emplace(PublicKey(makeSlice(pk))); - std::vector av; - av.reserve(ordered.size()); - for (auto const& k: ordered) - { - av.emplace_back(sfActiveValidator); - av.back().setFieldVL(sfPublicKey, k); - } + bool const hasAV = ctx_.tx.isFieldPresent(sfActiveValidator); + bool const hasVL = ctx_.tx.isFieldPresent(sfImportVLKey); // update - sle->setFieldArray(sfActiveValidators, STArray(av, sfActiveValidators)); + if (hasAV) + sle->setFieldArray(sfActiveValidators, + STArray(canonicalize(sfActiveValidators, sfActiveValidator),sfActiveValidators)); + + if (hasVL) + sle->setFieldArray(sfImportVLKeys, + STArray(canonicalize(sfImportVLKeys, sfImportVLKey),sfImportVLKeys)); if (created) view().insert(sle); diff --git a/src/ripple/app/tx/impl/GenesisMint.cpp b/src/ripple/app/tx/impl/GenesisMint.cpp index e8b13d220..e2d56a8b5 100644 --- a/src/ripple/app/tx/impl/GenesisMint.cpp +++ b/src/ripple/app/tx/impl/GenesisMint.cpp @@ -78,21 +78,38 @@ GenesisMint::preflight(PreflightContext const& ctx) return temMALFORMED; } - auto const amt = dest.getFieldAmount(sfAmount); - if (!isXRP(amt)) + + bool const hasAmt = dest.isFieldPresent(sfAmount); + bool const hasMarks = dest.isFieldPresent(sfGovernanceMarks); + bool const hasFlags = dest.isFieldPresent(sfGovernanceFlags); + + if (!hasAmt && !hasMarks && !hasFlags) { JLOG(ctx.j.warn()) - << "GenesisMint: only native amounts can be minted."; + << "GenesisMint: each destination must have at least one of: " + << "sfAmount, sfGovernanceFlags, sfGovernance marks."; return temMALFORMED; } - if (amt <= beast::zero) + if (hasAmt) { - JLOG(ctx.j.warn()) - << "GenesisMint: only positive amounts can be minted."; - return temMALFORMED; + auto const amt = dest.getFieldAmount(sfAmount); + if (!isXRP(amt)) + { + JLOG(ctx.j.warn()) + << "GenesisMint: only native amounts can be minted."; + return temMALFORMED; + } + + if (amt <= beast::zero) + { + JLOG(ctx.j.warn()) + << "GenesisMint: only positive amounts can be minted."; + return temMALFORMED; + } } + auto const accid = dest.getAccountID(sfDestination); if (accid == noAccount() || accid == xrpAccount()) @@ -139,11 +156,17 @@ GenesisMint::doApply() for (auto const& dest: dests) { - auto const amt = dest.getFieldAmount(sfAmount); + auto const amt = dest[~sfAmount]; + auto const flags = dest[~sfGovernanceFlags]; + auto const marks = dest[~sfGovernanceMarks]; + auto const id = dest.getAccountID(sfDestination); auto const k = keylet::account(id); auto sle = view().peek(k); - if (!sle) + + bool const created = !sle; + + if (created) { // Create the account. std::uint32_t const seqno{ @@ -153,26 +176,37 @@ GenesisMint::doApply() sle->setAccountID(sfAccount, id); sle->setFieldU32(sfSequence, seqno); - sle->setFieldAmount(sfBalance, amt); - view().insert(sle); + if (amt) + sle->setFieldAmount(sfBalance, *amt); + else // give them 2 XRP if the account didn't exist, same as ttIMPORT + sle->setFieldAmount(sfBalance, XRPAmount {2 * DROPS_PER_XRP}); } - else + else if (amt) { // Credit the account STAmount startBal = sle->getFieldAmount(sfBalance); - STAmount finalBal = startBal + amt; + STAmount finalBal = startBal + *amt; if (finalBal > startBal) - { sle->setFieldAmount(sfBalance, finalBal); - view().update(sle); - } else { JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << dest << " due to balance overflow"; } } + + // set flags and marks as applicable + if (flags) + sle->setFieldH256(sfGovernanceFlags, *flags); + + if (marks) + sle->setFieldH256(sfGovernanceMarks, *marks); + + if (created) + view().insert(sle); + else + view().update(sle); } return tesSUCCESS; @@ -181,7 +215,7 @@ GenesisMint::doApply() XRPAmount GenesisMint::calculateBaseFee(ReadView const& view, STTx const& tx) { - return Transactor::calculateBaseFee(view, tx); + return XRPAmount { 0 } ; } } // namespace ripple diff --git a/src/ripple/app/tx/impl/Import.cpp b/src/ripple/app/tx/impl/Import.cpp index 1f5e7d5a8..2bd4c2764 100644 --- a/src/ripple/app/tx/impl/Import.cpp +++ b/src/ripple/app/tx/impl/Import.cpp @@ -560,11 +560,28 @@ Import::preflight(PreflightContext const& ctx) if (!xpop) return temMALFORMED; - // check if we recognise the vl key - auto const& vlKeys = ctx.app.config().IMPORT_VL_KEYS; - auto const found = std::ranges::find(vlKeys, (*xpop)[jss::validation][jss::unl][jss::public_key].asString()); - if (found == vlKeys.end()) - return telIMPORT_VL_KEY_NOT_RECOGNISED; + // we will check if we recognise the vl key in preclaim because it may be from on-ledger object + std::optional masterVLKey; + { + std::string strPk = (*xpop)[jss::validation][jss::unl][jss::public_key].asString(); + auto pkHex = strUnHex(strPk); + if (!pkHex) + { + JLOG(ctx.j.warn()) + << "Import: validation.unl.public_key was not valid hex."; + return temMALFORMED; + } + + auto const pkType = publicKeyType(makeSlice(*pkHex)); + if (!pkType) + { + JLOG(ctx.j.warn()) + << "Import: validation.unl.public_key was not a recognised public key type."; + return temMALFORMED; + } + + masterVLKey = PublicKey(makeSlice(*pkHex)); + } auto const [stpTrans, meta] = getInnerTxn(tx, ctx.j, &(*xpop)); @@ -734,7 +751,9 @@ Import::preflight(PreflightContext const& ctx) return temMALFORMED; } - if (strHex(m->masterKey) != *found) + // we will check the master key matches a known one in preclaim, because the import vl key might be + // from the on-ledger object + if (m->masterKey != masterVLKey) { JLOG(ctx.j.warn()) << "Import: manifest master key did not match top level master key in unl section of xpop " @@ -749,6 +768,7 @@ Import::preflight(PreflightContext const& ctx) << tx.getTransactionID(); return temMALFORMED; } + // manifest signing (ephemeral) key auto const signingKey = m->signingKey; @@ -1248,7 +1268,34 @@ Import::preclaim(PreclaimContext const& ctx) if (sleVL && sleVL->getFieldU32(sfImportSequence) > vl->first) return tefPAST_IMPORT_VL_SEQ; - return tesSUCCESS; + // check master VL key + std::string strPk = (*xpop)[jss::validation][jss::unl][jss::public_key].asString(); + + if (auto const& found = ctx.app.config().IMPORT_VL_KEYS.find(strPk); + found != ctx.app.config().IMPORT_VL_KEYS.end()) + return tesSUCCESS; + + // not found in our local VL keys + auto pkHex = strUnHex(strPk); + if (!pkHex) + return tefINTERNAL; + + auto const pkType = publicKeyType(makeSlice(*pkHex)); + if (!pkType) + return tefINTERNAL; + + PublicKey const pk (makeSlice(*pkHex)); + + // check on ledger + if (auto const unlRep = ctx.view.read(keylet::UNLReport()); unlRep) + { + auto const& vlKeys = unlRep->getFieldArray(sfImportVLKeys); + for (auto const& k: vlKeys) + if (PublicKey(k[sfPublicKey]) == pk) + return tesSUCCESS; + } + + return telIMPORT_VL_KEY_NOT_RECOGNISED; } TER diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 22bab77b6..81aec79a8 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -25,6 +25,7 @@ #include #include #include +#include #include // VFALCO Breaks levelization #include #include // VFALCO FIX: This include should not be here @@ -150,7 +151,7 @@ public: std::vector IPS_FIXED; // Fixed Peer IPs from rippled.cfg. std::vector SNTP_SERVERS; // SNTP servers from rippled.cfg. - std::vector IMPORT_VL_KEYS; + std::map IMPORT_VL_KEYS; // hex string -> class PublicKey (for caching purposes) enum StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK }; StartUpType START_UP = NORMAL; diff --git a/src/ripple/core/impl/Config.cpp b/src/ripple/core/impl/Config.cpp index fa23413ae..021eb3575 100644 --- a/src/ripple/core/impl/Config.cpp +++ b/src/ripple/core/impl/Config.cpp @@ -904,15 +904,22 @@ Config::loadFromString(std::string const& fileContents) auto iniFile = parseIniFile(data, true); if (auto importKeys = - getIniFileSection(iniFile, SECTION_IMPORT_VL_KEYS)) - IMPORT_VL_KEYS = *importKeys; - else - Throw( - "The file specified in [" SECTION_VALIDATORS_FILE - "] " - "does not contain a [" SECTION_IMPORT_VL_KEYS - "] section: " + - validatorsFile.string()); + getIniFileSection(iniFile, SECTION_IMPORT_VL_KEYS); importKeys) + { + for (std::string const& strPk : *importKeys) + { + auto pkHex = strUnHex(strPk); + if (!pkHex) + Throw( + "Import VL Key '" + strPk + "' was not valid hex."); + + auto const pkType = publicKeyType(makeSlice(*pkHex)); + if (!pkType) + Throw( + "Import VL Key '" + strPk + "' was not a valid key type."); + IMPORT_VL_KEYS.emplace(strPk, makeSlice(*pkHex)); + } + } if (RUN_STANDALONE) break; diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index 85eb36328..f381eaa6d 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -477,6 +477,8 @@ extern SF_UINT256 const sfHookSetTxnID; extern SF_UINT256 const sfOfferID; extern SF_UINT256 const sfEscrowID; extern SF_UINT256 const sfURITokenID; +extern SF_UINT256 const sfGovernanceFlags; +extern SF_UINT256 const sfGovernanceMarks; // currency amount (common) extern SF_AMOUNT const sfAmount; @@ -582,6 +584,7 @@ extern SField const sfHookDefinition; extern SField const sfHookParameter; extern SField const sfHookGrant; extern SField const sfActiveValidator; +extern SField const sfImportVLKey; // array of objects (common) // ARRAY/1 is reserved for end of array @@ -607,6 +610,7 @@ extern SField const sfHooks; extern SField const sfHookGrants; extern SField const sfGenesisMints; extern SField const sfActiveValidators; +extern SField const sfImportVLKeys; //------------------------------------------------------------------------------ diff --git a/src/ripple/protocol/impl/InnerObjectFormats.cpp b/src/ripple/protocol/impl/InnerObjectFormats.cpp index f0a5c7918..f41ce97e7 100644 --- a/src/ripple/protocol/impl/InnerObjectFormats.cpp +++ b/src/ripple/protocol/impl/InnerObjectFormats.cpp @@ -130,7 +130,9 @@ InnerObjectFormats::InnerObjectFormats() sfGenesisMint.getCode(), { {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, + {sfGovernanceFlags, soeOPTIONAL}, + {sfGovernanceMarks, soeOPTIONAL}, }); } diff --git a/src/ripple/protocol/impl/LedgerFormats.cpp b/src/ripple/protocol/impl/LedgerFormats.cpp index 2235365af..98a47adcc 100644 --- a/src/ripple/protocol/impl/LedgerFormats.cpp +++ b/src/ripple/protocol/impl/LedgerFormats.cpp @@ -63,6 +63,8 @@ LedgerFormats::LedgerFormats() {sfRewardAccumulator, soeOPTIONAL}, {sfFirstNFTokenSequence, soeOPTIONAL}, {sfImportSequence, soeOPTIONAL}, + {sfGovernanceFlags, soeOPTIONAL}, + {sfGovernanceMarks, soeOPTIONAL}, }, commonFields); @@ -301,6 +303,7 @@ LedgerFormats::LedgerFormats() add(jss::UNLReport, ltUNL_REPORT, { + {sfImportVLKeys, soeREQUIRED}, {sfActiveValidators, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED}, diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 2f0157eee..c0b1e09a1 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -230,6 +230,8 @@ CONSTRUCT_TYPED_SFIELD(sfHookSetTxnID, "HookSetTxnID", UINT256, CONSTRUCT_TYPED_SFIELD(sfOfferID, "OfferID", UINT256, 34); CONSTRUCT_TYPED_SFIELD(sfEscrowID, "EscrowID", UINT256, 35); CONSTRUCT_TYPED_SFIELD(sfURITokenID, "URITokenID", UINT256, 36); +CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99); +CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98); // currency amount (common) CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1); @@ -338,6 +340,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfHookParameter, "HookParameter", OBJECT, CONSTRUCT_UNTYPED_SFIELD(sfHookGrant, "HookGrant", OBJECT, 24); CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT, 96); CONSTRUCT_UNTYPED_SFIELD(sfActiveValidator, "ActiveValidator", OBJECT, 95); +CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT, 94); // array of objects // ARRAY/1 is reserved for end of array @@ -360,6 +363,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfHookParameters, "HookParameters", ARRAY, CONSTRUCT_UNTYPED_SFIELD(sfHookGrants, "HookGrants", ARRAY, 20); CONSTRUCT_UNTYPED_SFIELD(sfGenesisMints, "GenesisMints", ARRAY, 96); CONSTRUCT_UNTYPED_SFIELD(sfActiveValidators, "ActiveValidators", ARRAY, 95); +CONSTRUCT_UNTYPED_SFIELD(sfImportVLKeys, "ImportVLKeys", ARRAY, 94); // clang-format on diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index c31996ae5..dadc06a9e 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -195,8 +195,10 @@ TxFormats::TxFormats() add(jss::UNLReport, ttUNL_REPORT, { - {sfLedgerSequence, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, + {sfLedgerSequence, soeREQUIRED}, + {sfActiveValidator, soeOPTIONAL}, + {sfImportVLKey, soeOPTIONAL}, + }, commonFields); diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index fee790281..401c8b786 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -752,7 +752,7 @@ voteAndCheck( std::size_t expect, PreVote const& pre = defaultPreVote) { - NegativeUNLVote vote(myId, history.env.journal); + NegativeUNLVote vote(myId, history.env.journal, history.env.app()); pre(vote); auto txSet = std::make_shared( SHAMapType::TRANSACTION, history.env.app().getNodeFamily()); @@ -773,7 +773,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite jtx::Env env(*this); NodeID myId(0xA0); - NegativeUNLVote vote(myId, env.journal); + NegativeUNLVote vote(myId, env.journal, env.app()); // one add, one remove auto txSet = std::make_shared( @@ -797,7 +797,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite jtx::Env env(*this); NodeID myId(0xA0); - NegativeUNLVote vote(myId, env.journal); + NegativeUNLVote vote(myId, env.journal, env.app()); uint256 pad_0(0); uint256 pad_f = ~pad_0; @@ -834,7 +834,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite if (history.goodHistory) { NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); + history.UNLNodeIDs[3], history.env.journal, history.env.app()); BEAST_EXPECT(!vote.buildScoreTable( history.lastLedger(), history.UNLNodeIDSet, @@ -849,7 +849,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite if (history.goodHistory) { NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); + history.UNLNodeIDs[3], history.env.journal, history.env.app()); BEAST_EXPECT(!vote.buildScoreTable( history.lastLedger(), history.UNLNodeIDSet, @@ -872,7 +872,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite history.UNLNodeIDs[idx] == myId && l->seq() % 2 == 0); }); - NegativeUNLVote vote(myId, history.env.journal); + NegativeUNLVote vote(myId, history.env.journal, history.env.app()); BEAST_EXPECT(!vote.buildScoreTable( history.lastLedger(), history.UNLNodeIDSet, @@ -915,7 +915,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite history.validations.add(badNode, v2); } - NegativeUNLVote vote(myId, history.env.journal); + NegativeUNLVote vote(myId, history.env.journal, history.env.app()); // local node still on wrong chain, can build a scoreTable, // but all other nodes' scores are zero @@ -954,7 +954,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite [&](std::shared_ptr const& l, std::size_t idx) -> bool { return true; }); NegativeUNLVote vote( - history.UNLNodeIDs[3], history.env.journal); + history.UNLNodeIDs[3], history.env.journal, history.env.app()); auto scoreTable = vote.buildScoreTable( history.lastLedger(), history.UNLNodeIDSet, @@ -1031,7 +1031,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite for (auto const& n : history.UNLNodeIDs) goodScoreTable[n] = NegativeUNLVote::negativeUNLHighWaterMark + 1; - NegativeUNLVote vote(history.UNLNodeIDs[0], history.env.journal); + NegativeUNLVote vote(history.UNLNodeIDs[0], history.env.journal, history.env.app()); { // all good scores @@ -1165,7 +1165,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite jtx::Env env(*this); NodeID myId(0xA0); - NegativeUNLVote vote(myId, env.journal); + NegativeUNLVote vote(myId, env.journal, env.app()); std::array unlSizes = {34, 35, 80}; std::array nUnlPercent = {0, 50, 100}; @@ -1338,7 +1338,7 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite jtx::Env env(*this); NodeID myId(0xA0); - NegativeUNLVote vote(myId, env.journal); + NegativeUNLVote vote(myId, env.journal, env.app()); // test cases: // newValidators_ of the NegativeUNLVote empty, add one @@ -1451,7 +1451,7 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite return add_50 || add_100 || add_me; }); - NegativeUNLVote vote(myId, history.env.journal); + NegativeUNLVote vote(myId, history.env.journal, history.env.app()); auto scoreTable = vote.buildScoreTable( history.lastLedger(), history.UNLNodeIDSet,