Skip to content

Commit

Permalink
Potentially provide information about the range of ledgers searched w…
Browse files Browse the repository at this point in the history
…hen returning a 'txnNotFound' error.

FIXES: XRPLF#2924

* Tx command now supports min_ledger and max_ledger fields.
* If the requested transaction isn't found and these fields are provided, the error
  response indicates whether or not every ledger in the the provided range was searched.
  • Loading branch information
undertome committed Nov 1, 2019
1 parent 98d55b9 commit 79be2ce
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/ripple/app/ledger/TransactionMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <ripple/shamap/SHAMapItem.h>
#include <ripple/shamap/SHAMapTreeNode.h>
#include <ripple/basics/RangeSet.h>

namespace ripple {

Expand All @@ -41,6 +42,10 @@ class TransactionMaster
std::shared_ptr<Transaction>
fetch (uint256 const& , bool checkDisk);

std::shared_ptr<Transaction>
fetch (uint256 const& , bool checkDisk,
ClosedInterval<uint32_t> const& range, bool& searched);

std::shared_ptr<STTx const>
fetch (std::shared_ptr<SHAMapItem> const& item,
SHAMapTreeNode::TNType type, bool checkDisk,
Expand Down
10 changes: 9 additions & 1 deletion src/ripple/app/ledger/impl/TransactionMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,21 @@ bool TransactionMaster::inLedger (uint256 const& hash, std::uint32_t ledger)

std::shared_ptr<Transaction>
TransactionMaster::fetch (uint256 const& txnID, bool checkDisk)
{
bool unused = false;
return fetch(txnID, checkDisk, {}, unused);
}

std::shared_ptr<Transaction>
TransactionMaster::fetch (uint256 const& txnID, bool checkDisk,
ClosedInterval<uint32_t> const& range, bool& searched)
{
auto txn = mCache.fetch (txnID);

if (!checkDisk || txn)
return txn;

txn = Transaction::load (txnID, mApp);
txn = Transaction::load (txnID, mApp, range, searched);

if (!txn)
return txn;
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/app/misc/Transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ class Transaction

Json::Value getJson (JsonOptions options, bool binary = false) const;

static Transaction::pointer load (uint256 const& id, Application& app);
static Transaction::pointer load (uint256 const& id, Application& app,
ClosedInterval<uint32_t> const& range, bool& searched);

private:
uint256 mTransactionID;
Expand Down
20 changes: 19 additions & 1 deletion src/ripple/app/misc/impl/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ Transaction::pointer Transaction::transactionFromSQLValidated(
return ret;
}

Transaction::pointer Transaction::load(uint256 const& id, Application& app)
Transaction::pointer Transaction::load(uint256 const& id, Application& app,
ClosedInterval<uint32_t> const& range, bool& searched)
{
std::string sql = "SELECT LedgerSeq,Status,RawTxn "
"FROM Transactions WHERE TransID='";
Expand All @@ -132,6 +133,23 @@ Transaction::pointer Transaction::load(uint256 const& id, Application& app)
soci::blob sociRawTxnBlob (*db);
soci::indicator rti;

if(range.last() != 0)
{
uint64_t count = 0;

*db << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE LedgerSeq BETWEEN "
<< range.first()
<< " AND "
<< range.last()
<< ";",
soci::into(count, rti);

if (!db->got_data () || rti != soci::i_ok)
return {};

searched = count == (range.last() - range.first() + 1);
}

*db << sql, soci::into (ledgerSeq), soci::into (status),
soci::into (sociRawTxnBlob, rti);
if (!db->got_data () || rti != soci::i_ok)
Expand Down
10 changes: 8 additions & 2 deletions src/ripple/net/impl/RPCCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,13 @@ class RPCParser
jvRequest[jss::binary] = true;
}

jvRequest["transaction"] = jvParams[0u].asString ();
if (jvParams.size () > 3)
{
jvRequest[jss::min_ledger] = jvParams[2u].asString ();
jvRequest[jss::max_ledger] = jvParams[3u].asString ();
}

jvRequest[jss::transaction] = jvParams[0u].asString ();
return jvRequest;
}

Expand Down Expand Up @@ -1182,7 +1188,7 @@ class RPCParser
{ "crawl_shards", &RPCParser::parseAsIs, 0, 2 },
{ "stop", &RPCParser::parseAsIs, 0, 0 },
{ "transaction_entry", &RPCParser::parseTransactionEntry, 2, 2 },
{ "tx", &RPCParser::parseTx, 1, 2 },
{ "tx", &RPCParser::parseTx, 1, 4 },
{ "tx_account", &RPCParser::parseTxAccount, 1, 7 },
{ "tx_history", &RPCParser::parseTxHistory, 1, 1 },
{ "unl_list", &RPCParser::parseAsIs, 0, 0 },
Expand Down
22 changes: 19 additions & 3 deletions src/ripple/rpc/handlers/Tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/TransactionMaster.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/misc/Transaction.h>
#include <ripple/net/RPCErr.h>
Expand Down Expand Up @@ -97,11 +96,28 @@ Json::Value doTx (RPC::Context& context)
if (!isHexTxID (txid))
return rpcError (rpcNOT_IMPL);

ClosedInterval<uint32_t> range;

if (context.params.isMember(jss::min_ledger) && context.params.isMember(jss::max_ledger))
{
range = ClosedInterval<uint32_t>(context.params[jss::min_ledger].asUInt (),
context.params[jss::max_ledger].asUInt ());
}

auto full = false;

auto txn = context.app.getMasterTransaction ().fetch (
from_hex_text<uint256>(txid), true);
from_hex_text<uint256>(txid), true, range, full);

if (!txn)
return rpcError (rpcTXN_NOT_FOUND);
{
auto jvResult = Json::Value (Json::objectValue);

if(range.last() != 0)
jvResult[jss::full] = full;

return rpcError (rpcTXN_NOT_FOUND, jvResult);
}

Json::Value ret = txn->getJson (JsonOptions::include_date, binary);

Expand Down

0 comments on commit 79be2ce

Please sign in to comment.