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:
JoelKatz
2013-02-25 12:51:06 -08:00
parent fc221a8d7c
commit 923446fb78
10 changed files with 167 additions and 37 deletions

View File

@@ -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 },

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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&);