diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 40c9fce1bb..ff4653e5c7 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -188,14 +188,14 @@ enum LedgerSpecificFlags { lsfMPTCanTransfer = 0x00000020, lsfMPTCanClawback = 0x00000040, - lmfMPTCanMutateCanLock = 0x00000002, - lmfMPTCanMutateRequireAuth = 0x00000004, - lmfMPTCanMutateCanEscrow = 0x00000008, - lmfMPTCanMutateCanTrade = 0x00000010, - lmfMPTCanMutateCanTransfer = 0x00000020, - lmfMPTCanMutateCanClawback = 0x00000040, - lmfMPTCanMutateMetadata = 0x00010000, - lmfMPTCanMutateTransferFee = 0x00020000, + lsmfMPTCanMutateCanLock = 0x00000002, + lsmfMPTCanMutateRequireAuth = 0x00000004, + lsmfMPTCanMutateCanEscrow = 0x00000008, + lsmfMPTCanMutateCanTrade = 0x00000010, + lsmfMPTCanMutateCanTransfer = 0x00000020, + lsmfMPTCanMutateCanClawback = 0x00000040, + lsmfMPTCanMutateMetadata = 0x00010000, + lsmfMPTCanMutateTransferFee = 0x00020000, // ltMPTOKEN lsfMPTAuthorized = 0x00000002, diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index 30d991e680..dcbc10b927 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -156,14 +156,14 @@ constexpr std::uint32_t const tfMPTokenIssuanceCreateMask = // MPTokenIssuanceCreate MutableFlags: // Indicating specific fields or flags may be changed after issuance. -constexpr std::uint32_t const tmfMPTCanMutateCanLock = lmfMPTCanMutateCanLock; -constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lmfMPTCanMutateRequireAuth; -constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lmfMPTCanMutateCanEscrow; -constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lmfMPTCanMutateCanTrade; -constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lmfMPTCanMutateCanTransfer; -constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lmfMPTCanMutateCanClawback; -constexpr std::uint32_t const tmfMPTCanMutateMetadata = lmfMPTCanMutateMetadata; -constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lmfMPTCanMutateTransferFee; +constexpr std::uint32_t const tmfMPTCanMutateCanLock = lsmfMPTCanMutateCanLock; +constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lsmfMPTCanMutateRequireAuth; +constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lsmfMPTCanMutateCanEscrow; +constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lsmfMPTCanMutateCanTrade; +constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTransfer; +constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback; +constexpr std::uint32_t const tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata; +constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee; constexpr std::uint32_t const tmfMPTokenIssuanceCreateMutableMask = ~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow | tmfMPTCanMutateCanTrade | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee); diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index d25d33b663..d5351b1c40 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -45,7 +45,7 @@ XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo) -XRPL_FEATURE(PermissionDelegation, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(PermissionDelegation, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) // Check flags in Credential transactions XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo) diff --git a/include/xrpl/server/detail/Door.h b/include/xrpl/server/detail/Door.h index 7906af2a52..65bc310d4c 100644 --- a/include/xrpl/server/detail/Door.h +++ b/include/xrpl/server/detail/Door.h @@ -30,15 +30,29 @@ #include #include #include +#include #include +#include #include #include #include #include +#include +#if !BOOST_OS_WINDOWS +#include + +#include +#include +#endif + +#include #include +#include #include #include +#include +#include namespace ripple { @@ -98,10 +112,27 @@ private: boost::asio::strand strand_; bool ssl_; bool plain_; + static constexpr std::chrono::milliseconds INITIAL_ACCEPT_DELAY{50}; + static constexpr std::chrono::milliseconds MAX_ACCEPT_DELAY{2000}; + std::chrono::milliseconds accept_delay_{INITIAL_ACCEPT_DELAY}; + boost::asio::steady_timer backoff_timer_; + static constexpr double FREE_FD_THRESHOLD = 0.70; + + struct FDStats + { + std::uint64_t used{0}; + std::uint64_t limit{0}; + }; void reOpen(); + std::optional + query_fd_stats() const; + + bool + should_throttle_for_fds(); + public: Door( Handler& handler, @@ -299,6 +330,7 @@ Door::Door( , plain_( port_.protocol.count("http") > 0 || port_.protocol.count("ws") > 0 || port_.protocol.count("ws2")) + , backoff_timer_(io_context) { reOpen(); } @@ -323,6 +355,7 @@ Door::close() return boost::asio::post( strand_, std::bind(&Door::close, this->shared_from_this())); + backoff_timer_.cancel(); error_code ec; acceptor_.close(ec); } @@ -368,6 +401,17 @@ Door::do_accept(boost::asio::yield_context do_yield) { while (acceptor_.is_open()) { + if (should_throttle_for_fds()) + { + backoff_timer_.expires_after(accept_delay_); + boost::system::error_code tec; + backoff_timer_.async_wait(do_yield[tec]); + accept_delay_ = std::min(accept_delay_ * 2, MAX_ACCEPT_DELAY); + JLOG(j_.warn()) << "Throttling do_accept for " + << accept_delay_.count() << "ms."; + continue; + } + error_code ec; endpoint_type remote_address; stream_type stream(ioc_); @@ -377,15 +421,28 @@ Door::do_accept(boost::asio::yield_context do_yield) { if (ec == boost::asio::error::operation_aborted) break; - JLOG(j_.error()) << "accept: " << ec.message(); - if (ec == boost::asio::error::no_descriptors) + + if (ec == boost::asio::error::no_descriptors || + ec == boost::asio::error::no_buffer_space) { - JLOG(j_.info()) << "re-opening acceptor"; - reOpen(); + JLOG(j_.warn()) << "accept: Too many open files. Pausing for " + << accept_delay_.count() << "ms."; + + backoff_timer_.expires_after(accept_delay_); + boost::system::error_code tec; + backoff_timer_.async_wait(do_yield[tec]); + + accept_delay_ = std::min(accept_delay_ * 2, MAX_ACCEPT_DELAY); + } + else + { + JLOG(j_.error()) << "accept error: " << ec.message(); } continue; } + accept_delay_ = INITIAL_ACCEPT_DELAY; + if (ssl_ && plain_) { if (auto sp = ios().template emplace( @@ -408,6 +465,60 @@ Door::do_accept(boost::asio::yield_context do_yield) } } +template +std::optional::FDStats> +Door::query_fd_stats() const +{ +#if BOOST_OS_WINDOWS + return std::nullopt; +#else + FDStats s; + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != 0 || rl.rlim_cur == RLIM_INFINITY) + return std::nullopt; + s.limit = static_cast(rl.rlim_cur); +#if BOOST_OS_LINUX + constexpr char const* kFdDir = "/proc/self/fd"; +#else + constexpr char const* kFdDir = "/dev/fd"; +#endif + if (DIR* d = ::opendir(kFdDir)) + { + std::uint64_t cnt = 0; + while (::readdir(d) != nullptr) + ++cnt; + ::closedir(d); + // readdir counts '.', '..', and the DIR* itself shows in the list + s.used = (cnt >= 3) ? (cnt - 3) : 0; + return s; + } + return std::nullopt; +#endif +} + +template +bool +Door::should_throttle_for_fds() +{ +#if BOOST_OS_WINDOWS + return false; +#else + auto const stats = query_fd_stats(); + if (!stats || stats->limit == 0) + return false; + + auto const& s = *stats; + auto const free = (s.limit > s.used) ? (s.limit - s.used) : 0ull; + double const free_ratio = + static_cast(free) / static_cast(s.limit); + if (free_ratio < FREE_FD_THRESHOLD) + { + return true; + } + return false; +#endif +} + } // namespace ripple #endif diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index 3e27741c2f..10b7e81b4f 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -3126,7 +3126,7 @@ rippleUnlockEscrowMPT( { // LCOV_EXCL_START JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE + return tecOBJECT_NOT_FOUND; } // LCOV_EXCL_STOP auto current = sle->getFieldU64(sfMPTAmount); diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index ae15ea6dec..b54c74c80d 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -36,7 +36,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.6.1-rc1" +char const* const versionString = "2.6.1" // clang-format on #if defined(DEBUG) || defined(SANITIZER) diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp index c406a8ec5f..6fb87711c8 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp @@ -51,14 +51,18 @@ struct MPTMutabilityFlags }; static constexpr std::array mptMutabilityFlags = { - {{tmfMPTSetCanLock, tmfMPTClearCanLock, lmfMPTCanMutateCanLock}, - {tmfMPTSetRequireAuth, tmfMPTClearRequireAuth, lmfMPTCanMutateRequireAuth}, - {tmfMPTSetCanEscrow, tmfMPTClearCanEscrow, lmfMPTCanMutateCanEscrow}, - {tmfMPTSetCanTrade, tmfMPTClearCanTrade, lmfMPTCanMutateCanTrade}, - {tmfMPTSetCanTransfer, tmfMPTClearCanTransfer, lmfMPTCanMutateCanTransfer}, + {{tmfMPTSetCanLock, tmfMPTClearCanLock, lsmfMPTCanMutateCanLock}, + {tmfMPTSetRequireAuth, + tmfMPTClearRequireAuth, + lsmfMPTCanMutateRequireAuth}, + {tmfMPTSetCanEscrow, tmfMPTClearCanEscrow, lsmfMPTCanMutateCanEscrow}, + {tmfMPTSetCanTrade, tmfMPTClearCanTrade, lsmfMPTCanMutateCanTrade}, + {tmfMPTSetCanTransfer, + tmfMPTClearCanTransfer, + lsmfMPTCanMutateCanTransfer}, {tmfMPTSetCanClawback, tmfMPTClearCanClawback, - lmfMPTCanMutateCanClawback}}}; + lsmfMPTCanMutateCanClawback}}}; NotTEC MPTokenIssuanceSet::preflight(PreflightContext const& ctx) @@ -243,7 +247,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) return tecNO_PERMISSION; } - if (!isMutableFlag(lmfMPTCanMutateMetadata) && + if (!isMutableFlag(lsmfMPTCanMutateMetadata) && ctx.tx.isFieldPresent(sfMPTokenMetadata)) return tecNO_PERMISSION; @@ -256,7 +260,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) if (fee > 0u && !sleMptIssuance->isFlag(lsfMPTCanTransfer)) return tecNO_PERMISSION; - if (!isMutableFlag(lmfMPTCanMutateTransferFee)) + if (!isMutableFlag(lsmfMPTCanMutateTransferFee)) return tecNO_PERMISSION; } diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 112017ebaf..f6b8b3c9d2 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -660,14 +660,15 @@ Transactor::apply() NotTEC Transactor::checkSign( - PreclaimContext const& ctx, + ReadView const& view, + ApplyFlags flags, AccountID const& idAccount, - STObject const& sigObject) + STObject const& sigObject, + beast::Journal const j) { auto const pkSigner = sigObject.getFieldVL(sfSigningPubKey); // Ignore signature check on batch inner transactions - if (sigObject.isFlag(tfInnerBatchTxn) && - ctx.view.rules().enabled(featureBatch)) + if (sigObject.isFlag(tfInnerBatchTxn) && view.rules().enabled(featureBatch)) { // Defensive Check: These values are also checked in Batch::preflight if (sigObject.isFieldPresent(sfTxnSignature) || !pkSigner.empty() || @@ -678,7 +679,7 @@ Transactor::checkSign( return tesSUCCESS; } - if ((ctx.flags & tapDRY_RUN) && pkSigner.empty() && + if ((flags & tapDRY_RUN) && pkSigner.empty() && !sigObject.isFieldPresent(sfSigners)) { // simulate: skip signature validation when neither SigningPubKey nor @@ -688,9 +689,9 @@ Transactor::checkSign( // If the pk is empty and not simulate or simulate and signers, // then we must be multi-signing. - if (ctx.tx.isFieldPresent(sfSigners)) + if (sigObject.isFieldPresent(sfSigners)) { - return checkMultiSign(ctx, idAccount, sigObject); + return checkMultiSign(view, flags, idAccount, sigObject, j); } // Check Single Sign @@ -699,7 +700,7 @@ Transactor::checkSign( if (!publicKeyType(makeSlice(pkSigner))) { - JLOG(ctx.j.trace()) << "checkSign: signing public key type is unknown"; + JLOG(j.trace()) << "checkSign: signing public key type is unknown"; return tefBAD_AUTH; // FIXME: should be better error! } @@ -707,11 +708,11 @@ Transactor::checkSign( auto const idSigner = pkSigner.empty() ? idAccount : calcAccountID(PublicKey(makeSlice(pkSigner))); - auto const sleAccount = ctx.view.read(keylet::account(idAccount)); + auto const sleAccount = view.read(keylet::account(idAccount)); if (!sleAccount) return terNO_ACCOUNT; - return checkSingleSign(ctx, idSigner, idAccount, sleAccount); + return checkSingleSign(view, idSigner, idAccount, sleAccount, j); } NotTEC @@ -720,7 +721,7 @@ Transactor::checkSign(PreclaimContext const& ctx) auto const idAccount = ctx.tx.isFieldPresent(sfDelegate) ? ctx.tx.getAccountID(sfDelegate) : ctx.tx.getAccountID(sfAccount); - return checkSign(ctx, idAccount, ctx.tx); + return checkSign(ctx.view, ctx.flags, idAccount, ctx.tx, ctx.j); } NotTEC @@ -735,7 +736,8 @@ Transactor::checkBatchSign(PreclaimContext const& ctx) Blob const& pkSigner = signer.getFieldVL(sfSigningPubKey); if (pkSigner.empty()) { - if (ret = checkMultiSign(ctx, idAccount, signer); + if (ret = checkMultiSign( + ctx.view, ctx.flags, idAccount, signer, ctx.j); !isTesSuccess(ret)) return ret; } @@ -759,7 +761,8 @@ Transactor::checkBatchSign(PreclaimContext const& ctx) return tesSUCCESS; } - if (ret = checkSingleSign(ctx, idSigner, idAccount, sleAccount); + if (ret = checkSingleSign( + ctx.view, idSigner, idAccount, sleAccount, ctx.j); !isTesSuccess(ret)) return ret; } @@ -769,14 +772,15 @@ Transactor::checkBatchSign(PreclaimContext const& ctx) NotTEC Transactor::checkSingleSign( - PreclaimContext const& ctx, + ReadView const& view, AccountID const& idSigner, AccountID const& idAccount, - std::shared_ptr sleAccount) + std::shared_ptr sleAccount, + beast::Journal const j) { bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster); - if (ctx.view.rules().enabled(fixMasterKeyAsRegularKey)) + if (view.rules().enabled(fixMasterKeyAsRegularKey)) { // Signed with regular key. if ((*sleAccount)[~sfRegularKey] == idSigner) @@ -813,16 +817,14 @@ Transactor::checkSingleSign( else if (sleAccount->isFieldPresent(sfRegularKey)) { // Signing key does not match master or regular key. - JLOG(ctx.j.trace()) - << "checkSingleSign: Not authorized to use account."; + JLOG(j.trace()) << "checkSingleSign: Not authorized to use account."; return tefBAD_AUTH; } else { // No regular key on account and signing key does not match master key. // FIXME: Why differentiate this case from tefBAD_AUTH? - JLOG(ctx.j.trace()) - << "checkSingleSign: Not authorized to use account."; + JLOG(j.trace()) << "checkSingleSign: Not authorized to use account."; return tefBAD_AUTH_MASTER; } @@ -831,17 +833,19 @@ Transactor::checkSingleSign( NotTEC Transactor::checkMultiSign( - PreclaimContext const& ctx, + ReadView const& view, + ApplyFlags flags, AccountID const& id, - STObject const& sigObject) + STObject const& sigObject, + beast::Journal const j) { // Get id's SignerList and Quorum. std::shared_ptr sleAccountSigners = - ctx.view.read(keylet::signers(id)); + view.read(keylet::signers(id)); // If the signer list doesn't exist the account is not multi-signing. if (!sleAccountSigners) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Invalid: Not a multi-signing account."; return tefNOT_MULTI_SIGNING; } @@ -856,7 +860,7 @@ Transactor::checkMultiSign( "ripple::Transactor::checkMultiSign : signer list ID is 0"); auto accountSigners = - SignerEntries::deserialize(*sleAccountSigners, ctx.j, "ledger"); + SignerEntries::deserialize(*sleAccountSigners, j, "ledger"); if (!accountSigners) return accountSigners.error(); @@ -880,7 +884,7 @@ Transactor::checkMultiSign( { if (++iter == accountSigners->end()) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Invalid SigningAccount.Account."; return tefBAD_SIGNATURE; } @@ -888,7 +892,7 @@ Transactor::checkMultiSign( if (iter->account != txSignerAcctID) { // The SigningAccount is not in the SignerEntries. - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Invalid SigningAccount.Account."; return tefBAD_SIGNATURE; } @@ -902,13 +906,13 @@ Transactor::checkMultiSign( // STTx::checkMultiSign if (!spk.empty() && !publicKeyType(makeSlice(spk))) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "checkMultiSign: signing public key type is unknown"; return tefBAD_SIGNATURE; } XRPL_ASSERT( - (ctx.flags & tapDRY_RUN) || !spk.empty(), + (flags & tapDRY_RUN) || !spk.empty(), "ripple::Transactor::checkMultiSign : non-empty signer or " "simulation"); AccountID const signingAcctIDFromPubKey = spk.empty() @@ -940,8 +944,7 @@ Transactor::checkMultiSign( // In any of these cases we need to know whether the account is in // the ledger. Determine that now. - auto const sleTxSignerRoot = - ctx.view.read(keylet::account(txSignerAcctID)); + auto const sleTxSignerRoot = view.read(keylet::account(txSignerAcctID)); if (signingAcctIDFromPubKey == txSignerAcctID) { @@ -954,7 +957,7 @@ Transactor::checkMultiSign( if (signerAccountFlags & lsfDisableMaster) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Signer:Account lsfDisableMaster."; return tefMASTER_DISABLED; } @@ -966,21 +969,21 @@ Transactor::checkMultiSign( // Public key must hash to the account's regular key. if (!sleTxSignerRoot) { - JLOG(ctx.j.trace()) << "applyTransaction: Non-phantom signer " - "lacks account root."; + JLOG(j.trace()) << "applyTransaction: Non-phantom signer " + "lacks account root."; return tefBAD_SIGNATURE; } if (!sleTxSignerRoot->isFieldPresent(sfRegularKey)) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Account lacks RegularKey."; return tefBAD_SIGNATURE; } if (signingAcctIDFromPubKey != sleTxSignerRoot->getAccountID(sfRegularKey)) { - JLOG(ctx.j.trace()) + JLOG(j.trace()) << "applyTransaction: Account doesn't match RegularKey."; return tefBAD_SIGNATURE; } @@ -992,8 +995,7 @@ Transactor::checkMultiSign( // Cannot perform transaction if quorum is not met. if (weightSum < sleAccountSigners->getFieldU32(sfSignerQuorum)) { - JLOG(ctx.j.trace()) - << "applyTransaction: Signers failed to meet quorum."; + JLOG(j.trace()) << "applyTransaction: Signers failed to meet quorum."; return tefBAD_QUORUM; } diff --git a/src/xrpld/app/tx/detail/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h index 429dcec6fc..17ef62e607 100644 --- a/src/xrpld/app/tx/detail/Transactor.h +++ b/src/xrpld/app/tx/detail/Transactor.h @@ -283,9 +283,11 @@ protected: static NotTEC checkSign( - PreclaimContext const& ctx, - AccountID const& id, - STObject const& sigObject); + ReadView const& view, + ApplyFlags flags, + AccountID const& idAccount, + STObject const& sigObject, + beast::Journal const j); // Base class always returns true static bool @@ -323,15 +325,18 @@ private: payFee(); static NotTEC checkSingleSign( - PreclaimContext const& ctx, + ReadView const& view, AccountID const& idSigner, AccountID const& idAccount, - std::shared_ptr sleAccount); + std::shared_ptr sleAccount, + beast::Journal const j); static NotTEC checkMultiSign( - PreclaimContext const& ctx, + ReadView const& view, + ApplyFlags flags, AccountID const& id, - STObject const& sigObject); + STObject const& sigObject, + beast::Journal const j); void trapTransaction(uint256) const;