mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Compare commits
27 Commits
vlntb/fd-e
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec01e14e6c | ||
|
|
5d79bfc531 | ||
|
|
51ef35ab55 | ||
|
|
330a3215bc | ||
|
|
3bb3f1b31d | ||
|
|
4063ccaa09 | ||
|
|
bb7042388a | ||
|
|
ee3cba2fd9 | ||
|
|
539074bdcf | ||
|
|
7e2dcbd221 | ||
|
|
e79416bc06 | ||
|
|
45fdb1b108 | ||
|
|
de84c82d0e | ||
|
|
376bca2866 | ||
|
|
649fd105f8 | ||
|
|
c491adc46b | ||
|
|
ac16c83a9f | ||
|
|
f6d15f3d16 | ||
|
|
a8d5d995e1 | ||
|
|
3d8c1a3e58 | ||
|
|
2f7cbc4f57 | ||
|
|
2e4b30dab5 | ||
|
|
14ff58aaaa | ||
|
|
72bb19c1a3 | ||
|
|
e26065176b | ||
|
|
ed7167c116 | ||
|
|
2ccd1082f5 |
@@ -31,13 +31,13 @@ namespace ripple {
|
|||||||
namespace RPC {
|
namespace RPC {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Adds common synthetic fields to transaction-related JSON responses
|
Adds common synthetic fields to transaction metadata JSON
|
||||||
|
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
insertNFTSyntheticInJson(
|
insertNFTSyntheticInJson(
|
||||||
Json::Value&,
|
Json::Value& metadata,
|
||||||
std::shared_ptr<STTx const> const&,
|
std::shared_ptr<STTx const> const&,
|
||||||
TxMeta const&);
|
TxMeta const&);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
@@ -3126,7 +3126,7 @@ rippleUnlockEscrowMPT(
|
|||||||
{ // LCOV_EXCL_START
|
{ // LCOV_EXCL_START
|
||||||
JLOG(j.error())
|
JLOG(j.error())
|
||||||
<< "rippleUnlockEscrowMPT: MPToken not found for " << receiver;
|
<< "rippleUnlockEscrowMPT: MPToken not found for " << receiver;
|
||||||
return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE
|
return tecOBJECT_NOT_FOUND;
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
|
||||||
auto current = sle->getFieldU64(sfMPTAmount);
|
auto current = sle->getFieldU64(sfMPTAmount);
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ namespace RPC {
|
|||||||
|
|
||||||
void
|
void
|
||||||
insertNFTSyntheticInJson(
|
insertNFTSyntheticInJson(
|
||||||
Json::Value& response,
|
Json::Value& metadata,
|
||||||
std::shared_ptr<STTx const> const& transaction,
|
std::shared_ptr<STTx const> const& transaction,
|
||||||
TxMeta const& transactionMeta)
|
TxMeta const& transactionMeta)
|
||||||
{
|
{
|
||||||
insertNFTokenID(response[jss::meta], transaction, transactionMeta);
|
insertNFTokenID(metadata, transaction, transactionMeta);
|
||||||
insertNFTokenOfferID(response[jss::meta], transaction, transactionMeta);
|
insertNFTokenOfferID(metadata, transaction, transactionMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace RPC
|
} // namespace RPC
|
||||||
|
|||||||
@@ -6894,41 +6894,118 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
|
|||||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||||
|
|
||||||
env.close();
|
env.close();
|
||||||
Json::Value const meta =
|
|
||||||
env.rpc("tx", txHash)[jss::result][jss::meta];
|
|
||||||
|
|
||||||
// Expect nftokens_id field
|
// Test 1: Check tx RPC response
|
||||||
if (!BEAST_EXPECT(meta.isMember(jss::nftoken_id)))
|
Json::Value const txResult = env.rpc("tx", txHash)[jss::result];
|
||||||
|
Json::Value const& txMeta = txResult[jss::meta];
|
||||||
|
|
||||||
|
// Expect nftoken_id field
|
||||||
|
if (!BEAST_EXPECT(txMeta.isMember(jss::nftoken_id)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check the value of NFT ID in the meta with the
|
// Check the value of NFT ID matches
|
||||||
// actual value
|
|
||||||
uint256 nftID;
|
uint256 nftID;
|
||||||
BEAST_EXPECT(nftID.parseHex(meta[jss::nftoken_id].asString()));
|
BEAST_EXPECT(nftID.parseHex(txMeta[jss::nftoken_id].asString()));
|
||||||
BEAST_EXPECT(nftID == actualNftID);
|
BEAST_EXPECT(nftID == actualNftID);
|
||||||
|
|
||||||
|
// Get ledger sequence from tx response
|
||||||
|
auto const ledgerSeq = txResult[jss::ledger_index].asUInt();
|
||||||
|
|
||||||
|
// Test 2: Check ledger RPC response with expanded transactions
|
||||||
|
Json::Value ledgerParams;
|
||||||
|
ledgerParams[jss::ledger_index] = ledgerSeq;
|
||||||
|
ledgerParams[jss::transactions] = true;
|
||||||
|
ledgerParams[jss::expand] = true;
|
||||||
|
|
||||||
|
auto const ledgerResult =
|
||||||
|
env.rpc("json", "ledger", to_string(ledgerParams));
|
||||||
|
auto const& tx =
|
||||||
|
ledgerResult[jss::result][jss::ledger][jss::transactions][0u];
|
||||||
|
|
||||||
|
// Verify transaction hash matches
|
||||||
|
BEAST_EXPECT(tx[jss::hash].asString() == txHash);
|
||||||
|
|
||||||
|
// Check synthetic fields in ledger response (this tests our
|
||||||
|
// LedgerToJson.cpp fix)
|
||||||
|
Json::Value const* meta = nullptr;
|
||||||
|
if (tx.isMember(jss::meta))
|
||||||
|
meta = &tx[jss::meta];
|
||||||
|
else if (tx.isMember(jss::metaData))
|
||||||
|
meta = &tx[jss::metaData];
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(meta != nullptr))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(meta->isMember(jss::nftoken_id));
|
||||||
|
if (meta->isMember(jss::nftoken_id))
|
||||||
|
{
|
||||||
|
uint256 ledgerNftId;
|
||||||
|
BEAST_EXPECT(ledgerNftId.parseHex(
|
||||||
|
(*meta)[jss::nftoken_id].asString()));
|
||||||
|
BEAST_EXPECT(ledgerNftId == actualNftID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 3: Check account_tx RPC response
|
||||||
|
Json::Value accountTxParams;
|
||||||
|
accountTxParams[jss::account] = alice.human();
|
||||||
|
accountTxParams[jss::limit] = 1;
|
||||||
|
|
||||||
|
auto const accountTxResult =
|
||||||
|
env.rpc("json", "account_tx", to_string(accountTxParams));
|
||||||
|
auto const& accountTx =
|
||||||
|
accountTxResult[jss::result][jss::transactions][0u];
|
||||||
|
|
||||||
|
// Check if the latest transaction is ours (it should be, but
|
||||||
|
// account_tx can be ordering-dependent)
|
||||||
|
bool isOurTransaction = (accountTx[jss::hash].asString() == txHash);
|
||||||
|
|
||||||
|
// Only check synthetic fields if this is our transaction
|
||||||
|
if (isOurTransaction)
|
||||||
|
{
|
||||||
|
// Check synthetic fields in account_tx response
|
||||||
|
Json::Value const* accountMeta = nullptr;
|
||||||
|
if (accountTx.isMember(jss::meta))
|
||||||
|
accountMeta = &accountTx[jss::meta];
|
||||||
|
else if (accountTx.isMember(jss::metaData))
|
||||||
|
accountMeta = &accountTx[jss::metaData];
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(accountMeta != nullptr))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(accountMeta->isMember(jss::nftoken_id));
|
||||||
|
if (accountMeta->isMember(jss::nftoken_id))
|
||||||
|
{
|
||||||
|
uint256 accountNftId;
|
||||||
|
BEAST_EXPECT(accountNftId.parseHex(
|
||||||
|
(*accountMeta)[jss::nftoken_id].asString()));
|
||||||
|
BEAST_EXPECT(accountNftId == actualNftID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify `nftoken_ids` value equals to the NFTokenIDs that were
|
// Verify `nftoken_ids` value equals to the NFTokenIDs that were
|
||||||
// changed in the most recent NFTokenCancelOffer transaction
|
// changed in the most recent NFTokenCancelOffer transaction
|
||||||
auto verifyNFTokenIDsInCancelOffer =
|
auto verifyNFTokenIDsInCancelOffer = [&](std::vector<uint256>
|
||||||
[&](std::vector<uint256> actualNftIDs) {
|
actualNftIDs) {
|
||||||
// Get the hash for the most recent transaction.
|
// Get the hash for the most recent transaction.
|
||||||
std::string const txHash{
|
std::string const txHash{
|
||||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||||
|
|
||||||
env.close();
|
env.close();
|
||||||
Json::Value const meta =
|
|
||||||
env.rpc("tx", txHash)[jss::result][jss::meta];
|
// Test 1: Check tx RPC response
|
||||||
|
Json::Value const txResult = env.rpc("tx", txHash)[jss::result];
|
||||||
|
Json::Value const& txMeta = txResult[jss::meta];
|
||||||
|
|
||||||
// Expect nftokens_ids field and verify the values
|
// Expect nftokens_ids field and verify the values
|
||||||
if (!BEAST_EXPECT(meta.isMember(jss::nftoken_ids)))
|
if (!BEAST_EXPECT(txMeta.isMember(jss::nftoken_ids)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Convert NFT IDs from Json::Value to uint256
|
// Convert NFT IDs from Json::Value to uint256
|
||||||
std::vector<uint256> metaIDs;
|
std::vector<uint256> metaIDs;
|
||||||
std::transform(
|
std::transform(
|
||||||
meta[jss::nftoken_ids].begin(),
|
txMeta[jss::nftoken_ids].begin(),
|
||||||
meta[jss::nftoken_ids].end(),
|
txMeta[jss::nftoken_ids].end(),
|
||||||
std::back_inserter(metaIDs),
|
std::back_inserter(metaIDs),
|
||||||
[this](Json::Value id) {
|
[this](Json::Value id) {
|
||||||
uint256 nftID;
|
uint256 nftID;
|
||||||
@@ -6947,6 +7024,104 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
|
|||||||
// actual values
|
// actual values
|
||||||
for (size_t i = 0; i < metaIDs.size(); ++i)
|
for (size_t i = 0; i < metaIDs.size(); ++i)
|
||||||
BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
|
BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
|
||||||
|
|
||||||
|
// Get ledger sequence from tx response
|
||||||
|
auto const ledgerSeq = txResult[jss::ledger_index].asUInt();
|
||||||
|
|
||||||
|
// Test 2: Check ledger RPC response with expanded transactions
|
||||||
|
Json::Value ledgerParams;
|
||||||
|
ledgerParams[jss::ledger_index] = ledgerSeq;
|
||||||
|
ledgerParams[jss::transactions] = true;
|
||||||
|
ledgerParams[jss::expand] = true;
|
||||||
|
|
||||||
|
auto const ledgerResult =
|
||||||
|
env.rpc("json", "ledger", to_string(ledgerParams));
|
||||||
|
auto const& tx =
|
||||||
|
ledgerResult[jss::result][jss::ledger][jss::transactions][0u];
|
||||||
|
|
||||||
|
// Verify transaction hash matches
|
||||||
|
BEAST_EXPECT(tx[jss::hash].asString() == txHash);
|
||||||
|
|
||||||
|
// Check synthetic fields in ledger response
|
||||||
|
Json::Value const* meta = nullptr;
|
||||||
|
if (tx.isMember(jss::meta))
|
||||||
|
meta = &tx[jss::meta];
|
||||||
|
else if (tx.isMember(jss::metaData))
|
||||||
|
meta = &tx[jss::metaData];
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(meta != nullptr))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(meta->isMember(jss::nftoken_ids));
|
||||||
|
if (meta->isMember(jss::nftoken_ids))
|
||||||
|
{
|
||||||
|
// Convert and verify NFT IDs in ledger response
|
||||||
|
std::vector<uint256> ledgerMetaIDs;
|
||||||
|
std::transform(
|
||||||
|
(*meta)[jss::nftoken_ids].begin(),
|
||||||
|
(*meta)[jss::nftoken_ids].end(),
|
||||||
|
std::back_inserter(ledgerMetaIDs),
|
||||||
|
[this](Json::Value id) {
|
||||||
|
uint256 nftID;
|
||||||
|
BEAST_EXPECT(nftID.parseHex(id.asString()));
|
||||||
|
return nftID;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::sort(ledgerMetaIDs.begin(), ledgerMetaIDs.end());
|
||||||
|
BEAST_EXPECT(ledgerMetaIDs.size() == actualNftIDs.size());
|
||||||
|
for (size_t i = 0; i < ledgerMetaIDs.size(); ++i)
|
||||||
|
BEAST_EXPECT(ledgerMetaIDs[i] == actualNftIDs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 3: Check account_tx RPC response
|
||||||
|
Json::Value accountTxParams;
|
||||||
|
accountTxParams[jss::account] = alice.human();
|
||||||
|
accountTxParams[jss::limit] = 1;
|
||||||
|
|
||||||
|
auto const accountTxResult =
|
||||||
|
env.rpc("json", "account_tx", to_string(accountTxParams));
|
||||||
|
auto const& accountTx =
|
||||||
|
accountTxResult[jss::result][jss::transactions][0u];
|
||||||
|
|
||||||
|
// Check if the latest transaction is ours (it should be, but
|
||||||
|
// account_tx can be ordering-dependent)
|
||||||
|
bool isOurTransaction = (accountTx[jss::hash].asString() == txHash);
|
||||||
|
|
||||||
|
// Only check synthetic fields if this is our transaction
|
||||||
|
if (isOurTransaction)
|
||||||
|
{
|
||||||
|
// Check synthetic fields in account_tx response
|
||||||
|
Json::Value const* accountMeta = nullptr;
|
||||||
|
if (accountTx.isMember(jss::meta))
|
||||||
|
accountMeta = &accountTx[jss::meta];
|
||||||
|
else if (accountTx.isMember(jss::metaData))
|
||||||
|
accountMeta = &accountTx[jss::metaData];
|
||||||
|
|
||||||
|
if (BEAST_EXPECT(accountMeta != nullptr))
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(accountMeta->isMember(jss::nftoken_ids));
|
||||||
|
if (accountMeta->isMember(jss::nftoken_ids))
|
||||||
|
{
|
||||||
|
// Convert and verify NFT IDs in account_tx response
|
||||||
|
std::vector<uint256> accountMetaIDs;
|
||||||
|
std::transform(
|
||||||
|
(*accountMeta)[jss::nftoken_ids].begin(),
|
||||||
|
(*accountMeta)[jss::nftoken_ids].end(),
|
||||||
|
std::back_inserter(accountMetaIDs),
|
||||||
|
[this](Json::Value id) {
|
||||||
|
uint256 nftID;
|
||||||
|
BEAST_EXPECT(nftID.parseHex(id.asString()));
|
||||||
|
return nftID;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::sort(accountMetaIDs.begin(), accountMetaIDs.end());
|
||||||
|
BEAST_EXPECT(
|
||||||
|
accountMetaIDs.size() == actualNftIDs.size());
|
||||||
|
for (size_t i = 0; i < accountMetaIDs.size(); ++i)
|
||||||
|
BEAST_EXPECT(accountMetaIDs[i] == actualNftIDs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify `offer_id` value equals to the offerID that was
|
// Verify `offer_id` value equals to the offerID that was
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
#include <xrpld/app/misc/DeliverMax.h>
|
#include <xrpld/app/misc/DeliverMax.h>
|
||||||
#include <xrpld/app/misc/TxQ.h>
|
#include <xrpld/app/misc/TxQ.h>
|
||||||
#include <xrpld/rpc/Context.h>
|
#include <xrpld/rpc/Context.h>
|
||||||
#include <xrpld/rpc/DeliveredAmount.h>
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
|
||||||
|
|
||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/protocol/ApiVersion.h>
|
#include <xrpl/protocol/ApiVersion.h>
|
||||||
|
#include <xrpl/protocol/NFTSyntheticSerializer.h>
|
||||||
#include <xrpl/protocol/jss.h>
|
#include <xrpl/protocol/jss.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -150,19 +150,12 @@ fillJsonTx(
|
|||||||
{
|
{
|
||||||
txJson[jss::meta] = stMeta->getJson(JsonOptions::none);
|
txJson[jss::meta] = stMeta->getJson(JsonOptions::none);
|
||||||
|
|
||||||
// If applicable, insert delivered amount
|
// Insert all synthetic fields
|
||||||
if (txnType == ttPAYMENT || txnType == ttCHECK_CASH)
|
RPC::insertAllSyntheticInJson(
|
||||||
RPC::insertDeliveredAmount(
|
|
||||||
txJson[jss::meta],
|
txJson[jss::meta],
|
||||||
fill.ledger,
|
fill.ledger,
|
||||||
txn,
|
txn,
|
||||||
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
||||||
|
|
||||||
// If applicable, insert mpt issuance id
|
|
||||||
RPC::insertMPTokenIssuanceID(
|
|
||||||
txJson[jss::meta],
|
|
||||||
txn,
|
|
||||||
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fill.ledger.open())
|
if (!fill.ledger.open())
|
||||||
@@ -187,19 +180,12 @@ fillJsonTx(
|
|||||||
{
|
{
|
||||||
txJson[jss::metaData] = stMeta->getJson(JsonOptions::none);
|
txJson[jss::metaData] = stMeta->getJson(JsonOptions::none);
|
||||||
|
|
||||||
// If applicable, insert delivered amount
|
// Insert all synthetic fields
|
||||||
if (txnType == ttPAYMENT || txnType == ttCHECK_CASH)
|
RPC::insertAllSyntheticInJson(
|
||||||
RPC::insertDeliveredAmount(
|
|
||||||
txJson[jss::metaData],
|
txJson[jss::metaData],
|
||||||
fill.ledger,
|
fill.ledger,
|
||||||
txn,
|
txn,
|
||||||
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
||||||
|
|
||||||
// If applicable, insert mpt issuance id
|
|
||||||
RPC::insertMPTokenIssuanceID(
|
|
||||||
txJson[jss::metaData],
|
|
||||||
txn,
|
|
||||||
{txn->getTransactionID(), fill.ledger.seq(), *stMeta});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,8 @@
|
|||||||
#include <xrpld/perflog/PerfLog.h>
|
#include <xrpld/perflog/PerfLog.h>
|
||||||
#include <xrpld/rpc/BookChanges.h>
|
#include <xrpld/rpc/BookChanges.h>
|
||||||
#include <xrpld/rpc/CTID.h>
|
#include <xrpld/rpc/CTID.h>
|
||||||
#include <xrpld/rpc/DeliveredAmount.h>
|
|
||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
|
||||||
#include <xrpld/rpc/ServerHandler.h>
|
#include <xrpld/rpc/ServerHandler.h>
|
||||||
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
|
|
||||||
#include <xrpl/basics/UptimeClock.h>
|
#include <xrpl/basics/UptimeClock.h>
|
||||||
#include <xrpl/basics/mulDiv.h>
|
#include <xrpl/basics/mulDiv.h>
|
||||||
@@ -3274,11 +3273,8 @@ NetworkOPsImp::transJson(
|
|||||||
if (meta)
|
if (meta)
|
||||||
{
|
{
|
||||||
jvObj[jss::meta] = meta->get().getJson(JsonOptions::none);
|
jvObj[jss::meta] = meta->get().getJson(JsonOptions::none);
|
||||||
RPC::insertDeliveredAmount(
|
RPC::insertAllSyntheticInJson(
|
||||||
jvObj[jss::meta], *ledger, transaction, meta->get());
|
jvObj[jss::meta], *ledger, transaction, meta->get());
|
||||||
RPC::insertNFTSyntheticInJson(jvObj, transaction, meta->get());
|
|
||||||
RPC::insertMPTokenIssuanceID(
|
|
||||||
jvObj[jss::meta], transaction, meta->get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add CTID where the needed data for it exists
|
// add CTID where the needed data for it exists
|
||||||
|
|||||||
@@ -660,14 +660,15 @@ Transactor::apply()
|
|||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
Transactor::checkSign(
|
Transactor::checkSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
|
ApplyFlags flags,
|
||||||
AccountID const& idAccount,
|
AccountID const& idAccount,
|
||||||
STObject const& sigObject)
|
STObject const& sigObject,
|
||||||
|
beast::Journal const j)
|
||||||
{
|
{
|
||||||
auto const pkSigner = sigObject.getFieldVL(sfSigningPubKey);
|
auto const pkSigner = sigObject.getFieldVL(sfSigningPubKey);
|
||||||
// Ignore signature check on batch inner transactions
|
// Ignore signature check on batch inner transactions
|
||||||
if (sigObject.isFlag(tfInnerBatchTxn) &&
|
if (sigObject.isFlag(tfInnerBatchTxn) && view.rules().enabled(featureBatch))
|
||||||
ctx.view.rules().enabled(featureBatch))
|
|
||||||
{
|
{
|
||||||
// Defensive Check: These values are also checked in Batch::preflight
|
// Defensive Check: These values are also checked in Batch::preflight
|
||||||
if (sigObject.isFieldPresent(sfTxnSignature) || !pkSigner.empty() ||
|
if (sigObject.isFieldPresent(sfTxnSignature) || !pkSigner.empty() ||
|
||||||
@@ -678,7 +679,7 @@ Transactor::checkSign(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ctx.flags & tapDRY_RUN) && pkSigner.empty() &&
|
if ((flags & tapDRY_RUN) && pkSigner.empty() &&
|
||||||
!sigObject.isFieldPresent(sfSigners))
|
!sigObject.isFieldPresent(sfSigners))
|
||||||
{
|
{
|
||||||
// simulate: skip signature validation when neither SigningPubKey nor
|
// simulate: skip signature validation when neither SigningPubKey nor
|
||||||
@@ -688,9 +689,9 @@ Transactor::checkSign(
|
|||||||
|
|
||||||
// If the pk is empty and not simulate or simulate and signers,
|
// If the pk is empty and not simulate or simulate and signers,
|
||||||
// then we must be multi-signing.
|
// then we must be multi-signing.
|
||||||
if (ctx.tx.isFieldPresent(sfSigners))
|
if (sigObject.isFieldPresent(sfSigners))
|
||||||
{
|
{
|
||||||
return checkMultiSign(ctx, idAccount, sigObject);
|
return checkMultiSign(view, flags, idAccount, sigObject, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Single Sign
|
// Check Single Sign
|
||||||
@@ -699,7 +700,7 @@ Transactor::checkSign(
|
|||||||
|
|
||||||
if (!publicKeyType(makeSlice(pkSigner)))
|
if (!publicKeyType(makeSlice(pkSigner)))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace()) << "checkSign: signing public key type is unknown";
|
JLOG(j.trace()) << "checkSign: signing public key type is unknown";
|
||||||
return tefBAD_AUTH; // FIXME: should be better error!
|
return tefBAD_AUTH; // FIXME: should be better error!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -707,11 +708,11 @@ Transactor::checkSign(
|
|||||||
auto const idSigner = pkSigner.empty()
|
auto const idSigner = pkSigner.empty()
|
||||||
? idAccount
|
? idAccount
|
||||||
: calcAccountID(PublicKey(makeSlice(pkSigner)));
|
: calcAccountID(PublicKey(makeSlice(pkSigner)));
|
||||||
auto const sleAccount = ctx.view.read(keylet::account(idAccount));
|
auto const sleAccount = view.read(keylet::account(idAccount));
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
return checkSingleSign(ctx, idSigner, idAccount, sleAccount);
|
return checkSingleSign(view, idSigner, idAccount, sleAccount, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
@@ -720,7 +721,7 @@ Transactor::checkSign(PreclaimContext const& ctx)
|
|||||||
auto const idAccount = ctx.tx.isFieldPresent(sfDelegate)
|
auto const idAccount = ctx.tx.isFieldPresent(sfDelegate)
|
||||||
? ctx.tx.getAccountID(sfDelegate)
|
? ctx.tx.getAccountID(sfDelegate)
|
||||||
: ctx.tx.getAccountID(sfAccount);
|
: ctx.tx.getAccountID(sfAccount);
|
||||||
return checkSign(ctx, idAccount, ctx.tx);
|
return checkSign(ctx.view, ctx.flags, idAccount, ctx.tx, ctx.j);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
@@ -735,7 +736,8 @@ Transactor::checkBatchSign(PreclaimContext const& ctx)
|
|||||||
Blob const& pkSigner = signer.getFieldVL(sfSigningPubKey);
|
Blob const& pkSigner = signer.getFieldVL(sfSigningPubKey);
|
||||||
if (pkSigner.empty())
|
if (pkSigner.empty())
|
||||||
{
|
{
|
||||||
if (ret = checkMultiSign(ctx, idAccount, signer);
|
if (ret = checkMultiSign(
|
||||||
|
ctx.view, ctx.flags, idAccount, signer, ctx.j);
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -759,7 +761,8 @@ Transactor::checkBatchSign(PreclaimContext const& ctx)
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret = checkSingleSign(ctx, idSigner, idAccount, sleAccount);
|
if (ret = checkSingleSign(
|
||||||
|
ctx.view, idSigner, idAccount, sleAccount, ctx.j);
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -769,14 +772,15 @@ Transactor::checkBatchSign(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
Transactor::checkSingleSign(
|
Transactor::checkSingleSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
AccountID const& idSigner,
|
AccountID const& idSigner,
|
||||||
AccountID const& idAccount,
|
AccountID const& idAccount,
|
||||||
std::shared_ptr<SLE const> sleAccount)
|
std::shared_ptr<SLE const> sleAccount,
|
||||||
|
beast::Journal const j)
|
||||||
{
|
{
|
||||||
bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster);
|
bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster);
|
||||||
|
|
||||||
if (ctx.view.rules().enabled(fixMasterKeyAsRegularKey))
|
if (view.rules().enabled(fixMasterKeyAsRegularKey))
|
||||||
{
|
{
|
||||||
// Signed with regular key.
|
// Signed with regular key.
|
||||||
if ((*sleAccount)[~sfRegularKey] == idSigner)
|
if ((*sleAccount)[~sfRegularKey] == idSigner)
|
||||||
@@ -813,16 +817,14 @@ Transactor::checkSingleSign(
|
|||||||
else if (sleAccount->isFieldPresent(sfRegularKey))
|
else if (sleAccount->isFieldPresent(sfRegularKey))
|
||||||
{
|
{
|
||||||
// Signing key does not match master or regular key.
|
// Signing key does not match master or regular key.
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace()) << "checkSingleSign: Not authorized to use account.";
|
||||||
<< "checkSingleSign: Not authorized to use account.";
|
|
||||||
return tefBAD_AUTH;
|
return tefBAD_AUTH;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No regular key on account and signing key does not match master key.
|
// No regular key on account and signing key does not match master key.
|
||||||
// FIXME: Why differentiate this case from tefBAD_AUTH?
|
// FIXME: Why differentiate this case from tefBAD_AUTH?
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace()) << "checkSingleSign: Not authorized to use account.";
|
||||||
<< "checkSingleSign: Not authorized to use account.";
|
|
||||||
return tefBAD_AUTH_MASTER;
|
return tefBAD_AUTH_MASTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,17 +833,19 @@ Transactor::checkSingleSign(
|
|||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
Transactor::checkMultiSign(
|
Transactor::checkMultiSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
|
ApplyFlags flags,
|
||||||
AccountID const& id,
|
AccountID const& id,
|
||||||
STObject const& sigObject)
|
STObject const& sigObject,
|
||||||
|
beast::Journal const j)
|
||||||
{
|
{
|
||||||
// Get id's SignerList and Quorum.
|
// Get id's SignerList and Quorum.
|
||||||
std::shared_ptr<STLedgerEntry const> sleAccountSigners =
|
std::shared_ptr<STLedgerEntry const> sleAccountSigners =
|
||||||
ctx.view.read(keylet::signers(id));
|
view.read(keylet::signers(id));
|
||||||
// If the signer list doesn't exist the account is not multi-signing.
|
// If the signer list doesn't exist the account is not multi-signing.
|
||||||
if (!sleAccountSigners)
|
if (!sleAccountSigners)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Invalid: Not a multi-signing account.";
|
<< "applyTransaction: Invalid: Not a multi-signing account.";
|
||||||
return tefNOT_MULTI_SIGNING;
|
return tefNOT_MULTI_SIGNING;
|
||||||
}
|
}
|
||||||
@@ -856,7 +860,7 @@ Transactor::checkMultiSign(
|
|||||||
"ripple::Transactor::checkMultiSign : signer list ID is 0");
|
"ripple::Transactor::checkMultiSign : signer list ID is 0");
|
||||||
|
|
||||||
auto accountSigners =
|
auto accountSigners =
|
||||||
SignerEntries::deserialize(*sleAccountSigners, ctx.j, "ledger");
|
SignerEntries::deserialize(*sleAccountSigners, j, "ledger");
|
||||||
if (!accountSigners)
|
if (!accountSigners)
|
||||||
return accountSigners.error();
|
return accountSigners.error();
|
||||||
|
|
||||||
@@ -880,7 +884,7 @@ Transactor::checkMultiSign(
|
|||||||
{
|
{
|
||||||
if (++iter == accountSigners->end())
|
if (++iter == accountSigners->end())
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Invalid SigningAccount.Account.";
|
<< "applyTransaction: Invalid SigningAccount.Account.";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
@@ -888,7 +892,7 @@ Transactor::checkMultiSign(
|
|||||||
if (iter->account != txSignerAcctID)
|
if (iter->account != txSignerAcctID)
|
||||||
{
|
{
|
||||||
// The SigningAccount is not in the SignerEntries.
|
// The SigningAccount is not in the SignerEntries.
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Invalid SigningAccount.Account.";
|
<< "applyTransaction: Invalid SigningAccount.Account.";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
@@ -902,13 +906,13 @@ Transactor::checkMultiSign(
|
|||||||
// STTx::checkMultiSign
|
// STTx::checkMultiSign
|
||||||
if (!spk.empty() && !publicKeyType(makeSlice(spk)))
|
if (!spk.empty() && !publicKeyType(makeSlice(spk)))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "checkMultiSign: signing public key type is unknown";
|
<< "checkMultiSign: signing public key type is unknown";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
(ctx.flags & tapDRY_RUN) || !spk.empty(),
|
(flags & tapDRY_RUN) || !spk.empty(),
|
||||||
"ripple::Transactor::checkMultiSign : non-empty signer or "
|
"ripple::Transactor::checkMultiSign : non-empty signer or "
|
||||||
"simulation");
|
"simulation");
|
||||||
AccountID const signingAcctIDFromPubKey = spk.empty()
|
AccountID const signingAcctIDFromPubKey = spk.empty()
|
||||||
@@ -940,8 +944,7 @@ Transactor::checkMultiSign(
|
|||||||
|
|
||||||
// In any of these cases we need to know whether the account is in
|
// In any of these cases we need to know whether the account is in
|
||||||
// the ledger. Determine that now.
|
// the ledger. Determine that now.
|
||||||
auto const sleTxSignerRoot =
|
auto const sleTxSignerRoot = view.read(keylet::account(txSignerAcctID));
|
||||||
ctx.view.read(keylet::account(txSignerAcctID));
|
|
||||||
|
|
||||||
if (signingAcctIDFromPubKey == txSignerAcctID)
|
if (signingAcctIDFromPubKey == txSignerAcctID)
|
||||||
{
|
{
|
||||||
@@ -954,7 +957,7 @@ Transactor::checkMultiSign(
|
|||||||
|
|
||||||
if (signerAccountFlags & lsfDisableMaster)
|
if (signerAccountFlags & lsfDisableMaster)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Signer:Account lsfDisableMaster.";
|
<< "applyTransaction: Signer:Account lsfDisableMaster.";
|
||||||
return tefMASTER_DISABLED;
|
return tefMASTER_DISABLED;
|
||||||
}
|
}
|
||||||
@@ -966,21 +969,21 @@ Transactor::checkMultiSign(
|
|||||||
// Public key must hash to the account's regular key.
|
// Public key must hash to the account's regular key.
|
||||||
if (!sleTxSignerRoot)
|
if (!sleTxSignerRoot)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace()) << "applyTransaction: Non-phantom signer "
|
JLOG(j.trace()) << "applyTransaction: Non-phantom signer "
|
||||||
"lacks account root.";
|
"lacks account root.";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sleTxSignerRoot->isFieldPresent(sfRegularKey))
|
if (!sleTxSignerRoot->isFieldPresent(sfRegularKey))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Account lacks RegularKey.";
|
<< "applyTransaction: Account lacks RegularKey.";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
if (signingAcctIDFromPubKey !=
|
if (signingAcctIDFromPubKey !=
|
||||||
sleTxSignerRoot->getAccountID(sfRegularKey))
|
sleTxSignerRoot->getAccountID(sfRegularKey))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace())
|
||||||
<< "applyTransaction: Account doesn't match RegularKey.";
|
<< "applyTransaction: Account doesn't match RegularKey.";
|
||||||
return tefBAD_SIGNATURE;
|
return tefBAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
@@ -992,8 +995,7 @@ Transactor::checkMultiSign(
|
|||||||
// Cannot perform transaction if quorum is not met.
|
// Cannot perform transaction if quorum is not met.
|
||||||
if (weightSum < sleAccountSigners->getFieldU32(sfSignerQuorum))
|
if (weightSum < sleAccountSigners->getFieldU32(sfSignerQuorum))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace())
|
JLOG(j.trace()) << "applyTransaction: Signers failed to meet quorum.";
|
||||||
<< "applyTransaction: Signers failed to meet quorum.";
|
|
||||||
return tefBAD_QUORUM;
|
return tefBAD_QUORUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,9 +283,11 @@ protected:
|
|||||||
|
|
||||||
static NotTEC
|
static NotTEC
|
||||||
checkSign(
|
checkSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
AccountID const& id,
|
ApplyFlags flags,
|
||||||
STObject const& sigObject);
|
AccountID const& idAccount,
|
||||||
|
STObject const& sigObject,
|
||||||
|
beast::Journal const j);
|
||||||
|
|
||||||
// Base class always returns true
|
// Base class always returns true
|
||||||
static bool
|
static bool
|
||||||
@@ -323,15 +325,18 @@ private:
|
|||||||
payFee();
|
payFee();
|
||||||
static NotTEC
|
static NotTEC
|
||||||
checkSingleSign(
|
checkSingleSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
AccountID const& idSigner,
|
AccountID const& idSigner,
|
||||||
AccountID const& idAccount,
|
AccountID const& idAccount,
|
||||||
std::shared_ptr<SLE const> sleAccount);
|
std::shared_ptr<SLE const> sleAccount,
|
||||||
|
beast::Journal const j);
|
||||||
static NotTEC
|
static NotTEC
|
||||||
checkMultiSign(
|
checkMultiSign(
|
||||||
PreclaimContext const& ctx,
|
ReadView const& view,
|
||||||
|
ApplyFlags flags,
|
||||||
AccountID const& id,
|
AccountID const& id,
|
||||||
STObject const& sigObject);
|
STObject const& sigObject,
|
||||||
|
beast::Journal const j);
|
||||||
|
|
||||||
void trapTransaction(uint256) const;
|
void trapTransaction(uint256) const;
|
||||||
|
|
||||||
|
|||||||
56
src/xrpld/rpc/detail/SyntheticFields.cpp
Normal file
56
src/xrpld/rpc/detail/SyntheticFields.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 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 <xrpld/rpc/DeliveredAmount.h>
|
||||||
|
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
||||||
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
|
|
||||||
|
#include <xrpl/json/json_value.h>
|
||||||
|
#include <xrpl/protocol/NFTSyntheticSerializer.h>
|
||||||
|
#include <xrpl/protocol/jss.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace RPC {
|
||||||
|
|
||||||
|
void
|
||||||
|
insertAllSyntheticInJson(
|
||||||
|
Json::Value& metadata,
|
||||||
|
ReadView const& ledger,
|
||||||
|
std::shared_ptr<STTx const> const& transaction,
|
||||||
|
TxMeta const& transactionMeta)
|
||||||
|
{
|
||||||
|
insertDeliveredAmount(metadata, ledger, transaction, transactionMeta);
|
||||||
|
insertNFTSyntheticInJson(metadata, transaction, transactionMeta);
|
||||||
|
insertMPTokenIssuanceID(metadata, transaction, transactionMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
insertAllSyntheticInJson(
|
||||||
|
Json::Value& metadata,
|
||||||
|
JsonContext const& context,
|
||||||
|
std::shared_ptr<STTx const> const& transaction,
|
||||||
|
TxMeta const& transactionMeta)
|
||||||
|
{
|
||||||
|
insertDeliveredAmount(metadata, context, transaction, transactionMeta);
|
||||||
|
insertNFTSyntheticInJson(metadata, transaction, transactionMeta);
|
||||||
|
insertMPTokenIssuanceID(metadata, transaction, transactionMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RPC
|
||||||
|
} // namespace ripple
|
||||||
62
src/xrpld/rpc/detail/SyntheticFields.h
Normal file
62
src/xrpld/rpc/detail/SyntheticFields.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_RPC_DETAIL_SYNTHETICFIELDS_H_INCLUDED
|
||||||
|
#define RIPPLE_RPC_DETAIL_SYNTHETICFIELDS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/json/json_forwards.h>
|
||||||
|
#include <xrpl/protocol/STTx.h>
|
||||||
|
#include <xrpl/protocol/TxMeta.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
class ReadView;
|
||||||
|
|
||||||
|
namespace RPC {
|
||||||
|
|
||||||
|
struct JsonContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds all synthetic fields to transaction metadata JSON.
|
||||||
|
This includes delivered amount, NFT synthetic fields, and MPToken issuance
|
||||||
|
ID.
|
||||||
|
|
||||||
|
@{
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
insertAllSyntheticInJson(
|
||||||
|
Json::Value& metadata,
|
||||||
|
ReadView const&,
|
||||||
|
std::shared_ptr<STTx const> const&,
|
||||||
|
TxMeta const&);
|
||||||
|
|
||||||
|
void
|
||||||
|
insertAllSyntheticInJson(
|
||||||
|
Json::Value& metadata,
|
||||||
|
JsonContext const&,
|
||||||
|
std::shared_ptr<STTx const> const&,
|
||||||
|
TxMeta const&);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
} // namespace RPC
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,9 +23,8 @@
|
|||||||
#include <xrpld/app/misc/Transaction.h>
|
#include <xrpld/app/misc/Transaction.h>
|
||||||
#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
|
#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
|
||||||
#include <xrpld/rpc/Context.h>
|
#include <xrpld/rpc/Context.h>
|
||||||
#include <xrpld/rpc/DeliveredAmount.h>
|
|
||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
|
||||||
#include <xrpld/rpc/Role.h>
|
#include <xrpld/rpc/Role.h>
|
||||||
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
|
|
||||||
#include <xrpl/json/json_value.h>
|
#include <xrpl/json/json_value.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
@@ -346,11 +345,8 @@ populateJsonResponse(
|
|||||||
{
|
{
|
||||||
jvObj[jss::meta] =
|
jvObj[jss::meta] =
|
||||||
txnMeta->getJson(JsonOptions::include_date);
|
txnMeta->getJson(JsonOptions::include_date);
|
||||||
insertDeliveredAmount(
|
RPC::insertAllSyntheticInJson(
|
||||||
jvObj[jss::meta], context, txn, *txnMeta);
|
jvObj[jss::meta], context, sttx, *txnMeta);
|
||||||
RPC::insertNFTSyntheticInJson(jvObj, sttx, *txnMeta);
|
|
||||||
RPC::insertMPTokenIssuanceID(
|
|
||||||
jvObj[jss::meta], sttx, *txnMeta);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
UNREACHABLE(
|
UNREACHABLE(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <xrpld/rpc/DeliveredAmount.h>
|
#include <xrpld/rpc/DeliveredAmount.h>
|
||||||
#include <xrpld/rpc/GRPCHandlers.h>
|
#include <xrpld/rpc/GRPCHandlers.h>
|
||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
||||||
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
#include <xrpld/rpc/detail/TransactionSign.h>
|
#include <xrpld/rpc/detail/TransactionSign.h>
|
||||||
|
|
||||||
#include <xrpl/protocol/ErrorCodes.h>
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
@@ -275,17 +276,11 @@ simulateTxn(RPC::JsonContext& context, std::shared_ptr<Transaction> transaction)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
jvResult[jss::meta] = result.metadata->getJson(JsonOptions::none);
|
jvResult[jss::meta] = result.metadata->getJson(JsonOptions::none);
|
||||||
RPC::insertDeliveredAmount(
|
RPC::insertAllSyntheticInJson(
|
||||||
jvResult[jss::meta],
|
jvResult[jss::meta],
|
||||||
view,
|
view,
|
||||||
transaction->getSTransaction(),
|
transaction->getSTransaction(),
|
||||||
*result.metadata);
|
*result.metadata);
|
||||||
RPC::insertNFTSyntheticInJson(
|
|
||||||
jvResult, transaction->getSTransaction(), *result.metadata);
|
|
||||||
RPC::insertMPTokenIssuanceID(
|
|
||||||
jvResult[jss::meta],
|
|
||||||
transaction->getSTransaction(),
|
|
||||||
*result.metadata);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,9 @@
|
|||||||
#include <xrpld/app/rdb/RelationalDatabase.h>
|
#include <xrpld/app/rdb/RelationalDatabase.h>
|
||||||
#include <xrpld/rpc/CTID.h>
|
#include <xrpld/rpc/CTID.h>
|
||||||
#include <xrpld/rpc/Context.h>
|
#include <xrpld/rpc/Context.h>
|
||||||
#include <xrpld/rpc/DeliveredAmount.h>
|
|
||||||
#include <xrpld/rpc/GRPCHandlers.h>
|
#include <xrpld/rpc/GRPCHandlers.h>
|
||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
|
||||||
#include <xrpld/rpc/detail/RPCHelpers.h>
|
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||||
|
#include <xrpld/rpc/detail/SyntheticFields.h>
|
||||||
|
|
||||||
#include <xrpl/basics/ToString.h>
|
#include <xrpl/basics/ToString.h>
|
||||||
#include <xrpl/protocol/ErrorCodes.h>
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
@@ -268,10 +267,8 @@ populateJsonResponse(
|
|||||||
if (meta)
|
if (meta)
|
||||||
{
|
{
|
||||||
response[jss::meta] = meta->getJson(JsonOptions::none);
|
response[jss::meta] = meta->getJson(JsonOptions::none);
|
||||||
insertDeliveredAmount(
|
RPC::insertAllSyntheticInJson(
|
||||||
response[jss::meta], context, result.txn, *meta);
|
response[jss::meta], context, sttx, *meta);
|
||||||
RPC::insertNFTSyntheticInJson(response, sttx, *meta);
|
|
||||||
RPC::insertMPTokenIssuanceID(response[jss::meta], sttx, *meta);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response[jss::validated] = result.validated;
|
response[jss::validated] = result.validated;
|
||||||
|
|||||||
Reference in New Issue
Block a user