diff --git a/src/ripple/app/ledger/impl/OpenLedger.cpp b/src/ripple/app/ledger/impl/OpenLedger.cpp index 4f15a5024..598c3b6f6 100644 --- a/src/ripple/app/ledger/impl/OpenLedger.cpp +++ b/src/ripple/app/ledger/impl/OpenLedger.cpp @@ -127,6 +127,11 @@ OpenLedger::accept( { auto const& tx = txpair.first; auto const txId = tx->getTransactionID(); + + // skip emitted txns + if (tx->isFieldPresent(sfEmitDetails)) + continue; + if (auto const toSkip = app.getHashRouter().shouldRelay(txId)) { JLOG(j_.debug()) << "Relaying recovered tx " << txId; diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index 30d70af34..4a0b2f146 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -1187,16 +1187,18 @@ NetworkOPsImp::processTransaction( auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXN"); auto const view = m_ledgerMaster.getCurrentLedger(); - - // Enforce Network bar for emitted txn + + // This function is called by several different parts of the codebase + // under no circumstances will we ever accept an emitted txn from the network. + // Emitted txns are *always* and *only* inserted by TxQ::accept, and only + // arise from processing ltEMITTED out of the EMITTED_DIR. + // This isn't always an error because a fetch pack etc might include an emitted txn + // and if this is a deliberate attempt to send an emitted txn over the network it was + // already billed in PeerImp if (view->rules().enabled(featureHooks) && hook::isEmittedTxn(*transaction->getSTransaction())) { - JLOG(m_journal.warn()) - << "Submitted transaction invalid: EmitDetails present."; //RH NOTE: cannot set SF_BAD because if the tx will be generated by a hook we are about to execute - //then this would poison consensus for that emitted tx - //RH TODO: (severely) charge peer who sent return; } @@ -1504,7 +1506,10 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) auto const toSkip = app_.getHashRouter().shouldRelay(e.transaction->getID()); - if (toSkip) + bool const isEmitted = + hook::isEmittedTxn(*(e.transaction->getSTransaction())); + + if (toSkip && !isEmitted) { protocol::TMTransaction tx; Serializer s; @@ -2709,6 +2714,11 @@ NetworkOPsImp::pubProposedTransaction( std::shared_ptr const& transaction, TER result) { + + // never publish emitted txns + if (hook::isEmittedTxn(*transaction)) + return; + Json::Value jvObj = transJson(*transaction, result, false, ledger); { diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/ripple/app/misc/impl/TxQ.cpp index c90b8432f..d26748b2f 100644 --- a/src/ripple/app/misc/impl/TxQ.cpp +++ b/src/ripple/app/misc/impl/TxQ.cpp @@ -1423,7 +1423,8 @@ TxQ::accept(Application& app, OpenView& view) std::lock_guard lock(mutex_); auto const metricsSnapshot = feeMetrics_.getSnapshot(); - // inject emitted transactions if any + + // Inject emitted transactions if any if (view.rules().enabled(featureHooks)) do { Keylet const emittedDirKeylet { keylet::emittedDir() }; diff --git a/src/ripple/app/tx/impl/SetHook.h b/src/ripple/app/tx/impl/SetHook.h index 2a35db99d..375153767 100644 --- a/src/ripple/app/tx/impl/SetHook.h +++ b/src/ripple/app/tx/impl/SetHook.h @@ -74,7 +74,6 @@ public: static TER preclaim(PreclaimContext const&); - // RH TODO: compute fee in transactor on chain execution static FeeUnit64 calculateBaseFee(ReadView const& view, STTx const& tx); diff --git a/src/ripple/app/tx/impl/Transactor.cpp b/src/ripple/app/tx/impl/Transactor.cpp index 17ab30da7..39fa4c2a0 100644 --- a/src/ripple/app/tx/impl/Transactor.cpp +++ b/src/ripple/app/tx/impl/Transactor.cpp @@ -477,7 +477,6 @@ Transactor::consumeSeqProxy(SLE::pointer const& sleAccount) { assert(sleAccount); - // RH TODO: determine what interactions between hooks and tickets might cause issues // do not update sequence of sfAccountTxnID for emitted tx if (ctx_.emitted()) return tesSUCCESS; diff --git a/src/ripple/app/tx/impl/Transactor.h b/src/ripple/app/tx/impl/Transactor.h index fc7edaab0..e9b083b47 100644 --- a/src/ripple/app/tx/impl/Transactor.h +++ b/src/ripple/app/tx/impl/Transactor.h @@ -29,13 +29,6 @@ #include #include -namespace hook { - // RH TODO: fix applyHook.h so this prototype isn't needed - struct HookContext; - struct HookResult; - bool isEmittedTxn(ripple::STTx const& tx); -} - namespace ripple { /** State information when preflighting a tx. */ diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp index e738f7908..91bdcd332 100644 --- a/src/ripple/overlay/impl/PeerImp.cpp +++ b/src/ripple/overlay/impl/PeerImp.cpp @@ -1547,10 +1547,12 @@ PeerImp::handleTransaction( auto stx = std::make_shared(sit); uint256 txID = stx->getTransactionID(); + // Charge strongly for attempting to relay a txn with sfEmitDetails if (stx->isFieldPresent(sfEmitDetails)) { - JLOG(p_journal_.warn()) << "Ignoring Network relayed Tx containing sfEmitDetails."; - return; + JLOG(p_journal_.warn()) << "Ignoring Network relayed Tx containing sfEmitDetails (handleTransaction)."; + //fee_ = Resource::feeHighBurdenPeer; // RH TODO: enable when relay bug is fixed + //return; } int flags; @@ -3064,6 +3066,15 @@ PeerImp::checkTransaction( // VFALCO TODO Rewrite to not use exceptions try { + + // charge strongly for relaying Hook emitted txns + if (stx->isFieldPresent(sfEmitDetails)) + { + JLOG(p_journal_.warn()) << "Ignoring Network relayed Tx containing sfEmitDetails (checkSignature)."; + //charge(Resource::feeHighBurdenPeer); //RH TODO: enable this charging when relay bug fix + return; + } + // Expired? if (stx->isFieldPresent(sfLastLedgerSequence) && (stx->getFieldU32(sfLastLedgerSequence) <