From 985490a36d7f47666fd54c3a203042d0ebd4c6fa Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 29 Aug 2024 19:55:09 +0200 Subject: [PATCH 1/2] add FilterRole to toJson Interaction, for debugging pagination error by search for involved public key --- .../interaction/toJson/Context.h | 3 + .../interaction/toJson/FilterRole.h | 25 ++++++++ src/blockchain/Abstract.cpp | 1 + src/blockchain/InMemory.cpp | 12 +++- src/interaction/toJson/FilterRole.cpp | 47 ++++++++++++++ test/blockchain/InMemoryTest.cpp | 62 +++++++++++++++++++ test/blockchain/InMemoryTest.h | 6 ++ 7 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 include/gradido_blockchain/interaction/toJson/FilterRole.h create mode 100644 src/interaction/toJson/FilterRole.cpp diff --git a/include/gradido_blockchain/interaction/toJson/Context.h b/include/gradido_blockchain/interaction/toJson/Context.h index d7adf60b..10a1b974 100644 --- a/include/gradido_blockchain/interaction/toJson/Context.h +++ b/include/gradido_blockchain/interaction/toJson/Context.h @@ -4,6 +4,7 @@ #include "TransactionBodyRole.h" #include "GradidoTransactionRole.h" #include "ConfirmedTransactionRole.h" +#include "FilterRole.h" namespace gradido { namespace interaction { @@ -17,6 +18,8 @@ namespace gradido { : mRole(std::make_unique(gradidoTransaction, format)) {} Context(const data::ConfirmedTransaction& confirmedTransaction, BodyBytesType format = BodyBytesType::JSON) : mRole(std::make_unique(confirmedTransaction, format)) {} + Context(const blockchain::Filter& filter) + : mRole(std::make_unique(filter)) {} inline std::string run(bool pretty = false) { return mRole->run(pretty);} protected: diff --git a/include/gradido_blockchain/interaction/toJson/FilterRole.h b/include/gradido_blockchain/interaction/toJson/FilterRole.h new file mode 100644 index 00000000..bf384ace --- /dev/null +++ b/include/gradido_blockchain/interaction/toJson/FilterRole.h @@ -0,0 +1,25 @@ +#ifndef __GRADIDO_BLOCKCHAIN_INTERACTION_TO_JSON_FILTER_ROLE_H +#define __GRADIDO_BLOCKCHAIN_INTERACTION_TO_JSON_FILTER_ROLE_H + +#include "gradido_blockchain/blockchain/Filter.h" +#include "AbstractRole.h" + +namespace gradido { + namespace interaction { + namespace toJson { + class FilterRole : public AbstractRole + { + public: + FilterRole(const blockchain::Filter& filter) + : mFilter(filter) {} + + rapidjson::Value composeJson(rapidjson::Document& rootDocument) const; + + protected: + const blockchain::Filter& mFilter; + }; + } + } +} + +#endif //__GRADIDO_BLOCKCHAIN_INTERACTION_TO_JSON_FILTER_ROLE_H \ No newline at end of file diff --git a/src/blockchain/Abstract.cpp b/src/blockchain/Abstract.cpp index 74c732c8..fd2a96a8 100644 --- a/src/blockchain/Abstract.cpp +++ b/src/blockchain/Abstract.cpp @@ -17,6 +17,7 @@ namespace gradido { return nullptr; } if (results.size() > 1) { + printf("filter pagination size: %d\n", filter.pagination.size); throw TransactionResultCountException("to many transactions found with blockchain::Abstract::findOne", 1, results.size()); } return results.front(); diff --git a/src/blockchain/InMemory.cpp b/src/blockchain/InMemory.cpp index 751e926d..73ebd6dd 100644 --- a/src/blockchain/InMemory.cpp +++ b/src/blockchain/InMemory.cpp @@ -6,6 +6,8 @@ #include "gradido_blockchain/const.h" #include "gradido_blockchain/blockchain/FilterBuilder.h" +#include "gradido_blockchain/interaction/toJson/Context.h" + #include namespace gradido { @@ -125,8 +127,10 @@ namespace gradido { if (FilterCriteria::NONE == startSetType) { return {}; } + printf("[InMemory::findAll] pagination size: %d\n", filter.pagination.size); auto processEntry = [&](auto& start, auto& end, FilterCriteria toFilter, const Filter& filter) -> TransactionEntries { + printf("[InMemory::findAll::processEntry] pagination size: %d\n", filter.pagination.size); end--; TransactionEntries transactionEntries; bool revert = SearchDirection::DESC == filter.searchDirection; @@ -138,6 +142,9 @@ namespace gradido { if (paginationCursor >= filter.pagination.skipEntriesCount()) { transactionEntries.push_back(it->second); if (filter.pagination.size && transactionEntries.size() >= filter.pagination.size) { + if(transactionEntries.size() > 1) { + printf("transaction size: %d, pagination size: %d\n", transactionEntries.size(), filter.pagination.size); + } return transactionEntries; } } @@ -180,8 +187,9 @@ namespace gradido { // disable pagination for prefilter round partFilter.pagination = Pagination(); auto prefilteredTransactions = processEntry(range.first, range.second, notYetFiltered, partFilter); - // and if a filter function exist we sort and call it in correct order - if (filter.filterFunction && !prefilteredTransactions.empty()) { + + // we need to call processEntry again for filterFunction, searchDirection and/or pagination + if (!prefilteredTransactions.empty()) { std::map> sortedTransactions; for (std::shared_ptr entry : prefilteredTransactions) { sortedTransactions.insert({ entry->getTransactionNr(), entry }); diff --git a/src/interaction/toJson/FilterRole.cpp b/src/interaction/toJson/FilterRole.cpp new file mode 100644 index 00000000..0a7c868b --- /dev/null +++ b/src/interaction/toJson/FilterRole.cpp @@ -0,0 +1,47 @@ +#include "gradido_blockchain/interaction/toJson/FilterRole.h" +#include "gradido_blockchain/lib/DataTypeConverter.h" + +#include "magic_enum/magic_enum.hpp" + +using namespace rapidjson; +using namespace magic_enum; + +namespace gradido { + namespace interaction { + namespace toJson { + Value FilterRole::composeJson(rapidjson::Document& rootDocument) const + { + Value d(kObjectType); + auto& alloc = rootDocument.GetAllocator(); + d.AddMember("minTransactionNr", mFilter.minTransactionNr, alloc); + d.AddMember("maxTransactionNr", mFilter.maxTransactionNr, alloc); + if(mFilter.involvedPublicKey) { + d.AddMember("involvedPublicKey", Value(mFilter.involvedPublicKey->convertToHex().data(), alloc), alloc); + } + d.AddMember("searchDirection", Value(enum_name(mFilter.searchDirection).data(), alloc), alloc); + Value pagination(kObjectType); + pagination.AddMember("size", mFilter.pagination.size, alloc); + pagination.AddMember("page", mFilter.pagination.page, alloc); + d.AddMember("pagination", pagination, alloc); + d.AddMember("coinCommunityId", Value(mFilter.coinCommunityId.data(), alloc), alloc); + + Value timepointInterval(kObjectType); + timepointInterval.AddMember( + "startDate", + Value(DataTypeConverter::timePointToString(mFilter.timepointInterval.getStartDate()).data(), alloc), + alloc + ); + timepointInterval.AddMember( + "endDate", + Value(DataTypeConverter::timePointToString(mFilter.timepointInterval.getEndDate()).data(), alloc), + alloc + ); + d.AddMember("timepointInterval", timepointInterval, alloc); + d.AddMember("transactionType", Value(enum_name(mFilter.transactionType).data(), alloc), alloc); + + return d; + } + + } + } +} \ No newline at end of file diff --git a/test/blockchain/InMemoryTest.cpp b/test/blockchain/InMemoryTest.cpp index 738802b1..eb2c7072 100644 --- a/test/blockchain/InMemoryTest.cpp +++ b/test/blockchain/InMemoryTest.cpp @@ -157,6 +157,44 @@ bool InMemoryTest::createGradidoCreation( return false; } +bool InMemoryTest::createGradidoTransfer( + int senderKeyPairIndex, + int recipientKeyPairIndex, + GradidoUnit amount, + Timepoint createdAt +) { + assert(senderKeyPairIndex > 0 && senderKeyPairIndex < g_KeyPairs.size()); + assert(recipientKeyPairIndex > 0 && recipientKeyPairIndex < g_KeyPairs.size()); + + TransactionBodyBuilder bodyBuilder; + bodyBuilder + .setMemo("dummy memo") + .setCreatedAt(createdAt) + .setVersionNumber(VERSION_STRING) + .setTransactionTransfer( + TransferAmount(g_KeyPairs[senderKeyPairIndex].publicKey, amount), + g_KeyPairs[recipientKeyPairIndex].publicKey + ) + ; + auto body = bodyBuilder.build(); + + serialize::Context c(*body); + auto bodyBytes = c.run(); + GradidoTransactionBuilder builder; + builder + .setTransactionBody(bodyBytes) + .addSignaturePair(g_KeyPairs[senderKeyPairIndex].publicKey, sign(bodyBytes, g_KeyPairs[senderKeyPairIndex])) + ; + if (mBlockchain->addGradidoTransaction(builder.build(), nullptr, createdAt + chrono::seconds{45})) { + auto lastTransaction = mBlockchain->findOne(Filter::LAST_TRANSACTION)->getConfirmedTransaction(); + auto accountIt = mKeyPairIndexAccountMap.find(senderKeyPairIndex); + accountIt->second.balance = lastTransaction->getAccountBalance(); + accountIt->second.balanceDate = lastTransaction->getConfirmedAt(); + return true; + } + return false; +} + void InMemoryTest::logBlockchain() { auto transactions = dynamic_cast(mBlockchain.get())->getSortedTransactions(); @@ -332,3 +370,27 @@ TEST_F(InMemoryTest, InvalidCreationTransactions) EXPECT_EQ(accountIt->second.balance, GradidoUnit(0.0)); } +TEST_F(InMemoryTest, ValidTransferTransaction) +{ + ASSERT_NO_THROW(createRegisterAddress(3)); + ASSERT_NO_THROW(createRegisterAddress(5)); + auto createdAt = generateNewCreatedAt(); + auto targetDate = getPreviousNMonth2(createdAt, 1); + try { + ASSERT_TRUE(createGradidoCreation(6, 4, 1000.0, createdAt, targetDate)); + } catch(GradidoBlockchainException& ex) { + logBlockchain(); + LOG_F(ERROR, ex.getFullString().data()); + } + auto accountIt = mKeyPairIndexAccountMap.find(6); + EXPECT_EQ(accountIt->second.balance, GradidoUnit(1000.0)); + EXPECT_GT(accountIt->second.balanceDate, createdAt); + + try { + ASSERT_TRUE(createGradidoTransfer(6, 4, 500.10, generateNewCreatedAt())); + } catch(GradidoBlockchainException& ex) { + logBlockchain(); + LOG_F(ERROR, ex.getFullString().data()); + } +} + diff --git a/test/blockchain/InMemoryTest.h b/test/blockchain/InMemoryTest.h index 4d7e2d8b..3cfea69e 100644 --- a/test/blockchain/InMemoryTest.h +++ b/test/blockchain/InMemoryTest.h @@ -26,6 +26,12 @@ class InMemoryTest : public ::testing::Test Timepoint createdAt, Timepoint targetDate ); + bool createGradidoTransfer( + int senderKeyPairIndex, + int recipientKeyPairIndex, + GradidoUnit amount, + Timepoint createdAt + ); void logBlockchain(); From 0dfafa76399016a8e614e8668897ee8a07fcfbfb Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 29 Aug 2024 20:29:21 +0200 Subject: [PATCH 2/2] fixed and debug messages removed --- src/blockchain/Abstract.cpp | 1 - src/blockchain/InMemory.cpp | 27 ++++++++++++--------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/blockchain/Abstract.cpp b/src/blockchain/Abstract.cpp index fd2a96a8..74c732c8 100644 --- a/src/blockchain/Abstract.cpp +++ b/src/blockchain/Abstract.cpp @@ -17,7 +17,6 @@ namespace gradido { return nullptr; } if (results.size() > 1) { - printf("filter pagination size: %d\n", filter.pagination.size); throw TransactionResultCountException("to many transactions found with blockchain::Abstract::findOne", 1, results.size()); } return results.front(); diff --git a/src/blockchain/InMemory.cpp b/src/blockchain/InMemory.cpp index 73ebd6dd..b78e58ab 100644 --- a/src/blockchain/InMemory.cpp +++ b/src/blockchain/InMemory.cpp @@ -127,10 +127,8 @@ namespace gradido { if (FilterCriteria::NONE == startSetType) { return {}; } - printf("[InMemory::findAll] pagination size: %d\n", filter.pagination.size); auto processEntry = [&](auto& start, auto& end, FilterCriteria toFilter, const Filter& filter) -> TransactionEntries { - printf("[InMemory::findAll::processEntry] pagination size: %d\n", filter.pagination.size); end--; TransactionEntries transactionEntries; bool revert = SearchDirection::DESC == filter.searchDirection; @@ -142,9 +140,6 @@ namespace gradido { if (paginationCursor >= filter.pagination.skipEntriesCount()) { transactionEntries.push_back(it->second); if (filter.pagination.size && transactionEntries.size() >= filter.pagination.size) { - if(transactionEntries.size() > 1) { - printf("transaction size: %d, pagination size: %d\n", transactionEntries.size(), filter.pagination.size); - } return transactionEntries; } } @@ -339,17 +334,19 @@ namespace gradido { ); if (lastFromSameSender) { auto lastFromSameSenderBody = lastFromSameSender->getTransactionBody(); - auto lastFromSameSenderRecipient = lastFromSameSenderBody->getDeferredTransfer()->getTransfer().getRecipient(); + auto pubkey = body->getTransfer()->getSender().getPubkey(); - if (lastFromSameSenderBody->isDeferredTransfer() && - lastFromSameSenderRecipient->isTheSame(pubkey)) { - auto lastFromSameSenderTimeout = lastFromSameSenderBody->getDeferredTransfer()->getTimeout(); - // seems we found a matching deferred transfer transaction - auto byTimeoutDeferredRedeemedPairsIt = mTimeoutDeferredRedeemedTransferPairs.equal_range(lastFromSameSenderTimeout.getAsTimepoint()); - for (auto it = byTimeoutDeferredRedeemedPairsIt.first; it != byTimeoutDeferredRedeemedPairsIt.second; ++it) { - if (lastFromSameSender->getSerializedTransaction()->isTheSame(it->second.first->getSerializedTransaction())) { - it->second.second = transactionEntry; - break; + if (lastFromSameSenderBody->isDeferredTransfer()) { + auto lastFromSameSenderRecipient = lastFromSameSenderBody->getDeferredTransfer()->getTransfer().getRecipient(); + if (lastFromSameSenderRecipient->isTheSame(pubkey)) { + auto lastFromSameSenderTimeout = lastFromSameSenderBody->getDeferredTransfer()->getTimeout(); + // seems we found a matching deferred transfer transaction + auto byTimeoutDeferredRedeemedPairsIt = mTimeoutDeferredRedeemedTransferPairs.equal_range(lastFromSameSenderTimeout.getAsTimepoint()); + for (auto it = byTimeoutDeferredRedeemedPairsIt.first; it != byTimeoutDeferredRedeemedPairsIt.second; ++it) { + if (lastFromSameSender->getSerializedTransaction()->isTheSame(it->second.first->getSerializedTransaction())) { + it->second.second = transactionEntry; + break; + } } } }