Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement MPT changes #1147

Open
wants to merge 78 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
3c98a06
Refactoring currency (WIP)
shawnxie999 Jan 10, 2024
f8bbf0c
compile
shawnxie999 Jan 10, 2024
924dd72
remove static cast
shawnxie999 Jan 10, 2024
59bcb97
wip
shawnxie999 Jan 9, 2024
f182a1d
Working account_objects and Ledger_entry
shawnxie999 Jan 11, 2024
b908b4e
Synthetic MPT ID
shawnxie999 Jan 11, 2024
2e297fa
reafactor
shawnxie999 Jan 11, 2024
efc839c
Working ledger entry
shawnxie999 Jan 13, 2024
5bc4ca5
use translation
shawnxie999 Jan 13, 2024
5bbf673
ledger_entry tests
shawnxie999 Jan 15, 2024
9ac779d
account object test
shawnxie999 Jan 15, 2024
a97d549
initial
shawnxie999 Jan 26, 2024
0dae3cb
compile
shawnxie999 Jan 26, 2024
f9b494e
working marker
shawnxie999 Jan 26, 2024
0adc32e
tests
shawnxie999 Jan 31, 2024
1d7e49f
typo
shawnxie999 Jan 31, 2024
a700caa
cmake
shawnxie999 Jan 31, 2024
7052364
comments
shawnxie999 Jan 31, 2024
ac5f48e
ledgerdata
shawnxie999 Jan 31, 2024
2decaa8
ledgerdata test
shawnxie999 Jan 31, 2024
880d036
clang
shawnxie999 Jan 31, 2024
412fa2e
change order
shawnxie999 Jan 31, 2024
18a8a4a
improve condition
shawnxie999 Feb 1, 2024
75eddfd
tests
shawnxie999 Feb 1, 2024
5fa9182
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Feb 1, 2024
96288d0
add deletion blocker
shawnxie999 Feb 1, 2024
c453391
Merge branch 'develop' into mpt-holders
shawnxie999 Feb 2, 2024
e6d34fa
Merge branch 'develop' into mpt-holders
shawnxie999 Feb 2, 2024
b6691bd
refactor validators and add tests
shawnxie999 Feb 5, 2024
62b01fe
remove comment
shawnxie999 Feb 5, 2024
eb138d2
Merge remote-tracking branch 'upstream/develop' into mpt-holders-bk
shawnxie999 Feb 5, 2024
f3d7f0d
template parameter type checking
shawnxie999 Feb 5, 2024
203fa8d
clang
shawnxie999 Feb 5, 2024
b368864
clang
shawnxie999 Feb 5, 2024
494f56f
doxygen and end of file line
shawnxie999 Feb 8, 2024
9a378b0
revert issue changes
shawnxie999 Feb 29, 2024
38804f6
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Feb 29, 2024
4d85852
update
shawnxie999 Feb 29, 2024
f224555
revert
shawnxie999 Feb 29, 2024
d28b21f
comment
shawnxie999 Feb 29, 2024
66a4fe7
improvements
shawnxie999 Mar 1, 2024
63b4f7c
remove rvalue ref
shawnxie999 Mar 1, 2024
5630132
clang
shawnxie999 Mar 1, 2024
1d166a7
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Mar 4, 2024
d316375
use copyif
shawnxie999 Mar 4, 2024
b988f2d
comment
shawnxie999 Mar 4, 2024
aac1e0c
use getaccountid
shawnxie999 Mar 4, 2024
90dc297
comment
shawnxie999 Mar 4, 2024
19b268f
Merge branch 'develop' into mpt-holders
shawnxie999 Mar 4, 2024
f4852a8
update libxrpl
shawnxie999 Mar 5, 2024
e7c77d3
doc
shawnxie999 Mar 5, 2024
d9c54be
comment
shawnxie999 Mar 5, 2024
8d798a6
doc
shawnxie999 Mar 5, 2024
55386e8
change var name
shawnxie999 Mar 5, 2024
0087ff5
var name
shawnxie999 Mar 5, 2024
01453ee
use toJson
shawnxie999 Mar 5, 2024
87838f6
clang
shawnxie999 Mar 5, 2024
cee9cd5
change libxrpl
shawnxie999 Mar 5, 2024
26ca942
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Mar 12, 2024
d2f40a9
revert libxrpl
shawnxie999 Mar 12, 2024
c4dbd11
libxrpl
shawnxie999 Mar 12, 2024
a39c90a
Delete CMake/deps/libxrpl.cmake
shawnxie999 Mar 12, 2024
3defe87
add renamed libxrpl
shawnxie999 Mar 12, 2024
57020c2
Merge branch 'develop' into mpt-holders
shawnxie999 Mar 13, 2024
e75e2cf
comments
shawnxie999 Mar 26, 2024
5df2068
predicate const ref
shawnxie999 Mar 28, 2024
a464fba
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Jul 8, 2024
703500f
clang
shawnxie999 Jul 8, 2024
8b8cc9b
add MPT amendment
shawnxie999 Jul 8, 2024
ca079a5
Merge branch 'develop' into mpt-holders
godexsoft Jul 18, 2024
1a03ae0
make compile
shawnxie999 Sep 5, 2024
1c271f4
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Sep 5, 2024
2fc2536
Merge remote-tracking branch 'upstream/develop' into mpt-holders
shawnxie999 Oct 7, 2024
d877e5d
update clio to compile with latest rippled
shawnxie999 Oct 8, 2024
cce63dc
comments
shawnxie999 Oct 9, 2024
a9b1430
fix API response discrepancies
shawnxie999 Oct 17, 2024
7bd4472
ledger entry test
shawnxie999 Oct 17, 2024
2ea0cb8
Merge branch 'develop' into mpt-holders
shawnxie999 Oct 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/deps/libxrpl.cmake
Original file line number Diff line number Diff line change
@@ -1 +1 @@
find_package(xrpl REQUIRED CONFIG)
find_package(xrpl-mpt REQUIRED CONFIG)
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Clio(ConanFile):
'protobuf/3.21.9',
'grpc/1.50.1',
'openssl/1.1.1u',
'xrpl/2.3.0-b4',
'xrpl-mpt/2.3.0-b4',
'libbacktrace/cci.20210118'
]

Expand Down
1 change: 1 addition & 0 deletions src/data/AmendmentCenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct Amendments {
REGISTER(fixInnerObjTemplate2);
REGISTER(fixNFTokenPageLinks);
REGISTER(InvariantsV1_1);
REGISTER(MPTokensV1);

// Obsolete but supported by libxrpl
REGISTER(CryptoConditionsSuite);
Expand Down
27 changes: 27 additions & 0 deletions src/data/BackendInterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,25 @@ class BackendInterface {
boost::asio::yield_context yield
) const = 0;

/**
* @brief Fetches all holders' balances for a MPTIssuanceID
*
* @param mptID MPTIssuanceID you wish you query.
* @param limit Paging limit.
* @param cursorIn Optional cursor to allow us to pick up from where we last left off.
* @param ledgerSequence The ledger sequence to fetch for
* @param yield Currently executing coroutine.
* @return std::vector<Blob> of MPToken balances and an optional marker
*/
virtual MPTHoldersAndCursor
fetchMPTHolders(
ripple::uint192 const& mptID,
std::uint32_t const limit,
std::optional<ripple::AccountID> const& cursorIn,
std::uint32_t const ledgerSequence,
boost::asio::yield_context yield
) const = 0;

/**
* @brief Fetches a specific ledger object.
*
Expand Down Expand Up @@ -617,6 +636,14 @@ class BackendInterface {
virtual void
writeNFTTransactions(std::vector<NFTTransactionsData> const& data) = 0;

/**
* @brief Write accounts that started holding onto a MPT.
*
* @param data A vector of MPT ID and account pairs
*/
virtual void
writeMPTHolders(std::vector<MPTHolderData> const& data) = 0;

/**
* @brief Write a new successor.
*
Expand Down
49 changes: 49 additions & 0 deletions src/data/CassandraBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,45 @@ class BasicCassandraBackend : public BackendInterface {
return ret;
}

MPTHoldersAndCursor
fetchMPTHolders(
ripple::uint192 const& mptID,
std::uint32_t const limit,
std::optional<ripple::AccountID> const& cursorIn,
std::uint32_t const ledgerSequence,
boost::asio::yield_context yield
) const override
{
auto const holderEntries = executor_.read(
Copy link
Collaborator

@cindyyan317 cindyyan317 Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually , Only this part needs to be virtual. The filter logic is same for different DB. By reducing the scope of virtual functions, you can unittest more of the logic without real DB.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you clarify what you mean? inside this function, there is another call to the database auto mptObjects = doFetchLedgerObjects(mptKeys, ledgerSequence, yield);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we create a function in CassandraBackend.hpp to just select MPT holder, then all the filter logic can move to BackendInterface. If we want to add a new database, you don't need to copy all the logic to new database implementation. How to filter the valid holder is database unrelated. Instead, new database only needs to provide how to select MPT holder.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But aren't existing functions in CassandraBackend.hpp also do something similar? BTW fetchMPTHolders doesn't only have filter logic, it does make another call to the objects table on line 576:

auto mptObjects = doFetchLedgerObjects(mptKeys, ledgerSequence, yield);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understood the fetchMPTHolders does not only have filter logic. So I suggested that we can add the pure virtual function doFetchMPTHolders in BackendInterface, which only obtains the data from selectMPTHolders table. Then the filer logic can move to BackendInterface normal function.

override doFetchfetchMPTHolders in CassandraBackend.hpp

    std::pair<std::vector<ripple::uint256>, std::optional<ripple::AccountID>>
    doFetchfetchMPTHolders(
        ripple::uint192 const& mptID,
        std::uint32_t const limit,
        std::optional<ripple::AccountID> const& cursorIn,
        boost::asio::yield_context yield
    ) const override
    {
        auto const holderEntries = executor_.read(
            yield, schema_->selectMPTHolders, mptID, cursorIn.value_or(ripple::AccountID(0)), Limit{limit}
        );

        auto const& holderResults = holderEntries.value();
        if (not holderResults.hasRows()) {
            LOG(log_.debug()) << "No rows returned";
            return {};
        }

        std::vector<ripple::uint256> mptKeys;
        std::optional<ripple::AccountID> cursor;
        for (auto const [holder] : extract<ripple::AccountID>(holderResults)) {
            mptKeys.push_back(ripple::keylet::mptoken(mptID, holder).key);
            cursor = holder;
        }
        return {mptKeys, cursor};
    }

Then your fetchMPTHolders will be like:

MPTHoldersAndCursor
BackendInterface::fetchMPTHolders(
    ripple::uint192 const& mptID,
    std::uint32_t const limit,
    std::optional<ripple::AccountID> const& cursorIn,
    std::uint32_t const ledgerSequence,
    boost::asio::yield_context yield
) const
{
    auto [mptKeys, cursor] = doFetchfetchMPTHolders(mptID, limit, cursorIn, yield);

    auto mptObjects = doFetchLedgerObjects(mptKeys, ledgerSequence, yield);

    auto it = std::remove_if(mptObjects.begin(), mptObjects.end(), [](Blob const& mpt) { return mpt.empty(); });

    mptObjects.erase(it, mptObjects.end());

    ASSERT(mptKeys.size() <= limit, "Number of keys can't exceed the limit");
    if (mptKeys.size() == limit)
        return {mptObjects, cursor};

    return {mptObjects, {}};
}

I admit that current CassandraBackend.hpp has similar implementation which is not correct. We will refactor them eventually. Feel free to leave it. We can refactor it in future.

yield, schema_->selectMPTHolders, mptID, cursorIn.value_or(ripple::AccountID(0)), Limit{limit}
);

auto const& holderResults = holderEntries.value();
if (not holderResults.hasRows()) {
LOG(log_.debug()) << "No rows returned";
return {};
}

std::vector<ripple::uint256> mptKeys;
std::optional<ripple::AccountID> cursor;
for (auto const [holder] : extract<ripple::AccountID>(holderResults)) {
mptKeys.push_back(ripple::keylet::mptoken(mptID, holder).key);
cursor = holder;
}

auto mptObjects = doFetchLedgerObjects(mptKeys, ledgerSequence, yield);

auto it = std::remove_if(mptObjects.begin(), mptObjects.end(), [](Blob const& mpt) { return mpt.size() == 0; });

mptObjects.erase(it, mptObjects.end());

ASSERT(mptKeys.size() <= limit, "Number of keys can't exceed the limit");
if (mptKeys.size() == limit)
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved
return {mptObjects, cursor};

return {mptObjects, {}};
}

std::optional<Blob>
doFetchLedgerObject(ripple::uint256 const& key, std::uint32_t const sequence, boost::asio::yield_context yield)
const override
Expand Down Expand Up @@ -905,6 +944,16 @@ class BasicCassandraBackend : public BackendInterface {
executor_.write(std::move(statements));
}

void
writeMPTHolders(std::vector<MPTHolderData> const& data) override
{
std::vector<Statement> statements;
for (auto [mptId, holder] : data)
statements.push_back(schema_->insertMPTHolder.bind(std::move(mptId), std::move(holder)));

executor_.write(std::move(statements));
}

void
startWrites() const override
{
Expand Down
8 changes: 8 additions & 0 deletions src/data/DBHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ struct NFTsData {
}
};

/**
* @brief Represents an MPT and holder pair
*/
struct MPTHolderData {
ripple::uint192 mptID;
ripple::AccountID holder;
};

/**
* @brief Check whether the supplied object is an offer.
*
Expand Down
8 changes: 8 additions & 0 deletions src/data/Types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ struct NFTsAndCursor {
std::optional<ripple::uint256> cursor;
};

/**
* @brief Represents an array of MPTokens
*/
struct MPTHoldersAndCursor {
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved
std::vector<Blob> mptokens;
std::optional<ripple::AccountID> cursor;
};

/**
* @brief Stores a range of sequences as a min and max pair.
*/
Expand Down
38 changes: 38 additions & 0 deletions src/data/cassandra/Schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,19 @@ class Schema {
qualifiedTableName(settingsProvider_.get(), "nf_token_transactions")
));

statements.emplace_back(fmt::format(
R"(
CREATE TABLE IF NOT EXISTS {}
(
mpt_id blob,
holder blob,
PRIMARY KEY (mpt_id, holder)
)
WITH CLUSTERING ORDER BY (holder ASC)
)",
qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
));

return statements;
}();

Expand Down Expand Up @@ -393,6 +406,17 @@ class Schema {
));
}();

PreparedStatement insertMPTHolder = [this]() {
return handle_.get().prepare(fmt::format(
R"(
INSERT INTO {}
(mpt_id, holder)
VALUES (?, ?)
)",
qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
));
}();

PreparedStatement insertLedgerHeader = [this]() {
return handle_.get().prepare(fmt::format(
R"(
Expand Down Expand Up @@ -687,6 +711,20 @@ class Schema {
));
}();

PreparedStatement selectMPTHolders = [this]() {
return handle_.get().prepare(fmt::format(
R"(
SELECT holder
FROM {}
WHERE mpt_id = ?
AND holder > ?
ORDER BY holder ASC
LIMIT ?
)",
qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
));
}();

PreparedStatement selectLedgerByHash = [this]() {
return handle_.get().prepare(fmt::format(
R"(
Expand Down
4 changes: 2 additions & 2 deletions src/data/cassandra/impl/Statement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class Statement : public ManagedObject<CassStatement> {
using UintByteTupleType = std::tuple<uint32_t, ripple::uint256>;
using ByteVectorType = std::vector<ripple::uint256>;

if constexpr (std::is_same_v<DecayedType, ripple::uint256>) {
if constexpr (std::is_same_v<DecayedType, ripple::uint256> || std::is_same_v<DecayedType, ripple::uint192>) {
auto const rc = bindBytes(value.data(), value.size());
throwErrorIfNeeded(rc, "Bind ripple::uint256");
throwErrorIfNeeded(rc, "Bind ripple::base_uint");
} else if constexpr (std::is_same_v<DecayedType, ripple::AccountID>) {
auto const rc = bindBytes(value.data(), value.size());
throwErrorIfNeeded(rc, "Bind ripple::AccountID");
Expand Down
1 change: 1 addition & 0 deletions src/etl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ target_sources(
NetworkValidatedLedgers.cpp
NFTHelpers.cpp
Source.cpp
MPTHelpers.cpp
impl/AmendmentBlockHandler.cpp
impl/ForwardingSource.cpp
impl/GrpcSource.cpp
Expand Down
78 changes: 78 additions & 0 deletions src/etl/MPTHelpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.

Permission to use, copy, modify, and 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 "data/BackendInterface.hpp"
#include "data/DBHelpers.hpp"
#include "data/Types.hpp"

#include <fmt/core.h>
#include <ripple/protocol/STBase.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/TxMeta.h>

#include <vector>

namespace etl {

/**
* @brief Get the MPToken created from a transaction
*
* @param txMeta Transaction metadata
* @return MPT and holder account pair
*/
static std::optional<MPTHolderData>
getMPTokenAuthorize(ripple::TxMeta const& txMeta)

Check warning on line 40 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L40

Added line #L40 was not covered by tests
{
for (ripple::STObject const& node : txMeta.getNodes()) {
if (node.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltMPTOKEN)
continue;

Check warning on line 44 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L44

Added line #L44 was not covered by tests

if (node.getFName() == ripple::sfCreatedNode) {
auto const& newMPT = node.peekAtField(ripple::sfNewFields).downcast<ripple::STObject>();
return MPTHolderData{newMPT[ripple::sfMPTokenIssuanceID], newMPT.getAccountID(ripple::sfAccount)};
}
}
return {};

Check warning on line 51 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L51

Added line #L51 was not covered by tests
}

std::optional<MPTHolderData>
getMPTHolderFromTx(ripple::TxMeta const& txMeta, ripple::STTx const& sttx)

Check warning on line 55 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L55

Added line #L55 was not covered by tests
{
if (txMeta.getResultTER() != ripple::tesSUCCESS || sttx.getTxnType() != ripple::TxType::ttMPTOKEN_AUTHORIZE)
cindyyan317 marked this conversation as resolved.
Show resolved Hide resolved
return {};

Check warning on line 58 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L58

Added line #L58 was not covered by tests

return getMPTokenAuthorize(txMeta);

Check warning on line 60 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L60

Added line #L60 was not covered by tests
cindyyan317 marked this conversation as resolved.
Show resolved Hide resolved
}

std::optional<MPTHolderData>
getMPTHolderFromObj(std::string const& key, std::string const& blob)
{
ripple::STLedgerEntry const sle =
ripple::STLedgerEntry(ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data()));

if (sle.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltMPTOKEN)
return {};

auto const mptIssuanceID = sle[ripple::sfMPTokenIssuanceID];
auto const holder = sle.getAccountID(ripple::sfAccount);

return MPTHolderData{mptIssuanceID, holder};

Check warning on line 75 in src/etl/MPTHelpers.cpp

View check run for this annotation

Codecov / codecov/patch

src/etl/MPTHelpers.cpp#L75

Added line #L75 was not covered by tests
}

} // namespace etl
50 changes: 50 additions & 0 deletions src/etl/MPTHelpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.

Permission to use, copy, modify, and 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.
*/
//==============================================================================

/** @file */
#pragma once

#include "data/DBHelpers.hpp"

#include <ripple/protocol/STTx.h>
#include <ripple/protocol/TxMeta.h>

namespace etl {

/**
* @brief Pull MPT data from TX via ETLService.
*
* @param txMeta Transaction metadata
* @param sttx The transaction
* @return The MPTIssuanceID and holder pair as a optional
*/
std::optional<MPTHolderData>
getMPTHolderFromTx(ripple::TxMeta const& txMeta, ripple::STTx const& sttx);

/**
* @brief Pull MPT data from ledger object via loadInitialLedger.
*
* @param key The owner key
* @param blob Object data as blob
* @return The MPTIssuanceID and holder pair as a optional
*/
std::optional<MPTHolderData>
getMPTHolderFromObj(std::string const& key, std::string const& blob);

} // namespace etl
6 changes: 6 additions & 0 deletions src/etl/impl/AsyncData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "data/BackendInterface.hpp"
#include "data/Types.hpp"
#include "etl/ETLHelpers.hpp"
#include "etl/MPTHelpers.hpp"
#include "etl/NFTHelpers.hpp"
#include "util/Assert.hpp"
#include "util/log/Logger.hpp"
Expand Down Expand Up @@ -154,6 +155,11 @@ class AsyncCallData {
backend.writeSuccessor(std::move(lastKey_), request_.ledger().sequence(), std::string{obj.key()});
lastKey_ = obj.key();
backend.writeNFTs(getNFTDataFromObj(request_.ledger().sequence(), obj.key(), obj.data()));

auto const maybeMPTHolder = getMPTHolderFromObj(obj.key(), obj.data());
if (maybeMPTHolder)
backend.writeMPTHolders({*maybeMPTHolder});

backend.writeLedgerObject(
std::move(*obj.mutable_key()), request_.ledger().sequence(), std::move(*obj.mutable_data())
);
Expand Down
Loading
Loading