From 64755110e45dd48e7d179c0f7336ae8b3cc9192d Mon Sep 17 00:00:00 2001 From: seelabs Date: Fri, 15 Sep 2023 09:51:58 -0400 Subject: [PATCH] Reduce boilerplate in applySteps: When a new transactor is added, there are several places in applySteps that need to be modified. This patch refactors the code so only one function needs to be modified. --- src/ripple/app/tx/impl/applySteps.cpp | 624 +++++++------------------- 1 file changed, 170 insertions(+), 454 deletions(-) diff --git a/src/ripple/app/tx/impl/applySteps.cpp b/src/ripple/app/tx/impl/applySteps.cpp index d4d9e72a830..4c882f3fb8a 100644 --- a/src/ripple/app/tx/impl/applySteps.cpp +++ b/src/ripple/app/tx/impl/applySteps.cpp @@ -50,371 +50,240 @@ #include #include +#include + namespace ripple { -// Templates so preflight does the right thing with T::ConsequencesFactory. -// -// This could be done more easily using if constexpr, but Visual Studio -// 2017 doesn't handle if constexpr correctly. So once we're no longer -// building with Visual Studio 2017 we can consider replacing the four -// templates with a single template function that uses if constexpr. -// -// For Transactor::Normal -template < - class T, - std::enable_if_t = 0> -TxConsequences -consequences_helper(PreflightContext const& ctx) -{ - return TxConsequences(ctx.tx); -}; +namespace { -// For Transactor::Blocker -template < - class T, - std::enable_if_t = 0> -TxConsequences -consequences_helper(PreflightContext const& ctx) -{ - return TxConsequences(ctx.tx, TxConsequences::blocker); -}; - -// For Transactor::Custom -template < - class T, - std::enable_if_t = 0> -TxConsequences -consequences_helper(PreflightContext const& ctx) +struct UnknownTxnType : std::exception { - return T::makeTxConsequences(ctx); + TxType txnType; + UnknownTxnType(TxType t) : txnType{t} + { + } }; -template -std::pair -invoke_preflight_helper(PreflightContext const& ctx) +// Call a lambda with the concrete transaction type as a template parameter +// throw an "UnknownTxnType" exception on error +template +auto +with_txn_type(TxType txnType, F&& f) { - auto const tec = T::preflight(ctx); - return { - tec, - isTesSuccess(tec) ? consequences_helper(ctx) : TxConsequences{tec}}; -} - -static std::pair -invoke_preflight(PreflightContext const& ctx) -{ - switch (ctx.tx.getTxnType()) + switch (txnType) { case ttACCOUNT_DELETE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttACCOUNT_SET: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttCHECK_CANCEL: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttCHECK_CASH: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttCHECK_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttDEPOSIT_PREAUTH: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttOFFER_CANCEL: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttOFFER_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttESCROW_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttESCROW_FINISH: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttESCROW_CANCEL: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttPAYCHAN_CLAIM: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttPAYCHAN_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttPAYCHAN_FUND: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttPAYMENT: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttREGULAR_KEY_SET: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttSIGNER_LIST_SET: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttTICKET_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttTRUST_SET: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMENDMENT: case ttFEE: case ttUNL_MODIFY: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttNFTOKEN_MINT: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttNFTOKEN_BURN: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttNFTOKEN_CREATE_OFFER: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttNFTOKEN_CANCEL_OFFER: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttNFTOKEN_ACCEPT_OFFER: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttCLAWBACK: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_CREATE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_DEPOSIT: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_WITHDRAW: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_VOTE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_BID: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttAMM_DELETE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_CREATE_BRIDGE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_MODIFY_BRIDGE: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_CREATE_CLAIM_ID: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_COMMIT: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_CLAIM: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_ADD_CLAIM_ATTESTATION: - return invoke_preflight_helper(ctx); + return f.template operator()(); case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION: - return invoke_preflight_helper( - ctx); + return f.template operator()(); case ttXCHAIN_ACCOUNT_CREATE_COMMIT: - return invoke_preflight_helper(ctx); + return f.template operator()(); default: - assert(false); - return {temUNKNOWN, TxConsequences{temUNKNOWN}}; + throw UnknownTxnType(txnType); } } +} // namespace -/* invoke_preclaim uses name hiding to accomplish - compile-time polymorphism of (presumably) static - class functions for Transactor and derived classes. -*/ +// Templates so preflight does the right thing with T::ConsequencesFactory. +// +// This could be done more easily using if constexpr, but Visual Studio +// 2017 doesn't handle if constexpr correctly. So once we're no longer +// building with Visual Studio 2017 we can consider replacing the four +// templates with a single template function that uses if constexpr. +// +// For Transactor::Normal +// + +// clang-format off +// Current formatter for rippled is based on clang-10, which does not handle `requires` clauses +template +requires(T::ConsequencesFactory == Transactor::Normal) +TxConsequences + consequences_helper(PreflightContext const& ctx) +{ + return TxConsequences(ctx.tx); +}; + +// For Transactor::Blocker +template +requires(T::ConsequencesFactory == Transactor::Blocker) +TxConsequences + consequences_helper(PreflightContext const& ctx) +{ + return TxConsequences(ctx.tx, TxConsequences::blocker); +}; + +// For Transactor::Custom template +requires(T::ConsequencesFactory == Transactor::Custom) +TxConsequences + consequences_helper(PreflightContext const& ctx) +{ + return T::makeTxConsequences(ctx); +}; +// clang-format on + +static std::pair +invoke_preflight(PreflightContext const& ctx) +{ + try + { + return with_txn_type(ctx.tx.getTxnType(), [&]() { + auto const tec = T::preflight(ctx); + return std::make_pair( + tec, + isTesSuccess(tec) ? consequences_helper(ctx) + : TxConsequences{tec}); + }); + } + catch (UnknownTxnType const& e) + { + // Should never happen + JLOG(ctx.j.fatal()) + << "Unknown transaction type in preflight: " << e.txnType; + assert(false); + return {temUNKNOWN, TxConsequences{temUNKNOWN}}; + } +} + static TER invoke_preclaim(PreclaimContext const& ctx) { - // If the transactor requires a valid account and the transaction doesn't - // list one, preflight will have already a flagged a failure. - auto const id = ctx.tx.getAccountID(sfAccount); - - if (id != beast::zero) + try { - TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j); + // use name hiding to accomplish compile-time polymorphism of static + // class functions for Transactor and derived classes. + return with_txn_type(ctx.tx.getTxnType(), [&]() { + // If the transactor requires a valid account and the transaction + // doesn't list one, preflight will have already a flagged a + // failure. + auto const id = ctx.tx.getAccountID(sfAccount); - if (result != tesSUCCESS) - return result; + if (id != beast::zero) + { + TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j); - result = T::checkPriorTxAndLastLedger(ctx); + if (result != tesSUCCESS) + return result; - if (result != tesSUCCESS) - return result; + result = T::checkPriorTxAndLastLedger(ctx); - result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx)); + if (result != tesSUCCESS) + return result; - if (result != tesSUCCESS) - return result; + result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx)); - result = T::checkSign(ctx); + if (result != tesSUCCESS) + return result; - if (result != tesSUCCESS) - return result; - } + result = T::checkSign(ctx); - return T::preclaim(ctx); -} + if (result != tesSUCCESS) + return result; + } -static TER -invoke_preclaim(PreclaimContext const& ctx) -{ - switch (ctx.tx.getTxnType()) + return T::preclaim(ctx); + }); + } + catch (UnknownTxnType const& e) { - case ttACCOUNT_DELETE: - return invoke_preclaim(ctx); - case ttACCOUNT_SET: - return invoke_preclaim(ctx); - case ttCHECK_CANCEL: - return invoke_preclaim(ctx); - case ttCHECK_CASH: - return invoke_preclaim(ctx); - case ttCHECK_CREATE: - return invoke_preclaim(ctx); - case ttDEPOSIT_PREAUTH: - return invoke_preclaim(ctx); - case ttOFFER_CANCEL: - return invoke_preclaim(ctx); - case ttOFFER_CREATE: - return invoke_preclaim(ctx); - case ttESCROW_CREATE: - return invoke_preclaim(ctx); - case ttESCROW_FINISH: - return invoke_preclaim(ctx); - case ttESCROW_CANCEL: - return invoke_preclaim(ctx); - case ttPAYCHAN_CLAIM: - return invoke_preclaim(ctx); - case ttPAYCHAN_CREATE: - return invoke_preclaim(ctx); - case ttPAYCHAN_FUND: - return invoke_preclaim(ctx); - case ttPAYMENT: - return invoke_preclaim(ctx); - case ttREGULAR_KEY_SET: - return invoke_preclaim(ctx); - case ttSIGNER_LIST_SET: - return invoke_preclaim(ctx); - case ttTICKET_CREATE: - return invoke_preclaim(ctx); - case ttTRUST_SET: - return invoke_preclaim(ctx); - case ttAMENDMENT: - case ttFEE: - case ttUNL_MODIFY: - return invoke_preclaim(ctx); - case ttNFTOKEN_MINT: - return invoke_preclaim(ctx); - case ttNFTOKEN_BURN: - return invoke_preclaim(ctx); - case ttNFTOKEN_CREATE_OFFER: - return invoke_preclaim(ctx); - case ttNFTOKEN_CANCEL_OFFER: - return invoke_preclaim(ctx); - case ttNFTOKEN_ACCEPT_OFFER: - return invoke_preclaim(ctx); - case ttCLAWBACK: - return invoke_preclaim(ctx); - case ttAMM_CREATE: - return invoke_preclaim(ctx); - case ttAMM_DEPOSIT: - return invoke_preclaim(ctx); - case ttAMM_WITHDRAW: - return invoke_preclaim(ctx); - case ttAMM_VOTE: - return invoke_preclaim(ctx); - case ttAMM_BID: - return invoke_preclaim(ctx); - case ttAMM_DELETE: - return invoke_preclaim(ctx); - case ttXCHAIN_CREATE_BRIDGE: - return invoke_preclaim(ctx); - case ttXCHAIN_MODIFY_BRIDGE: - return invoke_preclaim(ctx); - case ttXCHAIN_CREATE_CLAIM_ID: - return invoke_preclaim(ctx); - case ttXCHAIN_COMMIT: - return invoke_preclaim(ctx); - case ttXCHAIN_CLAIM: - return invoke_preclaim(ctx); - case ttXCHAIN_ACCOUNT_CREATE_COMMIT: - return invoke_preclaim(ctx); - case ttXCHAIN_ADD_CLAIM_ATTESTATION: - return invoke_preclaim(ctx); - case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION: - return invoke_preclaim(ctx); - default: - assert(false); - return temUNKNOWN; + // Should never happen + JLOG(ctx.j.fatal()) + << "Unknown transaction type in preclaim: " << e.txnType; + assert(false); + return temUNKNOWN; } } static XRPAmount invoke_calculateBaseFee(ReadView const& view, STTx const& tx) { - switch (tx.getTxnType()) + try { - case ttACCOUNT_DELETE: - return DeleteAccount::calculateBaseFee(view, tx); - case ttACCOUNT_SET: - return SetAccount::calculateBaseFee(view, tx); - case ttCHECK_CANCEL: - return CancelCheck::calculateBaseFee(view, tx); - case ttCHECK_CASH: - return CashCheck::calculateBaseFee(view, tx); - case ttCHECK_CREATE: - return CreateCheck::calculateBaseFee(view, tx); - case ttDEPOSIT_PREAUTH: - return DepositPreauth::calculateBaseFee(view, tx); - case ttOFFER_CANCEL: - return CancelOffer::calculateBaseFee(view, tx); - case ttOFFER_CREATE: - return CreateOffer::calculateBaseFee(view, tx); - case ttESCROW_CREATE: - return EscrowCreate::calculateBaseFee(view, tx); - case ttESCROW_FINISH: - return EscrowFinish::calculateBaseFee(view, tx); - case ttESCROW_CANCEL: - return EscrowCancel::calculateBaseFee(view, tx); - case ttPAYCHAN_CLAIM: - return PayChanClaim::calculateBaseFee(view, tx); - case ttPAYCHAN_CREATE: - return PayChanCreate::calculateBaseFee(view, tx); - case ttPAYCHAN_FUND: - return PayChanFund::calculateBaseFee(view, tx); - case ttPAYMENT: - return Payment::calculateBaseFee(view, tx); - case ttREGULAR_KEY_SET: - return SetRegularKey::calculateBaseFee(view, tx); - case ttSIGNER_LIST_SET: - return SetSignerList::calculateBaseFee(view, tx); - case ttTICKET_CREATE: - return CreateTicket::calculateBaseFee(view, tx); - case ttTRUST_SET: - return SetTrust::calculateBaseFee(view, tx); - case ttAMENDMENT: - case ttFEE: - case ttUNL_MODIFY: - return Change::calculateBaseFee(view, tx); - case ttNFTOKEN_MINT: - return NFTokenMint::calculateBaseFee(view, tx); - case ttNFTOKEN_BURN: - return NFTokenBurn::calculateBaseFee(view, tx); - case ttNFTOKEN_CREATE_OFFER: - return NFTokenCreateOffer::calculateBaseFee(view, tx); - case ttNFTOKEN_CANCEL_OFFER: - return NFTokenCancelOffer::calculateBaseFee(view, tx); - case ttNFTOKEN_ACCEPT_OFFER: - return NFTokenAcceptOffer::calculateBaseFee(view, tx); - case ttCLAWBACK: - return Clawback::calculateBaseFee(view, tx); - case ttAMM_CREATE: - return AMMCreate::calculateBaseFee(view, tx); - case ttAMM_DEPOSIT: - return AMMDeposit::calculateBaseFee(view, tx); - case ttAMM_WITHDRAW: - return AMMWithdraw::calculateBaseFee(view, tx); - case ttAMM_VOTE: - return AMMVote::calculateBaseFee(view, tx); - case ttAMM_BID: - return AMMBid::calculateBaseFee(view, tx); - case ttAMM_DELETE: - return AMMDelete::calculateBaseFee(view, tx); - case ttXCHAIN_CREATE_BRIDGE: - return XChainCreateBridge::calculateBaseFee(view, tx); - case ttXCHAIN_MODIFY_BRIDGE: - return BridgeModify::calculateBaseFee(view, tx); - case ttXCHAIN_CREATE_CLAIM_ID: - return XChainCreateClaimID::calculateBaseFee(view, tx); - case ttXCHAIN_COMMIT: - return XChainCommit::calculateBaseFee(view, tx); - case ttXCHAIN_CLAIM: - return XChainClaim::calculateBaseFee(view, tx); - case ttXCHAIN_ADD_CLAIM_ATTESTATION: - return XChainAddClaimAttestation::calculateBaseFee(view, tx); - case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION: - return XChainAddAccountCreateAttestation::calculateBaseFee( - view, tx); - case ttXCHAIN_ACCOUNT_CREATE_COMMIT: - return XChainCreateAccountCommit::calculateBaseFee(view, tx); - default: - assert(false); - return XRPAmount{0}; + return with_txn_type(tx.getTxnType(), [&]() { + return T::calculateBaseFee(view, tx); + }); + } + catch (UnknownTxnType const& e) + { + assert(false); + return XRPAmount{0}; } } @@ -460,173 +329,20 @@ TxConsequences::TxConsequences(STTx const& tx, std::uint32_t sequencesConsumed) static std::pair invoke_apply(ApplyContext& ctx) { - switch (ctx.tx.getTxnType()) + try { - case ttACCOUNT_DELETE: { - DeleteAccount p(ctx); - return p(); - } - case ttACCOUNT_SET: { - SetAccount p(ctx); - return p(); - } - case ttCHECK_CANCEL: { - CancelCheck p(ctx); - return p(); - } - case ttCHECK_CASH: { - CashCheck p(ctx); - return p(); - } - case ttCHECK_CREATE: { - CreateCheck p(ctx); - return p(); - } - case ttDEPOSIT_PREAUTH: { - DepositPreauth p(ctx); - return p(); - } - case ttOFFER_CANCEL: { - CancelOffer p(ctx); - return p(); - } - case ttOFFER_CREATE: { - CreateOffer p(ctx); - return p(); - } - case ttESCROW_CREATE: { - EscrowCreate p(ctx); - return p(); - } - case ttESCROW_FINISH: { - EscrowFinish p(ctx); - return p(); - } - case ttESCROW_CANCEL: { - EscrowCancel p(ctx); - return p(); - } - case ttPAYCHAN_CLAIM: { - PayChanClaim p(ctx); - return p(); - } - case ttPAYCHAN_CREATE: { - PayChanCreate p(ctx); - return p(); - } - case ttPAYCHAN_FUND: { - PayChanFund p(ctx); - return p(); - } - case ttPAYMENT: { - Payment p(ctx); - return p(); - } - case ttREGULAR_KEY_SET: { - SetRegularKey p(ctx); - return p(); - } - case ttSIGNER_LIST_SET: { - SetSignerList p(ctx); - return p(); - } - case ttTICKET_CREATE: { - CreateTicket p(ctx); - return p(); - } - case ttTRUST_SET: { - SetTrust p(ctx); + return with_txn_type(ctx.tx.getTxnType(), [&]() { + T p(ctx); return p(); - } - case ttAMENDMENT: - case ttFEE: - case ttUNL_MODIFY: { - Change p(ctx); - return p(); - } - case ttNFTOKEN_MINT: { - NFTokenMint p(ctx); - return p(); - } - case ttNFTOKEN_BURN: { - NFTokenBurn p(ctx); - return p(); - } - case ttNFTOKEN_CREATE_OFFER: { - NFTokenCreateOffer p(ctx); - return p(); - } - case ttNFTOKEN_CANCEL_OFFER: { - NFTokenCancelOffer p(ctx); - return p(); - } - case ttNFTOKEN_ACCEPT_OFFER: { - NFTokenAcceptOffer p(ctx); - return p(); - } - case ttCLAWBACK: { - Clawback p(ctx); - return p(); - } - case ttAMM_CREATE: { - AMMCreate p(ctx); - return p(); - } - case ttAMM_DEPOSIT: { - AMMDeposit p(ctx); - return p(); - } - case ttAMM_WITHDRAW: { - AMMWithdraw p(ctx); - return p(); - } - case ttAMM_VOTE: { - AMMVote p(ctx); - return p(); - } - case ttAMM_BID: { - AMMBid p(ctx); - return p(); - } - case ttAMM_DELETE: { - AMMDelete p(ctx); - return p(); - } - case ttXCHAIN_CREATE_BRIDGE: { - XChainCreateBridge p(ctx); - return p(); - } - case ttXCHAIN_MODIFY_BRIDGE: { - BridgeModify p(ctx); - return p(); - } - case ttXCHAIN_CREATE_CLAIM_ID: { - XChainCreateClaimID p(ctx); - return p(); - } - case ttXCHAIN_COMMIT: { - XChainCommit p(ctx); - return p(); - } - case ttXCHAIN_CLAIM: { - XChainClaim p(ctx); - return p(); - } - case ttXCHAIN_ADD_CLAIM_ATTESTATION: { - XChainAddClaimAttestation p(ctx); - return p(); - } - case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION: { - XChainAddAccountCreateAttestation p(ctx); - return p(); - } - case ttXCHAIN_ACCOUNT_CREATE_COMMIT: { - XChainCreateAccountCommit p(ctx); - return p(); - } - default: - assert(false); - return {temUNKNOWN, false}; + }); + } + catch (UnknownTxnType const& e) + { + // Should never happen + JLOG(ctx.journal.fatal()) + << "Unknown transaction type in apply: " << e.txnType; + assert(false); + return {temUNKNOWN, false}; } }