Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/xrpl/core/Job.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum JobType {
jtNETOP_CLUSTER, // NetworkOPs cluster peer report
jtNETOP_TIMER, // NetworkOPs net timer processing
jtADMIN, // An administrative operation
jtWRITE_RPC_DEBUG, // Write RPC debug logs to dbs

// Special job types which are not dispatched by the job pool
jtPEER,
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/core/JobTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class JobTypes
add(jtADMIN, "administration", maxLimit, 0ms, 0ms);
add(jtMISSING_TXN, "handleHaveTransactions", 1200, 0ms, 0ms);
add(jtREQUESTED_TXN, "doTransactions", 1200, 0ms, 0ms);
add(jtWRITE_RPC_DEBUG, "writeRPCDebug", maxLimit, 0ms, 0ms);

add(jtPEER, "peerCommand", 0, 200ms, 2500ms);
add(jtDISK, "diskAccess", 0, 500ms, 1000ms);
Expand Down
3 changes: 3 additions & 0 deletions include/xrpl/protocol/jss.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ JSS(engine_result); // out: NetworkOPs, TransactionSign, Submit
JSS(engine_result_code); // out: NetworkOPs, TransactionSign, Submit
JSS(engine_result_message); // out: NetworkOPs, TransactionSign, Submit
JSS(entire_set); // out: get_aggregate_price
JSS(entry_id); // out: tx
JSS(ephemeral_key); // out: ValidatorInfo
// in/out: Manifest
JSS(error); // out: error
Expand Down Expand Up @@ -608,6 +609,7 @@ JSS(total); // out: counters
JSS(total_bytes_recv); // out: Peers
JSS(total_bytes_sent); // out: Peers
JSS(total_coins); // out: LedgerToJson
JSS(traces); // out: tx
JSS(trading_fee); // out: amm_info
JSS(transTreeHash); // out: ledger/Ledger.cpp
JSS(transaction); // in: Tx
Expand Down Expand Up @@ -692,6 +694,7 @@ JSS(vote_slots); // out: amm_info
JSS(vote_weight); // out: amm_info
JSS(warning); // rpc:
JSS(warnings); // out: server_info, server_state
JSS(wasm_traces); // out: tx
JSS(workers);
JSS(write_load); // out: GetCounts
// clang-format on
Expand Down
23 changes: 22 additions & 1 deletion src/xrpld/app/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <xrpld/app/paths/PathRequests.h>
#include <xrpld/app/rdb/RelationalDatabase.h>
#include <xrpld/app/rdb/Wallet.h>
#include <xrpld/app/rdb/WasmTrace.h>
#include <xrpld/app/tx/apply.h>
#include <xrpld/core/DatabaseCon.h>
#include <xrpld/overlay/Cluster.h>
Expand Down Expand Up @@ -194,6 +195,7 @@ class ApplicationImp : public Application, public BasicApp

std::unique_ptr<RelationalDatabase> mRelationalDatabase;
std::unique_ptr<DatabaseCon> mWalletDB;
std::unique_ptr<DatabaseCon> mWasmTraceDB;
std::unique_ptr<Overlay> overlay_;
std::optional<uint256> trapTxID_;

Expand Down Expand Up @@ -744,6 +746,16 @@ class ApplicationImp : public Application, public BasicApp
return *mWalletDB;
}

DatabaseCon&
getWasmTraceDB() override
{
XRPL_ASSERT(
mWasmTraceDB,
"xrpl::ApplicationImp::getWasmTraceDB : null wasm debug "
"database");
return *mWasmTraceDB;
}

bool
serverOkay(std::string& reason) override;

Expand All @@ -759,16 +771,25 @@ class ApplicationImp : public Application, public BasicApp
mWalletDB.get() == nullptr,
"xrpl::ApplicationImp::initRelationalDatabase : null wallet "
"database");
XRPL_ASSERT(
mWasmTraceDB.get() == nullptr,
"xrpl::ApplicationImp::initRelationalDatabase : null wasm debug "
"database");

try
{
mRelationalDatabase = RelationalDatabase::init(*this, *config_, *m_jobQueue);

// wallet database
auto setup = setup_DatabaseCon(*config_, m_journal);
setup.useGlobalPragma = false;

// wallet database
mWalletDB = makeWalletDB(setup, m_journal);
if (config().useTxTables())
{
// wasm debug database
mWasmTraceDB = makeWasmTraceDB(setup, m_journal);
}
}
catch (std::exception const& e)
{
Expand Down
4 changes: 4 additions & 0 deletions src/xrpld/app/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ class Application : public ServiceRegistry, public beast::PropertyStream::Source
virtual DatabaseCon&
getWalletDB() = 0;

/** Retrieve the "WASM debug database" */
virtual DatabaseCon&
getWasmTraceDB() = 0;

/** Ensure that a newly-started validator does not sign proposals older
* than the last ledger it persisted. */
virtual LedgerIndex
Expand Down
14 changes: 14 additions & 0 deletions src/xrpld/app/main/DBInit.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,18 @@ inline constexpr std::array<char const*, 6> WalletDBInit{

"END TRANSACTION;"}};

inline constexpr auto WasmTraceDBName{"wasm_trace.db"};

inline constexpr std::array<char const*, 3> WasmTraceDBInit{
{"BEGIN TRANSACTION;",

"CREATE TABLE IF NOT EXISTS WasmTraceLogs ("
" TransID CHARACTER(64) NOT NULL,"
" ObjID CHARACTER(64) NOT NULL,"
" Data TEXT NOT NULL,"
" PRIMARY KEY(TransID, ObjID)"
");",

"END TRANSACTION;"}};

} // namespace xrpl
24 changes: 24 additions & 0 deletions src/xrpld/app/rdb/WasmTrace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef XRPL_APP_RDB_WasmTrace_H_INCLUDED
#define XRPL_APP_RDB_WasmTrace_H_INCLUDED

#include <xrpld/app/ledger/LedgerMaster.h>
#include <xrpld/app/main/Application.h>
#include <xrpld/core/Config.h>
#include <xrpld/core/DatabaseCon.h>

#include <xrpl/protocol/Indexes.h>

namespace xrpl {

std::unique_ptr<DatabaseCon>
makeWasmTraceDB(DatabaseCon::Setup const& setup, beast::Journal j);

void
addWasmTraceLogs(soci::session& session, TxID const& txId, Keylet const& keylet, std::vector<std::string> const& data);

std::map<uint256, std::vector<std::string>>
getWasmTraceByTxID(soci::session& session, TxID const& txId);

} // namespace xrpl

#endif
66 changes: 66 additions & 0 deletions src/xrpld/app/rdb/detail/WasmTrace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <xrpld/app/rdb/WasmTrace.h>

#include <boost/algorithm/string.hpp>

namespace xrpl {

std::unique_ptr<DatabaseCon>
makeWasmTraceDB(DatabaseCon::Setup const& setup, beast::Journal j)
{
// WASM debug log database
return std::make_unique<DatabaseCon>(setup, WasmTraceDBName, std::array<std::string, 0>(), WasmTraceDBInit, j);
}

void
addWasmTraceLogs(soci::session& session, TxID const& txId, Keylet const& keylet, std::vector<std::string> const& data)
{
soci::transaction tr(session);

// Convert all the info to appropriate formats
std::string const txHex = to_string(txId);
std::string const keyletHex = to_string(keylet.key);
std::string const logString = boost::algorithm::join(data, "\x1F");

// replace = because you run transactions twice: open _and_ closed ledger
session << "INSERT OR REPLACE INTO WasmTraceLogs "
"(TransID, ObjID, Data) VALUES "
"(:transID, :objId, :data)",
soci::use(txHex), soci::use(keyletHex), soci::use(logString);

tr.commit();
}

std::map<uint256, std::vector<std::string>>
getWasmTraceByTxID(soci::session& session, TxID const& txId)
{
std::map<uint256, std::vector<std::string>> ret;

std::string const txHex = to_string(txId);

std::string objHex;
std::string logString;

soci::statement st =
(session.prepare << "SELECT ObjID, Data FROM WasmTraceLogs "
"WHERE TransID = :txId",
soci::use(txHex),
soci::into(objHex),
soci::into(logString));

st.execute();

while (st.fetch())
{
uint256 objId;
if (objId.parseHex(objHex))
{
std::vector<std::string> logs;
boost::algorithm::split(logs, logString, boost::is_any_of("\x1F"));
ret.emplace(objId, logs);
}
}

return ret;
}

} // namespace xrpl
26 changes: 26 additions & 0 deletions src/xrpld/app/tx/detail/Escrow.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <xrpld/app/misc/HashRouter.h>
#include <xrpld/app/rdb/WasmTrace.h>
#include <xrpld/app/tx/detail/Escrow.h>
#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
#include <xrpld/app/wasm/HostFuncImpl.h>
Expand All @@ -17,6 +18,8 @@
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/protocol/XRPAmount.h>

#include <algorithm>

namespace xrpl {

// During an EscrowFinish, the transaction must specify both
Expand Down Expand Up @@ -1146,6 +1149,29 @@ EscrowFinish::doApply()
std::uint32_t allowance = ctx_.tx[sfComputationAllowance];
auto re = runEscrowWasm(wasm, ledgerDataProvider, ESCROW_FUNCTION_NAME, {}, allowance);
JLOG(j_.trace()) << "Escrow WASM ran";
auto const& logs = ledgerDataProvider.getLogs();
if (ctx_.app.config().useTxTables() && !logs.empty())
{
// Capture by value to avoid lifetime issues
auto txId = ctx_.tx.getTransactionID();
auto keylet = k;
auto logsCopy = logs;

ctx_.app.getJobQueue().addJob(
jtWRITE_RPC_DEBUG, "writeWasmTrace", [&app = ctx_.app, txId, keylet, logsCopy = std::move(logsCopy)]() {
try
{
auto db = app.getWasmTraceDB().checkoutDb();
addWasmTraceLogs(*db, txId, keylet, logsCopy);
}
catch (std::exception const& e)
{
// Log error but don't crash - debug logs are
// non-critical
JLOG(app.journal("WasmTrace").warn()) << "Failed to write WASM debug logs: " << e.what();
}
});
}

if (auto const& data = ledgerDataProvider->getData(); data.has_value())
{
Expand Down
11 changes: 10 additions & 1 deletion src/xrpld/app/wasm/HostFuncImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class WasmHostFunctionsImpl : public HostFunctions
Keylet leKey;
std::shared_ptr<SLE const> currentLedgerObj = nullptr;
bool isLedgerObjCached = false;
std::vector<std::string> logs_;

static int constexpr MAX_CACHE = 256;
std::array<std::shared_ptr<SLE const>, MAX_CACHE> cache;
Expand Down Expand Up @@ -52,11 +53,13 @@ class WasmHostFunctionsImpl : public HostFunctions
return;
auto j = getJournal().trace();
#endif
j << "WasmTrace[" << to_short_string(leKey.key) << "]: " << msg << " " << dataFn();
auto const data = dataFn();
j << "WasmTrace[" << to_short_string(leKey.key) << "]: " << msg << " " << data;

#ifdef DEBUG_OUTPUT
j << std::endl;
#endif
logs_.emplace_back(std::string(msg) + " " + data);
}

public:
Expand All @@ -82,6 +85,12 @@ class WasmHostFunctionsImpl : public HostFunctions
return data_;
}

std::vector<std::string> const&
getLogs() const
{
return logs_;
}

Expected<std::uint32_t, HostFunctionError>
getLedgerSqn() override;

Expand Down
25 changes: 25 additions & 0 deletions src/xrpld/rpc/handlers/Tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <xrpld/app/misc/NetworkOPs.h>
#include <xrpld/app/misc/Transaction.h>
#include <xrpld/app/rdb/RelationalDatabase.h>
#include <xrpld/app/rdb/WasmTrace.h>
#include <xrpld/rpc/CTID.h>
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/DeliveredAmount.h>
Expand Down Expand Up @@ -41,6 +42,7 @@ struct TxResult
std::optional<NetClock::time_point> closeTime;
std::optional<uint256> ledgerHash;
TxSearched searchedAll;
std::map<TxID, std::vector<std::string>> WasmTraceLogs;
};

struct TxArgs
Expand Down Expand Up @@ -153,6 +155,13 @@ doTxHelp(RPC::Context& context, TxArgs args)
}
}

if (txn->getSTransaction()->isFieldPresent(sfComputationAllowance))
{
auto db = context.app.getWasmTraceDB().checkoutDb();
auto const logs = getWasmTraceByTxID(*db, txn->getID());
result.WasmTraceLogs = logs;
}

return {result, rpcSUCCESS};
}

Expand Down Expand Up @@ -234,6 +243,22 @@ populateJsonResponse(std::pair<TxResult, RPC::Status> const& res, TxArgs const&

if (result.ctid)
response[jss::ctid] = *(result.ctid);

if (!result.WasmTraceLogs.empty())
{
response[jss::wasm_traces] = Json::Value(Json::arrayValue);
for (auto const& [entryId, logs] : result.WasmTraceLogs)
{
Json::Value logEntry = Json::objectValue;
logEntry[jss::entry_id] = to_string(entryId);
logEntry[jss::traces] = Json::arrayValue;
for (auto& log : logs)
{
logEntry[jss::traces].append(log);
}
response[jss::wasm_traces].append(logEntry);
}
}
}
return response;
}
Expand Down
Loading