mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 09:46:53 +00:00
217 lines
6.7 KiB
C++
217 lines
6.7 KiB
C++
#include <xrpl/protocol/TxMeta.h>
|
|
|
|
#include <xrpl/basics/Blob.h>
|
|
#include <xrpl/basics/Slice.h>
|
|
#include <xrpl/basics/base_uint.h>
|
|
#include <xrpl/basics/contract.h>
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/protocol/AccountID.h>
|
|
#include <xrpl/protocol/SField.h>
|
|
#include <xrpl/protocol/STAccount.h>
|
|
#include <xrpl/protocol/STAmount.h>
|
|
#include <xrpl/protocol/STLedgerEntry.h>
|
|
#include <xrpl/protocol/STObject.h>
|
|
#include <xrpl/protocol/Serializer.h>
|
|
#include <xrpl/protocol/TER.h>
|
|
|
|
#include <boost/container/flat_set.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <stdexcept>
|
|
|
|
namespace xrpl {
|
|
|
|
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
|
|
: transactionID_(txid), ledgerSeq_(ledger), nodes_(obj.getFieldArray(sfAffectedNodes))
|
|
{
|
|
result_ = obj.getFieldU8(sfTransactionResult);
|
|
index_ = obj.getFieldU32(sfTransactionIndex);
|
|
|
|
auto affectedNodes = dynamic_cast<STArray const*>(obj.peekAtPField(sfAffectedNodes));
|
|
XRPL_ASSERT(affectedNodes, "xrpl::TxMeta::TxMeta(STObject) : type cast succeeded");
|
|
if (affectedNodes != nullptr)
|
|
nodes_ = *affectedNodes;
|
|
|
|
setAdditionalFields(obj);
|
|
}
|
|
|
|
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
|
|
: transactionID_(txid), ledgerSeq_(ledger), nodes_(sfAffectedNodes, 32)
|
|
{
|
|
SerialIter sit(makeSlice(vec));
|
|
|
|
STObject const obj(sit, sfMetadata);
|
|
result_ = obj.getFieldU8(sfTransactionResult);
|
|
index_ = obj.getFieldU32(sfTransactionIndex);
|
|
nodes_ = obj.getFieldArray(sfAffectedNodes);
|
|
|
|
setAdditionalFields(obj);
|
|
}
|
|
|
|
TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger)
|
|
: transactionID_(transactionID)
|
|
, ledgerSeq_(ledger)
|
|
, index_(std::numeric_limits<std::uint32_t>::max())
|
|
, result_(255)
|
|
, nodes_(sfAffectedNodes)
|
|
{
|
|
nodes_.reserve(32);
|
|
}
|
|
|
|
void
|
|
TxMeta::setAffectedNode(uint256 const& node, SField const& type, std::uint16_t nodeType)
|
|
{
|
|
// make sure the node exists and force its type
|
|
for (auto& n : nodes_)
|
|
{
|
|
if (n.getFieldH256(sfLedgerIndex) == node)
|
|
{
|
|
n.setFName(type);
|
|
n.setFieldU16(sfLedgerEntryType, nodeType);
|
|
return;
|
|
}
|
|
}
|
|
|
|
nodes_.pushBack(STObject(type));
|
|
STObject& obj = nodes_.back();
|
|
|
|
XRPL_ASSERT(obj.getFName() == type, "xrpl::TxMeta::setAffectedNode : field type match");
|
|
obj.setFieldH256(sfLedgerIndex, node);
|
|
obj.setFieldU16(sfLedgerEntryType, nodeType);
|
|
}
|
|
|
|
boost::container::flat_set<AccountID>
|
|
TxMeta::getAffectedAccounts() const
|
|
{
|
|
boost::container::flat_set<AccountID> list;
|
|
list.reserve(10);
|
|
|
|
// This code should match the behavior of the JS method:
|
|
// Meta#getAffectedAccounts
|
|
for (auto const& node : nodes_)
|
|
{
|
|
int const index =
|
|
node.getFieldIndex((node.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields);
|
|
|
|
if (index != -1)
|
|
{
|
|
auto const* inner = dynamic_cast<STObject const*>(&node.peekAtIndex(index));
|
|
XRPL_ASSERT(inner, "xrpl::getAffectedAccounts : STObject type cast succeeded");
|
|
if (inner != nullptr)
|
|
{
|
|
for (auto const& field : *inner)
|
|
{
|
|
if (auto sa = dynamic_cast<STAccount const*>(&field))
|
|
{
|
|
XRPL_ASSERT(!sa->isDefault(), "xrpl::getAffectedAccounts : account is set");
|
|
if (!sa->isDefault())
|
|
list.insert(sa->value());
|
|
}
|
|
else if (
|
|
(field.getFName() == sfLowLimit) || (field.getFName() == sfHighLimit) ||
|
|
(field.getFName() == sfTakerPays) || (field.getFName() == sfTakerGets))
|
|
{
|
|
auto lim = dynamic_cast<STAmount const*>(&field);
|
|
XRPL_ASSERT(
|
|
lim,
|
|
"xrpl::getAffectedAccounts : STAmount type cast "
|
|
"succeeded");
|
|
|
|
if (lim != nullptr)
|
|
{
|
|
auto issuer = lim->getIssuer();
|
|
|
|
if (issuer.isNonZero())
|
|
list.insert(issuer);
|
|
}
|
|
}
|
|
else if (field.getFName() == sfMPTokenIssuanceID)
|
|
{
|
|
auto mptID = dynamic_cast<STBitString<192> const*>(&field);
|
|
if (mptID != nullptr)
|
|
{
|
|
auto issuer = MPTIssue(mptID->value()).getIssuer();
|
|
|
|
if (issuer.isNonZero())
|
|
list.insert(issuer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
STObject&
|
|
TxMeta::getAffectedNode(SLE::ref node, SField const& type)
|
|
{
|
|
uint256 const index = node->key();
|
|
for (auto& n : nodes_)
|
|
{
|
|
if (n.getFieldH256(sfLedgerIndex) == index)
|
|
return n;
|
|
}
|
|
nodes_.pushBack(STObject(type));
|
|
STObject& obj = nodes_.back();
|
|
|
|
XRPL_ASSERT(
|
|
obj.getFName() == type, "xrpl::TxMeta::getAffectedNode(SLE::ref) : field type match");
|
|
obj.setFieldH256(sfLedgerIndex, index);
|
|
obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType));
|
|
|
|
return obj;
|
|
}
|
|
|
|
STObject&
|
|
TxMeta::getAffectedNode(uint256 const& node)
|
|
{
|
|
for (auto& n : nodes_)
|
|
{
|
|
if (n.getFieldH256(sfLedgerIndex) == node)
|
|
return n;
|
|
}
|
|
// LCOV_EXCL_START
|
|
UNREACHABLE("xrpl::TxMeta::getAffectedNode(uint256) : node not found");
|
|
Throw<std::runtime_error>("Affected node not found");
|
|
return *(nodes_.begin()); // Silence compiler warning.
|
|
// LCOV_EXCL_STOP
|
|
}
|
|
|
|
STObject
|
|
TxMeta::getAsObject() const
|
|
{
|
|
STObject metaData(sfTransactionMetaData);
|
|
XRPL_ASSERT(result_ != 255, "xrpl::TxMeta::getAsObject : result_ is set");
|
|
metaData.setFieldU8(sfTransactionResult, result_);
|
|
metaData.setFieldU32(sfTransactionIndex, index_);
|
|
metaData.emplaceBack(nodes_);
|
|
if (deliveredAmount_.has_value())
|
|
metaData.setFieldAmount(sfDeliveredAmount, *deliveredAmount_);
|
|
|
|
if (parentBatchID_.has_value())
|
|
metaData.setFieldH256(sfParentBatchID, *parentBatchID_);
|
|
|
|
return metaData;
|
|
}
|
|
|
|
void
|
|
TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index)
|
|
{
|
|
result_ = TERtoInt(result);
|
|
index_ = index;
|
|
XRPL_ASSERT(
|
|
(result_ == 0) || ((result_ > 100) && (result_ <= 255)),
|
|
"xrpl::TxMeta::addRaw : valid TER input");
|
|
|
|
nodes_.sort([](STObject const& o1, STObject const& o2) {
|
|
return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);
|
|
});
|
|
|
|
getAsObject().add(s);
|
|
}
|
|
|
|
} // namespace xrpl
|