Files
rippled/src/libxrpl/protocol/TxMeta.cpp

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