diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..2c100a9d8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,39 @@ +## Standards checklist: + + + + + +- [ ] The PR title is descriptive. +- [ ] The PR doesn't replicate another PR which is already open. +- [ ] The PR has self-explained commits history. + +- [ ] The code is mine or it's from somewhere with an Apache-2.0 compatible license. +- [ ] The code is efficient, to the best of my ability, and does not waste computer resources. +- [ ] The code is stable and I have tested it myself, to the best of my abilities. +- [ ] If the code introduces new classes, methods, I provide a valid use case for all of them. + +## Changes: + +- [...] + +## Other comments: + +... diff --git a/src/pocketdb/consensus/Base.h b/src/pocketdb/consensus/Base.h index a60be64b6..814e5d894 100644 --- a/src/pocketdb/consensus/Base.h +++ b/src/pocketdb/consensus/Base.h @@ -306,7 +306,7 @@ namespace PocketConsensus { NetworkTest, { {0, 0} } } } }, { threshold_shark_likers_comment, { - { NetworkMain, { {0, 15} } }, + { NetworkMain, { {0, 15}, {1862000, 25} } }, { NetworkTest, { {0, 1} } } } }, { threshold_shark_likers_comment_answer, { @@ -426,7 +426,7 @@ namespace PocketConsensus { NetworkTest, { {0, 30} } } } }, { ConsensusLimit_full_score, { - { NetworkMain, { {0, 90}, {175600, 200}, {1757000, 60}, {1791787, 100} } }, + { NetworkMain, { {0, 90}, {175600, 200}, {1757000, 60}, {1791787, 100}, {1862000, 200} } }, { NetworkTest, { {0, 200} } } } }, { ConsensusLimit_full_complain, { @@ -438,7 +438,7 @@ namespace PocketConsensus { NetworkTest, { {0, 300} } } } }, { ConsensusLimit_full_comment_score, { - { NetworkMain, { {0, 600}, {1757000, 200} } }, + { NetworkMain, { {0, 600}, {1757000, 200}, {1862000, 300} } }, { NetworkTest, { {0, 600} } } } }, diff --git a/src/pocketdb/consensus/social/Blocking.hpp b/src/pocketdb/consensus/social/Blocking.hpp index 3b2d16383..f2805d4fc 100644 --- a/src/pocketdb/consensus/social/Blocking.hpp +++ b/src/pocketdb/consensus/social/Blocking.hpp @@ -192,8 +192,8 @@ namespace PocketConsensus { protected: const vector> m_rules = { - { 0, 0, [](int height) { return make_shared(height); }}, - { 5555555,1114500, [](int height) { return make_shared(height); }}, // TODO (o1q): set checkpoint height for multiple locks + { 0, 0, [](int height) { return make_shared(height); }}, + { 1862000, 1114500, [](int height) { return make_shared(height); }}, // TODO (o1q): set checkpoint height for multiple locks }; public: shared_ptr Instance(int height) diff --git a/src/pocketdb/consensus/social/CommentDelete.hpp b/src/pocketdb/consensus/social/CommentDelete.hpp index f1cc4dffb..41b51708a 100644 --- a/src/pocketdb/consensus/social/CommentDelete.hpp +++ b/src/pocketdb/consensus/social/CommentDelete.hpp @@ -40,8 +40,8 @@ namespace PocketConsensus if (!actuallTxOk || !originalTxOk) return {false, SocialConsensusResult_NotFound}; - auto originalPtx = static_pointer_cast(originalTx); - + auto originalPtx = static_pointer_cast(originalTx); + // Parent comment { auto currParentTxHash = IsEmpty(ptx->GetParentTxHash()) ? "" : *ptx->GetParentTxHash(); @@ -69,6 +69,17 @@ namespace PocketConsensus return {false, SocialConsensusResult_InvalidAnswerComment}; } + // Check exists content transaction + auto[contentOk, contentTx] = PocketDb::ConsensusRepoInst.GetLastContent( + *ptx->GetPostTxHash(), { CONTENT_POST, CONTENT_VIDEO, CONTENT_ARTICLE, CONTENT_DELETE }); + + if (!contentOk) + return {false, SocialConsensusResult_NotFound}; + + // Check author of comment + if (auto[ok, result] = CheckAuthor(ptx, originalPtx, contentTx); !ok) + return {false, result}; + return Success; } ConsensusValidateResult Check(const CTransactionRef& tx, const CommentDeleteRef& ptx) override @@ -113,6 +124,25 @@ namespace PocketConsensus { return {*ptx->GetString1()}; } + virtual ConsensusValidateResult CheckAuthor(const CommentDeleteRef& ptx, const CommentRef& originalPtx, const PTransactionRef& contentTx) + { + return Success; + } + }; + + // Protect deleting comment only for authors and authors of content + class CommentDeleteConsensus_checkpoint_check_author : public CommentDeleteConsensus + { + public: + CommentDeleteConsensus_checkpoint_check_author(int height) : CommentDeleteConsensus(height) {} + protected: + ConsensusValidateResult CheckAuthor(const CommentDeleteRef& ptx, const CommentRef& originalPtx, const PTransactionRef& contentTx) override + { + if (*ptx->GetAddress() != *originalPtx->GetAddress() && *ptx->GetAddress() != *contentTx->GetString1()) + return {false, SocialConsensusResult_ContentEditUnauthorized}; + + return Success; + } }; /******************************************************************************************************************* @@ -122,7 +152,8 @@ namespace PocketConsensus { private: const vector> m_rules = { - { 0, 0, [](int height) { return make_shared(height); }}, + { 0, 0, [](int height) { return make_shared(height); }}, + { 1862000, 1155000, [](int height) { return make_shared(height); }}, }; public: shared_ptr Instance(int height) diff --git a/src/pocketdb/consensus/social/CommentEdit.hpp b/src/pocketdb/consensus/social/CommentEdit.hpp index 05bd31582..13f16e755 100644 --- a/src/pocketdb/consensus/social/CommentEdit.hpp +++ b/src/pocketdb/consensus/social/CommentEdit.hpp @@ -41,7 +41,11 @@ namespace PocketConsensus if (!actuallTxOk || !originalTxOk) return {false, SocialConsensusResult_NotFound}; - auto originalPtx = static_pointer_cast(originalTx); + auto originalPtx = static_pointer_cast(originalTx); + + // Check author of comment + if (auto[ok, result] = CheckAuthor(ptx, originalPtx); !ok) + return {false, result}; // Parent comment { @@ -157,7 +161,7 @@ namespace PocketConsensus return {*ptx->GetAddress()}; } - virtual bool AllowEditWindow(const CommentEditRef& ptx, const CommentEditRef& blockPtx) + virtual bool AllowEditWindow(const CommentEditRef& ptx, const CommentRef& blockPtx) { return (*ptx->GetTime() - *blockPtx->GetTime()) <= GetConsensusLimit(ConsensusLimit_edit_comment_depth); } @@ -178,17 +182,19 @@ namespace PocketConsensus return Success; } + virtual ConsensusValidateResult CheckAuthor(const CommentEditRef& ptx, const CommentRef& originalPtx) + { + return Success; + } }; - /******************************************************************************************************************* - * Start checkpoint at 1180000 block - *******************************************************************************************************************/ + class CommentEditConsensus_checkpoint_1180000 : public CommentEditConsensus { public: CommentEditConsensus_checkpoint_1180000(int height) : CommentEditConsensus(height) {} protected: - bool AllowEditWindow(const CommentEditRef& ptx, const CommentEditRef& originalTx) override + bool AllowEditWindow(const CommentEditRef& ptx, const CommentRef& originalTx) override { auto[ok, originalTxHeight] = ConsensusRepoInst.GetTransactionHeight(*originalTx->GetHash()); if (!ok) return false; @@ -196,6 +202,21 @@ namespace PocketConsensus } }; + + class CommentEditConsensus_checkpoint_check_author : public CommentEditConsensus_checkpoint_1180000 + { + public: + CommentEditConsensus_checkpoint_check_author(int height) : CommentEditConsensus_checkpoint_1180000(height) {} + protected: + ConsensusValidateResult CheckAuthor(const CommentEditRef& ptx, const CommentRef& originalPtx) override + { + if (*ptx->GetAddress() != *originalPtx->GetAddress()) + return {false, SocialConsensusResult_ContentEditUnauthorized}; + + return Success; + } + }; + /******************************************************************************************************************* * Factory for select actual rules version *******************************************************************************************************************/ @@ -203,8 +224,9 @@ namespace PocketConsensus { private: const vector> m_rules = { - { 0, -1, [](int height) { return make_shared(height); }}, - { 1180000, 0, [](int height) { return make_shared(height); }}, + { 0, -1, [](int height) { return make_shared(height); }}, + { 1180000, 0, [](int height) { return make_shared(height); }}, + { 1862000, 1155000, [](int height) { return make_shared(height); }}, }; public: shared_ptr Instance(int height) diff --git a/src/pocketdb/helpers/PocketnetHelper.h b/src/pocketdb/helpers/PocketnetHelper.h index a54993736..a771c4aec 100644 --- a/src/pocketdb/helpers/PocketnetHelper.h +++ b/src/pocketdb/helpers/PocketnetHelper.h @@ -41,17 +41,18 @@ namespace PocketHelpers return find(PocketnetDevelopers[net].begin(), PocketnetDevelopers[net].end(), address) != PocketnetDevelopers[net].end(); } - static inline std::vector GetPocketnetteamAddresses() - { - switch (Params().NetworkID()) { - case NetworkMain: - return {"PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd"}; - case NetworkTest: - return {"TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"}; - default: - return {}; - } - } + // TODO: Notification from POCKETNET_TEAM + // static inline std::vector GetPocketnetteamAddresses() + // { + // switch (Params().NetworkID()) { + // case NetworkMain: + // return {"PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd"}; + // case NetworkTest: + // return {"TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"}; + // default: + // return {}; + // } + // } } #endif // POCKETHELPERS_POCKETNET_HELPER_H diff --git a/src/pocketdb/helpers/ShortFormHelper.cpp b/src/pocketdb/helpers/ShortFormHelper.cpp index ad8af9678..316dcfd85 100644 --- a/src/pocketdb/helpers/ShortFormHelper.cpp +++ b/src/pocketdb/helpers/ShortFormHelper.cpp @@ -11,7 +11,6 @@ static const std::map& GetTypesMap() { static const std::map typesMap = { - { PocketDb::ShortTxType::PocketnetTeam, "pocketnetteam" }, { PocketDb::ShortTxType::Money, "money" }, { PocketDb::ShortTxType::Referal, "referal" }, { PocketDb::ShortTxType::Answer, "answer" }, @@ -39,7 +38,6 @@ std::string PocketHelpers::ShortTxTypeConvertor::toString(PocketDb::ShortTxType bool PocketHelpers::ShortTxFilterValidator::Notifications::IsFilterAllowed(PocketDb::ShortTxType type) { static const std::set allowed = { - PocketDb::ShortTxType::PocketnetTeam, PocketDb::ShortTxType::Money, PocketDb::ShortTxType::Answer, PocketDb::ShortTxType::PrivateContent, diff --git a/src/pocketdb/models/shortform/ShortTxType.h b/src/pocketdb/models/shortform/ShortTxType.h index 80a700de5..f23fd0430 100644 --- a/src/pocketdb/models/shortform/ShortTxType.h +++ b/src/pocketdb/models/shortform/ShortTxType.h @@ -10,7 +10,6 @@ namespace PocketDb enum class ShortTxType { NotSet, - PocketnetTeam, Money, Referal, Answer, diff --git a/src/pocketdb/repositories/web/WebRpcRepository.cpp b/src/pocketdb/repositories/web/WebRpcRepository.cpp index a2135ef19..6ad999a53 100644 --- a/src/pocketdb/repositories/web/WebRpcRepository.cpp +++ b/src/pocketdb/repositories/web/WebRpcRepository.cpp @@ -92,18 +92,16 @@ namespace PocketDb void FeedRow(sqlite3_stmt* stmt) { auto shortForm = m_parser.ParseRow(stmt, 1); - if (shortForm.GetType() == ShortTxType::PocketnetTeam) { - // Pocketnetteam posts are special case because everyone need to be notified about them - m_pocketnetteamPosts.emplace_back(std::move(shortForm)); - } else { - auto [ok, address] = TryGetColumnString(stmt, 0); - if (!ok) throw std::runtime_error("Missing address of notifier"); - m_result[address].emplace_back(std::move(shortForm)); - } + + auto [ok, address] = TryGetColumnString(stmt, 0); + if (!ok) throw std::runtime_error("Missing address of notifier"); + + m_result[address].emplace_back(std::move(shortForm)); + } WebRpcRepository::NotificationsResult GetResult() const { - return { m_result, m_pocketnetteamPosts }; + return m_result; } private: ShortFormParser m_parser; @@ -3284,12 +3282,24 @@ namespace PocketDb langFilter += " cross join Payload p indexed by Payload_String1_TxHash on p.TxHash = t.Hash and p.String1 = ? "; string sql = R"sql( - select t.Id + select t.Id, + + ( + select count() + from Transactions s --indexed by Transactions_Type_Last_String3_Height + where s.Type in (204, 205) and s.Last = 1 and s.String3 = t.String2 and s.Height is not null + -- exclude commenters blocked by the author of the post + and not exists ( + select 1 + from Transactions b --indexed by Transactions_Type_Last_String1_String2_Height + where b.Type in (305) and b.Last = 1 and b.String1 = t.String1 and b.String2 = s.String1 and b.Height > 0 + ) + ) commentsCount from Transactions t indexed by Transactions_Type_Last_Height_Id - cross join Ratings cr indexed by Ratings_Type_Id_Last_Value - on cr.Type = 2 and cr.Last = 1 and cr.Id = t.Id and cr.Value > 0 + --cross join Ratings cr indexed by Ratings_Type_Id_Last_Value + -- on cr.Type = 2 and cr.Last = 1 and cr.Id = t.Id and cr.Value > 0 )sql" + langFilter + R"sql( @@ -3339,24 +3349,9 @@ namespace PocketDb ) )sql"; } - // sql += " order by cr.Value desc "; - sql += R"sql( - order by ( - select count() - from Transactions s indexed by Transactions_Type_Last_String3_Height - where s.Type in (204, 205) and s.Height is not null and s.String3 = t.String2 and s.Last = 1 - -- exclude commenters blocked by the author of the post - and not exists ( - select 1 - from Transactions b indexed by Transactions_Type_Last_String1_Height_Id - where b.Type in (305) and b.Last = 1 and b.Height > 0 and b.String1 = t.String1 and b.String2 = s.String1 - ) - ) desc - limit ? - )sql"; - // --------------------------------------------- + vector> idswithcomments; vector ids; TryTransactionStep(func, [&]() @@ -3403,24 +3398,38 @@ namespace PocketDb TryBindStatementText(stmt, i++, lang); } - TryBindStatementInt(stmt, i++, countOut); - // --------------------------------------------- while (sqlite3_step(*stmt) == SQLITE_ROW) { auto[ok0, contentId] = TryGetColumnInt64(*stmt, 0); - ids.push_back(contentId); + auto[ok1, commentsCount] = TryGetColumnInt(*stmt, 1); + + idswithcomments.emplace_back(contentId, commentsCount); } FinalizeSqlStatement(*stmt); }); - // Get content data - if (!ids.empty()) + if (!idswithcomments.empty()) { - auto contents = GetContentsData(ids, address); - result.push_backV(contents); + std::sort(idswithcomments.begin(), idswithcomments.end(), + [] (const auto &x, const auto &y) {return x.second > y.second;}); + + std::transform(idswithcomments.begin(), idswithcomments.end(), std::back_inserter(ids), + [](decltype(idswithcomments)::value_type const &pair) { + return pair.first; + }); + + if (ids.size() > countOut) + ids = {ids.begin(), ids.begin() + countOut}; + + // Get content data + if (!ids.empty()) + { + auto contents = GetContentsData(ids, address); + result.push_backV(contents); + } } // Complete! @@ -4707,25 +4716,26 @@ namespace PocketDb return result; } + + // Choosing predicate for function above based on filters. + std::function _choosePredicate(const std::set& filters) { + if (filters.empty()) { + // No filters mean that we should perform all selects + return [&filters](...) { return true; }; + } else { + // Perform only selects that are specified in filters. + return [&filters](const ShortTxType& select) { return filters.find(select) != filters.end(); }; + } + }; + // Method used to construct sql query and required bindings from provided selects based on filters template static inline auto _constructSelectsBasedOnFilters( const std::set& filters, const std::map&, QueryParams>>& selects, const std::string& footer) - { - // Choosing predicate for function above based on filters. - const static auto choosePredicate = [](const std::set& filters) -> std::function { - if (filters.empty()) { - // No filters mean that we should perform all selects - return [&filters](...) { return true; }; - } else { - // Perform only selects that are specified in filters. - return [&filters](const ShortTxType& select) { return filters.find(select) != filters.end(); }; - } - }; - - auto predicate = choosePredicate(filters); + { + auto predicate = _choosePredicate(filters); // Binds that should be performed to constructed query std::vector&, int&, QueryParams const&)>> binds; @@ -4758,7 +4768,6 @@ namespace PocketDb } queryParams {height}; // Static because it will not be changed for entire node run - static const auto pocketnetteamAddresses = GetPocketnetteamAddresses(); static const auto heightBinder = [this](std::shared_ptr& stmt, int& i, QueryParams const& queryParams){ @@ -4766,80 +4775,6 @@ namespace PocketDb }; static const std::map&, QueryParams>> selects = { - { - ShortTxType::PocketnetTeam, { R"sql( - -- Pocket posts - select - null, -- related address is null because pocketnetteam posts should be added for every address - (')sql" + ShortTxTypeConvertor::toString(ShortTxType::PocketnetTeam) + R"sql(')TP, - t.Hash, - t.Type, - t.String1, - t.Height as Height, - t.BlockNum as BlockNum, - null, - p.String2, -- Caption - null, - null, - pact.String2, - pact.String3, - null, - ifnull(ract.Value,0), - r.Hash, -- repost related data, if any - r.Type, - r.String1, - r.Height, - r.BlockNum, - null, - pr.String2, - null, - null, - null, -- TODO (losty): no account info - null, - null, - null - - from Transactions t indexed by Transactions_Type_String1_Height_Time_Int1 - - left join Payload p - on p.TxHash = t.Hash - - left join Transactions r indexed by Transactions_Hash_Height -- related content - possible reposts - on r.Type in (200,201,202) - and r.Last = 1 - and r.Height > 0 - and r.Hash = t.String3 - - left join Payload pr - on pr.TxHash = r.Hash - - left join Transactions act - on act.Type = 100 - and act.Last = 1 - and act.String1 = t.String1 - and act.Height > 0 - - left join Payload pact - on pact.TxHash = act.Hash - - left join Ratings ract indexed by Ratings_Type_Id_Last_Height - on ract.Type = 0 - and ract.Id = act.Id - and ract.Last = 1 - - where t.Type in (200,201,202) - and t.String1 in ( )sql" + join(vector(pocketnetteamAddresses.size(), "?"), ",") + R"sql( ) - and t.Hash = t.String2 -- Only orig - and t.Height = ? - )sql", - [this](std::shared_ptr& stmt, int& i, QueryParams const& queryParams) { - for (const auto& pocketnetAddress: pocketnetteamAddresses) { - TryBindStatementText(stmt, i++, pocketnetAddress); - } - TryBindStatementInt64(stmt, i++, queryParams.height); - } - }}, - { ShortTxType::Money, { R"sql( -- Incoming money @@ -5280,12 +5215,12 @@ namespace PocketDb c.Height as Height, c.BlockNum as BlockNum, null, + p.String2, null, null, - p.String2, pac.String2, pac.String3, - pac.String4, + null, ifnull(rac.Value,0), r.Hash, -- TODO (losty): probably reposts here? r.Type, @@ -5337,14 +5272,8 @@ namespace PocketDb where c.Type in (200,201,202) and c.Hash = c.String2 -- only orig and c.Height = ? - and c.String1 not in ( )sql" + join(vector(pocketnetteamAddresses.size(), "?"), ",") + R"sql( ) )sql", - [this](std::shared_ptr& stmt, int& i, QueryParams const& queryParams){ - TryBindStatementInt64(stmt, i++, queryParams.height); - for (const auto& pocketnetAddress: pocketnetteamAddresses) { - TryBindStatementText(stmt, i++, pocketnetAddress); - } - } + heightBinder }}, { @@ -5476,28 +5405,30 @@ namespace PocketDb // heightBinder // }} }; - - auto [elem1, elem2] = _constructSelectsBasedOnFilters(filters, selects, ""); - auto& sql = elem1; - auto& binds = elem2; + auto predicate = _choosePredicate(filters); + NotificationsReconstructor reconstructor; - TryTransactionStep(__func__, [&]() - { - auto stmt = SetupSqlStatement(sql); - int i = 1; + for(const auto& select: selects) { + if (predicate(select.first)) { + const auto& selectData = select.second; + TryTransactionStep(__func__, [&]() + { + auto stmt = SetupSqlStatement(selectData.query); - for (const auto& bind: binds) { - bind(stmt, i, queryParams); - } + int i = 1; + selectData.binding(stmt, i, queryParams); - while (sqlite3_step(*stmt) == SQLITE_ROW) - { - reconstructor.FeedRow(*stmt); + while (sqlite3_step(*stmt) == SQLITE_ROW) + { + reconstructor.FeedRow(*stmt); + } + + FinalizeSqlStatement(*stmt); + }); } + } - FinalizeSqlStatement(*stmt); - }); return reconstructor.GetResult(); } -} \ No newline at end of file +} diff --git a/src/pocketdb/repositories/web/WebRpcRepository.h b/src/pocketdb/repositories/web/WebRpcRepository.h index 1ecdbf377..2ce684515 100644 --- a/src/pocketdb/repositories/web/WebRpcRepository.h +++ b/src/pocketdb/repositories/web/WebRpcRepository.h @@ -160,7 +160,7 @@ namespace PocketDb UniValue GetContentActions(const string& postTxHash); // First - map where keys are addresses and values are ShortForms of events from given block. Second - pocketnetteam posts. - using NotificationsResult = std::pair>, std::vector>; + using NotificationsResult = std::map>; /** * Get all possible events for all adresses in concrete block * diff --git a/src/pocketdb/web/PocketContentRpc.cpp b/src/pocketdb/web/PocketContentRpc.cpp index 3c9e1a9b5..980f5d643 100644 --- a/src/pocketdb/web/PocketContentRpc.cpp +++ b/src/pocketdb/web/PocketContentRpc.cpp @@ -1355,25 +1355,22 @@ namespace PocketWeb::PocketWebRpc } } - auto [shortTxMap, pocketnetteamPosts] = request.DbConnection()->WebRpcRepoInst->GetNotifications(height, filters); + auto shortTxMap = request.DbConnection()->WebRpcRepoInst->GetNotifications(height, filters); UniValue userNotifications {UniValue::VOBJ}; + userNotifications.reserveKVSize(shortTxMap.size()); for (const auto& addressSpecific: shortTxMap) { UniValue txs {UniValue::VARR}; + std::vector tmp; for (const auto& tx: addressSpecific.second) { - txs.push_back(tx.Serialize()); + tmp.emplace_back(tx.Serialize()); } - userNotifications.pushKV(addressSpecific.first, txs); - } - - UniValue pocketnetteam {UniValue::VARR}; - for (const auto& pocketnetteanPost: pocketnetteamPosts) { - pocketnetteam.push_back(pocketnetteanPost.Serialize()); + txs.push_backV(std::move(tmp)); + userNotifications.pushKV(addressSpecific.first, txs, false /*searchDuplicate*/); } UniValue res {UniValue::VOBJ}; res.pushKV("users_notifications", userNotifications); - res.pushKV("pocketnetteam", pocketnetteam); return res; }, diff --git a/src/pocketdb/web/PocketTransactionRpc.cpp b/src/pocketdb/web/PocketTransactionRpc.cpp index f5c7e2be9..5ebb3b875 100644 --- a/src/pocketdb/web/PocketTransactionRpc.cpp +++ b/src/pocketdb/web/PocketTransactionRpc.cpp @@ -220,6 +220,11 @@ namespace PocketWeb::PocketWebRpc if (request.params[5].isNum()) fee = request.params[5].get_int64(); + // Content Author address + string contentAddressValue = ""; + if (request.params[6].isStr() && txPayload.exists("value") && txPayload["value"].isNum()) + contentAddressValue = request.params[6].get_str() + " " + to_string(txPayload["value"].get_int()); + // Build template for transaction auto txType = PocketHelpers::TransactionHelper::ConvertOpReturnToType(txTypeHex); shared_ptr _ptx = PocketHelpers::TransactionHelper::CreateInstance(txType); @@ -260,7 +265,9 @@ namespace PocketWeb::PocketWebRpc } // generate transaction - CTxOut _dataOut(0, CScript() << OP_RETURN << ParseHex(txTypeHex) << ParseHex(_ptx->BuildHash())); + auto _opReturn = CScript() << OP_RETURN << ParseHex(txTypeHex) << ParseHex(_ptx->BuildHash()); + if (contentAddressValue != "") _opReturn = _opReturn << ParseHex(HexStr(contentAddressValue)); + CTxOut _dataOut(0, _opReturn); CMutableTransaction mTx = ConstructPocketnetTransaction(_inputs, _dataOut, _outputs, NullUniValue, NullUniValue); // Decode private keys diff --git a/src/pocketdb/web/WebSocketRpc.cpp b/src/pocketdb/web/WebSocketRpc.cpp index f728e126a..61d2d062a 100644 --- a/src/pocketdb/web/WebSocketRpc.cpp +++ b/src/pocketdb/web/WebSocketRpc.cpp @@ -60,15 +60,16 @@ namespace PocketWeb::PocketWebRpc // --------------------------------------------------------------------- + // TODO: Notification from POCKETNET_TEAM // Pocketnet Team content - std::string teamAddress = (Params().NetworkIDString() == CBaseChainParams::MAIN) ? "PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd" : "TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"; - auto[teamCount, teamData] = request.DbConnection()->WebRpcRepoInst->GetLastAddressContent(teamAddress, blockNumber, 99); - for (size_t i = 0; i < teamData.size(); i++) - { - teamData.At(i).pushKV("msg", "sharepocketnet"); - teamData.At(i).pushKV("addrFrom", teamAddress); - result.push_back(teamData[i]); - } + // std::string teamAddress = (Params().NetworkIDString() == CBaseChainParams::MAIN) ? "PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd" : "TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"; + // auto[teamCount, teamData] = request.DbConnection()->WebRpcRepoInst->GetLastAddressContent(teamAddress, blockNumber, 99); + // for (size_t i = 0; i < teamData.size(); i++) + // { + // teamData.At(i).pushKV("msg", "sharepocketnet"); + // teamData.At(i).pushKV("addrFrom", teamAddress); + // result.push_back(teamData[i]); + // } // --------------------------------------------------------------------- diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 6fb4ae161..d412cfe84 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -114,8 +114,10 @@ class UniValue { } bool push_backV(const std::vector& vec); + void reserveKVSize(size_t size); + void __pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const UniValue& val); + bool pushKV(const std::string& key, const UniValue& val, bool searchDuplicate = true); bool pushKV(const std::string& key, const std::string& val_) { UniValue tmpVal(VSTR, val_); return pushKV(key, tmpVal); diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 69b8356f1..661601b5a 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -124,19 +124,25 @@ bool UniValue::push_backV(const std::vector& vec) return true; } +void UniValue::reserveKVSize(size_t size) +{ + keys.reserve(size); + values.reserve(size); +} + void UniValue::__pushKV(const std::string& key, const UniValue& val_) { keys.push_back(key); values.push_back(val_); } -bool UniValue::pushKV(const std::string& key, const UniValue& val_) +bool UniValue::pushKV(const std::string& key, const UniValue& val_, bool searchDuplicate) { if (typ != VOBJ) return false; size_t idx; - if (findKey(key, idx)) + if (searchDuplicate && findKey(key, idx)) values[idx] = val_; else __pushKV(key, val_); diff --git a/src/websocket/notifyprocessor.cpp b/src/websocket/notifyprocessor.cpp index bb98f1371..ea23e6d44 100644 --- a/src/websocket/notifyprocessor.cpp +++ b/src/websocket/notifyprocessor.cpp @@ -45,9 +45,10 @@ void NotifyBlockProcessor::Process(std::pair entry) int sharesCnt = 0; std::map> contentLangCnt; - std::string txidpocketnet; - std::string addrespocketnet = (Params().NetworkIDString() == CBaseChainParams::MAIN) ? "PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd" : "TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"; - auto pocketnetaccinfo = PocketDb::NotifierRepoInst.GetAccountInfoByAddress(addrespocketnet); + // TODO: Notification from POCKETNET_TEAM + // std::string txidpocketnet; + // std::string addrespocketnet = (Params().NetworkIDString() == CBaseChainParams::MAIN) ? "PEj7QNjKdDPqE9kMDRboKoCtp8V6vZeZPd" : "TAqR1ncH95eq9XKSDRR18DtpXqktxh74UU"; + // auto pocketnetaccinfo = PocketDb::NotifierRepoInst.GetAccountInfoByAddress(addrespocketnet); for (const auto& tx : block.vtx) { std::map> addrs; @@ -153,30 +154,31 @@ void NotifyBlockProcessor::Process(std::pair entry) if (response.exists("hash") && response.exists("rootHash") && response["hash"].get_str() != response["rootHash"].get_str()) continue; - if (addr.first == addrespocketnet && txidpocketnet.find(txid) == std::string::npos) - { - txidpocketnet += txid + ","; - } - else - { - auto response = PocketDb::NotifierRepoInst.GetOriginalPostAddressByRepost(txid); - if (response.exists("hash")) + // TODO: Notification from POCKETNET_TEAM + // if (addr.first == addrespocketnet && txidpocketnet.find(txid) == std::string::npos) + // { + // txidpocketnet += txid + ","; + // } + // else + // { + auto repostResponse = PocketDb::NotifierRepoInst.GetOriginalPostAddressByRepost(txid); + if (repostResponse.exists("hash")) { - std::string address = response["address"].get_str(); + std::string address = repostResponse["address"].get_str(); custom_fields cFields { {"mesType", "reshare"}, - {"txidRepost", response["hash"].get_str()}, - {"addrFrom", response["addressRepost"].get_str()}, - {"nameFrom", response["nameRepost"].get_str()} + {"txidRepost", repostResponse["hash"].get_str()}, + {"addrFrom", repostResponse["addressRepost"].get_str()}, + {"nameFrom", repostResponse["nameRepost"].get_str()} }; - if (response.exists("avatarRepost")) - cFields.emplace("avatarFrom",response["avatarRepost"].get_str()); + if (repostResponse.exists("avatarRepost")) + cFields.emplace("avatarFrom",repostResponse["avatarRepost"].get_str()); PrepareWSMessage(messages, "event", address, txid, txtime, cFields); } - } + // } // TODO: Notification from POCKETNET_TEAM auto subscribesResponse = PocketDb::NotifierRepoInst.GetPrivateSubscribeAddressesByAddressTo(addr.first); for (size_t i = 0; i < subscribesResponse.size(); ++i) @@ -392,24 +394,25 @@ void NotifyBlockProcessor::Process(std::pair entry) LogPrintf("Error: CChainState::NotifyWSClients (1) - %s\n", e.what()); } - if (txidpocketnet != "") - { - try - { - UniValue m(UniValue::VOBJ); - m.pushKV("msg", "sharepocketnet"); - m.pushKV("time", std::to_string(block.nTime)); - m.pushKV("addrFrom", addrespocketnet); - if (pocketnetaccinfo.exists("name")) m.pushKV("nameFrom", pocketnetaccinfo["name"].get_str()); - if (pocketnetaccinfo.exists("avatar")) m.pushKV("avatarFrom", pocketnetaccinfo["avatar"].get_str()); - m.pushKV("txids", txidpocketnet.substr(0, txidpocketnet.size() - 1)); - connWS.second.Connection->send(m.write(), [](const SimpleWeb::error_code& ec) {}); - } - catch (const std::exception& e) - { - LogPrintf("Error: CChainState::NotifyWSClients (1) - %s\n", e.what()); - } - } + // TODO: Notification from POCKETNET_TEAM + // if (txidpocketnet != "") + // { + // try + // { + // UniValue m(UniValue::VOBJ); + // m.pushKV("msg", "sharepocketnet"); + // m.pushKV("time", std::to_string(block.nTime)); + // m.pushKV("addrFrom", addrespocketnet); + // if (pocketnetaccinfo.exists("name")) m.pushKV("nameFrom", pocketnetaccinfo["name"].get_str()); + // if (pocketnetaccinfo.exists("avatar")) m.pushKV("avatarFrom", pocketnetaccinfo["avatar"].get_str()); + // m.pushKV("txids", txidpocketnet.substr(0, txidpocketnet.size() - 1)); + // connWS.second.Connection->send(m.write(), [](const SimpleWeb::error_code& ec) {}); + // } + // catch (const std::exception& e) + // { + // LogPrintf("Error: CChainState::NotifyWSClients (1) - %s\n", e.what()); + // } + // } if (messages.find(connWS.second.Address) != messages.end()) {