#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(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::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 TxMeta::getAffectedAccounts() const { boost::container::flat_set 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(&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(&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(&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 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("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