mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 21:45:52 +00:00
Fix 'tx' output format. Begin supporting a binary output format.
This adds support for binary in 'tx' and 'account_tx' commands. https://ripple.com/wiki/FormatChange
This commit is contained in:
@@ -100,19 +100,29 @@ Json::Value RPCParser::parseAccountInfo(const Json::Value& jvParams)
|
||||
|
||||
// account_tx <account> <minledger> <maxledger>
|
||||
// account_tx <account> <ledger>
|
||||
// account_tx <account> binary
|
||||
// account_tx <account> <minledger> <maxledger> binary
|
||||
Json::Value RPCParser::parseAccountTransactions(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
RippleAddress raAccount;
|
||||
|
||||
if (jvParams.size() < 2 || jvParams.size() > 3)
|
||||
unsigned size = jvParams.size();
|
||||
|
||||
if ((size > 1) && (jvParams[size - 1].asString() == "binary"))
|
||||
{
|
||||
jvRequest["binary"] = true;
|
||||
--size;
|
||||
}
|
||||
|
||||
if (size < 2 || size > 3)
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
if (!raAccount.setAccountID(jvParams[0u].asString()))
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
|
||||
// YYY This could be more strict and report casting errors.
|
||||
if (jvParams.size() == 2)
|
||||
if (size == 2)
|
||||
{
|
||||
jvRequest["ledger"] = jvParams[1u].asUInt();
|
||||
}
|
||||
@@ -365,8 +375,14 @@ Json::Value RPCParser::parseTx(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest;
|
||||
|
||||
if (jvParams.size() > 1)
|
||||
{
|
||||
if (jvParams[1u].asString() == "binary")
|
||||
jvRequest["binary"] = true;
|
||||
}
|
||||
|
||||
jvRequest["transaction"] = jvParams[0u].asString();
|
||||
return jvRequest;
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// tx_history <index>
|
||||
@@ -497,7 +513,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
{ "account_info", &RPCParser::parseAccountInfo, 1, 2 },
|
||||
{ "account_lines", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 2, 3 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 2, 4 },
|
||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
||||
@@ -522,7 +538,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
{ "server_state", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "stop", &RPCParser::parseAsIs, 0, 0 },
|
||||
// { "transaction_entry", &RPCParser::parseTransactionEntry, -1, -1 },
|
||||
{ "tx", &RPCParser::parseTx, 1, 1 },
|
||||
{ "tx", &RPCParser::parseTx, 1, 2 },
|
||||
{ "tx_history", &RPCParser::parseTxHistory, 1, 1 },
|
||||
|
||||
{ "unl_add", &RPCParser::parseUnlAdd, 1, 2 },
|
||||
|
||||
@@ -377,6 +377,22 @@ bool Ledger::getTransactionMeta(const uint256& txID, TransactionMetaSet::pointer
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ledger::getMetaHex(const uint256& transID, std::string& hex)
|
||||
{
|
||||
SHAMapTreeNode::TNType type;
|
||||
SHAMapItem::pointer item = mTransactionMap->peekItem(transID, type);
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
if (type != SHAMapTreeNode::tnTRANSACTION_MD)
|
||||
return false;
|
||||
|
||||
SerializerIterator it(item->peekSerializer());
|
||||
it.getVL(); // skip transaction
|
||||
hex = strHex(it.getVL());
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 Ledger::getHash()
|
||||
{
|
||||
if (!mValidHash)
|
||||
|
||||
@@ -184,6 +184,7 @@ public:
|
||||
Transaction::pointer getTransaction(const uint256& transID) const;
|
||||
bool getTransaction(const uint256& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta);
|
||||
bool getTransactionMeta(const uint256& transID, TransactionMetaSet::pointer& txMeta);
|
||||
bool getMetaHex(const uint256& transID, std::string& hex);
|
||||
|
||||
static SerializedTransaction::pointer getSTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType);
|
||||
SerializedTransaction::pointer getSMTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType,
|
||||
|
||||
@@ -1085,6 +1085,52 @@ std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<NetworkOPs::txnMetaLedgerType> NetworkOPs::getAccountTxsB(
|
||||
const RippleAddress& account, uint32 minLedger, uint32 maxLedger)
|
||||
{ // can be called with no locks
|
||||
std::vector< txnMetaLedgerType> ret;
|
||||
|
||||
std::string sql =
|
||||
str(boost::format("SELECT LedgerSeq, RawTxn,TxnMeta FROM Transactions where TransID in (SELECT TransID from AccountTransactions "
|
||||
" WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' LIMIT 500) ORDER BY LedgerSeq DESC;")
|
||||
% account.humanAccountID() % maxLedger % minLedger);
|
||||
|
||||
{
|
||||
Database* db = theApp->getTxnDB()->getDB();
|
||||
ScopedLock sl(theApp->getTxnDB()->getDBLock());
|
||||
|
||||
SQL_FOREACH(db, sql)
|
||||
{
|
||||
int txnSize = 2048;
|
||||
std::vector<unsigned char> rawTxn(txnSize);
|
||||
txnSize = db->getBinary("RawTxn", &rawTxn[0], rawTxn.size());
|
||||
if (txnSize > rawTxn.size())
|
||||
{
|
||||
rawTxn.resize(txnSize);
|
||||
db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.size());
|
||||
}
|
||||
else
|
||||
rawTxn.resize(txnSize);
|
||||
|
||||
int metaSize = 2048;
|
||||
std::vector<unsigned char> rawMeta(2048);
|
||||
metaSize = db->getBinary("TxnMeta", &rawMeta[0], rawMeta.size());
|
||||
if (metaSize > rawMeta.size())
|
||||
{
|
||||
rawMeta.resize(metaSize);
|
||||
db->getBinary("TxnMeta", &*rawMeta.begin(), rawMeta.size());
|
||||
}
|
||||
else
|
||||
rawMeta.resize(metaSize);
|
||||
|
||||
ret.push_back(boost::make_tuple(strHex(rawTxn), strHex(rawMeta), db->getInt("LedgerSeq")));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<RippleAddress>
|
||||
NetworkOPs::getLedgerAffectedAccounts(uint32 ledgerSeq)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include "AccountState.h"
|
||||
#include "LedgerMaster.h"
|
||||
@@ -273,6 +274,11 @@ public:
|
||||
// client information retrieval functions
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
getAccountTxs(const RippleAddress& account, uint32 minLedger, uint32 maxLedger);
|
||||
|
||||
typedef boost::tuple<std::string, std::string, uint32> txnMetaLedgerType;
|
||||
std::vector<txnMetaLedgerType>
|
||||
getAccountTxsB(const RippleAddress& account, uint32 minL, uint32 maxL);
|
||||
|
||||
std::vector<RippleAddress> getLedgerAffectedAccounts(uint32 ledgerSeq);
|
||||
std::vector<SerializedTransaction> getLedgerTransactions(uint32 ledgerSeq);
|
||||
|
||||
|
||||
@@ -1433,6 +1433,8 @@ Json::Value RPCHandler::doTx(Json::Value jvRequest)
|
||||
if (!jvRequest.isMember("transaction"))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
bool binary = jvRequest.isMember("binary") && jvRequest["binary"].asBool();
|
||||
|
||||
std::string strTransaction = jvRequest["transaction"].asString();
|
||||
|
||||
if (Transaction::isHexTxID(strTransaction))
|
||||
@@ -1441,21 +1443,39 @@ Json::Value RPCHandler::doTx(Json::Value jvRequest)
|
||||
|
||||
Transaction::pointer txn = theApp->getMasterTransaction().fetch(txid, true);
|
||||
|
||||
if (!txn) return rpcError(rpcTXN_NOT_FOUND);
|
||||
if (!txn)
|
||||
return rpcError(rpcTXN_NOT_FOUND);
|
||||
|
||||
Json::Value ret = txn->getJson(0);
|
||||
Json::Value ret;
|
||||
|
||||
ret["transaction"] = txn->getJson(0, binary);
|
||||
|
||||
if (txn->getLedger() != 0)
|
||||
{
|
||||
Ledger::pointer lgr = theApp->getLedgerMaster().getLedgerBySeq(txn->getLedger());
|
||||
if (lgr)
|
||||
{
|
||||
TransactionMetaSet::pointer set;
|
||||
if (lgr->getTransactionMeta(txid, set))
|
||||
bool okay = false;
|
||||
if (binary)
|
||||
{
|
||||
ret["meta"] = set->getJson(0);
|
||||
ret["validated"] = theApp->getOPs().isValidated(lgr);
|
||||
std::string meta;
|
||||
if (lgr->getMetaHex(txid, meta))
|
||||
{
|
||||
ret["meta"] = meta;
|
||||
okay = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TransactionMetaSet::pointer set;
|
||||
if (lgr->getTransactionMeta(txid, set))
|
||||
{
|
||||
okay = true;
|
||||
ret["meta"] = set->getJson(0);
|
||||
}
|
||||
}
|
||||
if (okay)
|
||||
ret["validated"] = theApp->getOPs().isValidated(lgr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1576,29 +1596,49 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest)
|
||||
int vl = theApp->getOPs().getValidatedSeq();
|
||||
ScopedUnlock su(theApp->getMasterLock());
|
||||
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getAccountTxs(raAccount, minLedger, maxLedger);
|
||||
Json::Value ret(Json::objectValue);
|
||||
ret["account"] = raAccount.humanAccountID();
|
||||
Json::Value ledgers(Json::arrayValue);
|
||||
|
||||
for (std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >::iterator it = txns.begin(), end = txns.end(); it != end; ++it)
|
||||
if (jvRequest.isMember("binary") && jvRequest["binary"].asBool())
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
|
||||
if (it->first)
|
||||
obj["tx"] = it->first->getJson(1);
|
||||
if (it->second)
|
||||
std::vector<NetworkOPs::txnMetaLedgerType> txns =
|
||||
mNetOps->getAccountTxsB(raAccount, minLedger, maxLedger);
|
||||
for (std::vector<NetworkOPs::txnMetaLedgerType>::const_iterator it = txns.begin(), end = txns.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
obj["meta"] = it->second->getJson(0);
|
||||
|
||||
uint32 s = it->second->getLgrSeq();
|
||||
if (s > vl)
|
||||
Json::Value obj(Json::objectValue);
|
||||
obj["transaction"] = it->get<0>();
|
||||
obj["meta"] = it->get<1>();
|
||||
obj["inLedger"] = it->get<2>();
|
||||
if (it->get<2>() > vl)
|
||||
obj["validated"] = false;
|
||||
else if (theApp->getOPs().haveLedger(s))
|
||||
else if (theApp->getOPs().haveLedger(it->get<2>()))
|
||||
obj["validated"] = true;
|
||||
ret["transactions"].append(obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getAccountTxs(raAccount, minLedger, maxLedger);
|
||||
for (std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >::iterator it = txns.begin(), end = txns.end(); it != end; ++it)
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
|
||||
ret["transactions"].append(obj);
|
||||
if (it->first)
|
||||
obj["tx"] = it->first->getJson(1);
|
||||
if (it->second)
|
||||
{
|
||||
obj["meta"] = it->second->getJson(0);
|
||||
|
||||
uint32 s = it->second->getLgrSeq();
|
||||
if (s > vl)
|
||||
obj["validated"] = false;
|
||||
else if (theApp->getOPs().haveLedger(s))
|
||||
obj["validated"] = true;
|
||||
}
|
||||
|
||||
ret["transactions"].append(obj);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#ifndef DEBUG
|
||||
|
||||
@@ -190,12 +190,19 @@ void SerializedTransaction::setSourceAccount(const RippleAddress& naSource)
|
||||
setFieldAccount(sfAccount, naSource);
|
||||
}
|
||||
|
||||
Json::Value SerializedTransaction::getJson(int options) const
|
||||
Json::Value SerializedTransaction::getJson(int options, bool binary) const
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
Json::Value ret;
|
||||
Serializer s = STObject::getSerializer();
|
||||
ret["tx"] = strHex(s.peekData());
|
||||
ret["hash"] = getTransactionID().GetHex();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value ret = STObject::getJson(0);
|
||||
|
||||
ret["hash"] = getTransactionID().GetHex();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
uint256 getTransactionID() const;
|
||||
|
||||
virtual Json::Value getJson(int options) const;
|
||||
virtual Json::Value getJson(int options, bool binary = false) const;
|
||||
|
||||
void sign(const RippleAddress& naAccountPrivate);
|
||||
bool checkSign(const RippleAddress& naAccountPublic) const;
|
||||
|
||||
@@ -299,22 +299,20 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg
|
||||
}
|
||||
|
||||
// options 1 to include the date of the transaction
|
||||
Json::Value Transaction::getJson(int options) const
|
||||
Json::Value Transaction::getJson(int options, bool binary) const
|
||||
{
|
||||
|
||||
Json::Value ret(mTransaction->getJson(0));
|
||||
Json::Value ret(mTransaction->getJson(0, binary));
|
||||
|
||||
if (mInLedger)
|
||||
{
|
||||
ret["inLedger"]=mInLedger;
|
||||
ret["inLedger"] = mInLedger;
|
||||
|
||||
if(options==1)
|
||||
if(options == 1)
|
||||
{
|
||||
Ledger::pointer ledger=theApp->getLedgerMaster().getLedgerBySeq(mInLedger);
|
||||
if(ledger)
|
||||
{
|
||||
ret["date"]=ledger->getCloseTimeNC();
|
||||
}
|
||||
ret["date"] = ledger->getCloseTimeNC();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
bool operator<=(const Transaction&) const;
|
||||
bool operator>=(const Transaction&) const;
|
||||
|
||||
Json::Value getJson(int options) const;
|
||||
Json::Value getJson(int options, bool binary = false) const;
|
||||
|
||||
static bool isHexTxID(const std::string&);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user