diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index afb4e95513..82ec2e5bf2 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -3090,6 +3090,9 @@ + + True + True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 73f67976fe..3c51b56bc0 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -4194,6 +4194,9 @@ ripple\rpc\impl + + ripple\rpc\impl + ripple\rpc\impl diff --git a/src/ripple/protocol/JsonFields.h b/src/ripple/protocol/JsonFields.h index c586c1de4c..15f5c1ab54 100644 --- a/src/ripple/protocol/JsonFields.h +++ b/src/ripple/protocol/JsonFields.h @@ -68,6 +68,7 @@ JSS ( converge_time_s ); JSS ( currency ); JSS ( data ); JSS ( date ); +JSS ( delivered_amount ); JSS ( engine_result ); JSS ( engine_result_code ); JSS ( engine_result_message ); diff --git a/src/ripple/rpc/handlers/AccountTx.cpp b/src/ripple/rpc/handlers/AccountTx.cpp index 35b0351b61..918a98ad66 100644 --- a/src/ripple/rpc/handlers/AccountTx.cpp +++ b/src/ripple/rpc/handlers/AccountTx.cpp @@ -110,15 +110,15 @@ Json::Value doAccountTx (RPC::Context& context) { Json::Value& jvObj = jvTxns.append (Json::objectValue); - std::uint32_t uLedgerIndex = std::get<2> (it); jvObj["tx_blob"] = std::get<0> (it); jvObj["meta"] = std::get<1> (it); - jvObj["ledger_index"] = uLedgerIndex; - jvObj[jss::validated] - = bValidated - && uValidatedMin <= uLedgerIndex - && uValidatedMax >= uLedgerIndex; + std::uint32_t uLedgerIndex = std::get<2> (it); + + jvObj["ledger_index"] = uLedgerIndex; + jvObj[jss::validated] = bValidated && + uValidatedMin <= uLedgerIndex && + uValidatedMax >= uLedgerIndex; } } else @@ -136,13 +136,15 @@ Json::Value doAccountTx (RPC::Context& context) if (it.second) { + auto meta = it.second->getJson (1); + addPaymentDeliveredAmount (meta, context, it.first, it.second); + jvObj[jss::meta] = meta; + std::uint32_t uLedgerIndex = it.second->getLgrSeq (); - jvObj[jss::meta] = it.second->getJson (0); - jvObj[jss::validated] - = bValidated - && uValidatedMin <= uLedgerIndex - && uValidatedMax >= uLedgerIndex; + jvObj[jss::validated] = bValidated && + uValidatedMin <= uLedgerIndex && + uValidatedMax >= uLedgerIndex; } } diff --git a/src/ripple/rpc/handlers/Tx.cpp b/src/ripple/rpc/handlers/Tx.cpp index 927bdac9c6..3f46fed4fc 100644 --- a/src/ripple/rpc/handlers/Tx.cpp +++ b/src/ripple/rpc/handlers/Tx.cpp @@ -17,7 +17,6 @@ */ //============================================================================== - namespace ripple { // { @@ -31,60 +30,53 @@ Json::Value doTx (RPC::Context& context) bool binary = context.params.isMember (jss::binary) && context.params[jss::binary].asBool (); - std::string strTransaction = context.params[jss::transaction].asString (); + auto const txid = context.params[jss::transaction].asString (); - if (Transaction::isHexTxID (strTransaction)) + if (!Transaction::isHexTxID (txid)) + return rpcError (rpcNOT_IMPL); + + auto txn = getApp().getMasterTransaction ().fetch (uint256 (txid), true); + + if (!txn) + return rpcError (rpcTXN_NOT_FOUND); + + Json::Value ret = txn->getJson (1, binary); + + if (txn->getLedger () == 0) + return ret; + + if (auto lgr = context.netOps.getLedgerBySeq (txn->getLedger ())) { - // transaction by ID - uint256 txid (strTransaction); + bool okay = false; - auto txn = getApp().getMasterTransaction ().fetch (txid, true); - - if (!txn) - return rpcError (rpcTXN_NOT_FOUND); - -#ifdef READY_FOR_NEW_TX_FORMAT - // TODO(tom): what new format is this? - Json::Value ret; - ret[jss::transaction] = txn->getJson (1, binary); -#else - Json::Value ret = txn->getJson (1, binary); -#endif - - if (txn->getLedger () != 0) + if (binary) { - if (auto lgr = context.netOps.getLedgerBySeq (txn->getLedger ())) + std::string meta; + + if (lgr->getMetaHex (txn->getID (), meta)) { - bool okay = false; - if (binary) - { - std::string meta; + ret[jss::meta] = meta; + okay = true; + } + } + else + { + TransactionMetaSet::pointer txMeta; - if (lgr->getMetaHex (txid, meta)) - { - ret[jss::meta] = meta; - okay = true; - } - } - else - { - TransactionMetaSet::pointer set; - if (lgr->getTransactionMeta (txid, set)) - { - okay = true; - ret[jss::meta] = set->getJson (0); - } - } - - if (okay) - ret[jss::validated] = context.netOps.isValidated (lgr); + if (lgr->getTransactionMeta (txn->getID (), txMeta)) + { + okay = true; + auto meta = txMeta->getJson (0); + addPaymentDeliveredAmount (meta, context, txn, txMeta); + ret[jss::meta] = meta; } } - return ret; + if (okay) + ret[jss::validated] = context.netOps.isValidated (lgr); } - return rpcError (rpcNOT_IMPL); + return ret; } } // ripple diff --git a/src/ripple/rpc/impl/Utilities.cpp b/src/ripple/rpc/impl/Utilities.cpp new file mode 100644 index 0000000000..ca4c7b847d --- /dev/null +++ b/src/ripple/rpc/impl/Utilities.cpp @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "boost/date_time/posix_time/posix_time.hpp" +#include + +namespace ripple { +namespace RPC { + +void +addPaymentDeliveredAmount ( + Json::Value& meta, + RPC::Context& context, + Transaction::pointer transaction, + TransactionMetaSet::pointer transactionMeta) +{ + STTx::pointer serializedTx; + + if (transaction) + serializedTx = transaction->getSTransaction (); + + if (serializedTx && serializedTx->getTxnType () == ttPAYMENT) + { + // If the transaction explicitly specifies a DeliveredAmount in the + // metadata then we use it. + if (transactionMeta && transactionMeta->hasDeliveredAmount ()) + { + meta[jss::delivered_amount] = + transactionMeta->getDeliveredAmount ().getJson (1); + return; + } + + if (auto ledger = context.netOps.getLedgerBySeq (transaction->getLedger ())) + { + // The first ledger where the DeliveredAmount flag appears is + // which closed on 2014-Jan-24 at 04:50:10. If the transaction we + // are dealing with is in a ledger that closed after this date then + // the absence of DeliveredAmount indicates that the correct amount + // is in the Amount field. + + boost::posix_time::ptime const cutoff ( + boost::posix_time::time_from_string ("2014-01-24 04:50:10")); + + if (ledger->getCloseTime () >= cutoff) + { + meta[jss::delivered_amount] = + serializedTx->getFieldAmount (sfAmount).getJson (1); + return; + } + } + + // Otherwise we report "unavailable" which cannot be parsed into a + // sensible amount. + meta[jss::delivered_amount] = Json::Value ("unavailable"); + } +} + +} +} diff --git a/src/ripple/unity/rpcx.cpp b/src/ripple/unity/rpcx.cpp index fb99addb35..a26d440d5c 100644 --- a/src/ripple/unity/rpcx.cpp +++ b/src/ripple/unity/rpcx.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include