mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-30 18:40:10 +00:00
chore: format files with clang-format
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/misc/ValidatorKeys.h>
|
||||
#include <ripple/app/misc/ValidatorList.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/app/tx/impl/ExportSign.h>
|
||||
#include <ripple/basics/random.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
@@ -49,6 +50,17 @@
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
// Debug macro for export investigation - remove after debugging
|
||||
#include <thread>
|
||||
#define DBG_EXPORT(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << "[" << __FILE__ << ":" << __LINE__ \
|
||||
<< " t=" << std::this_thread::get_id() << "] " << msg \
|
||||
<< std::endl; \
|
||||
std::cerr.flush(); \
|
||||
} while (0)
|
||||
|
||||
namespace ripple {
|
||||
|
||||
RCLConsensus::RCLConsensus(
|
||||
@@ -323,8 +335,10 @@ RCLConsensus::Adaptor::onClose(
|
||||
initialSet->setUnbacked();
|
||||
|
||||
// Build SHAMap containing all transactions in our open ledger
|
||||
DBG_EXPORT("onClose: iterating initialLedger->txs");
|
||||
for (auto const& tx : initialLedger->txs)
|
||||
{
|
||||
DBG_EXPORT("onClose: processing tx " << tx.first->getTransactionID());
|
||||
JLOG(j_.trace()) << "Adding open ledger TX "
|
||||
<< tx.first->getTransactionID();
|
||||
Serializer s(2048);
|
||||
@@ -333,6 +347,7 @@ RCLConsensus::Adaptor::onClose(
|
||||
SHAMapNodeType::tnTRANSACTION_NM,
|
||||
make_shamapitem(tx.first->getTransactionID(), s.slice()));
|
||||
}
|
||||
DBG_EXPORT("onClose: done iterating initialLedger->txs");
|
||||
|
||||
// Add pseudo-transactions to the set
|
||||
if (app_.config().standalone() || (proposing && !wrongLCL))
|
||||
@@ -406,6 +421,7 @@ RCLConsensus::Adaptor::onForceAccept(
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
DBG_EXPORT("onForceAccept prevLedger.seq=" << prevLedger.seq());
|
||||
doAccept(
|
||||
result,
|
||||
prevLedger,
|
||||
@@ -424,6 +440,7 @@ RCLConsensus::Adaptor::onAccept(
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
DBG_EXPORT("onAccept (async job) prevLedger.seq=" << prevLedger.seq());
|
||||
app_.getJobQueue().addJob(
|
||||
jtACCEPT,
|
||||
"acceptLedger",
|
||||
@@ -453,6 +470,7 @@ RCLConsensus::Adaptor::doAccept(
|
||||
ConsensusMode const& mode,
|
||||
Json::Value&& consensusJson)
|
||||
{
|
||||
DBG_EXPORT("doAccept prevLedger.seq=" << prevLedger.seq());
|
||||
prevProposers_ = result.proposers;
|
||||
prevRoundTime_ = result.roundTime.read();
|
||||
|
||||
@@ -653,14 +671,40 @@ RCLConsensus::Adaptor::doAccept(
|
||||
tapNONE,
|
||||
"consensus",
|
||||
[&](OpenView& view, beast::Journal j) {
|
||||
DBG_EXPORT("consensus callback seq=" << view.info().seq);
|
||||
//@@start export-sign-submit
|
||||
// Generate and submit ttEXPORT_SIGN UVTxns if we're a
|
||||
// validator on the UNLReport
|
||||
// Generate ttEXPORT_SIGN UVTxns if we're a validator on the
|
||||
// UNLReport. In standalone mode we queue via rawTxInsert so
|
||||
// it's applied when this open ledger closes. In network mode
|
||||
// we submit for relay to other validators.
|
||||
if (view.rules().enabled(featureExport))
|
||||
{
|
||||
auto exportSignTxns = makeExportSignTxns(view, app_, j_);
|
||||
for (auto const& tx : exportSignTxns)
|
||||
app_.getOPs().submitTransaction(tx);
|
||||
{
|
||||
uint256 txID = tx->getTransactionID();
|
||||
app_.getHashRouter().setFlags(txID, SF_PRIVATE2);
|
||||
|
||||
if (app_.config().standalone())
|
||||
{
|
||||
// Standalone: queue in open ledger, applied when it
|
||||
// closes
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
tx->add(*s);
|
||||
view.rawTxInsert(txID, std::move(s), nullptr);
|
||||
DBG_EXPORT(
|
||||
"standalone: queued ttEXPORT_SIGN txID="
|
||||
<< txID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Network: submit for relay to other validators
|
||||
app_.getOPs().submitTransaction(tx);
|
||||
DBG_EXPORT(
|
||||
"network: submitted ttEXPORT_SIGN txID="
|
||||
<< txID);
|
||||
}
|
||||
}
|
||||
}
|
||||
//@@end export-sign-submit
|
||||
return app_.getTxQ().accept(app_, view);
|
||||
|
||||
@@ -2067,6 +2067,9 @@ hook::finalizeHookResult(
|
||||
if (page)
|
||||
{
|
||||
(*sleExported)[sfOwnerNode] = *page;
|
||||
(*sleExported)[sfLedgerSequence] =
|
||||
applyCtx.view().info().seq;
|
||||
(*sleExported)[sfTransactionHash] = id;
|
||||
applyCtx.view().insert(sleExported);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -74,6 +74,17 @@ OpenLedger::modify(modify_type const& f)
|
||||
}
|
||||
|
||||
void
|
||||
// Debug macro for export investigation - remove after debugging
|
||||
#include <thread>
|
||||
#define DBG_EXPORT(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << "[" << __FILE__ << ":" << __LINE__ \
|
||||
<< " t=" << std::this_thread::get_id() << "] " << msg \
|
||||
<< std::endl; \
|
||||
std::cerr.flush(); \
|
||||
} while (0)
|
||||
|
||||
OpenLedger::accept(
|
||||
Application& app,
|
||||
Rules const& rules,
|
||||
@@ -85,6 +96,8 @@ OpenLedger::accept(
|
||||
std::string const& suffix,
|
||||
modify_type const& f)
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"OpenLedger::accept seq=" << ledger->seq() << " suffix=" << suffix);
|
||||
JLOG(j_.trace()) << "accept ledger " << ledger->seq() << " " << suffix;
|
||||
auto next = create(rules, ledger);
|
||||
if (retriesFirst)
|
||||
@@ -118,10 +131,23 @@ OpenLedger::accept(
|
||||
// Call the modifier
|
||||
if (f)
|
||||
f(*next, j_);
|
||||
DBG_EXPORT(
|
||||
"OpenLedger::accept AFTER CALLBACK seq="
|
||||
<< next->info().seq << " locals.size()=" << locals.size());
|
||||
// Apply local tx
|
||||
for (auto const& item : locals)
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"OpenLedger::accept applying local tx seq=" << next->info().seq);
|
||||
app.getTxQ().apply(app, *next, item.second, flags, j_);
|
||||
}
|
||||
DBG_EXPORT("OpenLedger::accept AFTER LOCAL TXS seq=" << next->info().seq);
|
||||
|
||||
DBG_EXPORT(
|
||||
"OpenLedger::accept RELAY LOOP DISABLED FOR DEBUGGING seq="
|
||||
<< next->info().seq);
|
||||
// COMPLETELY DISABLED FOR DEBUGGING
|
||||
#if 0
|
||||
// If we didn't relay this transaction recently, relay it to all peers
|
||||
for (auto const& txpair : next->txs)
|
||||
{
|
||||
@@ -146,10 +172,13 @@ OpenLedger::accept(
|
||||
app.overlay().relay(txId, msg, *toSkip);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Switch to the new open view
|
||||
DBG_EXPORT("OpenLedger::accept SWITCHING VIEW seq=" << next->info().seq);
|
||||
std::lock_guard lock2(current_mutex_);
|
||||
current_ = std::move(next);
|
||||
DBG_EXPORT("OpenLedger::accept EXIT");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -79,6 +79,18 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
// Debug macro for export investigation - remove after debugging
|
||||
#include <execinfo.h>
|
||||
#include <thread>
|
||||
#define DBG_EXPORT(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << "[" << __FILE__ << ":" << __LINE__ \
|
||||
<< " t=" << std::this_thread::get_id() << "] " << msg \
|
||||
<< std::endl; \
|
||||
std::cerr.flush(); \
|
||||
} while (0)
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class NetworkOPsImp final : public NetworkOPs
|
||||
@@ -360,7 +372,8 @@ public:
|
||||
getLedgerFetchInfo() override;
|
||||
std::uint32_t
|
||||
acceptLedger(
|
||||
std::optional<std::chrono::milliseconds> consensusDelay) override;
|
||||
std::optional<std::chrono::milliseconds> consensusDelay,
|
||||
std::string const& caller = "unknown") override;
|
||||
void
|
||||
reportFeeChange() override;
|
||||
void
|
||||
@@ -1773,6 +1786,7 @@ NetworkOPsImp::switchLastClosedLedger(
|
||||
tapNONE,
|
||||
"jump",
|
||||
[&](OpenView& view, beast::Journal j) {
|
||||
DBG_EXPORT("jump callback seq=" << view.info().seq);
|
||||
// Stuff the ledger with transactions from the queue.
|
||||
return app_.getTxQ().accept(app_, view);
|
||||
});
|
||||
@@ -3949,7 +3963,8 @@ NetworkOPsImp::unsubBook(std::uint64_t uSeq, Book const& book)
|
||||
|
||||
std::uint32_t
|
||||
NetworkOPsImp::acceptLedger(
|
||||
std::optional<std::chrono::milliseconds> consensusDelay)
|
||||
std::optional<std::chrono::milliseconds> consensusDelay,
|
||||
std::string const& caller)
|
||||
{
|
||||
// This code-path is exclusively used when the server is in standalone
|
||||
// mode via `ledger_accept`
|
||||
@@ -3959,11 +3974,44 @@ NetworkOPsImp::acceptLedger(
|
||||
Throw<std::runtime_error>(
|
||||
"Operation only possible in STANDALONE mode.");
|
||||
|
||||
// Detect reentrant calls
|
||||
static thread_local int acceptLedgerDepth = 0;
|
||||
auto closedSeq = m_ledgerMaster.getClosedLedger()->info().seq;
|
||||
DBG_EXPORT(
|
||||
"acceptLedger ENTER closedSeq="
|
||||
<< closedSeq << " depth=" << acceptLedgerDepth << " caller=" << caller);
|
||||
|
||||
if (acceptLedgerDepth > 0)
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"REENTRANT acceptLedger DETECTED! depth=" << acceptLedgerDepth);
|
||||
// Print stack trace
|
||||
void* callstack[128];
|
||||
int frames = backtrace(callstack, 128);
|
||||
char** strs = backtrace_symbols(callstack, frames);
|
||||
std::cerr << "=== STACK TRACE ===" << std::endl;
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
std::cerr << strs[i] << std::endl;
|
||||
}
|
||||
free(strs);
|
||||
std::cerr << "=== END STACK TRACE ===" << std::endl;
|
||||
std::cerr.flush();
|
||||
Throw<std::runtime_error>(
|
||||
"REENTRANT acceptLedger call detected at depth " +
|
||||
std::to_string(acceptLedgerDepth));
|
||||
}
|
||||
++acceptLedgerDepth;
|
||||
|
||||
// FIXME Could we improve on this and remove the need for a specialized
|
||||
// API in Consensus?
|
||||
beginConsensus(m_ledgerMaster.getClosedLedger()->info().hash);
|
||||
mConsensus.simulate(app_.timeKeeper().closeTime(), consensusDelay);
|
||||
return m_ledgerMaster.getCurrentLedger()->info().seq;
|
||||
|
||||
--acceptLedgerDepth;
|
||||
auto result = m_ledgerMaster.getCurrentLedger()->info().seq;
|
||||
DBG_EXPORT("acceptLedger EXIT result=" << result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// <-- bool: true=added, false=already there
|
||||
|
||||
@@ -219,8 +219,8 @@ public:
|
||||
*/
|
||||
virtual std::uint32_t
|
||||
acceptLedger(
|
||||
std::optional<std::chrono::milliseconds> consensusDelay =
|
||||
std::nullopt) = 0;
|
||||
std::optional<std::chrono::milliseconds> consensusDelay = std::nullopt,
|
||||
std::string const& caller = "unknown") = 0;
|
||||
|
||||
virtual void
|
||||
reportFeeChange() = 0;
|
||||
|
||||
@@ -33,6 +33,17 @@
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
|
||||
// Debug macro for export investigation - remove after debugging
|
||||
#include <thread>
|
||||
#define DBG_EXPORT(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << "[" << __FILE__ << ":" << __LINE__ \
|
||||
<< " t=" << std::this_thread::get_id() << "] " << msg \
|
||||
<< std::endl; \
|
||||
std::cerr.flush(); \
|
||||
} while (0)
|
||||
|
||||
namespace ripple {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -1446,13 +1457,17 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
Stop when the transaction fee level gets lower than the required fee
|
||||
level.
|
||||
*/
|
||||
DBG_EXPORT("TxQ::accept ENTER seq=" << view.info().seq);
|
||||
|
||||
auto ledgerChanged = false;
|
||||
|
||||
DBG_EXPORT("TxQ::accept BEFORE LOCK seq=" << view.info().seq);
|
||||
std::lock_guard lock(mutex_);
|
||||
DBG_EXPORT("TxQ::accept AFTER LOCK seq=" << view.info().seq);
|
||||
|
||||
auto const metricsSnapshot = feeMetrics_.getSnapshot();
|
||||
|
||||
DBG_EXPORT("TxQ::accept SECTION 1: debug inject seq=" << view.info().seq);
|
||||
// try to inject any debug txns waiting in the debug queue
|
||||
{
|
||||
std::unique_lock<std::mutex> trylock(
|
||||
@@ -1479,6 +1494,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
}
|
||||
}
|
||||
|
||||
DBG_EXPORT("TxQ::accept SECTION 2: cron inject seq=" << view.info().seq);
|
||||
// Inject cron transactions, if any
|
||||
if (view.rules().enabled(featureCron))
|
||||
{
|
||||
@@ -1541,49 +1557,49 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
}
|
||||
}
|
||||
|
||||
DBG_EXPORT("TxQ::accept SECTION 3: export inject seq=" << view.info().seq);
|
||||
//@@start txq-inject-export
|
||||
// Inject exported transactions/signatures, if any
|
||||
if (view.rules().enabled(featureExport))
|
||||
{
|
||||
do
|
||||
{
|
||||
DBG_EXPORT("export inject: checking validator key");
|
||||
// if we're not a validator we do nothing here
|
||||
if (app.getValidationPublicKey().empty())
|
||||
{
|
||||
DBG_EXPORT("export inject: no validator key, skipping");
|
||||
break;
|
||||
}
|
||||
|
||||
auto const& keys = app.getValidatorKeys();
|
||||
|
||||
if (keys.configInvalid())
|
||||
{
|
||||
DBG_EXPORT("export inject: config invalid, skipping");
|
||||
break;
|
||||
}
|
||||
|
||||
// and if we're not on the UNLReport we also do nothing
|
||||
|
||||
auto const unlRep = view.read(keylet::UNLReport());
|
||||
if (!unlRep || !unlRep->isFieldPresent(sfActiveValidators))
|
||||
// Use inUNLReport() which has a grace period for seq < 256
|
||||
// (testing)
|
||||
if (!inUNLReport(view, app, keys.masterPublicKey, j_))
|
||||
{
|
||||
// nothing to do without a unlreport object
|
||||
DBG_EXPORT("export inject: not in UNLReport, skipping");
|
||||
break;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
auto const& avs = unlRep->getFieldArray(sfActiveValidators);
|
||||
for (auto const& av : avs)
|
||||
{
|
||||
if (PublicKey(av[sfPublicKey]) == keys.masterPublicKey)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
break;
|
||||
DBG_EXPORT("export inject: we are a validator on UNLReport");
|
||||
|
||||
// execution to here means we're a validator and on the UNLReport
|
||||
|
||||
Keylet const exportedDirKeylet{keylet::exportedDir()};
|
||||
if (dirIsEmpty(view, exportedDirKeylet))
|
||||
{
|
||||
DBG_EXPORT("export inject: exportedDir is empty, skipping");
|
||||
break;
|
||||
}
|
||||
DBG_EXPORT("export inject: exportedDir has entries");
|
||||
|
||||
std::shared_ptr<SLE const> sleDirNode{};
|
||||
unsigned int uDirEntry{0};
|
||||
@@ -1637,18 +1653,28 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
auto const& txnHash = sleItem->getFieldH256(sfTransactionHash);
|
||||
|
||||
auto exportedLgrSeq = exported.getFieldU32(sfLedgerSequence);
|
||||
auto exportedLgrSeq = sleItem->getFieldU32(sfLedgerSequence);
|
||||
|
||||
auto const seq = view.seq();
|
||||
|
||||
DBG_EXPORT(
|
||||
"export inject: entry exportedLgrSeq="
|
||||
<< exportedLgrSeq << " viewSeq=" << seq);
|
||||
|
||||
if (exportedLgrSeq == seq)
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"export inject: exportedLgrSeq == seq, skipping");
|
||||
// this shouldn't happen, but do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exportedLgrSeq < seq - 1)
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"export inject: condition met! "
|
||||
<< exportedLgrSeq << " < " << (seq - 1)
|
||||
<< ", creating ttEXPORT");
|
||||
// all old entries need to be turned into Export
|
||||
// transactions so they can be removed from the directory
|
||||
|
||||
@@ -1659,21 +1685,28 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
// the ExportedTxn blob and publish the blob in the Export
|
||||
// transaction type.
|
||||
|
||||
DBG_EXPORT("export inject: getting signers array");
|
||||
STArray signers = sleItem->getFieldArray(sfSigners);
|
||||
DBG_EXPORT(
|
||||
"export inject: signers count=" << signers.size());
|
||||
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
exported.add(*s);
|
||||
SerialIter sitTrans(s->slice());
|
||||
try
|
||||
{
|
||||
DBG_EXPORT(
|
||||
"export inject: creating STTx from exported txn");
|
||||
auto stpTrans =
|
||||
std::make_shared<STTx>(std::ref(sitTrans));
|
||||
DBG_EXPORT("export inject: STTx created");
|
||||
|
||||
if (!stpTrans->isFieldPresent(sfAccount) ||
|
||||
stpTrans->getAccountID(sfAccount) == beast::zero)
|
||||
{
|
||||
JLOG(j_.warn()) << "Hook: Export failure: "
|
||||
<< "sfAccount missing or zero.";
|
||||
DBG_EXPORT(
|
||||
"export inject: sfAccount missing or zero, "
|
||||
"skipping");
|
||||
// RH TODO: if this ever happens the entry should be
|
||||
// gracefully removed (somehow)
|
||||
continue;
|
||||
@@ -1685,30 +1718,42 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
// Serialize the inner transaction and create an
|
||||
// STObject from it. sfExportedTxn is OBJECT type, not
|
||||
// VL, so we must use emplace_back with STObject, not
|
||||
// setFieldVL.
|
||||
// VL. Use set() to replace the existing template field,
|
||||
// not emplace_back which would add a duplicate.
|
||||
ripple::Serializer exportedSer;
|
||||
stpTrans->add(exportedSer);
|
||||
SerialIter exportedSit(exportedSer.slice());
|
||||
|
||||
// Create ttEXPORT pseudo-transaction
|
||||
// Note: sfSigners is already on the inner stpTrans
|
||||
// (sfExportedTxn) ttEXPORT itself must NOT have
|
||||
// sfSigners at top level (Change::preflight rejects it)
|
||||
STTx exportTx(ttEXPORT, [&](auto& obj) {
|
||||
obj.emplace_back(
|
||||
ripple::STObject(exportedSit, sfExportedTxn));
|
||||
// Pseudo-transaction required fields
|
||||
// (Change::preflight checks)
|
||||
obj[sfAccount] = AccountID();
|
||||
// Export-specific fields
|
||||
obj.set(std::make_unique<STObject>(
|
||||
exportedSit, sfExportedTxn));
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setFieldH256(sfTransactionHash, txnHash);
|
||||
obj.setFieldArray(sfSigners, signers);
|
||||
});
|
||||
|
||||
// submit to the ledger
|
||||
{
|
||||
uint256 txID = exportTx.getTransactionID();
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
exportTx.add(*s);
|
||||
app.getHashRouter().setFlags(txID, SF_PRIVATE2);
|
||||
app.getHashRouter().setFlags(txID, SF_EMITTED);
|
||||
view.rawTxInsert(txID, std::move(s), nullptr);
|
||||
ledgerChanged = true;
|
||||
}
|
||||
// Record the ttEXPORT transaction (like ttCRON)
|
||||
// Cleanup happens via Change::applyExport() when
|
||||
// processed
|
||||
uint256 txID = exportTx.getTransactionID();
|
||||
DBG_EXPORT(
|
||||
"export inject: rawTxInsert ttEXPORT txID="
|
||||
<< txID);
|
||||
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
exportTx.add(*s);
|
||||
|
||||
app.getHashRouter().setFlags(txID, SF_PRIVATE2);
|
||||
app.getHashRouter().setFlags(txID, SF_EMITTED);
|
||||
view.rawTxInsert(txID, std::move(s), nullptr);
|
||||
ledgerChanged = true;
|
||||
}
|
||||
|
||||
catch (std::exception& e)
|
||||
@@ -1733,6 +1778,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
}
|
||||
//@@end txq-inject-export
|
||||
|
||||
DBG_EXPORT("TxQ::accept SECTION 4: emit inject seq=" << view.info().seq);
|
||||
// Inject emitted transactions if any
|
||||
if (view.rules().enabled(featureHooks))
|
||||
do
|
||||
@@ -1884,6 +1930,9 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
} while (0);
|
||||
|
||||
DBG_EXPORT(
|
||||
"TxQ::accept SECTION 5: process queue seq="
|
||||
<< view.info().seq << " byFee_.size()=" << byFee_.size());
|
||||
for (auto candidateIter = byFee_.begin(); candidateIter != byFee_.end();)
|
||||
{
|
||||
auto& account = byAccount_.at(candidateIter->account);
|
||||
@@ -2003,6 +2052,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
}
|
||||
}
|
||||
|
||||
DBG_EXPORT("TxQ::accept SECTION 6: rebuild queue seq=" << view.info().seq);
|
||||
// All transactions that can be moved out of the queue into the open
|
||||
// ledger have been. Rebuild the queue using the open ledger's
|
||||
// parent hash, so that transactions paying the same fee are
|
||||
@@ -2010,6 +2060,18 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
LedgerHash const& parentHash = view.info().parentHash;
|
||||
#if !NDEBUG
|
||||
auto const startingSize = byFee_.size();
|
||||
DBG_EXPORT(
|
||||
"TxQ::accept CHECK seq=" << view.info().seq
|
||||
<< " parentHash=" << parentHash
|
||||
<< " parentHash_=" << parentHash_);
|
||||
if (parentHash == parentHash_)
|
||||
{
|
||||
JLOG(j_.fatal()) << "TxQ::accept DOUBLE-ACCEPT DETECTED!"
|
||||
<< " seq=" << view.info().seq
|
||||
<< " parentHash=" << parentHash
|
||||
<< " parentHash_=" << parentHash_
|
||||
<< " byFee_.size()=" << byFee_.size();
|
||||
}
|
||||
assert(parentHash != parentHash_);
|
||||
parentHash_ = parentHash;
|
||||
#endif
|
||||
|
||||
@@ -181,7 +181,7 @@ makeExportSignTxns(OpenView& view, Application& app, beast::Journal const& j)
|
||||
.getField(sfExportedTxn)
|
||||
.downcast<STObject>();
|
||||
|
||||
auto exportedLgrSeq = exported.getFieldU32(sfLedgerSequence);
|
||||
auto exportedLgrSeq = sleItem->getFieldU32(sfLedgerSequence);
|
||||
|
||||
// Only sign transactions that were added in the previous ledger
|
||||
if (exportedLgrSeq != seq - 1)
|
||||
|
||||
@@ -19,6 +19,17 @@
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
// Debug macro for export investigation
|
||||
#define DBG_DEREF(msg) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << "[OpenView::dereference t=" << std::this_thread::get_id() \
|
||||
<< "] " << msg << std::endl; \
|
||||
std::cerr.flush(); \
|
||||
} while (0)
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -59,16 +70,32 @@ public:
|
||||
value_type
|
||||
dereference() const override
|
||||
{
|
||||
DBG_DEREF("ENTER key=" << iter_->first);
|
||||
value_type result;
|
||||
{
|
||||
DBG_DEREF(
|
||||
"creating SerialIter, txn size=" << iter_->second.txn->size());
|
||||
SerialIter sit(iter_->second.txn->slice());
|
||||
result.first = std::make_shared<STTx const>(sit);
|
||||
DBG_DEREF("creating STTx...");
|
||||
try
|
||||
{
|
||||
result.first = std::make_shared<STTx const>(sit);
|
||||
DBG_DEREF("STTx created, type=" << result.first->getTxnType());
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
DBG_DEREF("STTx EXCEPTION: " << e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (metadata_)
|
||||
{
|
||||
DBG_DEREF("creating metadata");
|
||||
SerialIter sit(iter_->second.meta->slice());
|
||||
result.second = std::make_shared<STObject const>(sit, sfMetadata);
|
||||
DBG_DEREF("metadata created");
|
||||
}
|
||||
DBG_DEREF("EXIT");
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -388,6 +388,8 @@ LedgerFormats::LedgerFormats()
|
||||
{sfExportedTxn, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfTransactionHash, soeREQUIRED},
|
||||
{sfSigners, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
//@@end exported-txn-format
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/STBlob.h>
|
||||
#include <ripple/protocol/STObject.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -250,7 +251,17 @@ STObject::set(SerialIter& sit, int depth)
|
||||
});
|
||||
|
||||
if (dup != sf.cend())
|
||||
{
|
||||
// Debug: dump all field names to identify the duplicate
|
||||
std::cerr << "[STObject::set] DUPLICATE FIELD DETECTED!" << std::endl;
|
||||
std::cerr << "[STObject::set] Duplicate field name: "
|
||||
<< (*dup)->getFName().getName() << std::endl;
|
||||
std::cerr << "[STObject::set] All fields in object:" << std::endl;
|
||||
for (auto const& f : sf)
|
||||
std::cerr << " - " << f->getFName().getName() << std::endl;
|
||||
std::cerr.flush();
|
||||
Throw<std::runtime_error>("Duplicate field detected");
|
||||
}
|
||||
|
||||
return reachedEndOfObject;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ doLedgerAccept(RPC::JsonContext& context)
|
||||
else
|
||||
{
|
||||
std::unique_lock lock{context.app.getMasterMutex()};
|
||||
context.netOps.acceptLedger();
|
||||
context.netOps.acceptLedger(std::nullopt, "RPC:ledger_accept");
|
||||
jvResult[jss::ledger_current_index] =
|
||||
context.ledgerMaster.getCurrentLedgerIndex();
|
||||
}
|
||||
|
||||
@@ -477,6 +477,7 @@ struct Export_test : public beast::unit_test::suite
|
||||
*this,
|
||||
DebugLogs::Levels{
|
||||
{"View", kTrace},
|
||||
{"TxQ", kTrace},
|
||||
});
|
||||
|
||||
Env env{*this, makeConfig(), features, std::move(logs), kError};
|
||||
@@ -520,16 +521,70 @@ struct Export_test : public beast::unit_test::suite
|
||||
|
||||
// Close additional ledgers for signing flow
|
||||
env.close(); // N+1: validators submit ttEXPORT_SIGN
|
||||
env.close(); // N+2: ttEXPORT removes entry
|
||||
env.close(); // N+2: ttEXPORT created (rawTxInsert)
|
||||
env.close(); // N+3: does ttEXPORT get applied here?
|
||||
|
||||
// Check if cleanup happened
|
||||
{
|
||||
auto const exportedDirKey = keylet::exportedDir();
|
||||
bool dirEmpty = dirIsEmpty(*env.current(), exportedDirKey);
|
||||
|
||||
// Debug: if not empty, inspect what's in there
|
||||
if (!dirEmpty && expectCleanup)
|
||||
{
|
||||
std::cerr << "=== DEBUG: exportedDir not empty ==="
|
||||
<< std::endl;
|
||||
std::shared_ptr<SLE const> sleDirNode{};
|
||||
unsigned int uDirEntry{0};
|
||||
uint256 dirEntry{beast::zero};
|
||||
if (cdirFirst(
|
||||
*env.current(),
|
||||
exportedDirKey.key,
|
||||
sleDirNode,
|
||||
uDirEntry,
|
||||
dirEntry))
|
||||
{
|
||||
do
|
||||
{
|
||||
auto sleItem =
|
||||
env.current()->read(Keylet{ltCHILD, dirEntry});
|
||||
if (sleItem)
|
||||
{
|
||||
std::cerr << " Entry: " << dirEntry << std::endl;
|
||||
std::cerr << " LedgerSeq: "
|
||||
<< sleItem->getFieldU32(sfLedgerSequence)
|
||||
<< std::endl;
|
||||
std::cerr
|
||||
<< " TxnHash: "
|
||||
<< sleItem->getFieldH256(sfTransactionHash)
|
||||
<< std::endl;
|
||||
if (sleItem->isFieldPresent(sfSigners))
|
||||
{
|
||||
auto const& signers =
|
||||
sleItem->getFieldArray(sfSigners);
|
||||
std::cerr
|
||||
<< " Signers count: " << signers.size()
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << " Signers: NONE" << std::endl;
|
||||
}
|
||||
}
|
||||
} while (cdirNext(
|
||||
*env.current(),
|
||||
exportedDirKey.key,
|
||||
sleDirNode,
|
||||
uDirEntry,
|
||||
dirEntry));
|
||||
}
|
||||
std::cerr << "=== END DEBUG ===" << std::endl;
|
||||
}
|
||||
|
||||
BEAST_EXPECT(dirEmpty == expectCleanup);
|
||||
}
|
||||
|
||||
BEAST_EXPECT(env.current()->seq() == xportLedgerSeq + 3);
|
||||
BEAST_EXPECT(env.current()->seq() == xportLedgerSeq + 4);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -564,11 +619,11 @@ struct Export_test : public beast::unit_test::suite
|
||||
using namespace test::jtx;
|
||||
FeatureBitset const all{supported_amendments()};
|
||||
FeatureBitset const allWithExport{all | featureExport};
|
||||
testBasicSetup(all);
|
||||
testEmitPayment(all);
|
||||
testXportPayment(allWithExport);
|
||||
// TODO: re-enable once validator signing flow is debugged
|
||||
// testXportPaymentWithValidator(allWithExport);
|
||||
// testBasicSetup(all);
|
||||
// testEmitPayment(all);
|
||||
// testXportPayment(allWithExport);
|
||||
testXportPaymentWithValidator(
|
||||
allWithExport); // with push_back disabled
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@ Env::close(
|
||||
// Go through the rpc interface unless we need to simulate
|
||||
// a specific consensus delay.
|
||||
if (consensusDelay)
|
||||
app().getOPs().acceptLedger(consensusDelay);
|
||||
app().getOPs().acceptLedger(
|
||||
consensusDelay, "Env::close(consensusDelay)");
|
||||
else
|
||||
{
|
||||
auto resp = rpc("ledger_accept");
|
||||
|
||||
Reference in New Issue
Block a user