diff --git a/client/fresheyes-bot/comments/0.json b/client/fresheyes-bot/comments/0.json new file mode 100644 index 0000000..1401313 --- /dev/null +++ b/client/fresheyes-bot/comments/0.json @@ -0,0 +1,6860 @@ +[ + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372", + "pull_request_review_id": 1823506588, + "id": 1453480372, + "node_id": "PRRC_kwDOABII585Wolm0", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n /** Add fee and size of another FeeFrac to this one. */\r\n void inline operator+=(const FeeFrac& other) noexcept\r\n {\r\n fee += other.fee;\r\n size += other.size;\r\n }\r\n\r\n /** Subtrack fee and size of another FeeFrac from this one. */\r\n```", + "created_at": "2024-01-16T14:09:34Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480372", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480372" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679", + "pull_request_review_id": 1823506588, + "id": 1453480679, + "node_id": "PRRC_kwDOABII585Wolrn", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Reserve here?\r\n```suggestion\r\n diagram.clear();\r\n diagram.reserve(chunks.size() + 1);\r\n```", + "created_at": "2024-01-16T14:09:41Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480679", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480679" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 12, + "side": "RIGHT", + "original_position": 9, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107", + "pull_request_review_id": 1823506588, + "id": 1453482107, + "node_id": "PRRC_kwDOABII585WomB7", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+ return;\n+}", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "No need for this return here\r\n```suggestion\r\n}\r\n```", + "created_at": "2024-01-16T14:10:20Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453482107", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453482107" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 19, + "start_side": "RIGHT", + "line": null, + "original_line": 20, + "side": "RIGHT", + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633", + "pull_request_review_id": 1823506588, + "id": 1453487633, + "node_id": "PRRC_kwDOABII585WonYR", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe add a docstring on what `BuildDiagramFromUnsortedChunks` does in and out params description that are doxygen compatible?", + "created_at": "2024-01-16T14:14:22Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453487633", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453487633" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485", + "pull_request_review_id": 1823506588, + "id": 1453501485, + "node_id": "PRRC_kwDOABII585Woqwt", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: we can just use the empty constructor\r\n```suggestion\r\n FeeFrac empty{};\r\n```", + "created_at": "2024-01-16T14:24:35Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453501485", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453501485" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118", + "pull_request_review_id": 1823506588, + "id": 1453502118, + "node_id": "PRRC_kwDOABII585Woq6m", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "why can we have negative size ?", + "created_at": "2024-01-16T14:25:01Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453502118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453502118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924", + "pull_request_review_id": 1823506588, + "id": 1453604924, + "node_id": "PRRC_kwDOABII585WpEA8", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think you mean `all_conflicts` here\r\n```suggestion\r\n // old diagram will consist of each element of all_conflicts either at\r\n```", + "created_at": "2024-01-16T15:36:53Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453604924", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453604924" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1305, + "side": "RIGHT", + "original_position": 65, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523", + "pull_request_review_id": 1823506588, + "id": 1453612523, + "node_id": "PRRC_kwDOABII585WpF3r", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "use static cast?\r\n```suggestion\r\n FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\r\n```", + "created_at": "2024-01-16T15:42:19Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453612523", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453612523" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1327, + "side": "RIGHT", + "original_position": 87, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393", + "pull_request_review_id": 1823506588, + "id": 1453626393, + "node_id": "PRRC_kwDOABII585WpJQZ", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I understand what happens here but its a bit confusing to me the short forms `CON`, `CNK` `DIAGRAM`\r\nWill prefer something like the compute in computing the `OLD` chunk\r\n\r\n```suggestion\r\n // Step 2: build the new diagram\r\n\r\n // Add any parents of direct conflicts that are not conflicted themselves into the NEW chunk\r\n for (auto direct_conflict : direct_conflicts) {\r\n // If a direct conflict has an ancestor that is not in all_conflicts,\r\n // it can be affected by the replacement of the child.\r\n if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\r\n // Grab the parent.\r\n const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\r\n if (!all_conflicts.count(mapTx.iterator_to(parent))) {\r\n // This transaction would be left over, so add to the NEW\r\n // chunk.\r\n new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\r\n }\r\n }\r\n }\r\n // Add the replacement package to NEW\r\n new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));\r\n```", + "created_at": "2024-01-16T15:52:23Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453626393", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453626393" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765", + "pull_request_review_id": 1823506588, + "id": 1453667765, + "node_id": "PRRC_kwDOABII585WpTW1", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Should forward the detailed error message also?", + "created_at": "2024-01-16T16:23:36Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453667765", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453667765" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545", + "pull_request_review_id": 1827173808, + "id": 1455418545, + "node_id": "PRRC_kwDOABII585Wv-yx", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "Even better, I'll add a test that they're the same", + "created_at": "2024-01-17T12:19:19Z", + "updated_at": "2024-01-17T12:19:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455418545", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455418545" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "in_reply_to_id": 1453501485, + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851", + "pull_request_review_id": 1827178150, + "id": 1455423851, + "node_id": "PRRC_kwDOABII585WwAFr", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "These are shorthand labels from https://delvingbitcoin.org/t/post-clustermempool-package-rbf-per-chunk-processing/190 which helped me think through preciesely how it maps onto the concepts laid out.\r\n\r\nI'd like to keep track of these ideas somehow, maybe by defining the labels?", + "created_at": "2024-01-17T12:21:54Z", + "updated_at": "2024-01-17T12:21:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455423851", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455423851" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826", + "pull_request_review_id": 1827180557, + "id": 1455426826, + "node_id": "PRRC_kwDOABII585WwA0K", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "can you be more explicit in suggestion? The errors are being returned?", + "created_at": "2024-01-17T12:23:21Z", + "updated_at": "2024-01-17T12:23:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455426826", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455426826" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932", + "pull_request_review_id": 1827186462, + "id": 1455433932, + "node_id": "PRRC_kwDOABII585WwCjM", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "this is testing that subtraction works correctly, not that an individual chunk can have negative size", + "created_at": "2024-01-17T12:26:54Z", + "updated_at": "2024-01-17T12:26:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455433932", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455433932" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026", + "pull_request_review_id": 1827266447, + "id": 1455527026, + "node_id": "PRRC_kwDOABII585WwZRy", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I meant what is being returned by `err_string` and `CompareFeerateDiagram` was not used. why were you unable to compute mining score, same for `CompareFeerateDiagram` why is the fee rate insufficient.", + "created_at": "2024-01-17T13:11:40Z", + "updated_at": "2024-01-17T13:11:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455527026", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455527026" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078", + "pull_request_review_id": 1827272350, + "id": 1455534078, + "node_id": "PRRC_kwDOABII585Wwa_-", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "also, `Subtrack` isn't a word...", + "created_at": "2024-01-17T13:14:53Z", + "updated_at": "2024-01-17T13:14:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455534078", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455534078" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "in_reply_to_id": 1453480372, + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143", + "pull_request_review_id": 1827276759, + "id": 1455539143, + "node_id": "PRRC_kwDOABII585WwcPH", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "\r\nYeah, maybe to be consistent define the labels and do the same in the `OLD` `chunk` computation loop above.\r\nThough the explicit comments in the `OLD` `chunk` computation loop is more easier to parse for me :).", + "created_at": "2024-01-17T13:17:06Z", + "updated_at": "2024-01-17T13:17:06Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455539143", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455539143" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265", + "pull_request_review_id": 1827280890, + "id": 1455544265, + "node_id": "PRRC_kwDOABII585WwdfJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes, My question was... whats the rationale for `FeeFrac` to generally have negative size ?", + "created_at": "2024-01-17T13:19:22Z", + "updated_at": "2024-01-17T13:19:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455544265", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455544265" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183", + "pull_request_review_id": 1827381635, + "id": 1455658183, + "node_id": "PRRC_kwDOABII585Ww5TH", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "CompareFeerateDiagram won't return much very interesting, but you're right for the `err_string`, will return it", + "created_at": "2024-01-17T14:08:17Z", + "updated_at": "2024-01-17T14:08:17Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455658183", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455658183" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934", + "pull_request_review_id": 1833137718, + "id": 1459252934, + "node_id": "PRRC_kwDOABII585W-m7G", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:18Z", + "updated_at": "2024-01-19T16:01:18Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459252934", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459252934" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057", + "pull_request_review_id": 1833138006, + "id": 1459253057, + "node_id": "PRRC_kwDOABII585W-m9B", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "took some of hte language, and explicitly defined each term", + "created_at": "2024-01-19T16:01:24Z", + "updated_at": "2024-01-19T16:01:24Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253057", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253057" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223", + "pull_request_review_id": 1833138370, + "id": 1459253223, + "node_id": "PRRC_kwDOABII585W-m_n", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:31Z", + "updated_at": "2024-01-19T16:01:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253223", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253223" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1327, + "side": "RIGHT", + "in_reply_to_id": 1453612523, + "original_position": 87, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328", + "pull_request_review_id": 1833138587, + "id": 1459253328, + "node_id": "PRRC_kwDOABII585W-nBQ", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:35Z", + "updated_at": "2024-01-19T16:01:35Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253328", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253328" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1305, + "side": "RIGHT", + "in_reply_to_id": 1453604924, + "original_position": 65, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396", + "pull_request_review_id": 1833138722, + "id": 1459253396, + "node_id": "PRRC_kwDOABII585W-nCU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "We use subtraction, and should try to handle that?", + "created_at": "2024-01-19T16:01:37Z", + "updated_at": "2024-01-19T16:01:38Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253396", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253396" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460", + "pull_request_review_id": 1833138857, + "id": 1459253460, + "node_id": "PRRC_kwDOABII585W-nDU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:40Z", + "updated_at": "2024-01-19T16:01:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253460", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253460" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "in_reply_to_id": 1453501485, + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539", + "pull_request_review_id": 1833139037, + "id": 1459253539, + "node_id": "PRRC_kwDOABII585W-nEj", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "added comment", + "created_at": "2024-01-19T16:01:43Z", + "updated_at": "2024-01-19T16:01:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253539", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253539" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1453487633, + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631", + "pull_request_review_id": 1833139134, + "id": 1459253631, + "node_id": "PRRC_kwDOABII585W-nF_", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+ return;\n+}", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:46Z", + "updated_at": "2024-01-19T16:01:46Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253631", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253631" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 19, + "start_side": "RIGHT", + "line": null, + "original_line": 20, + "side": "RIGHT", + "in_reply_to_id": 1453482107, + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686", + "pull_request_review_id": 1833139262, + "id": 1459253686, + "node_id": "PRRC_kwDOABII585W-nG2", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:48Z", + "updated_at": "2024-01-19T16:01:48Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253686", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253686" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 12, + "side": "RIGHT", + "in_reply_to_id": 1453480679, + "original_position": 9, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728", + "pull_request_review_id": 1833139379, + "id": 1459253728, + "node_id": "PRRC_kwDOABII585W-nHg", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:50Z", + "updated_at": "2024-01-19T16:01:50Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253728", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253728" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "in_reply_to_id": 1453480372, + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030", + "pull_request_review_id": 1833161137, + "id": 1459264030, + "node_id": "PRRC_kwDOABII585W-poe", + "diff_hunk": "@@ -106,4 +108,23 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts\n+ * @param[in] replacement_fees Fees of replacement package\n+ * @param[in] replacement_vsize Size of replacement package\n+ * @returns error string if mempool diagram doesn't improve, otherwise std::nullopt.\n+ */\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+ EXCLUSIVE_LOCKS_REQUIRED(pool.cs);\n+\n+/** Compares two feerate diagrams. The shorter one is padded with a horizonal line. */\n+std::partial_ordering CompareFeerateDiagram(std::vector& dia0, std::vector& dia1);", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: perhaps this function belongs more in util/feefrac (as the building of the diagram also lives there)", + "created_at": "2024-01-19T16:09:00Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459264030", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459264030" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 128, + "side": "RIGHT", + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118", + "pull_request_review_id": 1833161137, + "id": 1459279118, + "node_id": "PRRC_kwDOABII585W-tUO", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "I can think of one use case where negative sizes are actually useful, though it's pretty far fetched.\r\n\r\nCurrently the code hardcodes a \"tail feerate\" (the feerate of which we assume there is an infinite supply) of 0 sat/vB for mempool improvement checks, but in theory this can be configurable. In that case, in addition to the diagram check between old and new package, we want the property that `fee_new >= fee_old + (size_new - size_old) * feerate_tail`. If `old`, `new`, and `tail` are CFeeFrac objects, this condition is exactly `!((new - old) << tail)`. If new is smaller than old, the `new - old` object has negative size.\r\n\r\nA more pragmatic answer is that there is no real reason to restrict it to just positive sizes, and not enforcing it is simpler.", + "created_at": "2024-01-19T16:18:54Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459279118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459279118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387", + "pull_request_review_id": 1833161137, + "id": 1459281387, + "node_id": "PRRC_kwDOABII585W-t3r", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: std::array.", + "created_at": "2024-01-19T16:20:13Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459281387", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459281387" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 47, + "side": "RIGHT", + "original_position": 47, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903", + "pull_request_review_id": 1833161137, + "id": 1459282903, + "node_id": "PRRC_kwDOABII585W-uPX", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: EMBRACE THE SPACESHIP\r\n\r\n```c++\r\nif (a[i] != b[i]) return a[i] <=> b[i];\r\n```", + "created_at": "2024-01-19T16:21:09Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459282903", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459282903" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 1, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 50, + "side": "RIGHT", + "original_position": 50, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849", + "pull_request_review_id": 1833161137, + "id": 1459283849, + "node_id": "PRRC_kwDOABII585W-ueJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: `2^64` -> `2^32`", + "created_at": "2024-01-19T16:21:44Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459283849", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459283849" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 39, + "side": "RIGHT", + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396", + "pull_request_review_id": 1833161137, + "id": 1459309396, + "node_id": "PRRC_kwDOABII585W-0tU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Suggested change that (I believe) avoids the need for suppressions (and may be more readable?):\r\n\r\n```c++\r\n auto add_fn = [&](uint64_t v, int pos) {\r\n uint64_t accum{0};\r\n for (int i = 0; i + pos < 4; ++i) {\r\n // Add current value at limb pos in ret.\r\n accum += ret[3 - pos - i];\r\n // Add low or high half of v.\r\n if (i == 0) accum += v & 0xffffffff;\r\n if (i == 1) accum += v >> 32;\r\n // Store lower half of result in limb pos in ret.\r\n ret[3 - pos - i] = accum & 0xffffffff;\r\n // Leave carry in accum.\r\n accum >>= 32;\r\n }\r\n // Make sure no overflow.\r\n assert(accum == 0);\r\n };\r\n```", + "created_at": "2024-01-19T16:36:25Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459309396", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459309396" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "original_position": 22, + "position": 22, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210", + "pull_request_review_id": 1833161137, + "id": 1459312210, + "node_id": "PRRC_kwDOABII585W-1ZS", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;\n+ if (a[i] > b[i]) return std::strong_ordering::greater;\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Avoid the need for a suppression:\r\n\r\n```c++\r\n// Compute absolute values.\r\nuint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\r\nuint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\r\n// Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\r\n// intentional here.\r\nif (a1 < 0) abs_a1 = ~abs_a1 + 1;\r\nif (a2 < 0) abs_a2 = ~abs_a2 + 1;\r\nif (b1 < 0) abs_b1 = ~abs_b1 + 1;\r\nif (b2 < 0) abs_b2 = ~abs_b2 + 1;\r\n```\r\n\r\n(The same trick is used in `CScriptNum::serialize`, it could be abstracted out)", + "created_at": "2024-01-19T16:38:05Z", + "updated_at": "2024-01-19T17:31:51Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459312210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459312210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 62, + "original_line": 62, + "side": "RIGHT", + "original_position": 63, + "position": 62, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118", + "pull_request_review_id": 1833161137, + "id": 1459315118, + "node_id": "PRRC_kwDOABII585W-2Gu", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: no need for this `namespace` anymore.", + "created_at": "2024-01-19T16:39:47Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459315118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459315118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 13, + "side": "RIGHT", + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281", + "pull_request_review_id": 1833161137, + "id": 1459316281, + "node_id": "PRRC_kwDOABII585W-2Y5", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: this operator can be dropped (C++20 will automatically generate it as negation of `operator==`).", + "created_at": "2024-01-19T16:40:32Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459316281", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459316281" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 125, + "side": "RIGHT", + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381", + "pull_request_review_id": 1833161137, + "id": 1459317381, + "node_id": "PRRC_kwDOABII585W-2qF", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee != b.fee || a.size != b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object is worse than another. */\n+ friend inline bool operator<(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: `operator<`, `operator>`, `operator<=` and `operator>=` can be dropped (C++20 will autogenerate them using `operator<=>` (inspecting the compiled code, it's marginally less efficient, but all the actually performance-critical uses use `operator<<`, `operator>>`, or `FeeRateCompare` anyway).", + "created_at": "2024-01-19T16:41:05Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459317381", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459317381" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 160, + "side": "RIGHT", + "original_position": 160, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324", + "pull_request_review_id": 1833628032, + "id": 1459709324, + "node_id": "PRRC_kwDOABII585XAWWM", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee != b.fee || a.size != b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object is worse than another. */\n+ friend inline bool operator<(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:20Z", + "updated_at": "2024-01-19T20:25:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709324", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709324" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 160, + "side": "RIGHT", + "in_reply_to_id": 1459317381, + "original_position": 160, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417", + "pull_request_review_id": 1833628227, + "id": 1459709417, + "node_id": "PRRC_kwDOABII585XAWXp", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:25Z", + "updated_at": "2024-01-19T20:25:25Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709417", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709417" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 125, + "side": "RIGHT", + "in_reply_to_id": 1459316281, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496", + "pull_request_review_id": 1833628323, + "id": 1459709496, + "node_id": "PRRC_kwDOABII585XAWY4", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:28Z", + "updated_at": "2024-01-19T20:25:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 13, + "side": "RIGHT", + "in_reply_to_id": 1459315118, + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630", + "pull_request_review_id": 1833628458, + "id": 1459709630, + "node_id": "PRRC_kwDOABII585XAWa-", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;\n+ if (a[i] > b[i]) return std::strong_ordering::greater;\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:34Z", + "updated_at": "2024-01-19T20:25:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709630", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709630" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 62, + "original_line": 62, + "side": "RIGHT", + "in_reply_to_id": 1459312210, + "original_position": 63, + "position": 62, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663", + "pull_request_review_id": 1833628511, + "id": 1459709663, + "node_id": "PRRC_kwDOABII585XAWbf", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "looks good, done", + "created_at": "2024-01-19T20:25:36Z", + "updated_at": "2024-01-19T20:25:36Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709663", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709663" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1459309396, + "original_position": 22, + "position": 22, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766", + "pull_request_review_id": 1833628606, + "id": 1459709766, + "node_id": "PRRC_kwDOABII585XAWdG", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:40Z", + "updated_at": "2024-01-19T20:25:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709766", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709766" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 39, + "side": "RIGHT", + "in_reply_to_id": 1459283849, + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852", + "pull_request_review_id": 1833628685, + "id": 1459709852, + "node_id": "PRRC_kwDOABII585XAWec", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:44Z", + "updated_at": "2024-01-19T20:25:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709852", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709852" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 50, + "side": "RIGHT", + "in_reply_to_id": 1459282903, + "original_position": 50, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932", + "pull_request_review_id": 1833628778, + "id": 1459709932, + "node_id": "PRRC_kwDOABII585XAWfs", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:48Z", + "updated_at": "2024-01-19T20:25:48Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709932", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709932" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 47, + "side": "RIGHT", + "in_reply_to_id": 1459281387, + "original_position": 47, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174", + "pull_request_review_id": 1833628978, + "id": 1459710174, + "node_id": "PRRC_kwDOABII585XAWje", + "diff_hunk": "@@ -106,4 +108,23 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts\n+ * @param[in] replacement_fees Fees of replacement package\n+ * @param[in] replacement_vsize Size of replacement package\n+ * @returns error string if mempool diagram doesn't improve, otherwise std::nullopt.\n+ */\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+ EXCLUSIVE_LOCKS_REQUIRED(pool.cs);\n+\n+/** Compares two feerate diagrams. The shorter one is padded with a horizonal line. */\n+std::partial_ordering CompareFeerateDiagram(std::vector& dia0, std::vector& dia1);", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "makes sense, moved", + "created_at": "2024-01-19T20:25:58Z", + "updated_at": "2024-01-19T20:25:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459710174", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459710174" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 128, + "side": "RIGHT", + "in_reply_to_id": 1459264030, + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681", + "pull_request_review_id": 1837231759, + "id": 1462332681, + "node_id": "PRRC_kwDOABII585XKW0J", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In the commit message of \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n> This new function takes the populated sets of\r\n> direct and all conflicts computed in the current\r\n> mempool, assuming the replacements are a single\r\n> chunk, and computes a diagram check.\r\n\r\nThe first sentence is confusing to me. Could you perhaps clarify \"the populated sets of direct and all conflicts\" and split the sentence up?", + "created_at": "2024-01-22T19:42:17Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462332681", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462332681" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934", + "pull_request_review_id": 1837231759, + "id": 1462348934, + "node_id": "PRRC_kwDOABII585XKayG", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nNit: The documentation is in opposite order as the checks. Perhaps switch these two lines.", + "created_at": "2024-01-22T19:55:55Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462348934", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462348934" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1274, + "start_side": "RIGHT", + "line": null, + "original_line": 1264, + "side": "RIGHT", + "original_position": 35, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586", + "pull_request_review_id": 1837231759, + "id": 1462350586, + "node_id": "PRRC_kwDOABII585XKbL6", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n```suggestion\r\n return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\r\n```", + "created_at": "2024-01-22T19:57:44Z", + "updated_at": "2024-01-22T21:59:55Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462350586", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462350586" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1271, + "side": "RIGHT", + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378", + "pull_request_review_id": 1837231759, + "id": 1462365378, + "node_id": "PRRC_kwDOABII585XKezC", + "diff_hunk": "@@ -106,4 +115,20 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nMaybe that’s my unfamiliarity with the mempool code, but it is not obvious to me what \"direct_conflicts\" and \"all_conflicts\" are, and the description here is self-referential. Do these transactions belong to original, replacement, or both, etc.?", + "created_at": "2024-01-22T20:12:42Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462365378", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462365378" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 121, + "start_side": "RIGHT", + "line": null, + "original_line": 122, + "side": "RIGHT", + "original_position": 32, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881", + "pull_request_review_id": 1837231759, + "id": 1462385881, + "node_id": "PRRC_kwDOABII585XKjzZ", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nNit: Spaces around that minus? It took me a moment to realize that dashes aren’t a thing in variables. ", + "created_at": "2024-01-22T20:34:34Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462385881", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462385881" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1335, + "side": "RIGHT", + "original_position": 95, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782", + "pull_request_review_id": 1837231759, + "id": 1462412782, + "node_id": "PRRC_kwDOABII585XKqXu", + "diff_hunk": "@@ -734,6 +735,23 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly (not via descendants)", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n```suggestion\r\n * @param[in] direct_conflicts All transactions that would be removed directly (not by being descendants of conflicting transactions)\r\n```", + "created_at": "2024-01-22T20:55:51Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462412782", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462412782" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 744, + "side": "RIGHT", + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899", + "pull_request_review_id": 1837231759, + "id": 1462453899, + "node_id": "PRRC_kwDOABII585XK0aL", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\nNit: I found the comment here confusing. How about: \"`new_diagram` is strictly better due to the first chunk, while the second chunk is worse.\"", + "created_at": "2024-01-22T21:40:35Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462453899", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462453899" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 296, + "side": "RIGHT", + "original_position": 206, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196", + "pull_request_review_id": 1837231759, + "id": 1462457196, + "node_id": "PRRC_kwDOABII585XK1Ns", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\n\r\nNit: in the new diagram, the last two chunks should be one chunk because the last chunk is better (151 sats, 150 vB) than the prior (249 sats, 250 vB).", + "created_at": "2024-01-22T21:44:38Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462457196", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462457196" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 303, + "start_side": "RIGHT", + "line": null, + "original_line": 304, + "side": "RIGHT", + "original_position": 214, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868", + "pull_request_review_id": 1837231759, + "id": 1462462868, + "node_id": "PRRC_kwDOABII585XK2mU", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Same aggregate fee, but different total size (trigger single tail fee check step)\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ // No change in evaluation when tail check needed.\n+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\n\r\nThis is the same old_diagram. Did you mean to repeat the same transactions,\r\n```suggestion\r\n\r\n old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\r\n new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\r\n```\r\nor just test in both directions?\r\n```suggestion\r\n```", + "created_at": "2024-01-22T21:51:02Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462462868", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462462868" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 326, + "start_side": "RIGHT", + "line": null, + "original_line": 328, + "side": "RIGHT", + "original_position": 238, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056", + "pull_request_review_id": 1838789825, + "id": 1463281056, + "node_id": "PRRC_kwDOABII585XN-Wg", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "direct_conflicts and all_conflicts. Does that help?", + "created_at": "2024-01-23T13:26:49Z", + "updated_at": "2024-01-23T13:26:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463281056", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463281056" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1462332681, + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858", + "pull_request_review_id": 1838797602, + "id": 1463285858, + "node_id": "PRRC_kwDOABII585XN_hi", + "diff_hunk": "@@ -106,4 +115,20 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "direct_conflicts -> the set of transactions that have at least one input conflicting with a proposed transaction.\r\nall_conflicts -> Everything that would be evicted by the proposed transaction\r\n\r\nI'll touch this up a bit but this is the nomenclature elsewhere", + "created_at": "2024-01-23T13:30:37Z", + "updated_at": "2024-01-23T13:30:37Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463285858", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463285858" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 121, + "start_side": "RIGHT", + "line": null, + "original_line": 122, + "side": "RIGHT", + "in_reply_to_id": 1462365378, + "original_position": 32, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427", + "pull_request_review_id": 1838845793, + "id": 1463314427, + "node_id": "PRRC_kwDOABII585XOGf7", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Same aggregate fee, but different total size (trigger single tail fee check step)\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ // No change in evaluation when tail check needed.\n+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I can't recall honestly, removed that line", + "created_at": "2024-01-23T13:51:39Z", + "updated_at": "2024-01-23T13:51:39Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314427", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314427" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 326, + "start_side": "RIGHT", + "line": null, + "original_line": 328, + "side": "RIGHT", + "in_reply_to_id": 1462462868, + "original_position": 238, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511", + "pull_request_review_id": 1838845897, + "id": 1463314511, + "node_id": "PRRC_kwDOABII585XOGhP", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "ah hmm, I'm not sure that matters for correctness of test, but jacked up the last chunk's size just to make it clearer what we're testing", + "created_at": "2024-01-23T13:51:42Z", + "updated_at": "2024-01-23T13:51:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314511", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314511" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 303, + "start_side": "RIGHT", + "line": null, + "original_line": 304, + "side": "RIGHT", + "in_reply_to_id": 1462457196, + "original_position": 214, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570", + "pull_request_review_id": 1838845988, + "id": 1463314570, + "node_id": "PRRC_kwDOABII585XOGiK", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "tried my own re-explanation. I agree as-is is confusing", + "created_at": "2024-01-23T13:51:45Z", + "updated_at": "2024-01-23T13:51:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314570", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314570" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 296, + "side": "RIGHT", + "in_reply_to_id": 1462453899, + "original_position": 206, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620", + "pull_request_review_id": 1838846083, + "id": 1463314620, + "node_id": "PRRC_kwDOABII585XOGi8", + "diff_hunk": "@@ -734,6 +735,23 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly (not via descendants)", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "tried my own explanation", + "created_at": "2024-01-23T13:51:47Z", + "updated_at": "2024-01-23T13:51:47Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314620", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314620" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 744, + "side": "RIGHT", + "in_reply_to_id": 1462412782, + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778", + "pull_request_review_id": 1838846344, + "id": 1463314778, + "node_id": "PRRC_kwDOABII585XOGla", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-01-23T13:51:54Z", + "updated_at": "2024-01-23T13:51:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314778", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314778" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1335, + "side": "RIGHT", + "in_reply_to_id": 1462385881, + "original_position": 95, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597", + "pull_request_review_id": 1838847715, + "id": 1463315597, + "node_id": "PRRC_kwDOABII585XOGyN", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken", + "created_at": "2024-01-23T13:52:33Z", + "updated_at": "2024-01-23T13:52:33Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315597", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315597" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1271, + "side": "RIGHT", + "in_reply_to_id": 1462350586, + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777", + "pull_request_review_id": 1838847976, + "id": 1463315777, + "node_id": "PRRC_kwDOABII585XOG1B", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-23T13:52:40Z", + "updated_at": "2024-01-23T13:52:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315777", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315777" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1274, + "start_side": "RIGHT", + "line": null, + "original_line": 1264, + "side": "RIGHT", + "in_reply_to_id": 1462348934, + "original_position": 35, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645", + "pull_request_review_id": 1839710319, + "id": 1463859645, + "node_id": "PRRC_kwDOABII585XQLm9", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yeah, that would improve it", + "created_at": "2024-01-23T19:05:54Z", + "updated_at": "2024-01-23T19:05:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463859645", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463859645" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1462332681, + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198", + "pull_request_review_id": 1839716607, + "id": 1463863198, + "node_id": "PRRC_kwDOABII585XQMee", + "diff_hunk": "@@ -734,6 +735,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input wih a proposed transaction", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n * having a conflicting input with a proposed transaction\r\n```", + "created_at": "2024-01-23T19:09:34Z", + "updated_at": "2024-01-23T19:14:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463863198", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463863198" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 745, + "side": "RIGHT", + "original_position": 19, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212", + "pull_request_review_id": 1839716607, + "id": 1463866212, + "node_id": "PRRC_kwDOABII585XQNNk", + "diff_hunk": "@@ -217,15 +232,154 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)\n+ const auto tx3 = make_tx(/*inputs=*/ {tx2}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx3));\n+ const auto res3 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size);\n+ BOOST_CHECK(res3.has_value());\n+ BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n+ BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "If all diagrams always start with `FeeFrac{0, 0}`, why do we need to mention that as a first element?", + "created_at": "2024-01-23T19:12:38Z", + "updated_at": "2024-01-23T19:14:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463866212", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463866212" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 508, + "original_start_line": 327, + "start_side": "RIGHT", + "line": 509, + "original_line": 509, + "side": "RIGHT", + "original_position": 238, + "position": 418, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538", + "pull_request_review_id": 1843766331, + "id": 1466391538, + "node_id": "PRRC_kwDOABII585XZ1vy", + "diff_hunk": "@@ -734,6 +735,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input wih a proposed transaction", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-01-25T13:37:24Z", + "updated_at": "2024-01-25T13:37:24Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466391538", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466391538" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 745, + "side": "RIGHT", + "in_reply_to_id": 1463863198, + "original_position": 19, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222", + "pull_request_review_id": 1843767479, + "id": 1466392222, + "node_id": "PRRC_kwDOABII585XZ16e", + "diff_hunk": "@@ -217,15 +232,154 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)\n+ const auto tx3 = make_tx(/*inputs=*/ {tx2}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx3));\n+ const auto res3 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size);\n+ BOOST_CHECK(res3.has_value());\n+ BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n+ BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I'll leave this as an ergonomics issue for later debate", + "created_at": "2024-01-25T13:37:59Z", + "updated_at": "2024-01-25T13:38:00Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466392222", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466392222" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 508, + "original_start_line": 327, + "start_side": "RIGHT", + "line": 509, + "original_line": 509, + "side": "RIGHT", + "in_reply_to_id": 1463866212, + "original_position": 238, + "position": 418, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777", + "pull_request_review_id": 1849127187, + "id": 1469871777, + "node_id": "PRRC_kwDOABII585XnHah", + "diff_hunk": "@@ -0,0 +1,164 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "c5e63487c52835645c5cda9779500a000c3a023c", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n int64_t fee;\r\n int32_t size;\r\n```\r\n\r\nShould their be more information that will describe the transaction size and fee, base / modified fee, vsize in bytes or something of that sort.\r\nIf not I think its okay like this.\r\n\r\n---\r\nUnrelated just asking to learn.\r\nWhy are'nt we using `CAmount` here for the fee?\r\n\r\nIn some places I see transaction size as `uint32_t` while some places its `int32_t`.\r\n\r\nShould we have a type for size just like `CAmount`?", + "created_at": "2024-01-29T16:37:19Z", + "updated_at": "2024-01-29T21:18:17Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1469871777", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1469871777" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 63, + "start_side": "RIGHT", + "line": null, + "original_line": 64, + "side": "RIGHT", + "original_position": 66, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523", + "pull_request_review_id": 1875569689, + "id": 1486385523, + "node_id": "PRRC_kwDOABII585YmHFz", + "diff_hunk": "@@ -0,0 +1,164 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "c5e63487c52835645c5cda9779500a000c3a023c", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "> If not I think its okay like this.\r\n\r\nremoved comments, how it's precisely used is an implementation detail outside of this code", + "created_at": "2024-02-12T15:54:53Z", + "updated_at": "2024-02-12T15:54:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1486385523", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1486385523" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 63, + "start_side": "RIGHT", + "line": null, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1469871777, + "original_position": 66, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848", + "pull_request_review_id": 1878540108, + "id": 1488282848, + "node_id": "PRRC_kwDOABII585YtWTg", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "In implementation they are sorted in increasing fee rate and the chunks in the comments should be ordered as is? and also the 0 fee and size chucks sorts first. \r\n```suggestion\r\n * by decreasing size. The empty FeeFrac (fee and size both 0) sorts first. So for example, the\r\n * following FeeFracs are in sorted order:\r\n *\r\n * - fee=0 size=0 (undefined feerate)\r\n * - fee=2 size=1 (feerate 2)\r\n * - fee=3 size=2 (feerate 1.5)\r\n * - fee=1 size=1 (feerate 1)\r\n * - fee=2 size=2 (feerate 1)\r\n * - fee=2 size=3 (feerate 0.667...)\r\n * - fee=1 size=2 (feerate 0.5)\r\n * - fee=0 size=1 (feerate 0)\r\n```", + "created_at": "2024-02-13T17:16:44Z", + "updated_at": "2024-02-13T17:35:07Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488282848", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488282848" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682", + "pull_request_review_id": 1878540108, + "id": 1488285682, + "node_id": "PRRC_kwDOABII585YtW_y", + "diff_hunk": "@@ -1235,3 +1236,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe add unit test for `CalculateFeerateDiagramsForRBF` also?", + "created_at": "2024-02-13T17:18:40Z", + "updated_at": "2024-02-13T17:34:23Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488285682", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488285682" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1283, + "side": "RIGHT", + "original_position": 53, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016", + "pull_request_review_id": 1878540108, + "id": 1488290016, + "node_id": "PRRC_kwDOABII585YtYDg", + "diff_hunk": "@@ -0,0 +1,127 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint64_t accum{0};\n+ for (int i = 0; i + pos < 4; ++i) {\n+ // Add current value at limb pos in ret.\n+ accum += ret[3 - pos - i];\n+ // Add low or high half of v.\n+ if (i == 0) accum += v & 0xffffffff;\n+ if (i == 1) accum += v >> 32;\n+ // Store lower half of result in limb pos in ret.\n+ ret[3 - pos - i] = accum & 0xffffffff;\n+ // Leave carry in accum.\n+ accum >>= 32;\n+ }\n+ // Make sure no overflow.\n+ assert(accum == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^32).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::array */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] != b[i]) return a[i] <=> b[i];\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.\n+ uint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\n+ uint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\n+ // Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\n+ // intentional here.\n+ if (a1 < 0) abs_a1 = ~abs_a1 + 1;\n+ if (a2 < 0) abs_a2 = ~abs_a2 + 1;\n+ if (b1 < 0) abs_b1 = ~abs_b1 + 1;\n+ if (b2 < 0) abs_b2 = ~abs_b2 + 1;\n+\n+ // Compute products of absolute values.\n+ auto mul_abs_a = Mul128(abs_a1, abs_a2);\n+ auto mul_abs_b = Mul128(abs_b1, abs_b2);\n+ if (sign_a < 0) {\n+ return compare_arrays(mul_abs_b, mul_abs_a);\n+ } else {\n+ return compare_arrays(mul_abs_a, mul_abs_b);\n+ }\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(feefrac)\n+{\n+ FuzzedDataProvider provider(buffer.data(), buffer.size());\n+\n+ int64_t f1 = provider.ConsumeIntegral();\n+ //int64_t f1 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);\n+ int32_t s1 = provider.ConsumeIntegral();\n+ if (s1 == 0) f1 = 0;\n+ FeeFrac fr1(f1, s1);\n+ assert(fr1.IsEmpty() == (s1 == 0));\n+\n+ int64_t f2 = provider.ConsumeIntegral();\n+ //int64_t f2 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Why not delete the commented version of f1 and f2.\r\n```suggestion\r\n int32_t s1 = provider.ConsumeIntegral();\r\n if (s1 == 0) f1 = 0;\r\n FeeFrac fr1(f1, s1);\r\n assert(fr1.IsEmpty() == (s1 == 0));\r\n\r\n int64_t f2 = provider.ConsumeIntegral();\r\n \r\n```", + "created_at": "2024-02-13T17:21:35Z", + "updated_at": "2024-02-13T17:35:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488290016", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488290016" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 89, + "start_side": "RIGHT", + "line": null, + "original_line": 98, + "side": "RIGHT", + "original_position": 98, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971", + "pull_request_review_id": 1880803374, + "id": 1489790971, + "node_id": "PRRC_kwDOABII585YzGf7", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "> If `old`, `new`, and `tail` are CFeeFrac objects, this condition is exactly `!((new - old) << tail)`. If new is smaller than old, the `new - old` object has negative size.\r\n\r\n@sipa With the various `Assume()` calls that check that if the size is 0, the fee must also be zero, doesn't that mean that we can't really write code like this example you gave? Unless we checked that new != old first -- otherwise you might create a FeeFrac with 0 size and non-zero fee.\r\n", + "created_at": "2024-02-14T16:54:49Z", + "updated_at": "2024-02-14T16:54:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1489790971", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1489790971" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 1 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524", + "pull_request_review_id": 1881279355, + "id": 1490043524, + "node_id": "PRRC_kwDOABII585Y0EKE", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I don't understand your comment, sorry. They're listed in increasing feerate, with decreasing size as a tie breaker.", + "created_at": "2024-02-14T20:44:55Z", + "updated_at": "2024-02-14T20:44:55Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1490043524", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1490043524" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911", + "pull_request_review_id": 1882814496, + "id": 1491039911, + "node_id": "PRRC_kwDOABII585Y33an", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes but in reverse I think.\r\nSuppose to be the other way around no?\r\n\r\nA sorted `FeeFracs` should have undefined chunks first, the highest fee rate chunk second continuously...\r\nIf their is a tie, the chunk with lower size comes first.\r\nHence the are sorted in increasing fee rates, and then by decreasing size.\r\n\r\nI've added test to verify this here https://github.com/ismaelsadeeq/bitcoin/commit/8ce89b132f4304a7feda067a88fd0a72330044a6, this test passed on this branch.", + "created_at": "2024-02-15T13:50:37Z", + "updated_at": "2024-02-15T13:50:37Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491039911", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491039911" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223", + "pull_request_review_id": 1882829496, + "id": 1491046223, + "node_id": "PRRC_kwDOABII585Y349P", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "@ismaelsadeeq The comparator you provide to `std::sort` is supposed to return whether the first argument should sort *before* the second one (if no comparator is provided, `operator<` is used). With that, you should see lowest feerate first, highest feerate last, and the undefined feefrac at the very end. Within equal-feerate groups, larger size comes first.", + "created_at": "2024-02-15T13:55:11Z", + "updated_at": "2024-02-15T13:55:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491046223", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491046223" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596", + "pull_request_review_id": 1882850491, + "id": 1491054596, + "node_id": "PRRC_kwDOABII585Y37AE", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes thanks for clarification 👍🏾 ", + "created_at": "2024-02-15T14:00:43Z", + "updated_at": "2024-02-15T14:00:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491054596", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491054596" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699", + "pull_request_review_id": 1882865782, + "id": 1491060699, + "node_id": "PRRC_kwDOABII585Y38fb", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I looked at it the other way around, using the result from `BuildDiagramFromUnsortedChunks` sort which uses custom > operator @instagibbs.", + "created_at": "2024-02-15T14:05:11Z", + "updated_at": "2024-02-15T14:05:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491060699", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491060699" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655", + "pull_request_review_id": 1882920075, + "id": 1491090655, + "node_id": "PRRC_kwDOABII585Y4Dzf", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "@sdaftuar Indeed. It wouldn't require anything more than dropping those `Assume()` calls, but right now FeeFrac objects represent (the aggregate fee and size of) sets of transactions, rather differences between such aggregates (as would be needed for this use case).", + "created_at": "2024-02-15T14:25:20Z", + "updated_at": "2024-02-15T14:25:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491090655", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491090655" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059", + "pull_request_review_id": 1883351956, + "id": 1491329059, + "node_id": "PRRC_kwDOABII585Y4-Aj", + "diff_hunk": "@@ -1235,3 +1236,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "good point; added", + "created_at": "2024-02-15T16:52:44Z", + "updated_at": "2024-02-15T16:52:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329059", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329059" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1283, + "side": "RIGHT", + "in_reply_to_id": 1488285682, + "original_position": 53, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325", + "pull_request_review_id": 1883352369, + "id": 1491329325, + "node_id": "PRRC_kwDOABII585Y4-Et", + "diff_hunk": "@@ -0,0 +1,127 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint64_t accum{0};\n+ for (int i = 0; i + pos < 4; ++i) {\n+ // Add current value at limb pos in ret.\n+ accum += ret[3 - pos - i];\n+ // Add low or high half of v.\n+ if (i == 0) accum += v & 0xffffffff;\n+ if (i == 1) accum += v >> 32;\n+ // Store lower half of result in limb pos in ret.\n+ ret[3 - pos - i] = accum & 0xffffffff;\n+ // Leave carry in accum.\n+ accum >>= 32;\n+ }\n+ // Make sure no overflow.\n+ assert(accum == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^32).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::array */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] != b[i]) return a[i] <=> b[i];\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.\n+ uint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\n+ uint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\n+ // Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\n+ // intentional here.\n+ if (a1 < 0) abs_a1 = ~abs_a1 + 1;\n+ if (a2 < 0) abs_a2 = ~abs_a2 + 1;\n+ if (b1 < 0) abs_b1 = ~abs_b1 + 1;\n+ if (b2 < 0) abs_b2 = ~abs_b2 + 1;\n+\n+ // Compute products of absolute values.\n+ auto mul_abs_a = Mul128(abs_a1, abs_a2);\n+ auto mul_abs_b = Mul128(abs_b1, abs_b2);\n+ if (sign_a < 0) {\n+ return compare_arrays(mul_abs_b, mul_abs_a);\n+ } else {\n+ return compare_arrays(mul_abs_a, mul_abs_b);\n+ }\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(feefrac)\n+{\n+ FuzzedDataProvider provider(buffer.data(), buffer.size());\n+\n+ int64_t f1 = provider.ConsumeIntegral();\n+ //int64_t f1 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);\n+ int32_t s1 = provider.ConsumeIntegral();\n+ if (s1 == 0) f1 = 0;\n+ FeeFrac fr1(f1, s1);\n+ assert(fr1.IsEmpty() == (s1 == 0));\n+\n+ int64_t f2 = provider.ConsumeIntegral();\n+ //int64_t f2 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "mistakenly left at some point; removed", + "created_at": "2024-02-15T16:52:56Z", + "updated_at": "2024-02-15T16:52:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329325", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329325" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 89, + "start_side": "RIGHT", + "line": null, + "original_line": 98, + "side": "RIGHT", + "in_reply_to_id": 1488290016, + "original_position": 98, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674", + "pull_request_review_id": 1883354202, + "id": 1491330674, + "node_id": "PRRC_kwDOABII585Y4-Zy", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I added some additional feefrac fuzzing for the +/- operations, marking as resolved", + "created_at": "2024-02-15T16:53:49Z", + "updated_at": "2024-02-15T16:53:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491330674", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491330674" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771", + "pull_request_review_id": 1885627769, + "id": 1492766771, + "node_id": "PRRC_kwDOABII585Y-dAz", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "this is odd, should we just `Assume()` `replacement_vsize>0` in `CalculateFeerateDiagramsForRBF`?", + "created_at": "2024-02-16T17:14:29Z", + "updated_at": "2024-02-16T17:14:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492766771", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492766771" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 354, + "side": "RIGHT", + "original_position": 46, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210", + "pull_request_review_id": 1885883009, + "id": 1492915210, + "node_id": "PRRC_kwDOABII585Y_BQK", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes, I can't think of a scenario where that will happen!", + "created_at": "2024-02-16T19:41:22Z", + "updated_at": "2024-02-16T19:41:22Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 354, + "side": "RIGHT", + "in_reply_to_id": 1492766771, + "original_position": 46, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977", + "pull_request_review_id": 1885884419, + "id": 1492915977, + "node_id": "PRRC_kwDOABII585Y_BcJ", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit:\r\n```suggestion\r\n const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\r\n```", + "created_at": "2024-02-16T19:42:15Z", + "updated_at": "2024-02-16T19:42:15Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915977", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915977" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 326, + "side": "RIGHT", + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062", + "pull_request_review_id": 1886533962, + "id": 1493302062, + "node_id": "PRRC_kwDOABII585ZAfsu", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string3.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto err_string4{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string4.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto err_string5{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto err_string6{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal}, old_diagram, new_diagram)};\n+ BOOST_CHECK(err_string6.has_value());\n+ BOOST_CHECK(err_string6.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ BOOST_CHECK(old_diagram.empty());\n+ BOOST_CHECK(new_diagram.empty());\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2= make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto err_string7{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+ old_diagram.clear();\n+ new_diagram.clear();\n }", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe weshould also check that we can have more than two directly conflicting transactions as long as they are all in a cluster size <=2.\r\n\r\n
\r\ndiff \r\n\r\n```diff\r\ndiff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp\r\nindex e15fd29da3..561ebd3881 100644\r\n--- a/src/test/rbf_tests.cpp\r\n+++ b/src/test/rbf_tests.cpp\r\n@@ -431,6 +431,53 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\r\n BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\r\n old_diagram.clear();\r\n new_diagram.clear();\r\n+\r\n+ // You can more than two direct conflicts, if all the directly conflicting transactions are in a cluster size < 2\r\n+ const auto conflict_1 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1));\r\n+ const auto conflict_1_entry = pool.GetIter(conflict_1->GetHash()).value();\r\n+\r\n+ const auto conflict_2 = make_tx(/*inputs=*/ {m_coinbase_txns[3]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_2));\r\n+ const auto conflict_2_entry = pool.GetIter(conflict_2->GetHash()).value();\r\n+\r\n+ const auto conflict_3 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_3));\r\n+ const auto conflict_3_entry = pool.GetIter(conflict_3->GetHash()).value();\r\n+\r\n+ const auto err_string8{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_ent\r\nry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(!err_string8.has_value());\r\n+ BOOST_CHECK(old_diagram.size() == 4);\r\n+ BOOST_CHECK(new_diagram.size() == 2);\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n+\r\n+ // Add a child transaction to conflict_1 and make it cluster size 2\r\n+ const auto conflict_1_child = make_tx(/*inputs=*/{conflict_1}, /*output_values=*/ {995 * CENT});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1_child));\r\n+ const auto conflict_1_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();\r\n+\r\n+ const auto err_string9{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_ent\r\nry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(!err_string8.has_value());\r\n+ BOOST_CHECK(old_diagram.size() == 4);\r\n+ BOOST_CHECK(new_diagram.size() == 2);\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n+\r\n+\r\n+ // Add another descendant to conflict_1, making the cluster size > 2 should fail at this point.\r\n+ const auto conflict_1_grand_child = make_tx(/*inputs=*/{conflict_1_child}, /*output_values=*/ {995 * CENT});\r\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(conflict_1_grand_child));\r\n+ const auto conflict_1_grand_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();\r\n+\r\n+ const auto err_string10{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_en\r\ntry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(err_string10.has_value());\r\n+ BOOST_CHECK(err_string10.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", conflict_1->GetHash().GetHex()));\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n }\r\n \r\n BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\r\n```\r\n
", + "created_at": "2024-02-17T10:43:13Z", + "updated_at": "2024-02-17T10:44:01Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302062", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302062" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 495, + "original_line": 495, + "side": "RIGHT", + "original_position": 126, + "position": 404, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276", + "pull_request_review_id": 1886534107, + "id": 1493302276, + "node_id": "PRRC_kwDOABII585ZAfwE", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "here an another place below!", + "created_at": "2024-02-17T10:44:31Z", + "updated_at": "2024-02-17T10:46:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302276", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302276" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 326, + "side": "RIGHT", + "in_reply_to_id": 1492915977, + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857", + "pull_request_review_id": 1886598516, + "id": 1493358857, + "node_id": "PRRC_kwDOABII585ZAtkJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think we should drop the `Assume()` calls, as otherwise I think we ought to do more to ensure that using operator- on FeeFrac's is safe everywhere that it might be invoked.", + "created_at": "2024-02-17T15:42:48Z", + "updated_at": "2024-02-17T15:43:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857/reactions", + "total_count": 3, + "+1": 3, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169", + "pull_request_review_id": 1886598977, + "id": 1493359169, + "node_id": "PRRC_kwDOABII585ZAtpB", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: As the functions here don't relate to the `FeeFrac` implementation, perhaps this should be in a different file? `feerate_diagram.cpp` maybe?", + "created_at": "2024-02-17T15:44:22Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359169", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359169" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 1, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700", + "pull_request_review_id": 1886598977, + "id": 1493359700, + "node_id": "PRRC_kwDOABII585ZAtxU", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: \"direction coefficient\" is not a term I'm familiar with (and from googling it doesn't seem like a super common term); perhaps it would be clearer to just use the word \"slope\" here?", + "created_at": "2024-02-17T15:48:07Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359700", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359700" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 50, + "start_side": "RIGHT", + "line": null, + "original_line": 51, + "side": "RIGHT", + "original_position": 51, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467", + "pull_request_review_id": 1886598977, + "id": 1493390467, + "node_id": "PRRC_kwDOABII585ZA1SD", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);\n+\n+/** Compares two feerate diagrams (which must both start at size=0). The shorter one is implicitly\n+ * extended with a horizontal straight line. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: Could add a comment here more precisely defining the preconditions for this function and what definition we are using for feerate diagram: specifically that a feerate diagram consists of a list of (fee, size) points with the property that size is strictly increasing and that the first entry is (0, 0). (If these conditions are violated then the function can fail with an `Assume()` failure.)", + "created_at": "2024-02-17T19:20:14Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493390467", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493390467" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 159, + "side": "RIGHT", + "original_position": 159, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184", + "pull_request_review_id": 1886598977, + "id": 1493391184, + "node_id": "PRRC_kwDOABII585ZA1dQ", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: \"fee vs. size diagram\" -- maybe we should standardize the terminology to \"feerate diagram\"? I was also thinking about adding some documentation to doc/policy/mempool-replacements.md explaining what we're doing now.", + "created_at": "2024-02-17T19:25:36Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493391184", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493391184" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 193, + "side": "RIGHT", + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259", + "pull_request_review_id": 1886598977, + "id": 1493401259, + "node_id": "PRRC_kwDOABII585ZA36r", + "diff_hunk": "@@ -733,6 +734,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: Maybe update the comment to be more explicit that this function only works for the situation where (replacement_fees, replacement_size) corresponds to a transaction package that has no in-mempool dependences.", + "created_at": "2024-02-17T20:43:39Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493401259", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493401259" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 757, + "side": "RIGHT", + "original_position": 25, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950", + "pull_request_review_id": 1887031929, + "id": 1493417950, + "node_id": "PRRC_kwDOABII585ZA7_e", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Oh, I seem to have translated literally from Dutch. \"Slope\" is indeed the proper English translation.", + "created_at": "2024-02-17T21:35:23Z", + "updated_at": "2024-02-17T21:35:23Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493417950", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493417950" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 50, + "start_side": "RIGHT", + "line": null, + "original_line": 51, + "side": "RIGHT", + "in_reply_to_id": 1493359700, + "original_position": 51, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026", + "pull_request_review_id": 1887045764, + "id": 1493469026, + "node_id": "PRRC_kwDOABII585ZBIdi", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Curious to know the full meaning of `FeeFrac` is it Fee Fraction?\r\nMaybe Chunk will be a better name?", + "created_at": "2024-02-17T23:22:50Z", + "updated_at": "2024-02-22T18:07:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493469026", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493469026" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 1, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1493359169, + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692", + "pull_request_review_id": 1890224651, + "id": 1495685692, + "node_id": "PRRC_kwDOABII585ZJlo8", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yeah, it means \"fee fraction\", though the name isn't perfect - it really represents any ratio where the numerator is an `int64_t` and the denominator is an `int32_t`, with a sort order that tie-breaks by putting larger denominators last.\r\n\r\nI don't think Chunk is a good name, as we're using that term for a subset of transactions. A `FeeFrac` is related, but represents the aggregate feerate of a chunk (or really of any set of transactions, or even the difference between the fees/sizes of two sets of transactions).", + "created_at": "2024-02-20T11:46:52Z", + "updated_at": "2024-02-20T11:46:52Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495685692", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495685692" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1493359169, + "original_position": 1, + "position": 1, + "subject_type": "line" + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/comments/1.json b/client/fresheyes-bot/comments/1.json new file mode 100644 index 0000000..b884d48 --- /dev/null +++ b/client/fresheyes-bot/comments/1.json @@ -0,0 +1,1146 @@ +[ + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889741023", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889741023", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889741023, + "node_id": "IC_kwDOABII585woyjf", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T18:07:47Z", + "updated_at": "2024-03-25T19:54:23Z", + "author_association": "CONTRIBUTOR", + "body": "\n\nThe following sections might be updated with supplementary metadata relevant to reviewers and maintainers.\n\n\n### Code Coverage\nFor detailed information about the code coverage, see the [test coverage report](https://corecheck.dev/bitcoin/bitcoin/pulls/29242).\n\n### Reviews\nSee [the guideline](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md#code-review) for information on the review process.\n| Type | Reviewers |\n| ---- | --------- |\n| ACK | [sipa](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943349194), [glozow](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1945992726), [murchandamus](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1937534483), [ismaelsadeeq](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948352078), [willcl-ark](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948504420), [sdaftuar](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958602404) |\n| Concept ACK | [hebasto](https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1959901619) |\n\nIf your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.\n\n### Conflicts\nNo conflicts as of last run.\n", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889741023/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889768276", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889768276", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889768276, + "node_id": "IC_kwDOABII585wo5NU", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T18:29:27Z", + "updated_at": "2024-01-12T18:29:27Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20435922692", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889768276/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889982713", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889982713", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889982713, + "node_id": "IC_kwDOABII585wptj5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T21:38:22Z", + "updated_at": "2024-01-12T21:38:22Z", + "author_association": "MEMBER", + "body": "ready for review\r\n\r\ncc @glozow @ismaelsadeeq @achow101 ", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889982713/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1899159499", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1899159499", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1899159499, + "node_id": "IC_kwDOABII585xMt_L", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-18T20:29:48Z", + "updated_at": "2024-01-18T20:29:48Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20632055548", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1899159499/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901072804", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1901072804", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1901072804, + "node_id": "IC_kwDOABII585xUBGk", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-19T20:32:35Z", + "updated_at": "2024-01-19T20:32:35Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20672153966", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901072804/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901152779", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1901152779", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1901152779, + "node_id": "IC_kwDOABII585xUUoL", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-19T21:42:00Z", + "updated_at": "2024-01-19T21:42:00Z", + "author_association": "MEMBER", + "body": "test failure appears to be spurious wallet failure, ready for review", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901152779/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1902638542", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1902638542", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1902638542, + "node_id": "IC_kwDOABII585xZ_XO", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-21T14:00:29Z", + "updated_at": "2024-01-21T14:00:29Z", + "author_association": "MEMBER", + "body": "In https://github.com/sipa/bitcoin/commits/pr29242 I pushed another commit which makes `CompareFeerateDiagram` not modify the diagrams in-place.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1902638542/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1904479665", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1904479665", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1904479665, + "node_id": "IC_kwDOABII585xhA2x", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-22T17:30:57Z", + "updated_at": "2024-01-22T17:30:57Z", + "author_association": "MEMBER", + "body": "> In https://github.com/sipa/bitcoin/commits/pr29242 I pushed another commit which makes CompareFeerateDiagram not modify the diagrams in-place.\r\n\r\nTaken only with minor comment changes, and added another test case or two to cover the iterative nature of the check", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1904479665/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906111930", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1906111930", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1906111930, + "node_id": "IC_kwDOABII585xnPW6", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-23T13:56:12Z", + "updated_at": "2024-01-23T13:56:12Z", + "author_association": "MEMBER", + "body": "@murchandamus comments should be addressed or taken", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906111930/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906919216", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1906919216", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1906919216, + "node_id": "IC_kwDOABII585xqUcw", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-23T21:07:22Z", + "updated_at": "2024-01-23T21:07:22Z", + "author_association": "MEMBER", + "body": "```\r\n$ echo \"BAIBAgICAgIABfcN/f11BwAAAPsAAAICAgICAgICAi0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwb3J0AgL+//////8hAQICAooBATIBAR4AAgICAgICAgICAgICAgICAgICAgICAgIC/v///////wECAgKKAQEyAQEeAgIiAgICAgICHgACAgIDAgICAgICAiICAgICAExLQAICAgICAgICAv//////////////////////////////////////////////////////AQEBAQEByQEBAQEBAQEB/P8AAC8AGvsAXAEAAgLcAgICAgICAlSbtqZ56uTNNhvmIHMu83ifTNtXiVGR9z3J4We8dnhZegAAAAAAAAD/AAAAAAAHAAAAAAAAXP96AAAAAgICAgAF9w39/QAAAAEAAAABAgICAgICAgICLZCPcnQCAgIC3AICAgICAgJUm7ameerkzRvmIHMu83ifTNtXiVGR9z3J4We8dnhZegAAAAAAAAAAAAAAAAcABgEAAAAAAAAAAAAAAPsCIlwBAAAHAAAAAQAAAAmLXAEVAAAAAAAAAAAAAAAAAAAAXP+B/////////wAAAAAABwAAAAAAAAAAAAAABwAALAACAgIATEtAAgICAgICAgIC//////////////////////////////////////////////////////8BAQEBAQHJAQEBAQEBAQH8/wAALwAa+wBcAQACAtwCAgICAgICVJu2pnnq5M02G+Ygcy7zeJ9M21eJUZH3PcnhZ7x2eFl6AAAAAAAAAP8AAAAAAAcAAAAAAABc/3oAAAACAgICAAX3Df39AAAAAQAAAAECAgICAgICAgItkI9ydAICAgLcAgICAgICAlSbtqZ56uTNG+Ygcy7zeJ9M21eJUZH3PcnhZ7x2eFl6AAAAAAAAAAAAAAAABwAGAQAAAAAAAAAAAAAA+wIiXAEAAAcAAAABAAAACYtcARUAAAAAAAAAAAAAAAAAAABc/4H/////////AAAAAAAHAAAAAAAAAAAAAAAHAAAsAAAAAPsCAlwBAAAHAAAAAQAAAAmLXAEDAwMDAwMD/729vb29vb29vb29vb29vb29vb29vb29vT+9/wUtYmluvb29vb29vb29vb29vb29vb29vb29/wUtYmluZC0U/////wAAAAAAAAAAHAAAAAAAAP///////////////////////4pVyFwAAAD7AgJcAQAABwAAAAEAAAAJi1wBAwMDAwMDA/+9vb29vb29vb29vb29vb29vb29vb29vb0/vf8FLWJpbr29vb29vb29vb29vb29vb29vb29vf8FLWJpbmQtFP////8AAAAAAAAAABwAAAAAAAD///////////////////////+KVchcToownpjPpiYHL06aRtJ04wyb/sdpyYUpxMKugP////////////////////////9t////AQAAAEZFRUVFRUVFRUVFRUVFRUVFRUVFRUVF/////////////////////3r//////////wMDAwP//////w==\" | base64 --decode > package_rbf-7d643e62d75f4ac67d3bdeaf9f5fbfd67675806a.crash\r\n$ FUZZ=package_rbf ./src/test/fuzz/fuzz package_rbf-7d643e62d75f4ac67d3bdeaf9f5fbfd67675806a.crash\r\nfuzz_libfuzzer: test/fuzz/rbf.cpp:147: void package_rbf_fuzz_target(FuzzBufferType): Assertion `old_diagram.back().fee - replaced_fee + replacement_fees == new_diagram.back().fee' failed.\r\n```", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906919216/reactions", + "total_count": 2, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 1, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908321622", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1908321622", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1908321622, + "node_id": "IC_kwDOABII585xvq1W", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-24T15:07:22Z", + "updated_at": "2024-01-24T15:07:22Z", + "author_association": "MEMBER", + "body": "@dergoegge fuzzer created a circular reference which caused incongruities between descendant counts and actually walking the descendants in mempool. Please run again?", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908321622/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908435057", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1908435057", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1908435057, + "node_id": "IC_kwDOABII585xwGhx", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-24T16:03:55Z", + "updated_at": "2024-01-24T16:03:55Z", + "author_association": "MEMBER", + "body": "> Please run again?\r\n\r\nRunning now.\r\n\r\nSome coverage reports from the previous runs (one per harness): http://bitcoind-fuzz.dergoegge.de/instagibbs/bitcoin/2024-01-diagram-checks/coverage/", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908435057/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 1, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1910238997", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1910238997", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1910238997, + "node_id": "IC_kwDOABII585x2-8V", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-25T13:38:11Z", + "updated_at": "2024-01-25T13:38:11Z", + "author_association": "MEMBER", + "body": "didn't see any fuzzer crashes locally, all comments addressed", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1910238997/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1924448996", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1924448996", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1924448996, + "node_id": "IC_kwDOABII585ytMLk", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-02T18:22:56Z", + "updated_at": "2024-02-02T18:22:56Z", + "author_association": "CONTRIBUTOR", + "body": "ACK a1414b3388a870aeb463e9cc293d47cbd86e7f0e \r\n\r\nvia rangediff a14b95129d3a2894b7a41ce919a426bb60f62e35..a1414b3388a870aeb463e9cc293d47cbd86e7f0e\r\n\r\nThe changes since my prior ACK appear to only pertain to improvements in the fuzz test to avoid circular packages and a typo fix on a comment in the code.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1924448996/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1938973409", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1938973409", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1938973409, + "node_id": "IC_kwDOABII585zkmLh", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-12T15:56:32Z", + "updated_at": "2024-02-12T15:56:32Z", + "author_association": "MEMBER", + "body": "rebased", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1938973409/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1946580499", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1946580499", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1946580499, + "node_id": "IC_kwDOABII5850BnYT", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-15T16:56:11Z", + "updated_at": "2024-02-15T16:56:11Z", + "author_association": "MEMBER", + "body": "addressed all comments", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1946580499/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1954669587", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1954669587", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1954669587, + "node_id": "IC_kwDOABII5850geQT", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-20T17:10:41Z", + "updated_at": "2024-02-20T17:10:41Z", + "author_association": "MEMBER", + "body": "> I commented https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857 that I think we should drop the Assume(size != 0 || fee == 0) calls in feefrac.h, so that we don't have to police all the places we invoke operator- to make sure we can never accidentally violate that.\r\nAnother nit: in the commit message for commit https://github.com/bitcoin/bitcoin/commit/860823fb93212fa78ab928589bd403da462be222, it should say \"FeeFrac\" and not \"FeeFrace\"\r\n\r\nAddressed these by removing Assumes and updating the commit text", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1954669587/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1959901619", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1959901619", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1959901619, + "node_id": "IC_kwDOABII58500bmz", + "user": { + "login": "hebasto", + "id": 32963518, + "node_id": "MDQ6VXNlcjMyOTYzNTE4", + "avatar_url": "https://avatars.githubusercontent.com/u/32963518?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/hebasto", + "html_url": "https://github.com/hebasto", + "followers_url": "https://api.github.com/users/hebasto/followers", + "following_url": "https://api.github.com/users/hebasto/following{/other_user}", + "gists_url": "https://api.github.com/users/hebasto/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hebasto/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hebasto/subscriptions", + "organizations_url": "https://api.github.com/users/hebasto/orgs", + "repos_url": "https://api.github.com/users/hebasto/repos", + "events_url": "https://api.github.com/users/hebasto/events{/privacy}", + "received_events_url": "https://api.github.com/users/hebasto/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-22T17:14:38Z", + "updated_at": "2024-02-22T17:14:38Z", + "author_association": "MEMBER", + "body": "Concept ACK on introducing feerate diagram checks for a subset of RBF transactions.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1959901619/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1976652095", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1976652095", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1976652095, + "node_id": "IC_kwDOABII58510VE_", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-04T14:03:24Z", + "updated_at": "2024-03-04T14:03:24Z", + "author_association": "MEMBER", + "body": "@ismaelsadeeq thanks, will fix up if I touch commits again", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1976652095/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1988490928", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1988490928", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1988490928, + "node_id": "IC_kwDOABII5852hfaw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-11T13:49:28Z", + "updated_at": "2024-03-11T13:49:28Z", + "author_association": "MEMBER", + "body": "took all suggestions and rebased", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1988490928/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1994878824", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1994878824", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1994878824, + "node_id": "IC_kwDOABII5852529o", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-13T16:26:15Z", + "updated_at": "2024-03-13T16:51:12Z", + "author_association": "MEMBER", + "body": "I believe I addressed all comments. (and failure unrelated?)", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1994878824/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1996069291", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1996069291", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1996069291, + "node_id": "IC_kwDOABII5852-Zmr", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-13T23:19:33Z", + "updated_at": "2024-03-13T23:19:33Z", + "author_association": "MEMBER", + "body": "Did some more fuzzing. No crashes. Coverage: http://bitcoind-fuzz.dergoegge.de/instagibbs/bitcoin/2024-01-diagram-checks/coverage/", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1996069291/reactions", + "total_count": 3, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 2, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2002476895", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2002476895", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2002476895, + "node_id": "IC_kwDOABII5853W19f", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-17T13:45:44Z", + "updated_at": "2024-03-17T13:45:44Z", + "author_association": "MEMBER", + "body": "Here is a commit that removes the need to explicitly compute the diagram, and instead makes the diagram comparison operate directly on a (sorted) list of chunks: https://github.com/sipa/bitcoin/commits/pr29242\r\n\r\nFeel free to ignore, postpone, include, or squash.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2002476895/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2004019811", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2004019811", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2004019811, + "node_id": "IC_kwDOABII5853cupj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-18T14:07:50Z", + "updated_at": "2024-03-18T14:07:50Z", + "author_association": "MEMBER", + "body": "@sipa to keep things moving (muh package rbf) I'll postpone/ promise to review your PR for that commit as a follow-up.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2004019811/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2007515375", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2007515375", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2007515375, + "node_id": "IC_kwDOABII5853qEDv", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-19T15:36:23Z", + "updated_at": "2024-03-19T15:36:23Z", + "author_association": "MEMBER", + "body": "Thanks for the review!\r\n\r\nAs long as it's nits only, I will compile a list of :+1: I will accomplish on a follow-up PR.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2007515375/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2018379583", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2018379583", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2018379583, + "node_id": "IC_kwDOABII5854Tgc_", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-25T16:14:28Z", + "updated_at": "2024-03-25T16:14:28Z", + "author_association": "MEMBER", + "body": "> I see you've added coverage for the \"not the only parent\" case, but I don't see a test for \"not the only child\" case. Also nothing failed when I commented it out.\r\n\r\n@glozow can't figure out github interface, I added a test in followup", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2018379583/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/comments/2.json b/client/fresheyes-bot/comments/2.json new file mode 100644 index 0000000..791bf74 --- /dev/null +++ b/client/fresheyes-bot/comments/2.json @@ -0,0 +1,3902 @@ +[ + { + "id": 1823506588, + "node_id": "PRR_kwDOABII585ssICc", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1823506588", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1823506588" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-16T20:00:31Z", + "commit_id": "5da41e6f851b53d5639dc12aa3d6c308a8a8b403" + }, + { + "id": 1827173808, + "node_id": "PRR_kwDOABII585s6HWw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827173808", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827173808" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:19:19Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827178150, + "node_id": "PRR_kwDOABII585s6Iam", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827178150", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827178150" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:21:54Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827180557, + "node_id": "PRR_kwDOABII585s6JAN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827180557", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827180557" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:23:21Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827186462, + "node_id": "PRR_kwDOABII585s6Kce", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827186462", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827186462" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:26:54Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827266447, + "node_id": "PRR_kwDOABII585s6d-P", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827266447", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827266447" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:11:40Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827272350, + "node_id": "PRR_kwDOABII585s6fae", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827272350", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827272350" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:14:53Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1827276759, + "node_id": "PRR_kwDOABII585s6gfX", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827276759", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827276759" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:17:06Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827280890, + "node_id": "PRR_kwDOABII585s6hf6", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827280890", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827280890" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:19:22Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827381635, + "node_id": "PRR_kwDOABII585s66GD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827381635", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827381635" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T14:08:17Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833137718, + "node_id": "PRR_kwDOABII585tQ3Y2", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833137718", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833137718" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:18Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138006, + "node_id": "PRR_kwDOABII585tQ3dW", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138006", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138006" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:24Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138370, + "node_id": "PRR_kwDOABII585tQ3jC", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138370", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138370" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:31Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138587, + "node_id": "PRR_kwDOABII585tQ3mb", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138587", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138587" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:35Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138722, + "node_id": "PRR_kwDOABII585tQ3oi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138722", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138722" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:37Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1833138857, + "node_id": "PRR_kwDOABII585tQ3qp", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138857", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138857" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:40Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1833139037, + "node_id": "PRR_kwDOABII585tQ3td", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139037", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139037" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:43Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139134, + "node_id": "PRR_kwDOABII585tQ3u-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139134", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139134" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:46Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139262, + "node_id": "PRR_kwDOABII585tQ3w-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139262", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139262" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:48Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139379, + "node_id": "PRR_kwDOABII585tQ3yz", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139379", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139379" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:50Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833161137, + "node_id": "PRR_kwDOABII585tQ9Gx", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833161137", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833161137" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:42:29Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628032, + "node_id": "PRR_kwDOABII585tSvGA", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628032", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628032" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:21Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628227, + "node_id": "PRR_kwDOABII585tSvJD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628227", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628227" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:25Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628323, + "node_id": "PRR_kwDOABII585tSvKj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628323", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628323" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:28Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628458, + "node_id": "PRR_kwDOABII585tSvMq", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628458", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628458" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:34Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628511, + "node_id": "PRR_kwDOABII585tSvNf", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628511", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628511" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:36Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628606, + "node_id": "PRR_kwDOABII585tSvO-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628606", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628606" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:40Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628685, + "node_id": "PRR_kwDOABII585tSvQN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628685", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628685" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:44Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628778, + "node_id": "PRR_kwDOABII585tSvRq", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628778", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628778" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:48Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628978, + "node_id": "PRR_kwDOABII585tSvUy", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628978", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628978" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:59Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1837231759, + "node_id": "PRR_kwDOABII585tge6P", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837231759", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837231759" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-22T21:59:34Z", + "commit_id": "f094a0370db7085b8a89842de0b6d12272d826cb" + }, + { + "id": 1837475718, + "node_id": "PRR_kwDOABII585thaeG", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Concept ACK, tentative crACK f094a0370db7085b8a89842de0b6d12272d826cb", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837475718", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837475718" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-22T22:06:39Z", + "commit_id": "f094a0370db7085b8a89842de0b6d12272d826cb" + }, + { + "id": 1838789825, + "node_id": "PRR_kwDOABII585tmbTB", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838789825", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838789825" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:26:49Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838797602, + "node_id": "PRR_kwDOABII585tmdMi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838797602", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838797602" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:30:37Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838845793, + "node_id": "PRR_kwDOABII585tmo9h", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845793", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845793" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:39Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838845897, + "node_id": "PRR_kwDOABII585tmo_J", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845897", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845897" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:42Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838845988, + "node_id": "PRR_kwDOABII585tmpAk", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845988", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845988" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:45Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838846083, + "node_id": "PRR_kwDOABII585tmpCD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846083", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846083" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:47Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838846344, + "node_id": "PRR_kwDOABII585tmpGI", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846344", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846344" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:54Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838847715, + "node_id": "PRR_kwDOABII585tmpbj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847715", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847715" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:52:33Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838847976, + "node_id": "PRR_kwDOABII585tmpfo", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847976", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847976" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:52:40Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1839710319, + "node_id": "PRR_kwDOABII585tp8Bv", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839710319", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839710319" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T19:05:54Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1839716607, + "node_id": "PRR_kwDOABII585tp9j_", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "ACK a14b95129d3a2894b7a41ce919a426bb60f62e35\r\n\r\nNote: I am fairly familiar with the concept of feerate diagram checks, but not particularly familiar with the mempool code.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839716607", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839716607" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T19:14:53Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1843766331, + "node_id": "PRR_kwDOABII585t5aQ7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843766331", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843766331" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-25T13:37:24Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1843767479, + "node_id": "PRR_kwDOABII585t5ai3", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843767479", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843767479" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-25T13:38:00Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1849127187, + "node_id": "PRR_kwDOABII585uN3ET", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1849127187", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1849127187" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-29T21:18:17Z", + "commit_id": "a1414b3388a870aeb463e9cc293d47cbd86e7f0e" + }, + { + "id": 1875569689, + "node_id": "PRR_kwDOABII585vyuwZ", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1875569689", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1875569689" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-12T15:54:53Z", + "commit_id": "c5e63487c52835645c5cda9779500a000c3a023c" + }, + { + "id": 1878540108, + "node_id": "PRR_kwDOABII585v-D9M", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Code review ACK 3a2c66cc4f0afad9aff300110b18a39981055d63\r\n\r\nI've reviewed the following commits\r\n- [x] [Add FeeFrac utils `d200d30431368c7637a3490509b9158844b69e0d` ](https://github.com/bitcoin/bitcoin/pull/29242/commits/d200d30431368c7637a3490509b9158844b69e0d)\r\n- [x] [Add FeeFrace unit tests `860823fb93212fa78ab928589bd403da462be222`](https://github.com/bitcoin/bitcoin/pull/29242/commits/860823fb93212fa78ab928589bd403da462be222)\r\n- [x] [Implement ImprovesFeerateDiagram `802a104d0e2f810d97567e161e0cf61331052906`](https://github.com/bitcoin/bitcoin/pull/29242/commits/802a104d0e2f810d97567e161e0cf61331052906)\r\n- [x] [test: Add tests for CompareFeerateDiagram and CheckConflictTopology `01f682d49aabec7e07f243a314f699bbca710469`](https://github.com/bitcoin/bitcoin/pull/29242/commits/01f682d49aabec7e07f243a314f699bbca710469)\r\n- [x] [test: unit test for ImprovesFeerateDiagram `3a2c66cc4f0afad9aff300110b18a39981055d63`](https://github.com/bitcoin/bitcoin/pull/29242/commits/3a2c66cc4f0afad9aff300110b18a39981055d63)\r\n\r\nAnd a light review of the fuzzing commits.\r\n\r\nThe code looks good to me, I did some local testing and mess around with the implementation and unit tests.\r\n\r\nI have just a few comments for potential further improvements.", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1878540108", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1878540108" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-13T17:34:23Z", + "commit_id": "3a2c66cc4f0afad9aff300110b18a39981055d63" + }, + { + "id": 1880803374, + "node_id": "PRR_kwDOABII585wGsgu", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1880803374", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1880803374" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-14T16:54:49Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1881279355, + "node_id": "PRR_kwDOABII585wIgt7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1881279355", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1881279355" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-14T20:44:55Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882814496, + "node_id": "PRR_kwDOABII585wOXgg", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882814496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882814496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T13:50:37Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882829496, + "node_id": "PRR_kwDOABII585wObK4", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882829496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882829496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T13:55:11Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882850491, + "node_id": "PRR_kwDOABII585wOgS7", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882850491", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882850491" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:00:43Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882865782, + "node_id": "PRR_kwDOABII585wOkB2", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882865782", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882865782" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:05:12Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882920075, + "node_id": "PRR_kwDOABII585wOxSL", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882920075", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882920075" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:25:20Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1883351956, + "node_id": "PRR_kwDOABII585wQauU", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883351956", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883351956" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:52:45Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1883352369, + "node_id": "PRR_kwDOABII585wQa0x", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883352369", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883352369" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:52:56Z", + "commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4" + }, + { + "id": 1883354202, + "node_id": "PRR_kwDOABII585wQbRa", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883354202", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883354202" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:53:49Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1885627769, + "node_id": "PRR_kwDOABII585wZGV5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885627769", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885627769" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T17:14:29Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1885883009, + "node_id": "PRR_kwDOABII585waEqB", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885883009", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885883009" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T19:41:22Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1885884419, + "node_id": "PRR_kwDOABII585waFAD", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885884419", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885884419" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T19:42:15Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886533962, + "node_id": "PRR_kwDOABII585wcjlK", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886533962", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886533962" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T10:43:13Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886534107, + "node_id": "PRR_kwDOABII585wcjnb", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Thanks for adding the test!\r\nre-ACK d57fbda350ee9051931d9a0dad4beb55f6b2e574\r\n\r\n", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886534107", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886534107" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T10:46:03Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886598516, + "node_id": "PRR_kwDOABII585wczV0", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598516", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598516" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T15:42:48Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1886598977, + "node_id": "PRR_kwDOABII585wczdB", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "Still reviewing all the tests -- leaving some nits that I've noticed so far.\r\n\r\nIn addition:\r\n * I commented [here](https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857) that I think we should drop the `Assume(size != 0 || fee == 0)` calls in feefrac.h, so that we don't have to police all the places we invoke operator- to make sure we can never accidentally violate that.\r\n * Another nit: in the commit message for commit 860823fb93212fa78ab928589bd403da462be222, it should say \"FeeFrac\" and not \"FeeFrace\"\r\n\r\nFinally, as a note to other reviewers, I recently wrote up more explanation of the logic for using feerate diagram comparisons in our RBF policy here: https://delvingbitcoin.org/t/mempool-incentive-compatibility/553/1.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598977", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598977" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T20:59:21Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1887031929, + "node_id": "PRR_kwDOABII585wedJ5", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887031929", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887031929" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T21:35:23Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1887045764, + "node_id": "PRR_kwDOABII585wegiE", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887045764", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887045764" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T23:22:50Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1890224651, + "node_id": "PRR_kwDOABII585wqooL", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890224651", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890224651" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T11:46:52Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1890451361, + "node_id": "PRR_kwDOABII585wrf-h", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890451361", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890451361" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T13:36:32Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891006405, + "node_id": "PRR_kwDOABII585wtnfF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006405", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006405" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:01Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891006649, + "node_id": "PRR_kwDOABII585wtni5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006649", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006649" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:06Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1891006882, + "node_id": "PRR_kwDOABII585wtnmi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006882", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006882" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:09Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1891007191, + "node_id": "PRR_kwDOABII585wtnrX", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007191", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007191" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:15Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891007480, + "node_id": "PRR_kwDOABII585wtnv4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007480", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007480" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:19Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891007709, + "node_id": "PRR_kwDOABII585wtnzd", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007709", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007709" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:23Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891009748, + "node_id": "PRR_kwDOABII585wtoTU", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009748", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009748" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:57Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1891009972, + "node_id": "PRR_kwDOABII585wtoW0", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009972", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009972" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:10:01Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1891010151, + "node_id": "PRR_kwDOABII585wtoZn", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891010151", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891010151" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:10:04Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1896209372, + "node_id": "PRR_kwDOABII585xBdvc", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896209372", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896209372" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:49:19Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896220277, + "node_id": "PRR_kwDOABII585xBgZ1", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896220277", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896220277" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:53:54Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1893687911, + "node_id": "PRR_kwDOABII585w32Jn", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Partial review.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1893687911", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1893687911" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:54:52Z", + "commit_id": "253feff1ba55b7a3de25614783f5d49aca78fa03" + }, + { + "id": 1896273458, + "node_id": "PRR_kwDOABII585xBtYy", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896273458", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896273458" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T16:13:40Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896480235, + "node_id": "PRR_kwDOABII585xCf3r", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480235", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480235" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:48:01Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896480925, + "node_id": "PRR_kwDOABII585xCgCd", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480925", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480925" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:48:28Z", + "commit_id": "947693bc8ed0622e02fd19137740b428e4ffc0be" + }, + { + "id": 1896522503, + "node_id": "PRR_kwDOABII585xCqMH", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896522503", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896522503" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:57:44Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1914140534, + "node_id": "PRR_kwDOABII585yF3d2", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Re-ACK 55eae36cfbd829eabc0772fc1b5312ec1f747e2c Reviewed [Diff](https://github.com/bitcoin/bitcoin/compare/3a2c66cc4f0afad9aff300110b18a39981055d63..55eae36cfbd829eabc0772fc1b5312ec1f747e2c)\r\n\r\nLeft some nits", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1914140534", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1914140534" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-04T13:33:13Z", + "commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c" + }, + { + "id": 1927887049, + "node_id": "PRR_kwDOABII585y6TjJ", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887049", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887049" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:12Z", + "commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c" + }, + { + "id": 1927887173, + "node_id": "PRR_kwDOABII585y6TlF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887173", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887173" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:15Z", + "commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3" + }, + { + "id": 1927887280, + "node_id": "PRR_kwDOABII585y6Tmw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887280", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887280" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:18Z", + "commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3" + }, + { + "id": 1890663129, + "node_id": "PRR_kwDOABII585wsTrZ", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?u=b7db7096ed9396b55dc5eb15159b8ae99ccfe20d&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "The code looks good, I'm still reading through the tests", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890663129", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890663129" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T14:50:54Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1931327057, + "node_id": "PRR_kwDOABII585zHbZR", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931327057", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931327057" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T14:58:53Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1931582907, + "node_id": "PRR_kwDOABII585zIZ27", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931582907", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931582907" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T16:31:31Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1931809010, + "node_id": "PRR_kwDOABII585zJRDy", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?u=b7db7096ed9396b55dc5eb15159b8ae99ccfe20d&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Reviewed tests, just have some nits", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931809010", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931809010" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T18:04:12Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1934526693, + "node_id": "PRR_kwDOABII585zTojl", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526693", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526693" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:27Z", + "commit_id": "eebe434383cf648c4395410d9d9764334fb8ee84" + }, + { + "id": 1934526853, + "node_id": "PRR_kwDOABII585zTomF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526853", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526853" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:31Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1934526974, + "node_id": "PRR_kwDOABII585zTon-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526974", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526974" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:34Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1934527106, + "node_id": "PRR_kwDOABII585zToqC", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527106", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527106" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:37Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1934527192, + "node_id": "PRR_kwDOABII585zTorY", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527192", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527192" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:39Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1934527349, + "node_id": "PRR_kwDOABII585zTot1", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527349", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527349" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:43Z", + "commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52" + }, + { + "id": 1934527493, + "node_id": "PRR_kwDOABII585zTowF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527493", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527493" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:47Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/comments/approval-commentsII.json b/client/fresheyes-bot/comments/approval-commentsII.json new file mode 100644 index 0000000..e422b0b --- /dev/null +++ b/client/fresheyes-bot/comments/approval-commentsII.json @@ -0,0 +1,5969 @@ +[ + { + "id": 1823506588, + "node_id": "PRR_kwDOABII585ssICc", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1823506588", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1823506588" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-16T20:00:31Z", + "commit_id": "5da41e6f851b53d5639dc12aa3d6c308a8a8b403" + }, + { + "id": 1827173808, + "node_id": "PRR_kwDOABII585s6HWw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827173808", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827173808" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:19:19Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827178150, + "node_id": "PRR_kwDOABII585s6Iam", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827178150", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827178150" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:21:54Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827180557, + "node_id": "PRR_kwDOABII585s6JAN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827180557", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827180557" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:23:21Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827186462, + "node_id": "PRR_kwDOABII585s6Kce", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827186462", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827186462" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T12:26:54Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827266447, + "node_id": "PRR_kwDOABII585s6d-P", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827266447", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827266447" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:11:40Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827272350, + "node_id": "PRR_kwDOABII585s6fae", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827272350", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827272350" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:14:53Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1827276759, + "node_id": "PRR_kwDOABII585s6gfX", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827276759", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827276759" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:17:06Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1827280890, + "node_id": "PRR_kwDOABII585s6hf6", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827280890", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827280890" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T13:19:22Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1827381635, + "node_id": "PRR_kwDOABII585s66GD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827381635", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1827381635" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-17T14:08:17Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833137718, + "node_id": "PRR_kwDOABII585tQ3Y2", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833137718", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833137718" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:18Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138006, + "node_id": "PRR_kwDOABII585tQ3dW", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138006", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138006" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:24Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138370, + "node_id": "PRR_kwDOABII585tQ3jC", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138370", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138370" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:31Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138587, + "node_id": "PRR_kwDOABII585tQ3mb", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138587", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138587" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:35Z", + "commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b" + }, + { + "id": 1833138722, + "node_id": "PRR_kwDOABII585tQ3oi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138722", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138722" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:37Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1833138857, + "node_id": "PRR_kwDOABII585tQ3qp", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138857", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833138857" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:40Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1833139037, + "node_id": "PRR_kwDOABII585tQ3td", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139037", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139037" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:43Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139134, + "node_id": "PRR_kwDOABII585tQ3u-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139134", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139134" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:46Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139262, + "node_id": "PRR_kwDOABII585tQ3w-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139262", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139262" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:48Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833139379, + "node_id": "PRR_kwDOABII585tQ3yz", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139379", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833139379" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:01:50Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1833161137, + "node_id": "PRR_kwDOABII585tQ9Gx", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833161137", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833161137" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T16:42:29Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628032, + "node_id": "PRR_kwDOABII585tSvGA", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628032", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628032" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:21Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628227, + "node_id": "PRR_kwDOABII585tSvJD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628227", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628227" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:25Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628323, + "node_id": "PRR_kwDOABII585tSvKj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628323", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628323" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:28Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628458, + "node_id": "PRR_kwDOABII585tSvMq", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628458", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628458" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:34Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628511, + "node_id": "PRR_kwDOABII585tSvNf", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628511", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628511" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:36Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628606, + "node_id": "PRR_kwDOABII585tSvO-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628606", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628606" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:40Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628685, + "node_id": "PRR_kwDOABII585tSvQN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628685", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628685" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:44Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628778, + "node_id": "PRR_kwDOABII585tSvRq", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628778", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628778" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:48Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1833628978, + "node_id": "PRR_kwDOABII585tSvUy", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628978", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1833628978" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-19T20:25:59Z", + "commit_id": "a4b92cfd641d65224528395f1f9b98406822f333" + }, + { + "id": 1837231759, + "node_id": "PRR_kwDOABII585tge6P", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837231759", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837231759" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-22T21:59:34Z", + "commit_id": "f094a0370db7085b8a89842de0b6d12272d826cb" + }, + { + "id": 1837475718, + "node_id": "PRR_kwDOABII585thaeG", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Concept ACK, tentative crACK f094a0370db7085b8a89842de0b6d12272d826cb", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837475718", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1837475718" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-22T22:06:39Z", + "commit_id": "f094a0370db7085b8a89842de0b6d12272d826cb" + }, + { + "id": 1838789825, + "node_id": "PRR_kwDOABII585tmbTB", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838789825", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838789825" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:26:49Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838797602, + "node_id": "PRR_kwDOABII585tmdMi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838797602", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838797602" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:30:37Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838845793, + "node_id": "PRR_kwDOABII585tmo9h", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845793", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845793" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:39Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838845897, + "node_id": "PRR_kwDOABII585tmo_J", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845897", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845897" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:42Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838845988, + "node_id": "PRR_kwDOABII585tmpAk", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845988", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838845988" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:45Z", + "commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b" + }, + { + "id": 1838846083, + "node_id": "PRR_kwDOABII585tmpCD", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846083", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846083" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:47Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838846344, + "node_id": "PRR_kwDOABII585tmpGI", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846344", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838846344" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:51:54Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838847715, + "node_id": "PRR_kwDOABII585tmpbj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847715", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847715" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:52:33Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1838847976, + "node_id": "PRR_kwDOABII585tmpfo", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847976", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1838847976" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T13:52:40Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1839710319, + "node_id": "PRR_kwDOABII585tp8Bv", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839710319", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839710319" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T19:05:54Z", + "commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f" + }, + { + "id": 1839716607, + "node_id": "PRR_kwDOABII585tp9j_", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "ACK a14b95129d3a2894b7a41ce919a426bb60f62e35\r\n\r\nNote: I am fairly familiar with the concept of feerate diagram checks, but not particularly familiar with the mempool code.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839716607", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1839716607" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-23T19:14:53Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1843766331, + "node_id": "PRR_kwDOABII585t5aQ7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843766331", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843766331" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-25T13:37:24Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1843767479, + "node_id": "PRR_kwDOABII585t5ai3", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843767479", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1843767479" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-25T13:38:00Z", + "commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35" + }, + { + "id": 1849127187, + "node_id": "PRR_kwDOABII585uN3ET", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1849127187", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1849127187" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-01-29T21:18:17Z", + "commit_id": "a1414b3388a870aeb463e9cc293d47cbd86e7f0e" + }, + { + "id": 1875569689, + "node_id": "PRR_kwDOABII585vyuwZ", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1875569689", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1875569689" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-12T15:54:53Z", + "commit_id": "c5e63487c52835645c5cda9779500a000c3a023c" + }, + { + "id": 1878540108, + "node_id": "PRR_kwDOABII585v-D9M", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Code review ACK 3a2c66cc4f0afad9aff300110b18a39981055d63\r\n\r\nI've reviewed the following commits\r\n- [x] [Add FeeFrac utils `d200d30431368c7637a3490509b9158844b69e0d` ](https://github.com/bitcoin/bitcoin/pull/29242/commits/d200d30431368c7637a3490509b9158844b69e0d)\r\n- [x] [Add FeeFrace unit tests `860823fb93212fa78ab928589bd403da462be222`](https://github.com/bitcoin/bitcoin/pull/29242/commits/860823fb93212fa78ab928589bd403da462be222)\r\n- [x] [Implement ImprovesFeerateDiagram `802a104d0e2f810d97567e161e0cf61331052906`](https://github.com/bitcoin/bitcoin/pull/29242/commits/802a104d0e2f810d97567e161e0cf61331052906)\r\n- [x] [test: Add tests for CompareFeerateDiagram and CheckConflictTopology `01f682d49aabec7e07f243a314f699bbca710469`](https://github.com/bitcoin/bitcoin/pull/29242/commits/01f682d49aabec7e07f243a314f699bbca710469)\r\n- [x] [test: unit test for ImprovesFeerateDiagram `3a2c66cc4f0afad9aff300110b18a39981055d63`](https://github.com/bitcoin/bitcoin/pull/29242/commits/3a2c66cc4f0afad9aff300110b18a39981055d63)\r\n\r\nAnd a light review of the fuzzing commits.\r\n\r\nThe code looks good to me, I did some local testing and mess around with the implementation and unit tests.\r\n\r\nI have just a few comments for potential further improvements.", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1878540108", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1878540108" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-13T17:34:23Z", + "commit_id": "3a2c66cc4f0afad9aff300110b18a39981055d63" + }, + { + "id": 1880803374, + "node_id": "PRR_kwDOABII585wGsgu", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1880803374", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1880803374" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-14T16:54:49Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1881279355, + "node_id": "PRR_kwDOABII585wIgt7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1881279355", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1881279355" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-14T20:44:55Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882814496, + "node_id": "PRR_kwDOABII585wOXgg", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882814496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882814496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T13:50:37Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882829496, + "node_id": "PRR_kwDOABII585wObK4", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882829496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882829496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T13:55:11Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882850491, + "node_id": "PRR_kwDOABII585wOgS7", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882850491", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882850491" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:00:43Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882865782, + "node_id": "PRR_kwDOABII585wOkB2", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882865782", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882865782" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:05:12Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1882920075, + "node_id": "PRR_kwDOABII585wOxSL", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882920075", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1882920075" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T14:25:20Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1883351956, + "node_id": "PRR_kwDOABII585wQauU", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883351956", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883351956" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:52:45Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1883352369, + "node_id": "PRR_kwDOABII585wQa0x", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883352369", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883352369" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:52:56Z", + "commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4" + }, + { + "id": 1883354202, + "node_id": "PRR_kwDOABII585wQbRa", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883354202", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1883354202" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-15T16:53:49Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1885627769, + "node_id": "PRR_kwDOABII585wZGV5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885627769", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885627769" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T17:14:29Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1885883009, + "node_id": "PRR_kwDOABII585waEqB", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885883009", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885883009" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T19:41:22Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1885884419, + "node_id": "PRR_kwDOABII585waFAD", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885884419", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1885884419" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-16T19:42:15Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886533962, + "node_id": "PRR_kwDOABII585wcjlK", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886533962", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886533962" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T10:43:13Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886534107, + "node_id": "PRR_kwDOABII585wcjnb", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Thanks for adding the test!\r\nre-ACK d57fbda350ee9051931d9a0dad4beb55f6b2e574\r\n\r\n", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886534107", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886534107" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T10:46:03Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1886598516, + "node_id": "PRR_kwDOABII585wczV0", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598516", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598516" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T15:42:48Z", + "commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a" + }, + { + "id": 1886598977, + "node_id": "PRR_kwDOABII585wczdB", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "Still reviewing all the tests -- leaving some nits that I've noticed so far.\r\n\r\nIn addition:\r\n * I commented [here](https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857) that I think we should drop the `Assume(size != 0 || fee == 0)` calls in feefrac.h, so that we don't have to police all the places we invoke operator- to make sure we can never accidentally violate that.\r\n * Another nit: in the commit message for commit 860823fb93212fa78ab928589bd403da462be222, it should say \"FeeFrac\" and not \"FeeFrace\"\r\n\r\nFinally, as a note to other reviewers, I recently wrote up more explanation of the logic for using feerate diagram comparisons in our RBF policy here: https://delvingbitcoin.org/t/mempool-incentive-compatibility/553/1.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598977", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1886598977" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T20:59:21Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1887031929, + "node_id": "PRR_kwDOABII585wedJ5", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887031929", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887031929" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T21:35:23Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1887045764, + "node_id": "PRR_kwDOABII585wegiE", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887045764", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1887045764" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-17T23:22:50Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1890224651, + "node_id": "PRR_kwDOABII585wqooL", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890224651", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890224651" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T11:46:52Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1890451361, + "node_id": "PRR_kwDOABII585wrf-h", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890451361", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890451361" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T13:36:32Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891006405, + "node_id": "PRR_kwDOABII585wtnfF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006405", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006405" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:01Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891006649, + "node_id": "PRR_kwDOABII585wtni5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006649", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006649" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:06Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1891006882, + "node_id": "PRR_kwDOABII585wtnmi", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006882", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891006882" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:09Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1891007191, + "node_id": "PRR_kwDOABII585wtnrX", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007191", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007191" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:15Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891007480, + "node_id": "PRR_kwDOABII585wtnv4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007480", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007480" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:19Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891007709, + "node_id": "PRR_kwDOABII585wtnzd", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007709", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891007709" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:23Z", + "commit_id": "d200d30431368c7637a3490509b9158844b69e0d" + }, + { + "id": 1891009748, + "node_id": "PRR_kwDOABII585wtoTU", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009748", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009748" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:09:57Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1891009972, + "node_id": "PRR_kwDOABII585wtoW0", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009972", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891009972" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:10:01Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1891010151, + "node_id": "PRR_kwDOABII585wtoZn", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891010151", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1891010151" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-20T17:10:04Z", + "commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574" + }, + { + "id": 1896209372, + "node_id": "PRR_kwDOABII585xBdvc", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896209372", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896209372" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:49:19Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896220277, + "node_id": "PRR_kwDOABII585xBgZ1", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896220277", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896220277" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:53:54Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1893687911, + "node_id": "PRR_kwDOABII585w32Jn", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Partial review.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1893687911", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1893687911" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T15:54:52Z", + "commit_id": "253feff1ba55b7a3de25614783f5d49aca78fa03" + }, + { + "id": 1896273458, + "node_id": "PRR_kwDOABII585xBtYy", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896273458", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896273458" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T16:13:40Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896480235, + "node_id": "PRR_kwDOABII585xCf3r", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480235", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480235" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:48:01Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1896480925, + "node_id": "PRR_kwDOABII585xCgCd", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480925", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896480925" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:48:28Z", + "commit_id": "947693bc8ed0622e02fd19137740b428e4ffc0be" + }, + { + "id": 1896522503, + "node_id": "PRR_kwDOABII585xCqMH", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896522503", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1896522503" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-02-22T17:57:44Z", + "commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef" + }, + { + "id": 1914140534, + "node_id": "PRR_kwDOABII585yF3d2", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Re-ACK 55eae36cfbd829eabc0772fc1b5312ec1f747e2c Reviewed [Diff](https://github.com/bitcoin/bitcoin/compare/3a2c66cc4f0afad9aff300110b18a39981055d63..55eae36cfbd829eabc0772fc1b5312ec1f747e2c)\r\n\r\nLeft some nits", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1914140534", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1914140534" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-04T13:33:13Z", + "commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c" + }, + { + "id": 1927887049, + "node_id": "PRR_kwDOABII585y6TjJ", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887049", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887049" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:12Z", + "commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c" + }, + { + "id": 1927887173, + "node_id": "PRR_kwDOABII585y6TlF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887173", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887173" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:15Z", + "commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3" + }, + { + "id": 1927887280, + "node_id": "PRR_kwDOABII585y6Tmw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887280", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1927887280" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-11T13:49:18Z", + "commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3" + }, + { + "id": 1890663129, + "node_id": "PRR_kwDOABII585wsTrZ", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?u=b7db7096ed9396b55dc5eb15159b8ae99ccfe20d&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "The code looks good, I'm still reading through the tests", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890663129", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1890663129" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T14:50:54Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1931327057, + "node_id": "PRR_kwDOABII585zHbZR", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931327057", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931327057" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T14:58:53Z", + "commit_id": "802a104d0e2f810d97567e161e0cf61331052906" + }, + { + "id": 1931582907, + "node_id": "PRR_kwDOABII585zIZ27", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931582907", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931582907" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T16:31:31Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1931809010, + "node_id": "PRR_kwDOABII585zJRDy", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?u=b7db7096ed9396b55dc5eb15159b8ae99ccfe20d&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Reviewed tests, just have some nits", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931809010", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1931809010" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-12T18:04:12Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1934526693, + "node_id": "PRR_kwDOABII585zTojl", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526693", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526693" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:27Z", + "commit_id": "eebe434383cf648c4395410d9d9764334fb8ee84" + }, + { + "id": 1934526853, + "node_id": "PRR_kwDOABII585zTomF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526853", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526853" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:31Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1934526974, + "node_id": "PRR_kwDOABII585zTon-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526974", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934526974" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:34Z", + "commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63" + }, + { + "id": 1934527106, + "node_id": "PRR_kwDOABII585zToqC", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527106", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527106" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:37Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1934527192, + "node_id": "PRR_kwDOABII585zTorY", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527192", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527192" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:39Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1934527349, + "node_id": "PRR_kwDOABII585zTot1", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527349", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527349" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:43Z", + "commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52" + }, + { + "id": 1934527493, + "node_id": "PRR_kwDOABII585zTowF", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527493", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934527493" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:47Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1934528017, + "node_id": "PRR_kwDOABII585zTo4R", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528017", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528017" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:56Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1934528266, + "node_id": "PRR_kwDOABII585zTo8K", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528266", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528266" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:33:59Z", + "commit_id": "70ffb25852fb274c2703ee07a5e225d047391571" + }, + { + "id": 1934528513, + "node_id": "PRR_kwDOABII585zTpAB", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528513", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528513" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:03Z", + "commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324" + }, + { + "id": 1934528682, + "node_id": "PRR_kwDOABII585zTpCq", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528682", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934528682" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:06Z", + "commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324" + }, + { + "id": 1934529628, + "node_id": "PRR_kwDOABII585zTpRc", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529628", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529628" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:27Z", + "commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324" + }, + { + "id": 1934529829, + "node_id": "PRR_kwDOABII585zTpUl", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529829", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529829" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:32Z", + "commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324" + }, + { + "id": 1934529959, + "node_id": "PRR_kwDOABII585zTpWn", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529959", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934529959" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:35Z", + "commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324" + }, + { + "id": 1934530102, + "node_id": "PRR_kwDOABII585zTpY2", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934530102", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1934530102" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-13T15:34:39Z", + "commit_id": "f4e7c2748d263daca9d6e6164bd0f6818445f9da" + }, + { + "id": 1940381796, + "node_id": "PRR_kwDOABII585zp-Bk", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1940381796", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1940381796" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-17T00:31:49Z", + "commit_id": "9d8bf1bf95cb20d62fd1fc70f60de61b9c10dce3" + }, + { + "id": 1943181069, + "node_id": "PRR_kwDOABII585z0pcN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943181069", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943181069" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:04:50Z", + "commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43" + }, + { + "id": 1943201769, + "node_id": "PRR_kwDOABII585z0ufp", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943201769", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943201769" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:10:39Z", + "commit_id": "9d8bf1bf95cb20d62fd1fc70f60de61b9c10dce3" + }, + { + "id": 1943216125, + "node_id": "PRR_kwDOABII585z0x_9", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943216125", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943216125" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:15:55Z", + "commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43" + }, + { + "id": 1943221493, + "node_id": "PRR_kwDOABII585z0zT1", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943221493", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943221493" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:17:59Z", + "commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43" + }, + { + "id": 1943248232, + "node_id": "PRR_kwDOABII585z051o", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943248232", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943248232" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:26:49Z", + "commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52" + }, + { + "id": 1943248552, + "node_id": "PRR_kwDOABII585z056o", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943248552", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943248552" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:26:56Z", + "commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43" + }, + { + "id": 1943254892, + "node_id": "PRR_kwDOABII585z07ds", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943254892", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943254892" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:29:19Z", + "commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52" + }, + { + "id": 1943273458, + "node_id": "PRR_kwDOABII585z0__y", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943273458", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943273458" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T14:35:34Z", + "commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52" + }, + { + "id": 1943349194, + "node_id": "PRR_kwDOABII585z1SfK", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "utACK 72959867784098137a50c34f86deca8235eef4f8\r\n\r\nSome non-blocking nits:", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943349194", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943349194" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-18T16:34:53Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1945992726, + "node_id": "PRR_kwDOABII585z_X4W", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?u=b7db7096ed9396b55dc5eb15159b8ae99ccfe20d&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "code review ACK 72959867784098137a50c34f86deca8235eef4f8\r\n\r\nVarious non-blocking comments about the tests, can be saved for a followup.", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1945992726", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1945992726" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T14:57:56Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1946634078, + "node_id": "PRR_kwDOABII5850B0de", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1946634078", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1946634078" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T15:34:25Z", + "commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73" + }, + { + "id": 1937534483, + "node_id": "PRR_kwDOABII585zfG4T", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "utACK 72959867784098137a50c34f86deca8235eef4f8\r\n\r\nI also only have non-blocking nits", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1937534483", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1937534483" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T19:42:27Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1947241589, + "node_id": "PRR_kwDOABII5850EIx1", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947241589", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947241589" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T19:49:41Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1947257675, + "node_id": "PRR_kwDOABII5850EMtL", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947257675", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947257675" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T19:59:03Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1947259711, + "node_id": "PRR_kwDOABII5850ENM_", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?u=7999a16349f0df0fb273fffa18e5a955c9d3f11c&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947259711", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947259711" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T20:00:16Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1947329188, + "node_id": "PRR_kwDOABII5850EeKk", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947329188", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947329188" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T20:32:19Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1947329420, + "node_id": "PRR_kwDOABII5850EeOM", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947329420", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947329420" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T20:32:27Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1947330877, + "node_id": "PRR_kwDOABII5850Eek9", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?u=d924616c3b45bdda9c3b78d1697f1fe6a92b49c5&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947330877", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947330877" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T20:33:20Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1947340500, + "node_id": "PRR_kwDOABII5850Eg7U", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947340500", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1947340500" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-19T20:38:26Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1948352078, + "node_id": "PRR_kwDOABII5850IX5O", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?u=751ec0e9a71dc02e49da617fe1b2cbfad732d1b6&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Re-ACK https://github.com/bitcoin/bitcoin/commit/72959867784098137a50c34f86deca8235eef4f8", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948352078", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948352078" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-20T09:32:47Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1948504420, + "node_id": "PRR_kwDOABII5850I9Fk", + "user": { + "login": "willcl-ark", + "id": 6606587, + "node_id": "MDQ6VXNlcjY2MDY1ODc=", + "avatar_url": "https://avatars.githubusercontent.com/u/6606587?u=e7275d52ca26972cc8ebb07996f558588cbda979&v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/willcl-ark", + "html_url": "https://github.com/willcl-ark", + "followers_url": "https://api.github.com/users/willcl-ark/followers", + "following_url": "https://api.github.com/users/willcl-ark/following{/other_user}", + "gists_url": "https://api.github.com/users/willcl-ark/gists{/gist_id}", + "starred_url": "https://api.github.com/users/willcl-ark/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/willcl-ark/subscriptions", + "organizations_url": "https://api.github.com/users/willcl-ark/orgs", + "repos_url": "https://api.github.com/users/willcl-ark/repos", + "events_url": "https://api.github.com/users/willcl-ark/events{/privacy}", + "received_events_url": "https://api.github.com/users/willcl-ark/received_events", + "type": "User", + "site_admin": false + }, + "body": "crACK 72959867784098137a50c34f86deca8235eef4f8\r\n\r\nThis looks good on a first pass of the code, and was a good introduction (to me) for how we are approaching implementation of the Diagrammatic fee rate checks, which matches my current understanding of the proposed concept.\r\n\r\nLeft only two small non-blocking nits.\r\n\r\nIn addition, while checking each commit I did notice that clang-format could be run on most (all?) of them too if wanted (but I'd guess it's not wanted at this stage of review 😄 ).", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948504420", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948504420" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-20T13:43:59Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1957559378, + "node_id": "PRR_kwDOABII5850rfxS", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1957559378", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1957559378" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T12:05:59Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1957562936, + "node_id": "PRR_kwDOABII5850rgo4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1957562936", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1957562936" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T12:07:06Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1958179723, + "node_id": "PRR_kwDOABII5850t3OL", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958179723", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958179723" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:13:32Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1958179835, + "node_id": "PRR_kwDOABII5850t3P7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958179835", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958179835" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:13:35Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1958180007, + "node_id": "PRR_kwDOABII5850t3Sn", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958180007", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958180007" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:13:40Z", + "commit_id": "e9c5aeb11d641b8cae373452339760809625021d" + }, + { + "id": 1958180109, + "node_id": "PRR_kwDOABII5850t3UN", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958180109", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958180109" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:13:43Z", + "commit_id": "e9c5aeb11d641b8cae373452339760809625021d" + }, + { + "id": 1958182075, + "node_id": "PRR_kwDOABII5850t3y7", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182075", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182075" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:33Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1958182185, + "node_id": "PRR_kwDOABII5850t30p", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182185", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182185" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:36Z", + "commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a" + }, + { + "id": 1958182331, + "node_id": "PRR_kwDOABII5850t327", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182331", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182331" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:39Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1958182429, + "node_id": "PRR_kwDOABII5850t34d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182429", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182429" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:42Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1958182534, + "node_id": "PRR_kwDOABII5850t36G", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182534", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182534" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:45Z", + "commit_id": "4d6528a3d6bf3821c216c68f99170e2faab5d63c" + }, + { + "id": 1958182643, + "node_id": "PRR_kwDOABII5850t37z", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182643", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182643" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:48Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1958182796, + "node_id": "PRR_kwDOABII5850t3-M", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182796", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182796" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:52Z", + "commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43" + }, + { + "id": 1958182933, + "node_id": "PRR_kwDOABII5850t4AV", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182933", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958182933" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:56Z", + "commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31" + }, + { + "id": 1958183051, + "node_id": "PRR_kwDOABII5850t4CL", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183051", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183051" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:14:59Z", + "commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31" + }, + { + "id": 1958183166, + "node_id": "PRR_kwDOABII5850t4D-", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183166", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183166" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:15:02Z", + "commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74" + }, + { + "id": 1958183255, + "node_id": "PRR_kwDOABII5850t4FX", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183255", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183255" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:15:04Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1958183367, + "node_id": "PRR_kwDOABII5850t4HH", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183367", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183367" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:15:08Z", + "commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31" + }, + { + "id": 1958183477, + "node_id": "PRR_kwDOABII5850t4I1", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183477", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958183477" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T16:15:11Z", + "commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74" + }, + { + "id": 1958602404, + "node_id": "PRR_kwDOABII5850veak", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "ACK 72959867784098137a50c34f86deca8235eef4f8\r\n\r\nLeft some nits that can be addressed (or not) in a followup.", + "state": "APPROVED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958602404", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958602404" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-25T19:54:18Z", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8" + }, + { + "id": 1960246673, + "node_id": "PRR_kwDOABII58501v2R", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960246673", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960246673" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-26T12:40:10Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + }, + { + "id": 1960252643, + "node_id": "PRR_kwDOABII58501xTj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960252643", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960252643" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-26T12:42:39Z", + "commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4" + }, + { + "id": 1960255715, + "node_id": "PRR_kwDOABII58501yDj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "", + "state": "COMMENTED", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960255715", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1960255715" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "submitted_at": "2024-03-26T12:44:05Z", + "commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473" + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/comments/issue-commentsII.json b/client/fresheyes-bot/comments/issue-commentsII.json new file mode 100644 index 0000000..b884d48 --- /dev/null +++ b/client/fresheyes-bot/comments/issue-commentsII.json @@ -0,0 +1,1146 @@ +[ + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889741023", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889741023", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889741023, + "node_id": "IC_kwDOABII585woyjf", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T18:07:47Z", + "updated_at": "2024-03-25T19:54:23Z", + "author_association": "CONTRIBUTOR", + "body": "\n\nThe following sections might be updated with supplementary metadata relevant to reviewers and maintainers.\n\n\n### Code Coverage\nFor detailed information about the code coverage, see the [test coverage report](https://corecheck.dev/bitcoin/bitcoin/pulls/29242).\n\n### Reviews\nSee [the guideline](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md#code-review) for information on the review process.\n| Type | Reviewers |\n| ---- | --------- |\n| ACK | [sipa](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1943349194), [glozow](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1945992726), [murchandamus](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1937534483), [ismaelsadeeq](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948352078), [willcl-ark](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1948504420), [sdaftuar](https://github.com/bitcoin/bitcoin/pull/29242#pullrequestreview-1958602404) |\n| Concept ACK | [hebasto](https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1959901619) |\n\nIf your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.\n\n### Conflicts\nNo conflicts as of last run.\n", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889741023/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889768276", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889768276", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889768276, + "node_id": "IC_kwDOABII585wo5NU", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T18:29:27Z", + "updated_at": "2024-01-12T18:29:27Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20435922692", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889768276/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889982713", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1889982713", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1889982713, + "node_id": "IC_kwDOABII585wptj5", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-12T21:38:22Z", + "updated_at": "2024-01-12T21:38:22Z", + "author_association": "MEMBER", + "body": "ready for review\r\n\r\ncc @glozow @ismaelsadeeq @achow101 ", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1889982713/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1899159499", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1899159499", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1899159499, + "node_id": "IC_kwDOABII585xMt_L", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-18T20:29:48Z", + "updated_at": "2024-01-18T20:29:48Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20632055548", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1899159499/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901072804", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1901072804", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1901072804, + "node_id": "IC_kwDOABII585xUBGk", + "user": { + "login": "DrahtBot", + "id": 39886733, + "node_id": "MDQ6VXNlcjM5ODg2NzMz", + "avatar_url": "https://avatars.githubusercontent.com/u/39886733?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/DrahtBot", + "html_url": "https://github.com/DrahtBot", + "followers_url": "https://api.github.com/users/DrahtBot/followers", + "following_url": "https://api.github.com/users/DrahtBot/following{/other_user}", + "gists_url": "https://api.github.com/users/DrahtBot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/DrahtBot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/DrahtBot/subscriptions", + "organizations_url": "https://api.github.com/users/DrahtBot/orgs", + "repos_url": "https://api.github.com/users/DrahtBot/repos", + "events_url": "https://api.github.com/users/DrahtBot/events{/privacy}", + "received_events_url": "https://api.github.com/users/DrahtBot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-19T20:32:35Z", + "updated_at": "2024-01-19T20:32:35Z", + "author_association": "CONTRIBUTOR", + "body": "\n\n🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the\ndocumentation.\n\nPossibly this is due to a silent merge conflict (the changes in this pull request being\nincompatible with the current code in the target branch). If so, make sure to rebase on the latest\ncommit of the target branch.\n\nLeave a comment here, if you need help tracking down a confusing failure.\n\nDebug: https://github.com/bitcoin/bitcoin/runs/20672153966", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901072804/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901152779", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1901152779", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1901152779, + "node_id": "IC_kwDOABII585xUUoL", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-19T21:42:00Z", + "updated_at": "2024-01-19T21:42:00Z", + "author_association": "MEMBER", + "body": "test failure appears to be spurious wallet failure, ready for review", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1901152779/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1902638542", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1902638542", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1902638542, + "node_id": "IC_kwDOABII585xZ_XO", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-21T14:00:29Z", + "updated_at": "2024-01-21T14:00:29Z", + "author_association": "MEMBER", + "body": "In https://github.com/sipa/bitcoin/commits/pr29242 I pushed another commit which makes `CompareFeerateDiagram` not modify the diagrams in-place.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1902638542/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1904479665", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1904479665", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1904479665, + "node_id": "IC_kwDOABII585xhA2x", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-22T17:30:57Z", + "updated_at": "2024-01-22T17:30:57Z", + "author_association": "MEMBER", + "body": "> In https://github.com/sipa/bitcoin/commits/pr29242 I pushed another commit which makes CompareFeerateDiagram not modify the diagrams in-place.\r\n\r\nTaken only with minor comment changes, and added another test case or two to cover the iterative nature of the check", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1904479665/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906111930", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1906111930", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1906111930, + "node_id": "IC_kwDOABII585xnPW6", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-23T13:56:12Z", + "updated_at": "2024-01-23T13:56:12Z", + "author_association": "MEMBER", + "body": "@murchandamus comments should be addressed or taken", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906111930/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906919216", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1906919216", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1906919216, + "node_id": "IC_kwDOABII585xqUcw", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-23T21:07:22Z", + "updated_at": "2024-01-23T21:07:22Z", + "author_association": "MEMBER", + "body": "```\r\n$ echo \"BAIBAgICAgIABfcN/f11BwAAAPsAAAICAgICAgICAi0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwb3J0AgL+//////8hAQICAooBATIBAR4AAgICAgICAgICAgICAgICAgICAgICAgIC/v///////wECAgKKAQEyAQEeAgIiAgICAgICHgACAgIDAgICAgICAiICAgICAExLQAICAgICAgICAv//////////////////////////////////////////////////////AQEBAQEByQEBAQEBAQEB/P8AAC8AGvsAXAEAAgLcAgICAgICAlSbtqZ56uTNNhvmIHMu83ifTNtXiVGR9z3J4We8dnhZegAAAAAAAAD/AAAAAAAHAAAAAAAAXP96AAAAAgICAgAF9w39/QAAAAEAAAABAgICAgICAgICLZCPcnQCAgIC3AICAgICAgJUm7ameerkzRvmIHMu83ifTNtXiVGR9z3J4We8dnhZegAAAAAAAAAAAAAAAAcABgEAAAAAAAAAAAAAAPsCIlwBAAAHAAAAAQAAAAmLXAEVAAAAAAAAAAAAAAAAAAAAXP+B/////////wAAAAAABwAAAAAAAAAAAAAABwAALAACAgIATEtAAgICAgICAgIC//////////////////////////////////////////////////////8BAQEBAQHJAQEBAQEBAQH8/wAALwAa+wBcAQACAtwCAgICAgICVJu2pnnq5M02G+Ygcy7zeJ9M21eJUZH3PcnhZ7x2eFl6AAAAAAAAAP8AAAAAAAcAAAAAAABc/3oAAAACAgICAAX3Df39AAAAAQAAAAECAgICAgICAgItkI9ydAICAgLcAgICAgICAlSbtqZ56uTNG+Ygcy7zeJ9M21eJUZH3PcnhZ7x2eFl6AAAAAAAAAAAAAAAABwAGAQAAAAAAAAAAAAAA+wIiXAEAAAcAAAABAAAACYtcARUAAAAAAAAAAAAAAAAAAABc/4H/////////AAAAAAAHAAAAAAAAAAAAAAAHAAAsAAAAAPsCAlwBAAAHAAAAAQAAAAmLXAEDAwMDAwMD/729vb29vb29vb29vb29vb29vb29vb29vT+9/wUtYmluvb29vb29vb29vb29vb29vb29vb29/wUtYmluZC0U/////wAAAAAAAAAAHAAAAAAAAP///////////////////////4pVyFwAAAD7AgJcAQAABwAAAAEAAAAJi1wBAwMDAwMDA/+9vb29vb29vb29vb29vb29vb29vb29vb0/vf8FLWJpbr29vb29vb29vb29vb29vb29vb29vf8FLWJpbmQtFP////8AAAAAAAAAABwAAAAAAAD///////////////////////+KVchcToownpjPpiYHL06aRtJ04wyb/sdpyYUpxMKugP////////////////////////9t////AQAAAEZFRUVFRUVFRUVFRUVFRUVFRUVFRUVF/////////////////////3r//////////wMDAwP//////w==\" | base64 --decode > package_rbf-7d643e62d75f4ac67d3bdeaf9f5fbfd67675806a.crash\r\n$ FUZZ=package_rbf ./src/test/fuzz/fuzz package_rbf-7d643e62d75f4ac67d3bdeaf9f5fbfd67675806a.crash\r\nfuzz_libfuzzer: test/fuzz/rbf.cpp:147: void package_rbf_fuzz_target(FuzzBufferType): Assertion `old_diagram.back().fee - replaced_fee + replacement_fees == new_diagram.back().fee' failed.\r\n```", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1906919216/reactions", + "total_count": 2, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 1, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908321622", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1908321622", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1908321622, + "node_id": "IC_kwDOABII585xvq1W", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-24T15:07:22Z", + "updated_at": "2024-01-24T15:07:22Z", + "author_association": "MEMBER", + "body": "@dergoegge fuzzer created a circular reference which caused incongruities between descendant counts and actually walking the descendants in mempool. Please run again?", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908321622/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908435057", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1908435057", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1908435057, + "node_id": "IC_kwDOABII585xwGhx", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-24T16:03:55Z", + "updated_at": "2024-01-24T16:03:55Z", + "author_association": "MEMBER", + "body": "> Please run again?\r\n\r\nRunning now.\r\n\r\nSome coverage reports from the previous runs (one per harness): http://bitcoind-fuzz.dergoegge.de/instagibbs/bitcoin/2024-01-diagram-checks/coverage/", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1908435057/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 1, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1910238997", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1910238997", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1910238997, + "node_id": "IC_kwDOABII585x2-8V", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-01-25T13:38:11Z", + "updated_at": "2024-01-25T13:38:11Z", + "author_association": "MEMBER", + "body": "didn't see any fuzzer crashes locally, all comments addressed", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1910238997/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1924448996", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1924448996", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1924448996, + "node_id": "IC_kwDOABII585ytMLk", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-02T18:22:56Z", + "updated_at": "2024-02-02T18:22:56Z", + "author_association": "CONTRIBUTOR", + "body": "ACK a1414b3388a870aeb463e9cc293d47cbd86e7f0e \r\n\r\nvia rangediff a14b95129d3a2894b7a41ce919a426bb60f62e35..a1414b3388a870aeb463e9cc293d47cbd86e7f0e\r\n\r\nThe changes since my prior ACK appear to only pertain to improvements in the fuzz test to avoid circular packages and a typo fix on a comment in the code.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1924448996/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1938973409", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1938973409", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1938973409, + "node_id": "IC_kwDOABII585zkmLh", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-12T15:56:32Z", + "updated_at": "2024-02-12T15:56:32Z", + "author_association": "MEMBER", + "body": "rebased", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1938973409/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1946580499", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1946580499", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1946580499, + "node_id": "IC_kwDOABII5850BnYT", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-15T16:56:11Z", + "updated_at": "2024-02-15T16:56:11Z", + "author_association": "MEMBER", + "body": "addressed all comments", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1946580499/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1954669587", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1954669587", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1954669587, + "node_id": "IC_kwDOABII5850geQT", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-20T17:10:41Z", + "updated_at": "2024-02-20T17:10:41Z", + "author_association": "MEMBER", + "body": "> I commented https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857 that I think we should drop the Assume(size != 0 || fee == 0) calls in feefrac.h, so that we don't have to police all the places we invoke operator- to make sure we can never accidentally violate that.\r\nAnother nit: in the commit message for commit https://github.com/bitcoin/bitcoin/commit/860823fb93212fa78ab928589bd403da462be222, it should say \"FeeFrac\" and not \"FeeFrace\"\r\n\r\nAddressed these by removing Assumes and updating the commit text", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1954669587/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1959901619", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1959901619", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1959901619, + "node_id": "IC_kwDOABII58500bmz", + "user": { + "login": "hebasto", + "id": 32963518, + "node_id": "MDQ6VXNlcjMyOTYzNTE4", + "avatar_url": "https://avatars.githubusercontent.com/u/32963518?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/hebasto", + "html_url": "https://github.com/hebasto", + "followers_url": "https://api.github.com/users/hebasto/followers", + "following_url": "https://api.github.com/users/hebasto/following{/other_user}", + "gists_url": "https://api.github.com/users/hebasto/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hebasto/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hebasto/subscriptions", + "organizations_url": "https://api.github.com/users/hebasto/orgs", + "repos_url": "https://api.github.com/users/hebasto/repos", + "events_url": "https://api.github.com/users/hebasto/events{/privacy}", + "received_events_url": "https://api.github.com/users/hebasto/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-02-22T17:14:38Z", + "updated_at": "2024-02-22T17:14:38Z", + "author_association": "MEMBER", + "body": "Concept ACK on introducing feerate diagram checks for a subset of RBF transactions.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1959901619/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1976652095", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1976652095", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1976652095, + "node_id": "IC_kwDOABII58510VE_", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-04T14:03:24Z", + "updated_at": "2024-03-04T14:03:24Z", + "author_association": "MEMBER", + "body": "@ismaelsadeeq thanks, will fix up if I touch commits again", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1976652095/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1988490928", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1988490928", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1988490928, + "node_id": "IC_kwDOABII5852hfaw", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-11T13:49:28Z", + "updated_at": "2024-03-11T13:49:28Z", + "author_association": "MEMBER", + "body": "took all suggestions and rebased", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1988490928/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1994878824", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1994878824", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1994878824, + "node_id": "IC_kwDOABII5852529o", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-13T16:26:15Z", + "updated_at": "2024-03-13T16:51:12Z", + "author_association": "MEMBER", + "body": "I believe I addressed all comments. (and failure unrelated?)", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1994878824/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1996069291", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-1996069291", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 1996069291, + "node_id": "IC_kwDOABII5852-Zmr", + "user": { + "login": "dergoegge", + "id": 8077169, + "node_id": "MDQ6VXNlcjgwNzcxNjk=", + "avatar_url": "https://avatars.githubusercontent.com/u/8077169?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/dergoegge", + "html_url": "https://github.com/dergoegge", + "followers_url": "https://api.github.com/users/dergoegge/followers", + "following_url": "https://api.github.com/users/dergoegge/following{/other_user}", + "gists_url": "https://api.github.com/users/dergoegge/gists{/gist_id}", + "starred_url": "https://api.github.com/users/dergoegge/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/dergoegge/subscriptions", + "organizations_url": "https://api.github.com/users/dergoegge/orgs", + "repos_url": "https://api.github.com/users/dergoegge/repos", + "events_url": "https://api.github.com/users/dergoegge/events{/privacy}", + "received_events_url": "https://api.github.com/users/dergoegge/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-13T23:19:33Z", + "updated_at": "2024-03-13T23:19:33Z", + "author_association": "MEMBER", + "body": "Did some more fuzzing. No crashes. Coverage: http://bitcoind-fuzz.dergoegge.de/instagibbs/bitcoin/2024-01-diagram-checks/coverage/", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/1996069291/reactions", + "total_count": 3, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 2, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2002476895", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2002476895", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2002476895, + "node_id": "IC_kwDOABII5853W19f", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-17T13:45:44Z", + "updated_at": "2024-03-17T13:45:44Z", + "author_association": "MEMBER", + "body": "Here is a commit that removes the need to explicitly compute the diagram, and instead makes the diagram comparison operate directly on a (sorted) list of chunks: https://github.com/sipa/bitcoin/commits/pr29242\r\n\r\nFeel free to ignore, postpone, include, or squash.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2002476895/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2004019811", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2004019811", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2004019811, + "node_id": "IC_kwDOABII5853cupj", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-18T14:07:50Z", + "updated_at": "2024-03-18T14:07:50Z", + "author_association": "MEMBER", + "body": "@sipa to keep things moving (muh package rbf) I'll postpone/ promise to review your PR for that commit as a follow-up.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2004019811/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2007515375", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2007515375", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2007515375, + "node_id": "IC_kwDOABII5853qEDv", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-19T15:36:23Z", + "updated_at": "2024-03-19T15:36:23Z", + "author_association": "MEMBER", + "body": "Thanks for the review!\r\n\r\nAs long as it's nits only, I will compile a list of :+1: I will accomplish on a follow-up PR.", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2007515375/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2018379583", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#issuecomment-2018379583", + "issue_url": "https://api.github.com/repos/bitcoin/bitcoin/issues/29242", + "id": 2018379583, + "node_id": "IC_kwDOABII5854Tgc_", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-03-25T16:14:28Z", + "updated_at": "2024-03-25T16:14:28Z", + "author_association": "MEMBER", + "body": "> I see you've added coverage for the \"not the only parent\" case, but I don't see a test for \"not the only child\" case. Also nothing failed when I commented it out.\r\n\r\n@glozow can't figure out github interface, I added a test in followup", + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/issues/comments/2018379583/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/comments/review-commentsII.json b/client/fresheyes-bot/comments/review-commentsII.json new file mode 100644 index 0000000..0458c9c --- /dev/null +++ b/client/fresheyes-bot/comments/review-commentsII.json @@ -0,0 +1,15300 @@ +[ + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372", + "pull_request_review_id": 1823506588, + "id": 1453480372, + "node_id": "PRRC_kwDOABII585Wolm0", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n /** Add fee and size of another FeeFrac to this one. */\r\n void inline operator+=(const FeeFrac& other) noexcept\r\n {\r\n fee += other.fee;\r\n size += other.size;\r\n }\r\n\r\n /** Subtrack fee and size of another FeeFrac from this one. */\r\n```", + "created_at": "2024-01-16T14:09:34Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480372", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480372" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480372/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679", + "pull_request_review_id": 1823506588, + "id": 1453480679, + "node_id": "PRRC_kwDOABII585Wolrn", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Reserve here?\r\n```suggestion\r\n diagram.clear();\r\n diagram.reserve(chunks.size() + 1);\r\n```", + "created_at": "2024-01-16T14:09:41Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480679", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453480679" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453480679/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 12, + "side": "RIGHT", + "original_position": 9, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107", + "pull_request_review_id": 1823506588, + "id": 1453482107, + "node_id": "PRRC_kwDOABII585WomB7", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+ return;\n+}", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "No need for this return here\r\n```suggestion\r\n}\r\n```", + "created_at": "2024-01-16T14:10:20Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453482107", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453482107" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453482107/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 19, + "start_side": "RIGHT", + "line": null, + "original_line": 20, + "side": "RIGHT", + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633", + "pull_request_review_id": 1823506588, + "id": 1453487633, + "node_id": "PRRC_kwDOABII585WonYR", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe add a docstring on what `BuildDiagramFromUnsortedChunks` does in and out params description that are doxygen compatible?", + "created_at": "2024-01-16T14:14:22Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453487633", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453487633" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453487633/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485", + "pull_request_review_id": 1823506588, + "id": 1453501485, + "node_id": "PRRC_kwDOABII585Woqwt", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: we can just use the empty constructor\r\n```suggestion\r\n FeeFrac empty{};\r\n```", + "created_at": "2024-01-16T14:24:35Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453501485", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453501485" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453501485/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118", + "pull_request_review_id": 1823506588, + "id": 1453502118, + "node_id": "PRRC_kwDOABII585Woq6m", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "why can we have negative size ?", + "created_at": "2024-01-16T14:25:01Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453502118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453502118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453502118/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924", + "pull_request_review_id": 1823506588, + "id": 1453604924, + "node_id": "PRRC_kwDOABII585WpEA8", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think you mean `all_conflicts` here\r\n```suggestion\r\n // old diagram will consist of each element of all_conflicts either at\r\n```", + "created_at": "2024-01-16T15:36:53Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453604924", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453604924" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453604924/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1305, + "side": "RIGHT", + "original_position": 65, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523", + "pull_request_review_id": 1823506588, + "id": 1453612523, + "node_id": "PRRC_kwDOABII585WpF3r", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "use static cast?\r\n```suggestion\r\n FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\r\n```", + "created_at": "2024-01-16T15:42:19Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453612523", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453612523" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453612523/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1327, + "side": "RIGHT", + "original_position": 87, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393", + "pull_request_review_id": 1823506588, + "id": 1453626393, + "node_id": "PRRC_kwDOABII585WpJQZ", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I understand what happens here but its a bit confusing to me the short forms `CON`, `CNK` `DIAGRAM`\r\nWill prefer something like the compute in computing the `OLD` chunk\r\n\r\n```suggestion\r\n // Step 2: build the new diagram\r\n\r\n // Add any parents of direct conflicts that are not conflicted themselves into the NEW chunk\r\n for (auto direct_conflict : direct_conflicts) {\r\n // If a direct conflict has an ancestor that is not in all_conflicts,\r\n // it can be affected by the replacement of the child.\r\n if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\r\n // Grab the parent.\r\n const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\r\n if (!all_conflicts.count(mapTx.iterator_to(parent))) {\r\n // This transaction would be left over, so add to the NEW\r\n // chunk.\r\n new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\r\n }\r\n }\r\n }\r\n // Add the replacement package to NEW\r\n new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));\r\n```", + "created_at": "2024-01-16T15:52:23Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453626393", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453626393" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453626393/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765", + "pull_request_review_id": 1823506588, + "id": 1453667765, + "node_id": "PRRC_kwDOABII585WpTW1", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Should forward the detailed error message also?", + "created_at": "2024-01-16T16:23:36Z", + "updated_at": "2024-01-16T20:00:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453667765", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1453667765" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1453667765/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545", + "pull_request_review_id": 1827173808, + "id": 1455418545, + "node_id": "PRRC_kwDOABII585Wv-yx", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "Even better, I'll add a test that they're the same", + "created_at": "2024-01-17T12:19:19Z", + "updated_at": "2024-01-17T12:19:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455418545", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455418545" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455418545/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "in_reply_to_id": 1453501485, + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851", + "pull_request_review_id": 1827178150, + "id": 1455423851, + "node_id": "PRRC_kwDOABII585WwAFr", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "These are shorthand labels from https://delvingbitcoin.org/t/post-clustermempool-package-rbf-per-chunk-processing/190 which helped me think through preciesely how it maps onto the concepts laid out.\r\n\r\nI'd like to keep track of these ideas somehow, maybe by defining the labels?", + "created_at": "2024-01-17T12:21:54Z", + "updated_at": "2024-01-17T12:21:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455423851", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455423851" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455423851/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826", + "pull_request_review_id": 1827180557, + "id": 1455426826, + "node_id": "PRRC_kwDOABII585WwA0K", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "can you be more explicit in suggestion? The errors are being returned?", + "created_at": "2024-01-17T12:23:21Z", + "updated_at": "2024-01-17T12:23:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455426826", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455426826" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455426826/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932", + "pull_request_review_id": 1827186462, + "id": 1455433932, + "node_id": "PRRC_kwDOABII585WwCjM", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "this is testing that subtraction works correctly, not that an individual chunk can have negative size", + "created_at": "2024-01-17T12:26:54Z", + "updated_at": "2024-01-17T12:26:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455433932", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455433932" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455433932/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026", + "pull_request_review_id": 1827266447, + "id": 1455527026, + "node_id": "PRRC_kwDOABII585WwZRy", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I meant what is being returned by `err_string` and `CompareFeerateDiagram` was not used. why were you unable to compute mining score, same for `CompareFeerateDiagram` why is the fee rate insufficient.", + "created_at": "2024-01-17T13:11:40Z", + "updated_at": "2024-01-17T13:11:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455527026", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455527026" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455527026/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078", + "pull_request_review_id": 1827272350, + "id": 1455534078, + "node_id": "PRRC_kwDOABII585Wwa_-", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "also, `Subtrack` isn't a word...", + "created_at": "2024-01-17T13:14:53Z", + "updated_at": "2024-01-17T13:14:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455534078", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455534078" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455534078/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "in_reply_to_id": 1453480372, + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143", + "pull_request_review_id": 1827276759, + "id": 1455539143, + "node_id": "PRRC_kwDOABII585WwcPH", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "\r\nYeah, maybe to be consistent define the labels and do the same in the `OLD` `chunk` computation loop above.\r\nThough the explicit comments in the `OLD` `chunk` computation loop is more easier to parse for me :).", + "created_at": "2024-01-17T13:17:06Z", + "updated_at": "2024-01-17T13:17:06Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455539143", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455539143" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455539143/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265", + "pull_request_review_id": 1827280890, + "id": 1455544265, + "node_id": "PRRC_kwDOABII585WwdfJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes, My question was... whats the rationale for `FeeFrac` to generally have negative size ?", + "created_at": "2024-01-17T13:19:22Z", + "updated_at": "2024-01-17T13:19:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455544265", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455544265" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455544265/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183", + "pull_request_review_id": 1827381635, + "id": 1455658183, + "node_id": "PRRC_kwDOABII585Ww5TH", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "CompareFeerateDiagram won't return much very interesting, but you're right for the `err_string`, will return it", + "created_at": "2024-01-17T14:08:17Z", + "updated_at": "2024-01-17T14:08:17Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455658183", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1455658183" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1455658183/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934", + "pull_request_review_id": 1833137718, + "id": 1459252934, + "node_id": "PRRC_kwDOABII585W-m7G", + "diff_hunk": "@@ -181,3 +201,108 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+// Compare two feerate points, where one of the points is interpolated from\n+// existing points in a feerate diagram.\n+// Return 1 if the interpolated point is greater than fee_compare; 0 if they\n+// are equal; -1 otherwise.\n+int InterpolateValueAndCompare(int64_t eval_size, const FeeFrac& p1, const FeeFrac& p2, CAmount fee_compare)\n+{\n+ // Interpolate between two points using the formula:\n+ // y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)\n+ // i.e.\n+ // y = p1.fee + (eval_size - p1.size) * (p2.fee - p1.fee) / (p2.size - p2.size)\n+ // fee_compare = fee value we want to compare against the interpolated y\n+ //\n+ // Then evaluating y > fee_compare is equivalent to checking if y*(x2-x1) > fee_compare*(x2-x1),\n+ // or y1*(x2-x1) + (x - x1) * (y2 - y1) > fee_compare*(x2-x1).\n+ const auto fee_compare_scaled = Mul128(fee_compare, p2.size - p1.size);\n+ const auto y_scaled = Add128(Mul128(p1.fee, p2.size - p1.size), Mul128(eval_size - p1.size , p2.fee - p1.fee));\n+\n+ if (y_scaled > fee_compare_scaled) {\n+ return 1;\n+ } else if (y_scaled == fee_compare_scaled) {\n+ return 0;\n+ } else {\n+ return -1;\n+ }\n+}\n+\n+// returns true if the new_diagram is strictly better than the old one; false\n+// otherwise.\n+bool CompareFeerateDiagram(std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ size_t old_index=0;\n+ size_t new_index=0;\n+\n+ // whether the new diagram has at least one point better than old_diagram\n+ bool new_better = false;\n+\n+ // whether the old diagram has at least one point better than new_diagram\n+ bool old_better = false;\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!old_diagram.empty() && !new_diagram.empty());\n+ Assert(old_diagram[0].fee == 0 && old_diagram[0].size == 0);\n+ Assert(new_diagram[0].fee == 0 && new_diagram[0].size == 0);\n+\n+ // Start by padding the smaller diagram with a transaction that pays the\n+ // tail feerate up to the size of the larger diagram.\n+ // For now, use an implicit tail feerate of 0, but we can change this if\n+ // there's an argument to be made that the true tail feerate is higher.\n+ // Also, if we end up needing to transform the feerates (eg to avoid\n+ // negative numbers or overflow in the calculations?), then the tail\n+ // feerate would need to be transformed as well.\n+ if (old_diagram.back().size < new_diagram.back().size) {\n+ old_diagram.emplace_back(old_diagram.back().fee, new_diagram.back().size);\n+ } else if (old_diagram.back().size > new_diagram.back().size) {\n+ new_diagram.emplace_back(new_diagram.back().fee, old_diagram.back().size);\n+ }\n+\n+ while (old_index < old_diagram.size() && new_index < new_diagram.size()) {\n+ int cmp = 0;\n+ if (old_diagram[old_index].size < new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(old_diagram[old_index].size, new_diagram[new_index-1], new_diagram[new_index], old_diagram[old_index].fee);\n+ old_better |= (cmp == -1);\n+ new_better |= (cmp == 1);\n+ old_index++;\n+ } else if (old_diagram[old_index].size > new_diagram[new_index].size) {\n+ cmp = InterpolateValueAndCompare(new_diagram[new_index].size, old_diagram[old_index-1], old_diagram[old_index], new_diagram[new_index].fee);\n+ old_better |= (cmp == 1);\n+ new_better |= (cmp == -1);\n+ new_index++;\n+ } else {\n+ if (old_diagram[old_index].fee > new_diagram[new_index].fee) {\n+ old_better = true;\n+ } else if (old_diagram[old_index].fee < new_diagram[new_index].fee) {\n+ new_better = true;\n+ }\n+ old_index++;\n+ new_index++;\n+ }\n+ }\n+\n+ // New is better at least one point, and at least as good on all points; we'll take it\n+ return new_better && !old_better;\n+}\n+\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ int64_t replacement_vsize,\n+ CAmount replacement_fees)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (err_string.has_value()) {\n+ return strprintf(\"unable to compute mining score\");\n+ }\n+\n+ if (!CompareFeerateDiagram(old_diagram, new_diagram)) {\n+ return strprintf(\"insufficient feerate\");\n+ }", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:18Z", + "updated_at": "2024-01-19T16:01:18Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459252934", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459252934" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459252934/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 300, + "start_side": "RIGHT", + "line": null, + "original_line": 204, + "side": "RIGHT", + "in_reply_to_id": 1453667765, + "original_position": 133, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057", + "pull_request_review_id": 1833138006, + "id": 1459253057, + "node_id": "PRRC_kwDOABII585W-m9B", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ BuildDiagramFromUnsortedChunks(old_chunks, old_diagram);\n+\n+ std::vector new_chunks;\n+\n+ // Step 2: build the NEW = OLD - CON + CNK diagram\n+\n+ // OLD - CON: Any parents of direct conflicts that are not conflicted themselves\n+ for (auto direct_conflict : direct_conflicts) {\n+ // If a direct conflict has an ancestor that is not in all_conflicts,\n+ // it can be affected by the replacement of the child.\n+ if (direct_conflict->GetMemPoolParentsConst().size() > 0) {\n+ // Grab the parent.\n+ const CTxMemPoolEntry& parent = direct_conflict->GetMemPoolParentsConst().begin()->get();\n+ if (!all_conflicts.count(mapTx.iterator_to(parent))) {\n+ // This transaction would be left over, so add to the new\n+ // diagram.\n+ new_chunks.emplace_back(parent.GetModifiedFee(), parent.GetTxSize());\n+ }\n+ }\n+ }\n+ // + CNK\n+ new_chunks.emplace_back(replacement_fees, int32_t(replacement_vsize));", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "took some of hte language, and explicitly defined each term", + "created_at": "2024-01-19T16:01:24Z", + "updated_at": "2024-01-19T16:01:24Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253057", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253057" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253057/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1348, + "start_side": "RIGHT", + "line": null, + "original_line": 1363, + "side": "RIGHT", + "in_reply_to_id": 1453626393, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223", + "pull_request_review_id": 1833138370, + "id": 1459253223, + "node_id": "PRRC_kwDOABII585W-m_n", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // Compute OLD chunks for all clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), int32_t(txiter->GetSizeWithAncestors())};", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:31Z", + "updated_at": "2024-01-19T16:01:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253223", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253223" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253223/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1327, + "side": "RIGHT", + "in_reply_to_id": 1453612523, + "original_position": 87, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328", + "pull_request_review_id": 1833138587, + "id": 1459253328, + "node_id": "PRRC_kwDOABII585W-nBQ", + "diff_hunk": "@@ -1248,3 +1249,121 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", ancestor_count, txid_string);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of direct_conflicts either at", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ab9a952bdd1406a4fc9fa71c63e6fbecb78d0a4b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:35Z", + "updated_at": "2024-01-19T16:01:35Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253328", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253328" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253328/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1305, + "side": "RIGHT", + "in_reply_to_id": 1453604924, + "original_position": 65, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396", + "pull_request_review_id": 1833138722, + "id": 1459253396, + "node_id": "PRRC_kwDOABII585W-nCU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "We use subtraction, and should try to handle that?", + "created_at": "2024-01-19T16:01:37Z", + "updated_at": "2024-01-19T16:01:38Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253396", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253396" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253396/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460", + "pull_request_review_id": 1833138857, + "id": 1459253460, + "node_id": "PRRC_kwDOABII585W-nDU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:40Z", + "updated_at": "2024-01-19T16:01:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253460", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253460" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253460/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 17, + "original_line": 17, + "side": "RIGHT", + "in_reply_to_id": 1453501485, + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539", + "pull_request_review_id": 1833139037, + "id": 1459253539, + "node_id": "PRRC_kwDOABII585W-nEj", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "added comment", + "created_at": "2024-01-19T16:01:43Z", + "updated_at": "2024-01-19T16:01:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253539", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253539" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253539/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1453487633, + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631", + "pull_request_review_id": 1833139134, + "id": 1459253631, + "node_id": "PRRC_kwDOABII585W-nF_", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+ return;\n+}", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:46Z", + "updated_at": "2024-01-19T16:01:46Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253631", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253631" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253631/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 19, + "start_side": "RIGHT", + "line": null, + "original_line": 20, + "side": "RIGHT", + "in_reply_to_id": 1453482107, + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686", + "pull_request_review_id": 1833139262, + "id": 1459253686, + "node_id": "PRRC_kwDOABII585W-nG2", + "diff_hunk": "@@ -0,0 +1,21 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:48Z", + "updated_at": "2024-01-19T16:01:48Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253686", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253686" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253686/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 12, + "side": "RIGHT", + "in_reply_to_id": 1453480679, + "original_position": 9, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728", + "pull_request_review_id": 1833139379, + "id": 1459253728, + "node_id": "PRRC_kwDOABII585W-nHg", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T16:01:50Z", + "updated_at": "2024-01-19T16:01:50Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253728", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459253728" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459253728/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 84, + "start_side": "RIGHT", + "line": null, + "original_line": 91, + "side": "RIGHT", + "in_reply_to_id": 1453480372, + "original_position": 91, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030", + "pull_request_review_id": 1833161137, + "id": 1459264030, + "node_id": "PRRC_kwDOABII585W-poe", + "diff_hunk": "@@ -106,4 +108,23 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts\n+ * @param[in] replacement_fees Fees of replacement package\n+ * @param[in] replacement_vsize Size of replacement package\n+ * @returns error string if mempool diagram doesn't improve, otherwise std::nullopt.\n+ */\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+ EXCLUSIVE_LOCKS_REQUIRED(pool.cs);\n+\n+/** Compares two feerate diagrams. The shorter one is padded with a horizonal line. */\n+std::partial_ordering CompareFeerateDiagram(std::vector& dia0, std::vector& dia1);", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: perhaps this function belongs more in util/feefrac (as the building of the diagram also lives there)", + "created_at": "2024-01-19T16:09:00Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459264030", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459264030" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459264030/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 128, + "side": "RIGHT", + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118", + "pull_request_review_id": 1833161137, + "id": 1459279118, + "node_id": "PRRC_kwDOABII585W-tUO", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "I can think of one use case where negative sizes are actually useful, though it's pretty far fetched.\r\n\r\nCurrently the code hardcodes a \"tail feerate\" (the feerate of which we assume there is an infinite supply) of 0 sat/vB for mempool improvement checks, but in theory this can be configurable. In that case, in addition to the diagram check between old and new package, we want the property that `fee_new >= fee_old + (size_new - size_old) * feerate_tail`. If `old`, `new`, and `tail` are CFeeFrac objects, this condition is exactly `!((new - old) << tail)`. If new is smaller than old, the `new - old` object has negative size.\r\n\r\nA more pragmatic answer is that there is no real reason to restrict it to just positive sizes, and not enforcing it is simpler.", + "created_at": "2024-01-19T16:18:54Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459279118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459279118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459279118/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387", + "pull_request_review_id": 1833161137, + "id": 1459281387, + "node_id": "PRRC_kwDOABII585W-t3r", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: std::array.", + "created_at": "2024-01-19T16:20:13Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459281387", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459281387" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459281387/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 47, + "side": "RIGHT", + "original_position": 47, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903", + "pull_request_review_id": 1833161137, + "id": 1459282903, + "node_id": "PRRC_kwDOABII585W-uPX", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: EMBRACE THE SPACESHIP\r\n\r\n```c++\r\nif (a[i] != b[i]) return a[i] <=> b[i];\r\n```", + "created_at": "2024-01-19T16:21:09Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459282903", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459282903" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459282903/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 1, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 50, + "side": "RIGHT", + "original_position": 50, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849", + "pull_request_review_id": 1833161137, + "id": 1459283849, + "node_id": "PRRC_kwDOABII585W-ueJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: `2^64` -> `2^32`", + "created_at": "2024-01-19T16:21:44Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459283849", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459283849" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459283849/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 39, + "side": "RIGHT", + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396", + "pull_request_review_id": 1833161137, + "id": 1459309396, + "node_id": "PRRC_kwDOABII585W-0tU", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Suggested change that (I believe) avoids the need for suppressions (and may be more readable?):\r\n\r\n```c++\r\n auto add_fn = [&](uint64_t v, int pos) {\r\n uint64_t accum{0};\r\n for (int i = 0; i + pos < 4; ++i) {\r\n // Add current value at limb pos in ret.\r\n accum += ret[3 - pos - i];\r\n // Add low or high half of v.\r\n if (i == 0) accum += v & 0xffffffff;\r\n if (i == 1) accum += v >> 32;\r\n // Store lower half of result in limb pos in ret.\r\n ret[3 - pos - i] = accum & 0xffffffff;\r\n // Leave carry in accum.\r\n accum >>= 32;\r\n }\r\n // Make sure no overflow.\r\n assert(accum == 0);\r\n };\r\n```", + "created_at": "2024-01-19T16:36:25Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459309396", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459309396" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459309396/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "original_position": 22, + "position": 22, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210", + "pull_request_review_id": 1833161137, + "id": 1459312210, + "node_id": "PRRC_kwDOABII585W-1ZS", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;\n+ if (a[i] > b[i]) return std::strong_ordering::greater;\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Avoid the need for a suppression:\r\n\r\n```c++\r\n// Compute absolute values.\r\nuint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\r\nuint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\r\n// Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\r\n// intentional here.\r\nif (a1 < 0) abs_a1 = ~abs_a1 + 1;\r\nif (a2 < 0) abs_a2 = ~abs_a2 + 1;\r\nif (b1 < 0) abs_b1 = ~abs_b1 + 1;\r\nif (b2 < 0) abs_b2 = ~abs_b2 + 1;\r\n```\r\n\r\n(The same trick is used in `CScriptNum::serialize`, it could be abstracted out)", + "created_at": "2024-01-19T16:38:05Z", + "updated_at": "2024-01-19T17:31:51Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459312210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459312210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459312210/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 62, + "original_line": 62, + "side": "RIGHT", + "original_position": 63, + "position": 62, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118", + "pull_request_review_id": 1833161137, + "id": 1459315118, + "node_id": "PRRC_kwDOABII585W-2Gu", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: no need for this `namespace` anymore.", + "created_at": "2024-01-19T16:39:47Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459315118", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459315118" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459315118/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 13, + "side": "RIGHT", + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281", + "pull_request_review_id": 1833161137, + "id": 1459316281, + "node_id": "PRRC_kwDOABII585W-2Y5", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: this operator can be dropped (C++20 will automatically generate it as negation of `operator==`).", + "created_at": "2024-01-19T16:40:32Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459316281", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459316281" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459316281/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 125, + "side": "RIGHT", + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381", + "pull_request_review_id": 1833161137, + "id": 1459317381, + "node_id": "PRRC_kwDOABII585W-2qF", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee != b.fee || a.size != b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object is worse than another. */\n+ friend inline bool operator<(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Self-nit: `operator<`, `operator>`, `operator<=` and `operator>=` can be dropped (C++20 will autogenerate them using `operator<=>` (inspecting the compiled code, it's marginally less efficient, but all the actually performance-critical uses use `operator<<`, `operator>>`, or `FeeRateCompare` anyway).", + "created_at": "2024-01-19T16:41:05Z", + "updated_at": "2024-01-19T16:42:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459317381", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459317381" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459317381/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 160, + "side": "RIGHT", + "original_position": 160, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324", + "pull_request_review_id": 1833628032, + "id": 1459709324, + "node_id": "PRRC_kwDOABII585XAWWM", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee != b.fee || a.size != b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object is worse than another. */\n+ friend inline bool operator<(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:20Z", + "updated_at": "2024-01-19T20:25:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709324", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709324" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709324/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 160, + "side": "RIGHT", + "in_reply_to_id": 1459317381, + "original_position": 160, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417", + "pull_request_review_id": 1833628227, + "id": 1459709417, + "node_id": "PRRC_kwDOABII585XAWXp", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Check if two FeeFrac objects are different (either fee or size differs). */\n+ friend inline bool operator!=(const FeeFrac& a, const FeeFrac& b) noexcept", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:25Z", + "updated_at": "2024-01-19T20:25:25Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709417", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709417" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709417/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 125, + "side": "RIGHT", + "in_reply_to_id": 1459316281, + "original_position": 125, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496", + "pull_request_review_id": 1833628323, + "id": 1459709496, + "node_id": "PRRC_kwDOABII585XAWY4", + "diff_hunk": "@@ -0,0 +1,202 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+\n+namespace {", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:28Z", + "updated_at": "2024-01-19T20:25:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709496", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709496" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709496/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 13, + "side": "RIGHT", + "in_reply_to_id": 1459315118, + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630", + "pull_request_review_id": 1833628458, + "id": 1459709630, + "node_id": "PRRC_kwDOABII585XAWa-", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;\n+ if (a[i] > b[i]) return std::strong_ordering::greater;\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:34Z", + "updated_at": "2024-01-19T20:25:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709630", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709630" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709630/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 62, + "original_line": 62, + "side": "RIGHT", + "in_reply_to_id": 1459312210, + "original_position": 63, + "position": 62, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663", + "pull_request_review_id": 1833628511, + "id": 1459709663, + "node_id": "PRRC_kwDOABII585XAWbf", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "looks good, done", + "created_at": "2024-01-19T20:25:36Z", + "updated_at": "2024-01-19T20:25:36Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709663", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709663" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709663/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1459309396, + "original_position": 22, + "position": 22, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766", + "pull_request_review_id": 1833628606, + "id": 1459709766, + "node_id": "PRRC_kwDOABII585XAWdG", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:40Z", + "updated_at": "2024-01-19T20:25:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709766", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709766" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709766/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 39, + "side": "RIGHT", + "in_reply_to_id": 1459283849, + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852", + "pull_request_review_id": 1833628685, + "id": 1459709852, + "node_id": "PRRC_kwDOABII585XAWec", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] < b[i]) return std::strong_ordering::less;", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:44Z", + "updated_at": "2024-01-19T20:25:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709852", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709852" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709852/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 50, + "side": "RIGHT", + "in_reply_to_id": 1459282903, + "original_position": 50, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932", + "pull_request_review_id": 1833628778, + "id": 1459709932, + "node_id": "PRRC_kwDOABII585XAWfs", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint32_t carry = 0;\n+ for (int i = 0; i + pos < 4; ++i) {\n+ uint32_t& limb = ret[3 - pos - i];\n+ uint32_t old = limb;\n+ // Add low or high half of v.\n+ if (i == 0) limb += v;\n+ if (i == 1) limb += v >> 32;\n+ // Add carry from previous position.\n+ limb += carry;\n+ // Compute carry for next position.\n+ carry = (limb < old) || ((limb == old) && carry);\n+ }\n+ // Make sure no overflow.\n+ assert(carry == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^64).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::vector */", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-19T20:25:48Z", + "updated_at": "2024-01-19T20:25:48Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709932", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459709932" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459709932/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 47, + "side": "RIGHT", + "in_reply_to_id": 1459281387, + "original_position": 47, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174", + "pull_request_review_id": 1833628978, + "id": 1459710174, + "node_id": "PRRC_kwDOABII585XAWje", + "diff_hunk": "@@ -106,4 +108,23 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts\n+ * @param[in] replacement_fees Fees of replacement package\n+ * @param[in] replacement_vsize Size of replacement package\n+ * @returns error string if mempool diagram doesn't improve, otherwise std::nullopt.\n+ */\n+std::optional ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+ EXCLUSIVE_LOCKS_REQUIRED(pool.cs);\n+\n+/** Compares two feerate diagrams. The shorter one is padded with a horizonal line. */\n+std::partial_ordering CompareFeerateDiagram(std::vector& dia0, std::vector& dia1);", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a4b92cfd641d65224528395f1f9b98406822f333", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "makes sense, moved", + "created_at": "2024-01-19T20:25:58Z", + "updated_at": "2024-01-19T20:25:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459710174", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1459710174" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1459710174/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 128, + "side": "RIGHT", + "in_reply_to_id": 1459264030, + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681", + "pull_request_review_id": 1837231759, + "id": 1462332681, + "node_id": "PRRC_kwDOABII585XKW0J", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In the commit message of \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n> This new function takes the populated sets of\r\n> direct and all conflicts computed in the current\r\n> mempool, assuming the replacements are a single\r\n> chunk, and computes a diagram check.\r\n\r\nThe first sentence is confusing to me. Could you perhaps clarify \"the populated sets of direct and all conflicts\" and split the sentence up?", + "created_at": "2024-01-22T19:42:17Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462332681", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462332681" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462332681/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934", + "pull_request_review_id": 1837231759, + "id": 1462348934, + "node_id": "PRRC_kwDOABII585XKayG", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nNit: The documentation is in opposite order as the checks. Perhaps switch these two lines.", + "created_at": "2024-01-22T19:55:55Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462348934", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462348934" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462348934/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1274, + "start_side": "RIGHT", + "line": null, + "original_line": 1264, + "side": "RIGHT", + "original_position": 35, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586", + "pull_request_review_id": 1837231759, + "id": 1462350586, + "node_id": "PRRC_kwDOABII585XKbL6", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n```suggestion\r\n return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\r\n```", + "created_at": "2024-01-22T19:57:44Z", + "updated_at": "2024-01-22T21:59:55Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462350586", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462350586" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462350586/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1271, + "side": "RIGHT", + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378", + "pull_request_review_id": 1837231759, + "id": 1462365378, + "node_id": "PRRC_kwDOABII585XKezC", + "diff_hunk": "@@ -106,4 +115,20 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nMaybe that’s my unfamiliarity with the mempool code, but it is not obvious to me what \"direct_conflicts\" and \"all_conflicts\" are, and the description here is self-referential. Do these transactions belong to original, replacement, or both, etc.?", + "created_at": "2024-01-22T20:12:42Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462365378", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462365378" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462365378/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 121, + "start_side": "RIGHT", + "line": null, + "original_line": 122, + "side": "RIGHT", + "original_position": 32, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881", + "pull_request_review_id": 1837231759, + "id": 1462385881, + "node_id": "PRRC_kwDOABII585XKjzZ", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\nNit: Spaces around that minus? It took me a moment to realize that dashes aren’t a thing in variables. ", + "created_at": "2024-01-22T20:34:34Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462385881", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462385881" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462385881/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1335, + "side": "RIGHT", + "original_position": 95, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782", + "pull_request_review_id": 1837231759, + "id": 1462412782, + "node_id": "PRRC_kwDOABII585XKqXu", + "diff_hunk": "@@ -734,6 +735,23 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly (not via descendants)", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (9257f33d259bf68f1df1cc41b7b3caaea341782f):\r\n\r\n```suggestion\r\n * @param[in] direct_conflicts All transactions that would be removed directly (not by being descendants of conflicting transactions)\r\n```", + "created_at": "2024-01-22T20:55:51Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462412782", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462412782" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462412782/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 744, + "side": "RIGHT", + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899", + "pull_request_review_id": 1837231759, + "id": 1462453899, + "node_id": "PRRC_kwDOABII585XK0aL", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\nNit: I found the comment here confusing. How about: \"`new_diagram` is strictly better due to the first chunk, while the second chunk is worse.\"", + "created_at": "2024-01-22T21:40:35Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462453899", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462453899" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462453899/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 296, + "side": "RIGHT", + "original_position": 206, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196", + "pull_request_review_id": 1837231759, + "id": 1462457196, + "node_id": "PRRC_kwDOABII585XK1Ns", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\n\r\nNit: in the new diagram, the last two chunks should be one chunk because the last chunk is better (151 sats, 150 vB) than the prior (249 sats, 250 vB).", + "created_at": "2024-01-22T21:44:38Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462457196", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462457196" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462457196/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 303, + "start_side": "RIGHT", + "line": null, + "original_line": 304, + "side": "RIGHT", + "original_position": 214, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868", + "pull_request_review_id": 1837231759, + "id": 1462462868, + "node_id": "PRRC_kwDOABII585XK2mU", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Same aggregate fee, but different total size (trigger single tail fee check step)\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ // No change in evaluation when tail check needed.\n+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"test: Add tests for CompareFeerateDiagram and CheckConflictTopology\" (b3d415fe84be7edfbed567a79a25d406b438622b):\r\n\r\nThis is the same old_diagram. Did you mean to repeat the same transactions,\r\n```suggestion\r\n\r\n old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\r\n new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\r\n```\r\nor just test in both directions?\r\n```suggestion\r\n```", + "created_at": "2024-01-22T21:51:02Z", + "updated_at": "2024-01-22T21:59:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462462868", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1462462868" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1462462868/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 326, + "start_side": "RIGHT", + "line": null, + "original_line": 328, + "side": "RIGHT", + "original_position": 238, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056", + "pull_request_review_id": 1838789825, + "id": 1463281056, + "node_id": "PRRC_kwDOABII585XN-Wg", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "direct_conflicts and all_conflicts. Does that help?", + "created_at": "2024-01-23T13:26:49Z", + "updated_at": "2024-01-23T13:26:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463281056", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463281056" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463281056/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1462332681, + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858", + "pull_request_review_id": 1838797602, + "id": 1463285858, + "node_id": "PRRC_kwDOABII585XN_hi", + "diff_hunk": "@@ -106,4 +115,20 @@ std::optional PaysForRBF(CAmount original_fees,\n CFeeRate relay_fee,\n const uint256& txid);\n \n+/**\n+ * The replacement transaction must improve the feerate diagram of the mempool.\n+ * @param[in] pool The mempool.\n+ * @param[in] direct_conflicts Set of txids corresponding to the direct conflicts\n+ * @param[in] all_conflicts Set of mempool entries corresponding to all conflicts", + "path": "src/policy/rbf.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "direct_conflicts -> the set of transactions that have at least one input conflicting with a proposed transaction.\r\nall_conflicts -> Everything that would be evicted by the proposed transaction\r\n\r\nI'll touch this up a bit but this is the nomenclature elsewhere", + "created_at": "2024-01-23T13:30:37Z", + "updated_at": "2024-01-23T13:30:37Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463285858", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463285858" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463285858/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 121, + "start_side": "RIGHT", + "line": null, + "original_line": 122, + "side": "RIGHT", + "in_reply_to_id": 1462365378, + "original_position": 32, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427", + "pull_request_review_id": 1838845793, + "id": 1463314427, + "node_id": "PRRC_kwDOABII585XOGf7", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Same aggregate fee, but different total size (trigger single tail fee check step)\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ // No change in evaluation when tail check needed.\n+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I can't recall honestly, removed that line", + "created_at": "2024-01-23T13:51:39Z", + "updated_at": "2024-01-23T13:51:39Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314427", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314427" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314427/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 326, + "start_side": "RIGHT", + "line": null, + "original_line": 328, + "side": "RIGHT", + "in_reply_to_id": 1462462868, + "original_position": 238, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511", + "pull_request_review_id": 1838845897, + "id": 1463314511, + "node_id": "PRRC_kwDOABII585XOGhP", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is better, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 500}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "ah hmm, I'm not sure that matters for correctness of test, but jacked up the last chunk's size just to make it clearer what we're testing", + "created_at": "2024-01-23T13:51:42Z", + "updated_at": "2024-01-23T13:51:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314511", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314511" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314511/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 303, + "start_side": "RIGHT", + "line": null, + "original_line": 304, + "side": "RIGHT", + "in_reply_to_id": 1462457196, + "original_position": 214, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570", + "pull_request_review_id": 1838845988, + "id": 1463314570, + "node_id": "PRRC_kwDOABII585XOGiK", + "diff_hunk": "@@ -217,15 +232,113 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first chunk is sufficiently better, but second chunk is worse.", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b3d415fe84be7edfbed567a79a25d406b438622b", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "tried my own re-explanation. I agree as-is is confusing", + "created_at": "2024-01-23T13:51:45Z", + "updated_at": "2024-01-23T13:51:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314570", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314570" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314570/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 296, + "side": "RIGHT", + "in_reply_to_id": 1462453899, + "original_position": 206, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620", + "pull_request_review_id": 1838846083, + "id": 1463314620, + "node_id": "PRRC_kwDOABII585XOGi8", + "diff_hunk": "@@ -734,6 +735,23 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly (not via descendants)", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "tried my own explanation", + "created_at": "2024-01-23T13:51:47Z", + "updated_at": "2024-01-23T13:51:47Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314620", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314620" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314620/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 744, + "side": "RIGHT", + "in_reply_to_id": 1462412782, + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778", + "pull_request_review_id": 1838846344, + "id": 1463314778, + "node_id": "PRRC_kwDOABII585XOGla", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)\n+{\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return err_string;\n+ }\n+\n+ // new_diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package-individual);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-01-23T13:51:54Z", + "updated_at": "2024-01-23T13:51:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314778", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463314778" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463314778/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1335, + "side": "RIGHT", + "in_reply_to_id": 1462385881, + "original_position": 95, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597", + "pull_request_review_id": 1838847715, + "id": 1463315597, + "node_id": "PRRC_kwDOABII585XOGyN", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken", + "created_at": "2024-01-23T13:52:33Z", + "updated_at": "2024-01-23T13:52:33Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315597", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315597" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315597/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1271, + "side": "RIGHT", + "in_reply_to_id": 1462350586, + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777", + "pull_request_review_id": 1838847976, + "id": 1463315777, + "node_id": "PRRC_kwDOABII585XOG1B", + "diff_hunk": "@@ -1248,3 +1249,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a parent, we are its only child.\n+ // If we have a child, we are its only parent.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-01-23T13:52:40Z", + "updated_at": "2024-01-23T13:52:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315777", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463315777" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463315777/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 1274, + "start_side": "RIGHT", + "line": null, + "original_line": 1264, + "side": "RIGHT", + "in_reply_to_id": 1462348934, + "original_position": 35, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645", + "pull_request_review_id": 1839710319, + "id": 1463859645, + "node_id": "PRRC_kwDOABII585XQLm9", + "diff_hunk": "@@ -19,6 +19,8 @@\n #include \n #include \n \n+#include ", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "9257f33d259bf68f1df1cc41b7b3caaea341782f", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yeah, that would improve it", + "created_at": "2024-01-23T19:05:54Z", + "updated_at": "2024-01-23T19:05:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463859645", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463859645" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463859645/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 22, + "original_line": 22, + "side": "RIGHT", + "in_reply_to_id": 1462332681, + "original_position": 4, + "position": 4, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198", + "pull_request_review_id": 1839716607, + "id": 1463863198, + "node_id": "PRRC_kwDOABII585XQMee", + "diff_hunk": "@@ -734,6 +735,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input wih a proposed transaction", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n * having a conflicting input with a proposed transaction\r\n```", + "created_at": "2024-01-23T19:09:34Z", + "updated_at": "2024-01-23T19:14:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463863198", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463863198" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463863198/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 745, + "side": "RIGHT", + "original_position": 19, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212", + "pull_request_review_id": 1839716607, + "id": 1463866212, + "node_id": "PRRC_kwDOABII585XQNNk", + "diff_hunk": "@@ -217,15 +232,154 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)\n+ const auto tx3 = make_tx(/*inputs=*/ {tx2}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx3));\n+ const auto res3 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size);\n+ BOOST_CHECK(res3.has_value());\n+ BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n+ BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "If all diagrams always start with `FeeFrac{0, 0}`, why do we need to mention that as a first element?", + "created_at": "2024-01-23T19:12:38Z", + "updated_at": "2024-01-23T19:14:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463866212", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1463866212" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1463866212/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 508, + "original_start_line": 327, + "start_side": "RIGHT", + "line": 509, + "original_line": 509, + "side": "RIGHT", + "original_position": 238, + "position": 418, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538", + "pull_request_review_id": 1843766331, + "id": 1466391538, + "node_id": "PRRC_kwDOABII585XZ1vy", + "diff_hunk": "@@ -734,6 +735,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input wih a proposed transaction", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-01-25T13:37:24Z", + "updated_at": "2024-01-25T13:37:24Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466391538", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466391538" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466391538/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 745, + "side": "RIGHT", + "in_reply_to_id": 1463863198, + "original_position": 19, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222", + "pull_request_review_id": 1843767479, + "id": 1466392222, + "node_id": "PRRC_kwDOABII585XZ16e", + "diff_hunk": "@@ -217,15 +232,154 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto child_tx2 = add_descendants(tx10, 1, pool);\n+ const auto entry10_child2 = pool.GetIter(child_tx2->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).has_value());\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)\n+ const auto tx3 = make_tx(/*inputs=*/ {tx2}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx3));\n+ const auto res3 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size);\n+ BOOST_CHECK(res3.has_value());\n+ BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n+ BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "a14b95129d3a2894b7a41ce919a426bb60f62e35", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I'll leave this as an ergonomics issue for later debate", + "created_at": "2024-01-25T13:37:59Z", + "updated_at": "2024-01-25T13:38:00Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466392222", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1466392222" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1466392222/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 508, + "original_start_line": 327, + "start_side": "RIGHT", + "line": 509, + "original_line": 509, + "side": "RIGHT", + "in_reply_to_id": 1463866212, + "original_position": 238, + "position": 418, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777", + "pull_request_review_id": 1849127187, + "id": 1469871777, + "node_id": "PRRC_kwDOABII585XnHah", + "diff_hunk": "@@ -0,0 +1,164 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "c5e63487c52835645c5cda9779500a000c3a023c", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n int64_t fee;\r\n int32_t size;\r\n```\r\n\r\nShould their be more information that will describe the transaction size and fee, base / modified fee, vsize in bytes or something of that sort.\r\nIf not I think its okay like this.\r\n\r\n---\r\nUnrelated just asking to learn.\r\nWhy are'nt we using `CAmount` here for the fee?\r\n\r\nIn some places I see transaction size as `uint32_t` while some places its `int32_t`.\r\n\r\nShould we have a type for size just like `CAmount`?", + "created_at": "2024-01-29T16:37:19Z", + "updated_at": "2024-01-29T21:18:17Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1469871777", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1469871777" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1469871777/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 63, + "start_side": "RIGHT", + "line": null, + "original_line": 64, + "side": "RIGHT", + "original_position": 66, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523", + "pull_request_review_id": 1875569689, + "id": 1486385523, + "node_id": "PRRC_kwDOABII585YmHFz", + "diff_hunk": "@@ -0,0 +1,164 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "c5e63487c52835645c5cda9779500a000c3a023c", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "> If not I think its okay like this.\r\n\r\nremoved comments, how it's precisely used is an implementation detail outside of this code", + "created_at": "2024-02-12T15:54:53Z", + "updated_at": "2024-02-12T15:54:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1486385523", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1486385523" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1486385523/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 63, + "start_side": "RIGHT", + "line": null, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1469871777, + "original_position": 66, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848", + "pull_request_review_id": 1878540108, + "id": 1488282848, + "node_id": "PRRC_kwDOABII585YtWTg", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "In implementation they are sorted in increasing fee rate and the chunks in the comments should be ordered as is? and also the 0 fee and size chucks sorts first. \r\n```suggestion\r\n * by decreasing size. The empty FeeFrac (fee and size both 0) sorts first. So for example, the\r\n * following FeeFracs are in sorted order:\r\n *\r\n * - fee=0 size=0 (undefined feerate)\r\n * - fee=2 size=1 (feerate 2)\r\n * - fee=3 size=2 (feerate 1.5)\r\n * - fee=1 size=1 (feerate 1)\r\n * - fee=2 size=2 (feerate 1)\r\n * - fee=2 size=3 (feerate 0.667...)\r\n * - fee=1 size=2 (feerate 0.5)\r\n * - fee=0 size=1 (feerate 0)\r\n```", + "created_at": "2024-02-13T17:16:44Z", + "updated_at": "2024-02-13T17:35:07Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488282848", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488282848" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488282848/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682", + "pull_request_review_id": 1878540108, + "id": 1488285682, + "node_id": "PRRC_kwDOABII585YtW_y", + "diff_hunk": "@@ -1235,3 +1236,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe add unit test for `CalculateFeerateDiagramsForRBF` also?", + "created_at": "2024-02-13T17:18:40Z", + "updated_at": "2024-02-13T17:34:23Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488285682", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488285682" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488285682/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1283, + "side": "RIGHT", + "original_position": 53, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016", + "pull_request_review_id": 1878540108, + "id": 1488290016, + "node_id": "PRRC_kwDOABII585YtYDg", + "diff_hunk": "@@ -0,0 +1,127 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint64_t accum{0};\n+ for (int i = 0; i + pos < 4; ++i) {\n+ // Add current value at limb pos in ret.\n+ accum += ret[3 - pos - i];\n+ // Add low or high half of v.\n+ if (i == 0) accum += v & 0xffffffff;\n+ if (i == 1) accum += v >> 32;\n+ // Store lower half of result in limb pos in ret.\n+ ret[3 - pos - i] = accum & 0xffffffff;\n+ // Leave carry in accum.\n+ accum >>= 32;\n+ }\n+ // Make sure no overflow.\n+ assert(accum == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^32).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::array */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] != b[i]) return a[i] <=> b[i];\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.\n+ uint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\n+ uint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\n+ // Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\n+ // intentional here.\n+ if (a1 < 0) abs_a1 = ~abs_a1 + 1;\n+ if (a2 < 0) abs_a2 = ~abs_a2 + 1;\n+ if (b1 < 0) abs_b1 = ~abs_b1 + 1;\n+ if (b2 < 0) abs_b2 = ~abs_b2 + 1;\n+\n+ // Compute products of absolute values.\n+ auto mul_abs_a = Mul128(abs_a1, abs_a2);\n+ auto mul_abs_b = Mul128(abs_b1, abs_b2);\n+ if (sign_a < 0) {\n+ return compare_arrays(mul_abs_b, mul_abs_a);\n+ } else {\n+ return compare_arrays(mul_abs_a, mul_abs_b);\n+ }\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(feefrac)\n+{\n+ FuzzedDataProvider provider(buffer.data(), buffer.size());\n+\n+ int64_t f1 = provider.ConsumeIntegral();\n+ //int64_t f1 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);\n+ int32_t s1 = provider.ConsumeIntegral();\n+ if (s1 == 0) f1 = 0;\n+ FeeFrac fr1(f1, s1);\n+ assert(fr1.IsEmpty() == (s1 == 0));\n+\n+ int64_t f2 = provider.ConsumeIntegral();\n+ //int64_t f2 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Why not delete the commented version of f1 and f2.\r\n```suggestion\r\n int32_t s1 = provider.ConsumeIntegral();\r\n if (s1 == 0) f1 = 0;\r\n FeeFrac fr1(f1, s1);\r\n assert(fr1.IsEmpty() == (s1 == 0));\r\n\r\n int64_t f2 = provider.ConsumeIntegral();\r\n \r\n```", + "created_at": "2024-02-13T17:21:35Z", + "updated_at": "2024-02-13T17:35:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488290016", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1488290016" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1488290016/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 89, + "start_side": "RIGHT", + "line": null, + "original_line": 98, + "side": "RIGHT", + "original_position": 98, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971", + "pull_request_review_id": 1880803374, + "id": 1489790971, + "node_id": "PRRC_kwDOABII585YzGf7", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "> If `old`, `new`, and `tail` are CFeeFrac objects, this condition is exactly `!((new - old) << tail)`. If new is smaller than old, the `new - old` object has negative size.\r\n\r\n@sipa With the various `Assume()` calls that check that if the size is 0, the fee must also be zero, doesn't that mean that we can't really write code like this example you gave? Unless we checked that new != old first -- otherwise you might create a FeeFrac with 0 size and non-zero fee.\r\n", + "created_at": "2024-02-14T16:54:49Z", + "updated_at": "2024-02-14T16:54:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1489790971", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1489790971" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1489790971/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 1 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524", + "pull_request_review_id": 1881279355, + "id": 1490043524, + "node_id": "PRRC_kwDOABII585Y0EKE", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I don't understand your comment, sorry. They're listed in increasing feerate, with decreasing size as a tie breaker.", + "created_at": "2024-02-14T20:44:55Z", + "updated_at": "2024-02-14T20:44:55Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1490043524", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1490043524" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1490043524/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911", + "pull_request_review_id": 1882814496, + "id": 1491039911, + "node_id": "PRRC_kwDOABII585Y33an", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes but in reverse I think.\r\nSuppose to be the other way around no?\r\n\r\nA sorted `FeeFracs` should have undefined chunks first, the highest fee rate chunk second continuously...\r\nIf their is a tie, the chunk with lower size comes first.\r\nHence the are sorted in increasing fee rates, and then by decreasing size.\r\n\r\nI've added test to verify this here https://github.com/ismaelsadeeq/bitcoin/commit/8ce89b132f4304a7feda067a88fd0a72330044a6, this test passed on this branch.", + "created_at": "2024-02-15T13:50:37Z", + "updated_at": "2024-02-15T13:50:37Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491039911", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491039911" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491039911/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223", + "pull_request_review_id": 1882829496, + "id": 1491046223, + "node_id": "PRRC_kwDOABII585Y349P", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "@ismaelsadeeq The comparator you provide to `std::sort` is supposed to return whether the first argument should sort *before* the second one (if no comparator is provided, `operator<` is used). With that, you should see lowest feerate first, highest feerate last, and the undefined feefrac at the very end. Within equal-feerate groups, larger size comes first.", + "created_at": "2024-02-15T13:55:11Z", + "updated_at": "2024-02-15T13:55:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491046223", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491046223" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491046223/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596", + "pull_request_review_id": 1882850491, + "id": 1491054596, + "node_id": "PRRC_kwDOABII585Y37AE", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes thanks for clarification 👍🏾 ", + "created_at": "2024-02-15T14:00:43Z", + "updated_at": "2024-02-15T14:00:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491054596", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491054596" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491054596/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699", + "pull_request_review_id": 1882865782, + "id": 1491060699, + "node_id": "PRRC_kwDOABII585Y38fb", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "I looked at it the other way around, using the result from `BuildDiagramFromUnsortedChunks` sort which uses custom > operator @instagibbs.", + "created_at": "2024-02-15T14:05:11Z", + "updated_at": "2024-02-15T14:05:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491060699", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491060699" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491060699/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655", + "pull_request_review_id": 1882920075, + "id": 1491090655, + "node_id": "PRRC_kwDOABII585Y4Dzf", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "@sdaftuar Indeed. It wouldn't require anything more than dropping those `Assume()` calls, but right now FeeFrac objects represent (the aggregate fee and size of) sets of transactions, rather differences between such aggregates (as would be needed for this use case).", + "created_at": "2024-02-15T14:25:20Z", + "updated_at": "2024-02-15T14:25:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491090655", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491090655" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491090655/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059", + "pull_request_review_id": 1883351956, + "id": 1491329059, + "node_id": "PRRC_kwDOABII585Y4-Aj", + "diff_hunk": "@@ -1235,3 +1236,126 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+std::optional CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram)", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "good point; added", + "created_at": "2024-02-15T16:52:44Z", + "updated_at": "2024-02-15T16:52:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329059", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329059" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329059/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1283, + "side": "RIGHT", + "in_reply_to_id": 1488285682, + "original_position": 53, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325", + "pull_request_review_id": 1883352369, + "id": 1491329325, + "node_id": "PRRC_kwDOABII585Y4-Et", + "diff_hunk": "@@ -0,0 +1,127 @@\n+// Copyright (c) 2024 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+/** Compute a * b, represented in 4x32 bits, highest limb first. */\n+std::array Mul128(uint64_t a, uint64_t b)\n+{\n+ std::array ret{0, 0, 0, 0};\n+\n+ /** Perform ret += v << (32 * pos), at 128-bit precision. */\n+ auto add_fn = [&](uint64_t v, int pos) {\n+ uint64_t accum{0};\n+ for (int i = 0; i + pos < 4; ++i) {\n+ // Add current value at limb pos in ret.\n+ accum += ret[3 - pos - i];\n+ // Add low or high half of v.\n+ if (i == 0) accum += v & 0xffffffff;\n+ if (i == 1) accum += v >> 32;\n+ // Store lower half of result in limb pos in ret.\n+ ret[3 - pos - i] = accum & 0xffffffff;\n+ // Leave carry in accum.\n+ accum >>= 32;\n+ }\n+ // Make sure no overflow.\n+ assert(accum == 0);\n+ };\n+\n+ // Multiply the 4 individual limbs (schoolbook multiply, with base 2^32).\n+ add_fn((a & 0xffffffff) * (b & 0xffffffff), 0);\n+ add_fn((a >> 32) * (b & 0xffffffff), 1);\n+ add_fn((a & 0xffffffff) * (b >> 32), 1);\n+ add_fn((a >> 32) * (b >> 32), 2);\n+ return ret;\n+}\n+\n+/* comparison helper for std::array */\n+std::strong_ordering compare_arrays(const std::array& a, const std::array& b) {\n+ for (size_t i = 0; i < a.size(); ++i) {\n+ if (a[i] != b[i]) return a[i] <=> b[i];\n+ }\n+ return std::strong_ordering::equal;\n+}\n+\n+std::strong_ordering MulCompare(int64_t a1, int64_t a2, int64_t b1, int64_t b2)\n+{\n+ // Compute and compare signs.\n+ int sign_a = (a1 == 0 ? 0 : a1 < 0 ? -1 : 1) * (a2 == 0 ? 0 : a2 < 0 ? -1 : 1);\n+ int sign_b = (b1 == 0 ? 0 : b1 < 0 ? -1 : 1) * (b2 == 0 ? 0 : b2 < 0 ? -1 : 1);\n+ if (sign_a != sign_b) return sign_a <=> sign_b;\n+\n+ // Compute absolute values.\n+ uint64_t abs_a1 = static_cast(a1), abs_a2 = static_cast(a2);\n+ uint64_t abs_b1 = static_cast(b1), abs_b2 = static_cast(b2);\n+ // Use (~x + 1) instead of the equivalent (-x) to silence the linter; mod 2^64 behavior is\n+ // intentional here.\n+ if (a1 < 0) abs_a1 = ~abs_a1 + 1;\n+ if (a2 < 0) abs_a2 = ~abs_a2 + 1;\n+ if (b1 < 0) abs_b1 = ~abs_b1 + 1;\n+ if (b2 < 0) abs_b2 = ~abs_b2 + 1;\n+\n+ // Compute products of absolute values.\n+ auto mul_abs_a = Mul128(abs_a1, abs_a2);\n+ auto mul_abs_b = Mul128(abs_b1, abs_b2);\n+ if (sign_a < 0) {\n+ return compare_arrays(mul_abs_b, mul_abs_a);\n+ } else {\n+ return compare_arrays(mul_abs_a, mul_abs_b);\n+ }\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(feefrac)\n+{\n+ FuzzedDataProvider provider(buffer.data(), buffer.size());\n+\n+ int64_t f1 = provider.ConsumeIntegral();\n+ //int64_t f1 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);\n+ int32_t s1 = provider.ConsumeIntegral();\n+ if (s1 == 0) f1 = 0;\n+ FeeFrac fr1(f1, s1);\n+ assert(fr1.IsEmpty() == (s1 == 0));\n+\n+ int64_t f2 = provider.ConsumeIntegral();\n+ //int64_t f2 = provider.ConsumeIntegralInRange(std::numeric_limits::min() + 1,\n+ // std::numeric_limits::max() - 1);", + "path": "src/test/fuzz/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ff96f3a7a690d60e50fa49014ea895df348faad4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "mistakenly left at some point; removed", + "created_at": "2024-02-15T16:52:56Z", + "updated_at": "2024-02-15T16:52:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329325", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491329325" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491329325/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 89, + "start_side": "RIGHT", + "line": null, + "original_line": 98, + "side": "RIGHT", + "in_reply_to_id": 1488290016, + "original_position": 98, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674", + "pull_request_review_id": 1883354202, + "id": 1491330674, + "node_id": "PRRC_kwDOABII585Y4-Zy", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I added some additional feefrac fuzzing for the +/- operations, marking as resolved", + "created_at": "2024-02-15T16:53:49Z", + "updated_at": "2024-02-15T16:53:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491330674", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1491330674" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1491330674/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 19, + "original_start_line": 19, + "start_side": "RIGHT", + "line": 30, + "original_line": 30, + "side": "RIGHT", + "in_reply_to_id": 1488282848, + "original_position": 30, + "position": 30, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771", + "pull_request_review_id": 1885627769, + "id": 1492766771, + "node_id": "PRRC_kwDOABII585Y-dAz", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "this is odd, should we just `Assume()` `replacement_vsize>0` in `CalculateFeerateDiagramsForRBF`?", + "created_at": "2024-02-16T17:14:29Z", + "updated_at": "2024-02-16T17:14:29Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492766771", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492766771" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492766771/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 354, + "side": "RIGHT", + "original_position": 46, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210", + "pull_request_review_id": 1885883009, + "id": 1492915210, + "node_id": "PRRC_kwDOABII585Y_BQK", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yes, I can't think of a scenario where that will happen!", + "created_at": "2024-02-16T19:41:22Z", + "updated_at": "2024-02-16T19:41:22Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915210/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 354, + "side": "RIGHT", + "in_reply_to_id": 1492766771, + "original_position": 46, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977", + "pull_request_review_id": 1885884419, + "id": 1492915977, + "node_id": "PRRC_kwDOABII585Y_BcJ", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit:\r\n```suggestion\r\n const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\r\n```", + "created_at": "2024-02-16T19:42:15Z", + "updated_at": "2024-02-16T19:42:15Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915977", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1492915977" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1492915977/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 326, + "side": "RIGHT", + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062", + "pull_request_review_id": 1886533962, + "id": 1493302062, + "node_id": "PRRC_kwDOABII585ZAfsu", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string3.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto err_string4{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string4.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto err_string5{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto err_string6{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal}, old_diagram, new_diagram)};\n+ BOOST_CHECK(err_string6.has_value());\n+ BOOST_CHECK(err_string6.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ BOOST_CHECK(old_diagram.empty());\n+ BOOST_CHECK(new_diagram.empty());\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2= make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto err_string7{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+ old_diagram.clear();\n+ new_diagram.clear();\n }", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe weshould also check that we can have more than two directly conflicting transactions as long as they are all in a cluster size <=2.\r\n\r\n
\r\ndiff \r\n\r\n```diff\r\ndiff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp\r\nindex e15fd29da3..561ebd3881 100644\r\n--- a/src/test/rbf_tests.cpp\r\n+++ b/src/test/rbf_tests.cpp\r\n@@ -431,6 +431,53 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\r\n BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\r\n old_diagram.clear();\r\n new_diagram.clear();\r\n+\r\n+ // You can more than two direct conflicts, if all the directly conflicting transactions are in a cluster size < 2\r\n+ const auto conflict_1 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1));\r\n+ const auto conflict_1_entry = pool.GetIter(conflict_1->GetHash()).value();\r\n+\r\n+ const auto conflict_2 = make_tx(/*inputs=*/ {m_coinbase_txns[3]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_2));\r\n+ const auto conflict_2_entry = pool.GetIter(conflict_2->GetHash()).value();\r\n+\r\n+ const auto conflict_3 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {10 * COIN});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_3));\r\n+ const auto conflict_3_entry = pool.GetIter(conflict_3->GetHash()).value();\r\n+\r\n+ const auto err_string8{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_ent\r\nry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(!err_string8.has_value());\r\n+ BOOST_CHECK(old_diagram.size() == 4);\r\n+ BOOST_CHECK(new_diagram.size() == 2);\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n+\r\n+ // Add a child transaction to conflict_1 and make it cluster size 2\r\n+ const auto conflict_1_child = make_tx(/*inputs=*/{conflict_1}, /*output_values=*/ {995 * CENT});\r\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1_child));\r\n+ const auto conflict_1_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();\r\n+\r\n+ const auto err_string9{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_ent\r\nry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(!err_string8.has_value());\r\n+ BOOST_CHECK(old_diagram.size() == 4);\r\n+ BOOST_CHECK(new_diagram.size() == 2);\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n+\r\n+\r\n+ // Add another descendant to conflict_1, making the cluster size > 2 should fail at this point.\r\n+ const auto conflict_1_grand_child = make_tx(/*inputs=*/{conflict_1_child}, /*output_values=*/ {995 * CENT});\r\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(conflict_1_grand_child));\r\n+ const auto conflict_1_grand_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();\r\n+\r\n+ const auto err_string10{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_en\r\ntry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry}, old_diagram, new_diagram)};\r\n+\r\n+ BOOST_CHECK(err_string10.has_value());\r\n+ BOOST_CHECK(err_string10.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", conflict_1->GetHash().GetHex()));\r\n+ old_diagram.clear();\r\n+ new_diagram.clear();\r\n }\r\n \r\n BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\r\n```\r\n
", + "created_at": "2024-02-17T10:43:13Z", + "updated_at": "2024-02-17T10:44:01Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302062", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302062" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302062/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 495, + "original_line": 495, + "side": "RIGHT", + "original_position": 126, + "position": 404, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276", + "pull_request_review_id": 1886534107, + "id": 1493302276, + "node_id": "PRRC_kwDOABII585ZAfwE", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "here an another place below!", + "created_at": "2024-02-17T10:44:31Z", + "updated_at": "2024-02-17T10:46:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302276", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493302276" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493302276/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 326, + "side": "RIGHT", + "in_reply_to_id": 1492915977, + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857", + "pull_request_review_id": 1886598516, + "id": 1493358857, + "node_id": "PRRC_kwDOABII585ZAtkJ", + "diff_hunk": "@@ -0,0 +1,126 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8d74a28a62083bbbee1fd6a2dee56994f293a61a", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think we should drop the `Assume()` calls, as otherwise I think we ought to do more to ensure that using operator- on FeeFrac's is safe everywhere that it might be invoked.", + "created_at": "2024-02-17T15:42:48Z", + "updated_at": "2024-02-17T15:43:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493358857" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493358857/reactions", + "total_count": 3, + "+1": 3, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 16, + "original_line": 16, + "side": "RIGHT", + "in_reply_to_id": 1453502118, + "original_position": 16, + "position": 16, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169", + "pull_request_review_id": 1886598977, + "id": 1493359169, + "node_id": "PRRC_kwDOABII585ZAtpB", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: As the functions here don't relate to the `FeeFrac` implementation, perhaps this should be in a different file? `feerate_diagram.cpp` maybe?", + "created_at": "2024-02-17T15:44:22Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359169", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359169" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359169/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 1, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700", + "pull_request_review_id": 1886598977, + "id": 1493359700, + "node_id": "PRRC_kwDOABII585ZAtxU", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: \"direction coefficient\" is not a term I'm familiar with (and from googling it doesn't seem like a super common term); perhaps it would be clearer to just use the word \"slope\" here?", + "created_at": "2024-02-17T15:48:07Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359700", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493359700" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493359700/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 50, + "start_side": "RIGHT", + "line": null, + "original_line": 51, + "side": "RIGHT", + "original_position": 51, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467", + "pull_request_review_id": 1886598977, + "id": 1493390467, + "node_id": "PRRC_kwDOABII585ZA1SD", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);\n+\n+/** Compares two feerate diagrams (which must both start at size=0). The shorter one is implicitly\n+ * extended with a horizontal straight line. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: Could add a comment here more precisely defining the preconditions for this function and what definition we are using for feerate diagram: specifically that a feerate diagram consists of a list of (fee, size) points with the property that size is strictly increasing and that the first entry is (0, 0). (If these conditions are violated then the function can fail with an `Assume()` failure.)", + "created_at": "2024-02-17T19:20:14Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493390467", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493390467" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493390467/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 159, + "side": "RIGHT", + "original_position": 159, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184", + "pull_request_review_id": 1886598977, + "id": 1493391184, + "node_id": "PRRC_kwDOABII585ZA1dQ", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: \"fee vs. size diagram\" -- maybe we should standardize the terminology to \"feerate diagram\"? I was also thinking about adding some documentation to doc/policy/mempool-replacements.md explaining what we're doing now.", + "created_at": "2024-02-17T19:25:36Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493391184", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493391184" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493391184/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 193, + "side": "RIGHT", + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259", + "pull_request_review_id": 1886598977, + "id": 1493401259, + "node_id": "PRRC_kwDOABII585ZA36r", + "diff_hunk": "@@ -733,6 +734,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: Maybe update the comment to be more explicit that this function only works for the situation where (replacement_fees, replacement_size) corresponds to a transaction package that has no in-mempool dependences.", + "created_at": "2024-02-17T20:43:39Z", + "updated_at": "2024-02-17T20:59:21Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493401259", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493401259" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493401259/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 757, + "side": "RIGHT", + "original_position": 25, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950", + "pull_request_review_id": 1887031929, + "id": 1493417950, + "node_id": "PRRC_kwDOABII585ZA7_e", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Oh, I seem to have translated literally from Dutch. \"Slope\" is indeed the proper English translation.", + "created_at": "2024-02-17T21:35:23Z", + "updated_at": "2024-02-17T21:35:23Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493417950", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493417950" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493417950/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 50, + "start_side": "RIGHT", + "line": null, + "original_line": 51, + "side": "RIGHT", + "in_reply_to_id": 1493359700, + "original_position": 51, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026", + "pull_request_review_id": 1887045764, + "id": 1493469026, + "node_id": "PRRC_kwDOABII585ZBIdi", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "Curious to know the full meaning of `FeeFrac` is it Fee Fraction?\r\nMaybe Chunk will be a better name?", + "created_at": "2024-02-17T23:22:50Z", + "updated_at": "2024-02-22T18:07:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493469026", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1493469026" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1493469026/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 1, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1493359169, + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692", + "pull_request_review_id": 1890224651, + "id": 1495685692, + "node_id": "PRRC_kwDOABII585ZJlo8", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Yeah, it means \"fee fraction\", though the name isn't perfect - it really represents any ratio where the numerator is an `int64_t` and the denominator is an `int32_t`, with a sort order that tie-breaks by putting larger denominators last.\r\n\r\nI don't think Chunk is a good name, as we're using that term for a subset of transactions. A `FeeFrac` is related, but represents the aggregate feerate of a chunk (or really of any set of transactions, or even the difference between the fees/sizes of two sets of transactions).", + "created_at": "2024-02-20T11:46:52Z", + "updated_at": "2024-02-20T11:46:52Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495685692", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495685692" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495685692/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1493359169, + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495837621", + "pull_request_review_id": 1890451361, + "id": 1495837621, + "node_id": "PRRC_kwDOABII585ZKKu1", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+ const FeeFrac& point_b = next_point(!unproc_side);\n+ const auto coef_ab = point_b - point_a;\n+ const auto coef_ap = point_p - point_a;\n+ Assume(coef_ap.size > 0);\n+ Assume(coef_ab.size >= coef_ap.size);\n+ // Perform the comparison. If P lies above AB, unproc_side is better in P. If P lies below\n+ // AB, then !unproc_side is better in P.\n+ const auto cmp = FeeRateCompare(coef_ap, coef_ab);\n+ if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\n+ if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\n+\n+ // Mark P as processed. If B and P have the same size, B can also be marked as processed as\n+ // we've already performed a comparison at this size.\n+ ++next_index[unproc_side];\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\n+ }\n+\n+ // Tail check at 0 feerate: Compare the remaining area. Use similar logic as in the loop above,\n+ // except we use a horizontal line instead of AB, as no point B exists anymore.\n+ const int long_side = next_index[1] != dias[1].size();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Here is a patch that merges the two processing loops into one (deduplicating some logic between them), and also makes the tail feerate explicit (even though only `FeeFrac{0, 1}` is used for now).\r\n\r\nNo need to take this, but in case people find it simpler to review a generic approach, perhaps it's useful.\r\n\r\n```patch\r\ndiff --git a/src/util/feefrac.cpp b/src/util/feefrac.cpp\r\nindex a970adedc30..569f32f4615 100644\r\n--- a/src/util/feefrac.cpp\r\n+++ b/src/util/feefrac.cpp\r\n@@ -22,7 +22,7 @@ void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector dia0, Span dia1)\r\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1, FeeFrac tail_feerate)\r\n {\r\n /** Array to allow indexed access to input diagrams. */\r\n const std::array, 2> dias = {dia0, dia1};\r\n@@ -40,51 +40,47 @@ std::partial_ordering CompareFeerateDiagram(Span dia0, Span next_point(1).size;\r\n+ do {\r\n+ bool done_0 = next_index[0] == dias[0].size();\r\n+ bool done_1 = next_index[1] == dias[1].size();\r\n+ if (done_0 && done_1) break;\r\n+\r\n+ // Determine which diagram has the first unprocessed point. If one side is finished, use the\r\n+ // other one.\r\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\r\n \r\n // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\r\n // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\r\n- // compute the direction coefficients of line AB and of line AP, and compare them. These\r\n- // direction coefficients are fee per size, and can thus be expressed as FeeFracs.\r\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\r\n+ // and can thus be expressed as FeeFracs.\r\n const FeeFrac& point_p = next_point(unproc_side);\r\n const FeeFrac& point_a = prev_point(!unproc_side);\r\n- const FeeFrac& point_b = next_point(!unproc_side);\r\n- const auto coef_ab = point_b - point_a;\r\n- const auto coef_ap = point_p - point_a;\r\n- Assume(coef_ap.size > 0);\r\n- Assume(coef_ab.size >= coef_ap.size);\r\n- // Perform the comparison. If P lies above AB, unproc_side is better in P. If P lies below\r\n- // AB, then !unproc_side is better in P.\r\n- const auto cmp = FeeRateCompare(coef_ap, coef_ab);\r\n+ const auto slope_ap = point_p - point_a;\r\n+ Assume(slope_ap.size > 0);\r\n+ std::weak_ordering cmp = std::weak_ordering::equivalent;\r\n+ if (!(done_0 || done_1)) {\r\n+ // If both sides have points left, compute B, and the slope of AB explicitly.\r\n+ const FeeFrac& point_b = next_point(!unproc_side);\r\n+ const auto slope_ab = point_b - point_a;\r\n+ Assume(slope_ab.size >= slope_ap.size);\r\n+ cmp = FeeRateCompare(slope_ap, slope_ab);\r\n+\r\n+ // If B and P have the same size, B can be marked as processed (in addition to P, see\r\n+ // below), as we've already performed a comparison at this size.\r\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\r\n+ } else {\r\n+ // If one of the sides has no points left, act as if AB has slope tail_feerate.\r\n+ cmp = FeeRateCompare(slope_ap, tail_feerate);\r\n+ }\r\n+\r\n+ // If P lies above AB, unproc_side is better in P. If P lies below AB, then !unproc_side is\r\n+ // better in P.\r\n if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\r\n if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\r\n \r\n- // Mark P as processed. If B and P have the same size, B can also be marked as processed as\r\n- // we've already performed a comparison at this size.\r\n- ++next_index[unproc_side];\r\n- if (point_b.size == point_p.size) ++next_index[!unproc_side];\r\n- }\r\n-\r\n- // Tail check at 0 feerate: Compare the remaining area. Use similar logic as in the loop above,\r\n- // except we use a horizontal line instead of AB, as no point B exists anymore.\r\n- const int long_side = next_index[1] != dias[1].size();\r\n- Assume(next_index[!long_side] == dias[!long_side].size());\r\n- // The point A now remains fixed: the last point of the shorter diagram.\r\n- const FeeFrac& point_a = prev_point(!long_side);\r\n- while (next_index[long_side] < dias[long_side].size()) {\r\n- // Compare AP (where P is the next unprocessed point on the longer diagram) with a horizontal line\r\n- // extending infinitely from A. This is equivalent to checking the sign of the fee of P-A.\r\n- const FeeFrac& point_p = next_point(long_side);\r\n- const auto coef_ap = point_p - point_a;\r\n- const auto cmp = coef_ap.fee <=> 0;\r\n- if (std::is_gt(cmp)) better_somewhere[long_side] = true;\r\n- if (std::is_lt(cmp)) better_somewhere[!long_side] = true;\r\n // Mark P as processed.\r\n- ++next_index[long_side];\r\n- }\r\n+ ++next_index[unproc_side];\r\n+ } while(true);\r\n \r\n // If both diagrams are better somewhere, they are incomparable.\r\n if (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered;\r\ndiff --git a/src/util/feefrac.h b/src/util/feefrac.h\r\nindex 12698a4a653..706facc34b0 100644\r\n--- a/src/util/feefrac.h\r\n+++ b/src/util/feefrac.h\r\n@@ -156,7 +156,7 @@ struct FeeFrac\r\n void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);\r\n \r\n /** Compares two feerate diagrams (which must both start at size=0). The shorter one is implicitly\r\n- * extended with a horizontal straight line. */\r\n-std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1);\r\n+ * extended with an infinite line whose slope equals tail_feefrac (by default: horizontal). */\r\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1, FeeFrac tail_feerate={0, 1});\r\n \r\n #endif // BITCOIN_UTIL_FEEFRAC_H\r\n```", + "created_at": "2024-02-20T13:36:32Z", + "updated_at": "2024-02-20T13:39:15Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495837621", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495837621" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495837621" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495837621/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 73, + "side": "RIGHT", + "original_position": 73, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495970838", + "pull_request_review_id": 1890663129, + "id": 1495970838, + "node_id": "PRRC_kwDOABII585ZKrQW", + "diff_hunk": "@@ -733,6 +734,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);\n+\n+ /* Check that all direct conflicts are in a cluster size of two or less. */\n+ std::optional CheckConflictTopology(const setEntries& direct_conflicts);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Question: is the idea that in the future we'll use the same function but loosen it beyond cluster <=2? Otherwise, I wonder why it isn't called `LimitTopology1P1C` or `LimitClusterSize2` or something.", + "created_at": "2024-02-20T14:58:57Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495970838", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495970838" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1495970838" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1495970838/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 760, + "original_line": 760, + "side": "RIGHT", + "original_position": 28, + "position": 32, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496191920", + "pull_request_review_id": 1891006405, + "id": 1496191920, + "node_id": "PRRC_kwDOABII585ZLhOw", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+ const FeeFrac& point_b = next_point(!unproc_side);\n+ const auto coef_ab = point_b - point_a;\n+ const auto coef_ap = point_p - point_a;\n+ Assume(coef_ap.size > 0);\n+ Assume(coef_ab.size >= coef_ap.size);\n+ // Perform the comparison. If P lies above AB, unproc_side is better in P. If P lies below\n+ // AB, then !unproc_side is better in P.\n+ const auto cmp = FeeRateCompare(coef_ap, coef_ab);\n+ if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\n+ if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\n+\n+ // Mark P as processed. If B and P have the same size, B can also be marked as processed as\n+ // we've already performed a comparison at this size.\n+ ++next_index[unproc_side];\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\n+ }\n+\n+ // Tail check at 0 feerate: Compare the remaining area. Use similar logic as in the loop above,\n+ // except we use a horizontal line instead of AB, as no point B exists anymore.\n+ const int long_side = next_index[1] != dias[1].size();", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "took in a modified form since it does seem to read cleaner to me, left the direct exposure of `tail_feerate` as a YNGNI extension", + "created_at": "2024-02-20T17:09:01Z", + "updated_at": "2024-02-20T17:12:22Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496191920", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496191920" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496191920" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496191920/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 73, + "side": "RIGHT", + "in_reply_to_id": 1495837621, + "original_position": 73, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192018", + "pull_request_review_id": 1891006649, + "id": 1496192018, + "node_id": "PRRC_kwDOABII585ZLhQS", + "diff_hunk": "@@ -733,6 +734,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "updated to be more explicit on what those values represent", + "created_at": "2024-02-20T17:09:06Z", + "updated_at": "2024-02-20T17:09:06Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192018", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192018" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192018" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192018/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 757, + "side": "RIGHT", + "in_reply_to_id": 1493401259, + "original_position": 25, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192101", + "pull_request_review_id": 1891006882, + "id": 1496192101, + "node_id": "PRRC_kwDOABII585ZLhRl", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's fee vs. size diagram.", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "changed to standard lingo", + "created_at": "2024-02-20T17:09:09Z", + "updated_at": "2024-02-20T17:09:10Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192101", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192101" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192101" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192101/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 193, + "side": "RIGHT", + "in_reply_to_id": 1493391184, + "original_position": 20, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192220", + "pull_request_review_id": 1891007191, + "id": 1496192220, + "node_id": "PRRC_kwDOABII585ZLhTc", + "diff_hunk": "@@ -0,0 +1,162 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ Assume(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);\n+\n+/** Compares two feerate diagrams (which must both start at size=0). The shorter one is implicitly\n+ * extended with a horizontal straight line. */", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken with some liberties", + "created_at": "2024-02-20T17:09:14Z", + "updated_at": "2024-02-20T17:09:15Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192220", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192220" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192220" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192220/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 159, + "side": "RIGHT", + "in_reply_to_id": 1493390467, + "original_position": 159, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192331", + "pull_request_review_id": 1891007480, + "id": 1496192331, + "node_id": "PRRC_kwDOABII585ZLhVL", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ // Compare the overlapping area of the diagrams.\n+ while (next_index[0] < dias[0].size() && next_index[1] < dias[1].size()) {\n+ // Determine which diagram has the first unprocessed point.\n+ const int unproc_side = next_point(0).size > next_point(1).size;\n+\n+ // let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the direction coefficients of line AB and of line AP, and compare them. These\n+ // direction coefficients are fee per size, and can thus be expressed as FeeFracs.", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "replaced, even though I thought it sounded pretty smart", + "created_at": "2024-02-20T17:09:19Z", + "updated_at": "2024-02-20T17:09:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192331", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192331" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192331" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192331/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 1, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 50, + "start_side": "RIGHT", + "line": null, + "original_line": 51, + "side": "RIGHT", + "in_reply_to_id": 1493359700, + "original_position": 51, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192417", + "pull_request_review_id": 1891007709, + "id": 1496192417, + "node_id": "PRRC_kwDOABII585ZLhWh", + "diff_hunk": "@@ -0,0 +1,93 @@\n+// Copyright (c) The Bitcoin Core developers", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d200d30431368c7637a3490509b9158844b69e0d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "@sdaftuar going to hold off on this for now if that's ok", + "created_at": "2024-02-20T17:09:23Z", + "updated_at": "2024-02-20T17:09:24Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192417", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192417" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496192417" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496192417/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1493359169, + "original_position": 1, + "position": 1, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193191", + "pull_request_review_id": 1891009748, + "id": 1496193191, + "node_id": "PRRC_kwDOABII585ZLhin", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string3.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto err_string4{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string4.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto err_string5{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto err_string6{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal}, old_diagram, new_diagram)};\n+ BOOST_CHECK(err_string6.has_value());\n+ BOOST_CHECK(err_string6.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ BOOST_CHECK(old_diagram.empty());\n+ BOOST_CHECK(new_diagram.empty());\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2= make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto err_string7{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+ old_diagram.clear();\n+ new_diagram.clear();\n }", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken with only light modifications, thanks!", + "created_at": "2024-02-20T17:09:57Z", + "updated_at": "2024-02-20T17:09:58Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193191", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193191" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193191" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193191/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 495, + "original_line": 495, + "side": "RIGHT", + "in_reply_to_id": 1493302062, + "original_position": 126, + "position": 404, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193271", + "pull_request_review_id": 1891009972, + "id": 1496193271, + "node_id": "PRRC_kwDOABII585ZLhj3", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-02-20T17:10:01Z", + "updated_at": "2024-02-20T17:10:01Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193271", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193271" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193271" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193271/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 326, + "side": "RIGHT", + "in_reply_to_id": 1492915977, + "original_position": 18, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193353", + "pull_request_review_id": 1891010151, + "id": 1496193353, + "node_id": "PRRC_kwDOABII585ZLhlJ", + "diff_hunk": "@@ -309,6 +309,128 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx= make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // No replacement fees makes new empty diagram of length 2\n+ const auto err_string2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/0, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string2.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 0));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d57fbda350ee9051931d9a0dad4beb55f6b2e574", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "Added `Assume` for this and remove test", + "created_at": "2024-02-20T17:10:04Z", + "updated_at": "2024-02-20T17:10:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193353", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193353" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1496193353" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1496193353/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 354, + "side": "RIGHT", + "in_reply_to_id": 1492766771, + "original_position": 46, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497874754", + "pull_request_review_id": 1893687911, + "id": 1497874754, + "node_id": "PRRC_kwDOABII585ZR8FC", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "The correctness of the result of `BuildDiagramFromUnsortedChunks` very much depends on the assumption that the chunks can be reordered w.r.t. one another, which seems to be the case in the current PR, but will very much not be the case going forward in a general cluster mempool world.\r\n\r\nI would suggest either:\r\n* Removing the sorting step in this function (moving it to the caller). The function can then take `Span` as input too, and perhaps in a further iteration (in a later PR) this function could then be turned into one that actually performs chunking too.\r\n* Adding a big comment on the function definition that it needs independent chunks.", + "created_at": "2024-02-21T16:20:56Z", + "updated_at": "2024-02-22T15:54:52Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497874754", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497874754" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497874754" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497874754/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1453487633, + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497886010", + "pull_request_review_id": 1893687911, + "id": 1497886010, + "node_id": "PRRC_kwDOABII585ZR-06", + "diff_hunk": "@@ -0,0 +1,128 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);\n+\n+ FeeFrac p3{2000, 200};\n+ BOOST_CHECK(p1 != p3); // feefracs only equal if both fee and size are same\n+ BOOST_CHECK(p2 != p3);\n+\n+ FeeFrac p4{3000, 300};\n+ BOOST_CHECK(p1 == p4-p3);\n+ BOOST_CHECK(p1 + p3 == p4);\n+\n+ // Fee-rate comparison\n+ BOOST_CHECK(p1 > p2);\n+ BOOST_CHECK(p1 >= p2);\n+ BOOST_CHECK(p1 >= p4-p3);\n+ BOOST_CHECK(!(p1 >> p3)); // not strictly better\n+ BOOST_CHECK(p1 >> p2); // strictly greater feerate\n+\n+ BOOST_CHECK(p2 < p1);\n+ BOOST_CHECK(p2 <= p1);\n+ BOOST_CHECK(p1 <= p4-p3);\n+ BOOST_CHECK(!(p3 << p1)); // not strictly worse\n+ BOOST_CHECK(p2 << p1); // strictly lower feerate\n+\n+ // \"empty\" comparisons\n+ BOOST_CHECK(!(p1 >> empty)); // << will always result in false\n+ BOOST_CHECK(!(p1 << empty));\n+ BOOST_CHECK(!(empty >> empty));\n+ BOOST_CHECK(!(empty << empty));\n+\n+ // empty is always bigger than everything else\n+ BOOST_CHECK(empty > p1);\n+ BOOST_CHECK(empty > p2);\n+ BOOST_CHECK(empty > p3);\n+ BOOST_CHECK(empty >= p1);\n+ BOOST_CHECK(empty >= p2);\n+ BOOST_CHECK(empty >= p3);\n+\n+ // check \"max\" values for comparison\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ BOOST_CHECK(oversized_1 < oversized_2);\n+ BOOST_CHECK(oversized_1 <= oversized_2);\n+ BOOST_CHECK(oversized_1 << oversized_2);\n+ BOOST_CHECK(oversized_1 != oversized_2);\n+\n+ // Tests paths that use double arithmetic\n+ FeeFrac busted{((int64_t) INT32_MAX) + 1, INT32_MAX};\n+ BOOST_CHECK(!(busted < busted));\n+\n+ FeeFrac max_fee{2100000000000000, INT32_MAX};\n+ BOOST_CHECK(!(max_fee < max_fee));\n+ BOOST_CHECK(!(max_fee > max_fee));\n+ BOOST_CHECK(max_fee <= max_fee);\n+ BOOST_CHECK(max_fee >= max_fee);\n+\n+ FeeFrac max_fee2{1, 1};\n+ BOOST_CHECK(max_fee >= max_fee2);\n+\n+}\n+\n+BOOST_AUTO_TEST_CASE(build_diagram_test)\n+{\n+ FeeFrac p1{1000, 100};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1};\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ // Diagram-building will reorder chunks\n+ std::vector chunks;\n+ chunks.push_back(p1);\n+ chunks.push_back(zero_fee);\n+ chunks.push_back(empty);\n+ chunks.push_back(oversized_1);\n+ chunks.push_back(oversized_2);\n+\n+ FastRandomContext rng{/*fDeterministic=*/true};\n+ std::shuffle(chunks.begin(), chunks.end(), rng);", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "947693bc8ed0622e02fd19137740b428e4ffc0be", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "We have `Shuffle()` in random.h, which is more efficient than `std::shuffle` (but only works with `FastRandomContext`).", + "created_at": "2024-02-21T16:27:31Z", + "updated_at": "2024-02-22T15:54:52Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497886010", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497886010" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497886010" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497886010/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 102, + "side": "RIGHT", + "original_position": 102, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497917895", + "pull_request_review_id": 1893687911, + "id": 1497917895, + "node_id": "PRRC_kwDOABII585ZSGnH", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: no need to reimplement `FeeFrac` addition:\r\n\r\n```\r\ndiagram.push_back(diagram.back() + chunk);\r\n```", + "created_at": "2024-02-21T16:49:48Z", + "updated_at": "2024-02-22T15:55:55Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497917895", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497917895" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1497917895" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1497917895/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 21, + "side": "RIGHT", + "original_position": 21, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499465556", + "pull_request_review_id": 1896209372, + "id": 1499465556, + "node_id": "PRRC_kwDOABII585ZYAdU", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think the slope of AB can be negative, because a user could use the `prioritisetransaction` to give a transaction a negative fee?", + "created_at": "2024-02-22T15:49:19Z", + "updated_at": "2024-02-22T15:49:19Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499465556", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499465556" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499465556" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499465556/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 56, + "original_line": 56, + "side": "RIGHT", + "original_position": 59, + "position": 56, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499472337", + "pull_request_review_id": 1896220277, + "id": 1499472337, + "node_id": "PRRC_kwDOABII585ZYCHR", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "one weird trick! will remove the comment", + "created_at": "2024-02-22T15:53:54Z", + "updated_at": "2024-02-22T15:53:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499472337", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499472337" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499472337" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499472337/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 56, + "original_line": 56, + "side": "RIGHT", + "in_reply_to_id": 1499465556, + "original_position": 59, + "position": 56, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499507266", + "pull_request_review_id": 1896273458, + "id": 1499507266, + "node_id": "PRRC_kwDOABII585ZYKpC", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "> The correctness of the result of `BuildDiagramFromUnsortedChunks` very much depends on the assumption that the chunks can be reordered w.r.t. one another, which seems to be the case in the current PR, but will very much not be the case going forward in a general cluster mempool world.\r\n\r\nNo objection to your suggested change here, but I don't follow this comment -- in a general cluster mempool world, unless we were to bound chunk sizes to something smaller than a cluster size (resulting in the possibility of chunk feerates not being monotonically decreasing), I think for the purposes of a feerate diagram it is fine to sort by chunk feerate and permit equal-feerate-chunks to be reordered? From the perspective of a feerate diagram, two such diagrams are equivalent.\r\n\r\nIf you're suggesting that we want to preserve the ability in the future to impose a chunk size limit, then yes I agree that we should rewrite this... Is there another case that I'm overlooking?", + "created_at": "2024-02-22T16:13:40Z", + "updated_at": "2024-02-22T16:13:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499507266", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499507266" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499507266" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499507266/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1453487633, + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641315", + "pull_request_review_id": 1896480235, + "id": 1499641315, + "node_id": "PRRC_kwDOABII585ZYrXj", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-02-22T17:48:01Z", + "updated_at": "2024-02-22T17:48:01Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499641315", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641315" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499641315" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641315/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 21, + "side": "RIGHT", + "in_reply_to_id": 1497917895, + "original_position": 21, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641781", + "pull_request_review_id": 1896480925, + "id": 1499641781, + "node_id": "PRRC_kwDOABII585ZYre1", + "diff_hunk": "@@ -0,0 +1,128 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);\n+\n+ FeeFrac p3{2000, 200};\n+ BOOST_CHECK(p1 != p3); // feefracs only equal if both fee and size are same\n+ BOOST_CHECK(p2 != p3);\n+\n+ FeeFrac p4{3000, 300};\n+ BOOST_CHECK(p1 == p4-p3);\n+ BOOST_CHECK(p1 + p3 == p4);\n+\n+ // Fee-rate comparison\n+ BOOST_CHECK(p1 > p2);\n+ BOOST_CHECK(p1 >= p2);\n+ BOOST_CHECK(p1 >= p4-p3);\n+ BOOST_CHECK(!(p1 >> p3)); // not strictly better\n+ BOOST_CHECK(p1 >> p2); // strictly greater feerate\n+\n+ BOOST_CHECK(p2 < p1);\n+ BOOST_CHECK(p2 <= p1);\n+ BOOST_CHECK(p1 <= p4-p3);\n+ BOOST_CHECK(!(p3 << p1)); // not strictly worse\n+ BOOST_CHECK(p2 << p1); // strictly lower feerate\n+\n+ // \"empty\" comparisons\n+ BOOST_CHECK(!(p1 >> empty)); // << will always result in false\n+ BOOST_CHECK(!(p1 << empty));\n+ BOOST_CHECK(!(empty >> empty));\n+ BOOST_CHECK(!(empty << empty));\n+\n+ // empty is always bigger than everything else\n+ BOOST_CHECK(empty > p1);\n+ BOOST_CHECK(empty > p2);\n+ BOOST_CHECK(empty > p3);\n+ BOOST_CHECK(empty >= p1);\n+ BOOST_CHECK(empty >= p2);\n+ BOOST_CHECK(empty >= p3);\n+\n+ // check \"max\" values for comparison\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ BOOST_CHECK(oversized_1 < oversized_2);\n+ BOOST_CHECK(oversized_1 <= oversized_2);\n+ BOOST_CHECK(oversized_1 << oversized_2);\n+ BOOST_CHECK(oversized_1 != oversized_2);\n+\n+ // Tests paths that use double arithmetic\n+ FeeFrac busted{((int64_t) INT32_MAX) + 1, INT32_MAX};\n+ BOOST_CHECK(!(busted < busted));\n+\n+ FeeFrac max_fee{2100000000000000, INT32_MAX};\n+ BOOST_CHECK(!(max_fee < max_fee));\n+ BOOST_CHECK(!(max_fee > max_fee));\n+ BOOST_CHECK(max_fee <= max_fee);\n+ BOOST_CHECK(max_fee >= max_fee);\n+\n+ FeeFrac max_fee2{1, 1};\n+ BOOST_CHECK(max_fee >= max_fee2);\n+\n+}\n+\n+BOOST_AUTO_TEST_CASE(build_diagram_test)\n+{\n+ FeeFrac p1{1000, 100};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1};\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ // Diagram-building will reorder chunks\n+ std::vector chunks;\n+ chunks.push_back(p1);\n+ chunks.push_back(zero_fee);\n+ chunks.push_back(empty);\n+ chunks.push_back(oversized_1);\n+ chunks.push_back(oversized_2);\n+\n+ FastRandomContext rng{/*fDeterministic=*/true};\n+ std::shuffle(chunks.begin(), chunks.end(), rng);", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "947693bc8ed0622e02fd19137740b428e4ffc0be", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "removed, since I stripped out the sorting function from `BuildDiagramFromUnsortedChunks`", + "created_at": "2024-02-22T17:48:27Z", + "updated_at": "2024-02-22T17:48:28Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499641781", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641781" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499641781" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499641781/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 102, + "side": "RIGHT", + "in_reply_to_id": 1497886010, + "original_position": 102, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499665791", + "pull_request_review_id": 1896522503, + "id": 1499665791, + "node_id": "PRRC_kwDOABII585ZYxV_", + "diff_hunk": "@@ -0,0 +1,158 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+namespace {\n+\n+inline std::pair Mul128(int64_t a, int64_t b)\n+{\n+#ifdef __SIZEOF_INT128__\n+ __int128 ret = (__int128)a * b;\n+ return {ret >> 64, ret};\n+#else\n+ uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;\n+ int64_t lh = (uint32_t)a * (b >> 32);\n+ int64_t hl = (a >> 32) * (uint32_t)b;\n+ int64_t hh = (a >> 32) * (b >> 32);\n+ uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;\n+ int64_t hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);\n+ uint64_t lo = (mid34 << 32) + (uint32_t)ll;\n+ return {hi, lo};\n+#endif\n+}\n+\n+} // namespace\n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (==, !=, >, <, >=, <=, <=>) respect this ordering.\n+ *\n+ * The >> and << operators only compare feerate and treat equal feerate but different size as\n+ * equivalent. The empty FeeFrac is neither lower or higher in feerate than any other.\n+ * The FeeRateCompare function returns the three-way comparison for this order.\n+ */\n+struct FeeFrac\n+{\n+ /** Fee. */\n+ int64_t fee;\n+ /** Size. */\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t s, int32_t b) noexcept : fee{s}, size{b}\n+ {\n+ // If size==0, fee must be 0 as well.\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add size and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtrack size and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ assert(size != 0 || fee == 0);\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ friend inline std::strong_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ if (a.fee > INT32_MAX || a.fee < INT32_MIN || b.fee > INT32_MAX || b.fee < INT32_MIN) {\n+ auto a_cross = Mul128(a.fee, b.size);\n+ auto b_cross = Mul128(b.fee, a.size);\n+ return a_cross <=> b_cross;\n+ } else {\n+ auto a_cross = a.fee * b.size;\n+ auto b_cross = b.fee * a.size;\n+ return a_cross <=> b_cross;\n+ }\n+ }\n+\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto feerate_cmp = FeeRateCompare(a, b);\n+ if (feerate_cmp != 0) return feerate_cmp; // NOLINT(modernize-use-nullptr)\n+ return b.size <=> a.size;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) < 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return FeeRateCompare(a, b) > 0; // NOLINT(modernize-use-nullptr)\n+ }\n+\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ec3cf62361912a85ccd8d93abc3606df695c69ef", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "@sdaftuar that matches my understanding.\r\n\r\n>Removing the sorting step in this function (moving it to the caller). The function can then take Span as input too, and perhaps in a further iteration (in a later PR) this function could then be turned into one that actually performs chunking too. \r\n\r\nTook this suggestion", + "created_at": "2024-02-22T17:57:44Z", + "updated_at": "2024-02-22T17:57:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499665791", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499665791" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1499665791" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1499665791/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1453487633, + "original_position": 156, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511053264", + "pull_request_review_id": 1914140534, + "id": 1511053264, + "node_id": "PRRC_kwDOABII585aENfQ", + "diff_hunk": "@@ -309,6 +309,162 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string3.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto err_string4{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string4.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto err_string5{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto err_string6{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal}, old_diagram, new_diagram)};\n+ BOOST_CHECK(err_string6.has_value());\n+ BOOST_CHECK(err_string6.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ BOOST_CHECK(old_diagram.empty());\n+ BOOST_CHECK(new_diagram.empty());\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto err_string7{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // You can have more than two direct conflicts if the therea re multiple effected clusters, all of size 2 or less", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n // You can have more than two direct conflicts if the there are multiple effected clusters, all of size 2 or less\r\n```", + "created_at": "2024-03-04T12:03:58Z", + "updated_at": "2024-03-04T13:33:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511053264", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511053264" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511053264" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511053264/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 423, + "side": "RIGHT", + "original_position": 115, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511090989", + "pull_request_review_id": 1914140534, + "id": 1511090989, + "node_id": "PRRC_kwDOABII585aEWst", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: inconsistent use of the spaces between operators and operands here and other places\r\n```suggestion\r\n BOOST_CHECK(p1 + p2 == sum);\r\n BOOST_CHECK(p1 - p2 == diff);\r\n```", + "created_at": "2024-03-04T12:29:40Z", + "updated_at": "2024-03-04T13:33:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511090989", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511090989" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511090989" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511090989/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 23, + "start_side": "RIGHT", + "line": null, + "original_line": 24, + "side": "RIGHT", + "original_position": 24, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511092171", + "pull_request_review_id": 1914140534, + "id": 1511092171, + "node_id": "PRRC_kwDOABII585aEW_L", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);\n+\n+ FeeFrac p3{2000, 200};\n+ BOOST_CHECK(p1 != p3); // feefracs only equal if both fee and size are same\n+ BOOST_CHECK(p2 != p3);\n+\n+ FeeFrac p4{3000, 300};\n+ BOOST_CHECK(p1 == p4-p3);\n+ BOOST_CHECK(p1 + p3 == p4);\n+\n+ // Fee-rate comparison\n+ BOOST_CHECK(p1 > p2);\n+ BOOST_CHECK(p1 >= p2);\n+ BOOST_CHECK(p1 >= p4-p3);\n+ BOOST_CHECK(!(p1 >> p3)); // not strictly better\n+ BOOST_CHECK(p1 >> p2); // strictly greater feerate\n+\n+ BOOST_CHECK(p2 < p1);\n+ BOOST_CHECK(p2 <= p1);\n+ BOOST_CHECK(p1 <= p4-p3);\n+ BOOST_CHECK(!(p3 << p1)); // not strictly worse\n+ BOOST_CHECK(p2 << p1); // strictly lower feerate\n+\n+ // \"empty\" comparisons\n+ BOOST_CHECK(!(p1 >> empty)); // << will always result in false\n+ BOOST_CHECK(!(p1 << empty));\n+ BOOST_CHECK(!(empty >> empty));\n+ BOOST_CHECK(!(empty << empty));\n+\n+ // empty is always bigger than everything else\n+ BOOST_CHECK(empty > p1);\n+ BOOST_CHECK(empty > p2);\n+ BOOST_CHECK(empty > p3);\n+ BOOST_CHECK(empty >= p1);\n+ BOOST_CHECK(empty >= p2);\n+ BOOST_CHECK(empty >= p3);\n+\n+ // check \"max\" values for comparison\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ BOOST_CHECK(oversized_1 < oversized_2);\n+ BOOST_CHECK(oversized_1 <= oversized_2);\n+ BOOST_CHECK(oversized_1 << oversized_2);\n+ BOOST_CHECK(oversized_1 != oversized_2);\n+\n+ // Tests paths that use double arithmetic\n+ FeeFrac busted{((int64_t) INT32_MAX) + 1, INT32_MAX};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3", + "user": { + "login": "ismaelsadeeq", + "id": 48946461, + "node_id": "MDQ6VXNlcjQ4OTQ2NDYx", + "avatar_url": "https://avatars.githubusercontent.com/u/48946461?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ismaelsadeeq", + "html_url": "https://github.com/ismaelsadeeq", + "followers_url": "https://api.github.com/users/ismaelsadeeq/followers", + "following_url": "https://api.github.com/users/ismaelsadeeq/following{/other_user}", + "gists_url": "https://api.github.com/users/ismaelsadeeq/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ismaelsadeeq/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ismaelsadeeq/subscriptions", + "organizations_url": "https://api.github.com/users/ismaelsadeeq/orgs", + "repos_url": "https://api.github.com/users/ismaelsadeeq/repos", + "events_url": "https://api.github.com/users/ismaelsadeeq/events{/privacy}", + "received_events_url": "https://api.github.com/users/ismaelsadeeq/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: static cast\r\n```suggestion\r\n FeeFrac busted{static_cast(INT32_MAX) + 1, INT32_MAX};\r\n```", + "created_at": "2024-03-04T12:30:46Z", + "updated_at": "2024-03-04T13:33:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511092171", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511092171" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1511092171" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1511092171/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 71, + "side": "RIGHT", + "original_position": 71, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753669", + "pull_request_review_id": 1927887049, + "id": 1519753669, + "node_id": "PRRC_kwDOABII585alZnF", + "diff_hunk": "@@ -309,6 +309,162 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string3.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto err_string4{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string4.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto err_string5{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto err_string6{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal}, old_diagram, new_diagram)};\n+ BOOST_CHECK(err_string6.has_value());\n+ BOOST_CHECK(err_string6.value() == strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ BOOST_CHECK(old_diagram.empty());\n+ BOOST_CHECK(new_diagram.empty());\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto err_string7{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string5.has_value());\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // You can have more than two direct conflicts if the therea re multiple effected clusters, all of size 2 or less", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "55eae36cfbd829eabc0772fc1b5312ec1f747e2c", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-11T13:49:12Z", + "updated_at": "2024-03-11T13:49:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753669", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753669" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753669" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753669/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 423, + "side": "RIGHT", + "in_reply_to_id": 1511053264, + "original_position": 115, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753748", + "pull_request_review_id": 1927887173, + "id": 1519753748, + "node_id": "PRRC_kwDOABII585alZoU", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-11T13:49:15Z", + "updated_at": "2024-03-11T13:49:15Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753748", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753748" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753748" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753748/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 23, + "start_side": "RIGHT", + "line": null, + "original_line": 24, + "side": "RIGHT", + "in_reply_to_id": 1511090989, + "original_position": 24, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753812", + "pull_request_review_id": 1927887280, + "id": 1519753812, + "node_id": "PRRC_kwDOABII585alZpU", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+\n+#include \n+\n+BOOST_AUTO_TEST_SUITE(feefrac_tests)\n+\n+BOOST_AUTO_TEST_CASE(feefrac_operators)\n+{\n+ FeeFrac p1{1000, 100}, p2{500, 300};\n+ FeeFrac sum{1500, 400};\n+ FeeFrac diff{500, -200};\n+ FeeFrac empty{0, 0};\n+ FeeFrac zero_fee{0, 1}; // zero-fee allowed\n+\n+ BOOST_CHECK(empty == FeeFrac{}); // same as no-args\n+\n+ BOOST_CHECK(p1 == p1);\n+ BOOST_CHECK(p1+p2 == sum);\n+ BOOST_CHECK(p1-p2 == diff);\n+\n+ FeeFrac p3{2000, 200};\n+ BOOST_CHECK(p1 != p3); // feefracs only equal if both fee and size are same\n+ BOOST_CHECK(p2 != p3);\n+\n+ FeeFrac p4{3000, 300};\n+ BOOST_CHECK(p1 == p4-p3);\n+ BOOST_CHECK(p1 + p3 == p4);\n+\n+ // Fee-rate comparison\n+ BOOST_CHECK(p1 > p2);\n+ BOOST_CHECK(p1 >= p2);\n+ BOOST_CHECK(p1 >= p4-p3);\n+ BOOST_CHECK(!(p1 >> p3)); // not strictly better\n+ BOOST_CHECK(p1 >> p2); // strictly greater feerate\n+\n+ BOOST_CHECK(p2 < p1);\n+ BOOST_CHECK(p2 <= p1);\n+ BOOST_CHECK(p1 <= p4-p3);\n+ BOOST_CHECK(!(p3 << p1)); // not strictly worse\n+ BOOST_CHECK(p2 << p1); // strictly lower feerate\n+\n+ // \"empty\" comparisons\n+ BOOST_CHECK(!(p1 >> empty)); // << will always result in false\n+ BOOST_CHECK(!(p1 << empty));\n+ BOOST_CHECK(!(empty >> empty));\n+ BOOST_CHECK(!(empty << empty));\n+\n+ // empty is always bigger than everything else\n+ BOOST_CHECK(empty > p1);\n+ BOOST_CHECK(empty > p2);\n+ BOOST_CHECK(empty > p3);\n+ BOOST_CHECK(empty >= p1);\n+ BOOST_CHECK(empty >= p2);\n+ BOOST_CHECK(empty >= p3);\n+\n+ // check \"max\" values for comparison\n+ FeeFrac oversized_1{4611686000000, 4000000};\n+ FeeFrac oversized_2{184467440000000, 100000};\n+\n+ BOOST_CHECK(oversized_1 < oversized_2);\n+ BOOST_CHECK(oversized_1 <= oversized_2);\n+ BOOST_CHECK(oversized_1 << oversized_2);\n+ BOOST_CHECK(oversized_1 != oversized_2);\n+\n+ // Tests paths that use double arithmetic\n+ FeeFrac busted{((int64_t) INT32_MAX) + 1, INT32_MAX};", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "cc7b730683da055171a5967a28a1be3b642aefb3", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-11T13:49:17Z", + "updated_at": "2024-03-11T13:49:18Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753812", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753812" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1519753812" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1519753812/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 71, + "side": "RIGHT", + "in_reply_to_id": 1511092171, + "original_position": 71, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521424340", + "pull_request_review_id": 1890663129, + "id": 1521424340, + "node_id": "PRRC_kwDOABII585arxfU", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "eebe434383cf648c4395410d9d9764334fb8ee84", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: wrong dates", + "created_at": "2024-03-12T13:00:28Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521424340", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521424340" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521424340" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521424340/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1, + "side": "RIGHT", + "original_position": 1, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521462945", + "pull_request_review_id": 1890663129, + "id": 1521462945, + "node_id": "PRRC_kwDOABII585ar66h", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: I see you use `BOOST_CHECK(x == y)` a lot. `BOOST_CHECK_EQUAL` is nice since it prints more helpfully", + "created_at": "2024-03-12T13:25:25Z", + "updated_at": "2024-03-12T14:51:28Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521462945", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521462945" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521462945" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521462945/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 324, + "original_line": 324, + "side": "RIGHT", + "original_position": 31, + "position": 233, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521493476", + "pull_request_review_id": 1890663129, + "id": 1521493476, + "node_id": "PRRC_kwDOABII585asCXk", + "diff_hunk": "@@ -309,6 +309,162 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit: you skipped `err_string2`, maybe you could give them descriptive names like `result_cpfp_replace_cpfp`, `result_replace_3gen` `result_replace_3independent`, etc.", + "created_at": "2024-03-12T13:44:59Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521493476", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521493476" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521493476" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521493476/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 347, + "side": "RIGHT", + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521495616", + "pull_request_review_id": 1890663129, + "id": 1521495616, + "node_id": "PRRC_kwDOABII585asC5A", + "diff_hunk": "@@ -736,6 +737,28 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ * (replacement_fees, replacement_vsize) values are gathered from a\n+ * proposed set of replacement transactions that are considered as a single\n+ * chunk, and represent their complete cluster. In other words, they have no\n+ * in-mempool ancestors.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size (must be greater than 0)\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);\n+\n+ /* Check that all direct conflicts are in a cluster size of two or less. */", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "5f6ddba2635ca2100ed46560f338b64a58f61b73 Maybe mention can contain multiple clusters?", + "created_at": "2024-03-12T13:46:20Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521495616", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521495616" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521495616" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521495616/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 759, + "side": "RIGHT", + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521597108", + "pull_request_review_id": 1890663129, + "id": 1521597108, + "node_id": "PRRC_kwDOABII585asbq0", + "diff_hunk": "@@ -736,6 +737,28 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ * (replacement_fees, replacement_vsize) values are gathered from a\n+ * proposed set of replacement transactions that are considered as a single\n+ * chunk, and represent their complete cluster. In other words, they have no\n+ * in-mempool ancestors.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size (must be greater than 0)\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Did you consider using `util::Result` for this instead? Seems like you want `std::pair, std::vector>` on success or a `std::string` on failure.", + "created_at": "2024-03-12T14:43:13Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521597108", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521597108" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521597108" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521597108/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 753, + "start_side": "RIGHT", + "line": null, + "original_line": 757, + "side": "RIGHT", + "original_position": 29, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521599568", + "pull_request_review_id": 1890663129, + "id": 1521599568, + "node_id": "PRRC_kwDOABII585ascRQ", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Would you consider creating an alias `using FeerateDiagram = std::vector`? Could be a bit easier to write/read.", + "created_at": "2024-03-12T14:44:38Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521599568", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521599568" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521599568" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521599568/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521609927", + "pull_request_review_id": 1890663129, + "id": 1521609927, + "node_id": "PRRC_kwDOABII585asezH", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nothing failed when I commented out this chunk, maybe need some 1p2c or 2p1c `CheckConflictTopology` tests?", + "created_at": "2024-03-12T14:49:32Z", + "updated_at": "2024-03-12T14:50:54Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521609927", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521609927" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521609927" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521609927/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 1266, + "original_start_line": 1266, + "start_side": "RIGHT", + "line": 1278, + "original_line": 1278, + "side": "RIGHT", + "original_position": 48, + "position": 48, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521627191", + "pull_request_review_id": 1931327057, + "id": 1521627191, + "node_id": "PRRC_kwDOABII585asjA3", + "diff_hunk": "@@ -733,6 +734,24 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);\n+\n+ /* Check that all direct conflicts are in a cluster size of two or less. */\n+ std::optional CheckConflictTopology(const setEntries& direct_conflicts);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "802a104d0e2f810d97567e161e0cf61331052906", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "Potentially yes. I suspect it will become fully unrestricted next post-cluster mempool, but we don't know anything for sure.", + "created_at": "2024-03-12T14:58:52Z", + "updated_at": "2024-03-12T14:59:14Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521627191", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521627191" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521627191" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521627191/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 760, + "original_line": 760, + "side": "RIGHT", + "in_reply_to_id": 1495970838, + "original_position": 28, + "position": 32, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521785938", + "pull_request_review_id": 1931582907, + "id": 1521785938, + "node_id": "PRRC_kwDOABII585atJxS", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "seems I have to implement overloaded operator `std::ostream& operator<<(std::ostream& os, const FeeFrac& type)` to support it, and seems somewhat rare in the codebase. I can do it of course. Thoughts?", + "created_at": "2024-03-12T16:31:31Z", + "updated_at": "2024-03-12T16:31:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521785938", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521785938" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521785938" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521785938/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 324, + "original_line": 324, + "side": "RIGHT", + "in_reply_to_id": 1521462945, + "original_position": 31, + "position": 233, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521876319", + "pull_request_review_id": 1931809010, + "id": 1521876319, + "node_id": "PRRC_kwDOABII585atf1f", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "typo: s/be/by\r\n\r\nIf you're taking suggestions,\r\n```suggestion\r\n // low feerate parent with normal feerate child\r\n```", + "created_at": "2024-03-12T17:35:16Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521876319", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521876319" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521876319" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521876319/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 281, + "side": "RIGHT", + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521880005", + "pull_request_review_id": 1931809010, + "id": 1521880005, + "node_id": "PRRC_kwDOABII585atgvF", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "What does \"for now\" mean in this context?\r\n```suggestion\r\n // Adding a grandchild makes the cluster size 3, which is uncalculable\r\n```", + "created_at": "2024-03-12T17:37:20Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521880005", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521880005" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521880005" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521880005/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 305, + "side": "RIGHT", + "original_position": 37, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521881097", + "pull_request_review_id": 1931809010, + "id": 1521881097, + "node_id": "PRRC_kwDOABII585athAJ", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Just a nit, so feel free to ignore.", + "created_at": "2024-03-12T17:38:00Z", + "updated_at": "2024-03-12T18:04:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521881097", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521881097" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521881097" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521881097/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 324, + "original_line": 324, + "side": "RIGHT", + "in_reply_to_id": 1521462945, + "original_position": 31, + "position": 233, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521886497", + "pull_request_review_id": 1931809010, + "id": 1521886497, + "node_id": "PRRC_kwDOABII585atiUh", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "nit 5661fbaec3cb2f8d8790e8c347889a6dea29f324\r\n\r\n`mempool_txs` would be a helpful name", + "created_at": "2024-03-12T17:42:12Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521886497", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521886497" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521886497" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521886497/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 107, + "side": "RIGHT", + "original_position": 67, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521895271", + "pull_request_review_id": 1931809010, + "id": 1521895271, + "node_id": "PRRC_kwDOABII585atkdn", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;\n+ size_t iter{0};\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ txs.emplace_back(*parent);\n+ LOCK2(cs_main, pool.cs);", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Is there any reason to unlock and lock in the loop? Why not just hold throughout?", + "created_at": "2024-03-12T17:49:17Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521895271", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521895271" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521895271" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521895271/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 121, + "side": "RIGHT", + "original_position": 81, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521899151", + "pull_request_review_id": 1931809010, + "id": 1521899151, + "node_id": "PRRC_kwDOABII585atlaP", + "diff_hunk": "@@ -23,12 +23,30 @@ namespace {\n const BasicTestingSetup* g_setup;\n } // namespace\n \n+const int NUM_ITERS = 10000;\n+\n+std::vector g_outpoints;\n+\n void initialize_rbf()\n {\n static const auto testing_setup = MakeNoLogFileContext<>();\n g_setup = testing_setup.get();\n }\n \n+void initialize_package_rbf()\n+{\n+ static const auto testing_setup = MakeNoLogFileContext<>();\n+ g_setup = testing_setup.get();\n+\n+ // Create a fixed set of unique \"UTXOs\" to source parents from\n+ // to avoid fuzzer giving circular references\n+ for (int i = 0; i < NUM_ITERS * 2; ++i) {", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "I don't think you need * 2", + "created_at": "2024-03-12T17:52:30Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521899151", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521899151" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521899151" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521899151/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 43, + "side": "RIGHT", + "original_position": 21, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521904313", + "pull_request_review_id": 1931809010, + "id": 1521904313, + "node_id": "PRRC_kwDOABII585atmq5", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;\n+ size_t iter{0};\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ txs.emplace_back(*parent);\n+ LOCK2(cs_main, pool.cs);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !mtx->vin.empty()) {\n+ mtx->vin[0].prevout = COutPoint{txs.back().GetHash(), 0};\n+ }\n+ txs.emplace_back(*mtx);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, txs.back()));\n+ }\n+ LOCK(pool.cs);\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ std::vector old_diagram, new_diagram;\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (!err_string.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(old_diagram.front().size == 0);\n+ assert(old_diagram.front().fee == 0);\n+ assert(new_diagram.front().size == 0);\n+ assert(new_diagram.front().fee == 0);\n+\n+ CheckDiagramConcave(old_diagram);\n+ CheckDiagramConcave(new_diagram);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(old_diagram.back().fee - replaced_fee + replacement_fees == new_diagram.back().fee);\n+ assert(old_diagram.back().size - replaced_size + replacement_vsize == new_diagram.back().size);\n+ }\n+\n+ // If internals report error, wrapper should too\n+ auto err_tuple{ImprovesFeerateDiagram(pool, direct_conflicts, all_conflicts, replacement_fees, replacement_vsize)};\n+ if (err_string.has_value()) assert(err_tuple.has_value());", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "It seems like the 10000 mempool setup could be reused for multiple iterations of replacement tests?", + "created_at": "2024-03-12T17:56:33Z", + "updated_at": "2024-03-12T18:04:12Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521904313", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521904313" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521904313" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521904313/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 131, + "start_side": "RIGHT", + "line": null, + "original_line": 177, + "side": "RIGHT", + "original_position": 137, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521910913", + "pull_request_review_id": 1931809010, + "id": 1521910913, + "node_id": "PRRC_kwDOABII585atoSB", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Why make this ahead of time instead of just creating a new `CMutableTransaction` for each child?", + "created_at": "2024-03-12T18:01:55Z", + "updated_at": "2024-03-12T18:04:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521910913", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521910913" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521910913" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521910913/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 101, + "start_side": "RIGHT", + "line": null, + "original_line": 102, + "side": "RIGHT", + "original_position": 62, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521911697", + "pull_request_review_id": 1931809010, + "id": 1521911697, + "node_id": "PRRC_kwDOABII585atoeR", + "diff_hunk": "@@ -0,0 +1,156 @@\n+// Copyright (c) 2023 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+#include \n+\n+#include \n+#include \n+\n+#include \n+#include \n+\n+#include \n+\n+namespace {\n+\n+/** Evaluate a diagram at a specific size, returning the fee as a fraction.\n+ *\n+ * Fees in diagram cannot exceed 2^32, as the returned evaluation could overflow\n+ * the FeeFrac::fee field in the result. */\n+FeeFrac EvaluateDiagram(int32_t size, Span diagram)\n+{\n+ assert(diagram.size() > 0);\n+ unsigned not_above = 0;\n+ unsigned not_below = diagram.size() - 1;\n+ // If outside the range of diagram, extend begin/end.\n+ if (size < diagram[not_above].size) return {diagram[not_above].fee, 1};\n+ if (size > diagram[not_below].size) return {diagram[not_below].fee, 1};\n+ // Perform bisection search to locate the diagram segment that size is in.\n+ while (not_below > not_above + 1) {\n+ unsigned mid = (not_below + not_above) / 2;\n+ if (diagram[mid].size <= size) not_above = mid;\n+ if (diagram[mid].size >= size) not_below = mid;\n+ }\n+ // If the size matches a transition point between segments, return its fee.\n+ if (not_below == not_above) return {diagram[not_below].fee, 1};\n+ // Otherwise, interpolate.\n+ auto dir_coef = diagram[not_below] - diagram[not_above];\n+ assert(dir_coef.size > 0);\n+ // Let A = diagram[not_above] and B = diagram[not_below]\n+ const auto& point_a = diagram[not_above];\n+ // We want to return:\n+ // A.fee + (B.fee - A.fee) / (B.size - A.size) * (size - A.size)\n+ // = A.fee + dir_coef.fee / dir_coef.size * (size - A.size)\n+ // = (A.fee * dir_coef.size + dir_coef.fee * (size - A.size)) / dir_coef.size\n+ assert(size >= point_a.size);\n+ return {point_a.fee * dir_coef.size + dir_coef.fee * (size - point_a.size), dir_coef.size};\n+}\n+\n+std::weak_ordering CompareFeeFracWithDiagram(const FeeFrac& ff, Span diagram)\n+{\n+ return FeeRateCompare(FeeFrac{ff.fee, 1}, EvaluateDiagram(ff.size, diagram));\n+}\n+\n+std::partial_ordering CompareDiagrams(Span dia1, Span dia2)\n+{\n+ bool all_ge = true;\n+ bool all_le = true;\n+ for (const auto p1 : dia1) {\n+ auto cmp = CompareFeeFracWithDiagram(p1, dia2);\n+ if (std::is_lt(cmp)) all_ge = false;\n+ if (std::is_gt(cmp)) all_le = false;\n+ }\n+ for (const auto p2 : dia2) {\n+ auto cmp = CompareFeeFracWithDiagram(p2, dia1);\n+ if (std::is_lt(cmp)) all_le = false;\n+ if (std::is_gt(cmp)) all_ge = false;\n+ }\n+ if (all_ge && all_le) return std::partial_ordering::equivalent;\n+ if (all_ge && !all_le) return std::partial_ordering::greater;\n+ if (!all_ge && all_le) return std::partial_ordering::less;\n+ return std::partial_ordering::unordered;\n+}\n+\n+void PopulateDiagram(FuzzedDataProvider& fuzzed_data_provider, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.emplace_back(0, 0);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50)\n+ {\n+ const auto& last_point = diagram.back();\n+ diagram.emplace_back(last_point.fee + fuzzed_data_provider.ConsumeIntegralInRange(INT32_MIN>>1, INT32_MAX>>1), last_point.size+fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000));\n+ }\n+ return;\n+}\n+\n+void PopulateChunks(FuzzedDataProvider& fuzzed_data_provider, std::vector& chunks)\n+{\n+ chunks.clear();\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50)\n+ {\n+ chunks.emplace_back(fuzzed_data_provider.ConsumeIntegralInRange(INT32_MIN>>1, INT32_MAX>>1), fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000));\n+ }\n+ return;\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(rbf_compare_feerate_diagram)\n+{\n+ // Generate two random feerate diagrams, and verify that the comparison results match.\n+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());\n+ std::vector diagram1, diagram2;\n+\n+ PopulateDiagram(fuzzed_data_provider, diagram1);\n+ PopulateDiagram(fuzzed_data_provider, diagram2);\n+\n+ auto real = CompareFeerateDiagram(diagram1, diagram2);\n+ auto sim = CompareDiagrams(diagram1, diagram2);\n+ assert(real == sim);\n+\n+ // Do explicit evaluation at up to 1000 points, and verify consistency with the result.\n+ LIMITED_WHILE(fuzzed_data_provider.remaining_bytes(), 1000) {\n+ int32_t size = fuzzed_data_provider.ConsumeIntegralInRange(0, diagram2.back().size);\n+ auto eval1 = EvaluateDiagram(size, diagram1);\n+ auto eval2 = EvaluateDiagram(size, diagram2);\n+ auto cmp = FeeRateCompare(eval1, eval2);\n+ if (std::is_lt(cmp)) assert(!std::is_gt(real));\n+ if (std::is_gt(cmp)) assert(!std::is_lt(real));\n+ }\n+}\n+\n+FUZZ_TARGET(build_and_compare_feerate_diagram)\n+{\n+ // Generate a random set of chunks", + "path": "src/test/fuzz/feeratediagram.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "f4e7c2748d263daca9d6e6164bd0f6818445f9da", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Maybe \"same as above, but start with chunks instead of diagrams\" ? Can any of the code maybe be helper funcitoned?", + "created_at": "2024-03-12T18:02:34Z", + "updated_at": "2024-03-12T18:04:13Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521911697", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521911697" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1521911697" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1521911697/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 92, + "original_line": 92, + "side": "RIGHT", + "original_position": 129, + "position": 92, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493020", + "pull_request_review_id": 1934526693, + "id": 1523493020, + "node_id": "PRRC_kwDOABII585azqic", + "diff_hunk": "@@ -0,0 +1,124 @@\n+// Copyright (c) 2016-2021 The Bitcoin Core developers", + "path": "src/test/feefrac_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "eebe434383cf648c4395410d9d9764334fb8ee84", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "fixed", + "created_at": "2024-03-13T15:33:27Z", + "updated_at": "2024-03-13T15:33:28Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493020", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493020" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493020" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493020/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1, + "side": "RIGHT", + "in_reply_to_id": 1521424340, + "original_position": 1, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493141", + "pull_request_review_id": 1934526853, + "id": 1523493141, + "node_id": "PRRC_kwDOABII585azqkV", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "ignoring for now", + "created_at": "2024-03-13T15:33:31Z", + "updated_at": "2024-03-13T15:33:31Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493141", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493141" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493141" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493141/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 324, + "original_line": 324, + "side": "RIGHT", + "in_reply_to_id": 1521462945, + "original_position": 31, + "position": 233, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493228", + "pull_request_review_id": 1934526974, + "id": 1523493228, + "node_id": "PRRC_kwDOABII585azqls", + "diff_hunk": "@@ -309,6 +309,162 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto err_string{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low}, old_diagram, new_diagram)};\n+ BOOST_CHECK(!err_string.has_value());\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Non-zero replacement fee/size\n+ const auto err_string3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low}, old_diagram, new_diagram)};", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "8c77f2552a72e6f252c30be45e386cf842a53c63", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "an attempt was made!", + "created_at": "2024-03-13T15:33:33Z", + "updated_at": "2024-03-13T15:33:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493228", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493228" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493228" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493228/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 347, + "side": "RIGHT", + "in_reply_to_id": 1521493476, + "original_position": 39, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493325", + "pull_request_review_id": 1934527106, + "id": 1523493325, + "node_id": "PRRC_kwDOABII585azqnN", + "diff_hunk": "@@ -736,6 +737,28 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ * (replacement_fees, replacement_vsize) values are gathered from a\n+ * proposed set of replacement transactions that are considered as a single\n+ * chunk, and represent their complete cluster. In other words, they have no\n+ * in-mempool ancestors.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size (must be greater than 0)\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);\n+\n+ /* Check that all direct conflicts are in a cluster size of two or less. */", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-13T15:33:37Z", + "updated_at": "2024-03-13T15:33:37Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493325", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493325" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493325" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493325/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 759, + "side": "RIGHT", + "in_reply_to_id": 1521495616, + "original_position": 31, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493395", + "pull_request_review_id": 1934527192, + "id": 1523493395, + "node_id": "PRRC_kwDOABII585azqoT", + "diff_hunk": "@@ -736,6 +737,28 @@ class CTxMemPool\n return m_sequence_number;\n }\n \n+ /**\n+ * Calculate the old and new mempool feerate diagrams relating to the\n+ * clusters that would be affected by a potential replacement transaction.\n+ * (replacement_fees, replacement_vsize) values are gathered from a\n+ * proposed set of replacement transactions that are considered as a single\n+ * chunk, and represent their complete cluster. In other words, they have no\n+ * in-mempool ancestors.\n+ *\n+ * @param[in] replacement_fees Package fees\n+ * @param[in] replacement_vsize Package size (must be greater than 0)\n+ * @param[in] direct_conflicts All transactions that would be removed directly by\n+ * having a conflicting input with a proposed transaction\n+ * @param[in] all_conflicts All transactions that would be removed\n+ * @param[out] old_diagram The feerate diagram of the relevant clusters before accepting the new tx\n+ * @param[out] new_diagram The feerate diagram of the relevant clusters after accepting the new tx\n+ * @return An optional error string if the conflicts don't match a calculable topology\n+ */\n+ std::optional CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts, std::vector& old_diagram, std::vector& new_diagram) EXCLUSIVE_LOCKS_REQUIRED(cs);", + "path": "src/txmempool.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-13T15:33:39Z", + "updated_at": "2024-03-13T15:33:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493395", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493395" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493395" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493395/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 753, + "start_side": "RIGHT", + "line": null, + "original_line": 757, + "side": "RIGHT", + "in_reply_to_id": 1521597108, + "original_position": 29, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493513", + "pull_request_review_id": 1934527349, + "id": 1523493513, + "node_id": "PRRC_kwDOABII585azqqJ", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "doesn't seem to save much typing/reading if we're using `Span`, leaving as is for now", + "created_at": "2024-03-13T15:33:43Z", + "updated_at": "2024-03-13T15:33:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493513", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493513" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493513" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493513/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1521599568, + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493623", + "pull_request_review_id": 1934527493, + "id": 1523493623, + "node_id": "PRRC_kwDOABII585azqr3", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "oops, bad test setup was missing this. Fixed and added string assertions to check what it's actually catching.", + "created_at": "2024-03-13T15:33:47Z", + "updated_at": "2024-03-13T15:33:47Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493623", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493623" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493623" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493623/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 1266, + "original_start_line": 1266, + "start_side": "RIGHT", + "line": 1278, + "original_line": 1278, + "side": "RIGHT", + "in_reply_to_id": 1521609927, + "original_position": 48, + "position": 48, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493948", + "pull_request_review_id": 1934528017, + "id": 1523493948, + "node_id": "PRRC_kwDOABII585azqw8", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken", + "created_at": "2024-03-13T15:33:55Z", + "updated_at": "2024-03-13T15:33:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493948", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493948" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523493948" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523493948/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 281, + "side": "RIGHT", + "in_reply_to_id": 1521876319, + "original_position": 13, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494089", + "pull_request_review_id": 1934528266, + "id": 1523494089, + "node_id": "PRRC_kwDOABII585azqzJ", + "diff_hunk": "@@ -269,6 +269,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_child2, entry11_unchained}).has_value());\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // One low feerate txn followed be normal feerate\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+\n+ // Make conflict un-calculable(for now)", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "70ffb25852fb274c2703ee07a5e225d047391571", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "we could expand acceptable topologies later. Took language.", + "created_at": "2024-03-13T15:33:59Z", + "updated_at": "2024-03-13T15:33:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494089", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494089" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494089" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494089/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 305, + "side": "RIGHT", + "in_reply_to_id": 1521880005, + "original_position": 37, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494210", + "pull_request_review_id": 1934528513, + "id": 1523494210, + "node_id": "PRRC_kwDOABII585azq1C", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-13T15:34:03Z", + "updated_at": "2024-03-13T15:34:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494210/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 107, + "side": "RIGHT", + "in_reply_to_id": 1521886497, + "original_position": 67, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494301", + "pull_request_review_id": 1934528682, + "id": 1523494301, + "node_id": "PRRC_kwDOABII585azq2d", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;\n+ size_t iter{0};\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ txs.emplace_back(*parent);\n+ LOCK2(cs_main, pool.cs);", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "changed to hold it throughout ", + "created_at": "2024-03-13T15:34:06Z", + "updated_at": "2024-03-13T15:34:06Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494301", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494301" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494301" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494301/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 121, + "side": "RIGHT", + "in_reply_to_id": 1521895271, + "original_position": 81, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494859", + "pull_request_review_id": 1934529628, + "id": 1523494859, + "node_id": "PRRC_kwDOABII585azq_L", + "diff_hunk": "@@ -23,12 +23,30 @@ namespace {\n const BasicTestingSetup* g_setup;\n } // namespace\n \n+const int NUM_ITERS = 10000;\n+\n+std::vector g_outpoints;\n+\n void initialize_rbf()\n {\n static const auto testing_setup = MakeNoLogFileContext<>();\n g_setup = testing_setup.get();\n }\n \n+void initialize_package_rbf()\n+{\n+ static const auto testing_setup = MakeNoLogFileContext<>();\n+ g_setup = testing_setup.get();\n+\n+ // Create a fixed set of unique \"UTXOs\" to source parents from\n+ // to avoid fuzzer giving circular references\n+ for (int i = 0; i < NUM_ITERS * 2; ++i) {", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "removed", + "created_at": "2024-03-13T15:34:27Z", + "updated_at": "2024-03-13T15:34:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494859", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494859" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494859" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494859/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 43, + "side": "RIGHT", + "in_reply_to_id": 1521899151, + "original_position": 21, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494986", + "pull_request_review_id": 1934529829, + "id": 1523494986, + "node_id": "PRRC_kwDOABII585azrBK", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector txs;\n+ size_t iter{0};\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ txs.emplace_back(*parent);\n+ LOCK2(cs_main, pool.cs);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !mtx->vin.empty()) {\n+ mtx->vin[0].prevout = COutPoint{txs.back().GetHash(), 0};\n+ }\n+ txs.emplace_back(*mtx);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, txs.back()));\n+ }\n+ LOCK(pool.cs);\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ std::vector old_diagram, new_diagram;\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto err_string{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts, old_diagram, new_diagram)};\n+\n+ if (!err_string.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(old_diagram.front().size == 0);\n+ assert(old_diagram.front().fee == 0);\n+ assert(new_diagram.front().size == 0);\n+ assert(new_diagram.front().fee == 0);\n+\n+ CheckDiagramConcave(old_diagram);\n+ CheckDiagramConcave(new_diagram);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(old_diagram.back().fee - replaced_fee + replacement_fees == new_diagram.back().fee);\n+ assert(old_diagram.back().size - replaced_size + replacement_vsize == new_diagram.back().size);\n+ }\n+\n+ // If internals report error, wrapper should too\n+ auto err_tuple{ImprovesFeerateDiagram(pool, direct_conflicts, all_conflicts, replacement_fees, replacement_vsize)};\n+ if (err_string.has_value()) assert(err_tuple.has_value());", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I guess the question is if unique mempools per run are worth the overhead. I think it's pretty fast still?", + "created_at": "2024-03-13T15:34:32Z", + "updated_at": "2024-03-13T15:34:32Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494986", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494986" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523494986" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523494986/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 131, + "start_side": "RIGHT", + "line": null, + "original_line": 177, + "side": "RIGHT", + "in_reply_to_id": 1521904313, + "original_position": 137, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495074", + "pull_request_review_id": 1934529959, + "id": 1523495074, + "node_id": "PRRC_kwDOABII585azrCi", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i mtx = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!mtx) return;", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5661fbaec3cb2f8d8790e8c347889a6dea29f324", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "Aping the current rbf tests, probably. Picks a valid transaction structure, then sticks with it for the run. Suggestions for follow-up improvements maybe?", + "created_at": "2024-03-13T15:34:35Z", + "updated_at": "2024-03-13T15:34:36Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523495074", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495074" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523495074" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495074/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": 101, + "start_side": "RIGHT", + "line": null, + "original_line": 102, + "side": "RIGHT", + "in_reply_to_id": 1521910913, + "original_position": 62, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495165", + "pull_request_review_id": 1934530102, + "id": 1523495165, + "node_id": "PRRC_kwDOABII585azrD9", + "diff_hunk": "@@ -0,0 +1,156 @@\n+// Copyright (c) 2023 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+#include \n+\n+#include \n+#include \n+\n+#include \n+#include \n+\n+#include \n+\n+namespace {\n+\n+/** Evaluate a diagram at a specific size, returning the fee as a fraction.\n+ *\n+ * Fees in diagram cannot exceed 2^32, as the returned evaluation could overflow\n+ * the FeeFrac::fee field in the result. */\n+FeeFrac EvaluateDiagram(int32_t size, Span diagram)\n+{\n+ assert(diagram.size() > 0);\n+ unsigned not_above = 0;\n+ unsigned not_below = diagram.size() - 1;\n+ // If outside the range of diagram, extend begin/end.\n+ if (size < diagram[not_above].size) return {diagram[not_above].fee, 1};\n+ if (size > diagram[not_below].size) return {diagram[not_below].fee, 1};\n+ // Perform bisection search to locate the diagram segment that size is in.\n+ while (not_below > not_above + 1) {\n+ unsigned mid = (not_below + not_above) / 2;\n+ if (diagram[mid].size <= size) not_above = mid;\n+ if (diagram[mid].size >= size) not_below = mid;\n+ }\n+ // If the size matches a transition point between segments, return its fee.\n+ if (not_below == not_above) return {diagram[not_below].fee, 1};\n+ // Otherwise, interpolate.\n+ auto dir_coef = diagram[not_below] - diagram[not_above];\n+ assert(dir_coef.size > 0);\n+ // Let A = diagram[not_above] and B = diagram[not_below]\n+ const auto& point_a = diagram[not_above];\n+ // We want to return:\n+ // A.fee + (B.fee - A.fee) / (B.size - A.size) * (size - A.size)\n+ // = A.fee + dir_coef.fee / dir_coef.size * (size - A.size)\n+ // = (A.fee * dir_coef.size + dir_coef.fee * (size - A.size)) / dir_coef.size\n+ assert(size >= point_a.size);\n+ return {point_a.fee * dir_coef.size + dir_coef.fee * (size - point_a.size), dir_coef.size};\n+}\n+\n+std::weak_ordering CompareFeeFracWithDiagram(const FeeFrac& ff, Span diagram)\n+{\n+ return FeeRateCompare(FeeFrac{ff.fee, 1}, EvaluateDiagram(ff.size, diagram));\n+}\n+\n+std::partial_ordering CompareDiagrams(Span dia1, Span dia2)\n+{\n+ bool all_ge = true;\n+ bool all_le = true;\n+ for (const auto p1 : dia1) {\n+ auto cmp = CompareFeeFracWithDiagram(p1, dia2);\n+ if (std::is_lt(cmp)) all_ge = false;\n+ if (std::is_gt(cmp)) all_le = false;\n+ }\n+ for (const auto p2 : dia2) {\n+ auto cmp = CompareFeeFracWithDiagram(p2, dia1);\n+ if (std::is_lt(cmp)) all_le = false;\n+ if (std::is_gt(cmp)) all_ge = false;\n+ }\n+ if (all_ge && all_le) return std::partial_ordering::equivalent;\n+ if (all_ge && !all_le) return std::partial_ordering::greater;\n+ if (!all_ge && all_le) return std::partial_ordering::less;\n+ return std::partial_ordering::unordered;\n+}\n+\n+void PopulateDiagram(FuzzedDataProvider& fuzzed_data_provider, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.emplace_back(0, 0);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50)\n+ {\n+ const auto& last_point = diagram.back();\n+ diagram.emplace_back(last_point.fee + fuzzed_data_provider.ConsumeIntegralInRange(INT32_MIN>>1, INT32_MAX>>1), last_point.size+fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000));\n+ }\n+ return;\n+}\n+\n+void PopulateChunks(FuzzedDataProvider& fuzzed_data_provider, std::vector& chunks)\n+{\n+ chunks.clear();\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50)\n+ {\n+ chunks.emplace_back(fuzzed_data_provider.ConsumeIntegralInRange(INT32_MIN>>1, INT32_MAX>>1), fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000));\n+ }\n+ return;\n+}\n+\n+} // namespace\n+\n+FUZZ_TARGET(rbf_compare_feerate_diagram)\n+{\n+ // Generate two random feerate diagrams, and verify that the comparison results match.\n+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());\n+ std::vector diagram1, diagram2;\n+\n+ PopulateDiagram(fuzzed_data_provider, diagram1);\n+ PopulateDiagram(fuzzed_data_provider, diagram2);\n+\n+ auto real = CompareFeerateDiagram(diagram1, diagram2);\n+ auto sim = CompareDiagrams(diagram1, diagram2);\n+ assert(real == sim);\n+\n+ // Do explicit evaluation at up to 1000 points, and verify consistency with the result.\n+ LIMITED_WHILE(fuzzed_data_provider.remaining_bytes(), 1000) {\n+ int32_t size = fuzzed_data_provider.ConsumeIntegralInRange(0, diagram2.back().size);\n+ auto eval1 = EvaluateDiagram(size, diagram1);\n+ auto eval2 = EvaluateDiagram(size, diagram2);\n+ auto cmp = FeeRateCompare(eval1, eval2);\n+ if (std::is_lt(cmp)) assert(!std::is_gt(real));\n+ if (std::is_gt(cmp)) assert(!std::is_lt(real));\n+ }\n+}\n+\n+FUZZ_TARGET(build_and_compare_feerate_diagram)\n+{\n+ // Generate a random set of chunks", + "path": "src/test/fuzz/feeratediagram.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "f4e7c2748d263daca9d6e6164bd0f6818445f9da", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "removed the more limited fuzz test, as I don't think it adds additional coverage", + "created_at": "2024-03-13T15:34:39Z", + "updated_at": "2024-03-13T15:34:39Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523495165", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495165" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1523495165" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1523495165/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 92, + "original_line": 92, + "side": "RIGHT", + "in_reply_to_id": 1521911697, + "original_position": 129, + "position": 92, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1525381280", + "pull_request_review_id": 1937534483, + "id": 1525381280, + "node_id": "PRRC_kwDOABII585a63ig", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit:\r\n```suggestion\r\n // they have a strict topology of one or two connected transactions.\r\n```\r\nor\r\n```suggestion\r\n // they have a strict topology of 1 or 2 connected transactions.\r\n```", + "created_at": "2024-03-14T19:19:17Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1525381280", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1525381280" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1525381280" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1525381280/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1305, + "original_line": 1305, + "side": "RIGHT", + "original_position": 75, + "position": 75, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526774027", + "pull_request_review_id": 1940381796, + "id": 1526774027, + "node_id": "PRRC_kwDOABII585bALkL", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "In commit \"Add FeeFrac utils\"\r\n\r\nNit: the `const` before `Span` doesn't do anything (it's ignored in the declaration of by-value function arguments). You can have it be `const` in the function definition (in feefrac.cpp) without having it `const` here (where it does have the effect that the function body cannot modify the copy it receives).", + "created_at": "2024-03-15T19:54:52Z", + "updated_at": "2024-03-17T00:31:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526774027", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526774027" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526774027" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526774027/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526807556", + "pull_request_review_id": 1940381796, + "id": 1526807556, + "node_id": "PRRC_kwDOABII585bATwE", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (!diagram_results.has_value()) {", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "In commit \"Implement ImprovesFeerateDiagram\"\r\n\r\nI'm confused about this. If `diagram_results` has no value, does it make sense to pass it to `util::ErrorString` below?", + "created_at": "2024-03-15T20:36:27Z", + "updated_at": "2024-03-17T00:31:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526807556", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526807556" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526807556" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526807556/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 198, + "original_line": 198, + "side": "RIGHT", + "original_position": 25, + "position": 25, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526833187", + "pull_request_review_id": 1940381796, + "id": 1526833187, + "node_id": "PRRC_kwDOABII585bAaAj", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ std::sort(old_chunks.begin(), old_chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "In commit \"Implement ImprovesFeerateDiagram\"\r\n\r\nNit: shorter as:\r\n\r\n```c++\r\nstd::sort(old_chunks.begin(), old_chunks.end(), std::greater{});\r\n```\r\n\r\n(here and below)", + "created_at": "2024-03-15T21:01:12Z", + "updated_at": "2024-03-17T00:31:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526833187", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526833187" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1526833187" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1526833187/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1336, + "side": "RIGHT", + "original_position": 106, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528629298", + "pull_request_review_id": 1943181069, + "id": 1528629298, + "node_id": "PRRC_kwDOABII585bHQgy", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (!diagram_results.has_value()) {", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "`util::Result` lets you pass an error string in lieu of a `std::nullopt`, and based on the docs it seems I'm using this right. @glozow ?\r\n\r\n\r\n```\r\n//! `std::optional` can be updated to return `util::Result` and return\r\n//! error strings usually just replacing `return std::nullopt;` with `return\r\n//! util::Error{error_string};`.\r\n```", + "created_at": "2024-03-18T14:04:50Z", + "updated_at": "2024-03-18T14:04:51Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528629298", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528629298" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528629298" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528629298/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 198, + "original_line": 198, + "side": "RIGHT", + "in_reply_to_id": 1526807556, + "original_position": 25, + "position": 25, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528643105", + "pull_request_review_id": 1943201769, + "id": 1528643105, + "node_id": "PRRC_kwDOABII585bHT4h", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (!diagram_results.has_value()) {", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "~~But you aren't passing it an error string, you're passing it `diagram_results`, which is at this stage known to be `std::nullopt`?~~\r\n\r\nNevermind, I missed that `diagram_results` is an `util::Result`, not an `std::optional`, so the `!diagram_results.has_value()` means it *does* contain an error. Sorry!", + "created_at": "2024-03-18T14:10:39Z", + "updated_at": "2024-03-18T14:16:44Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528643105", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528643105" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528643105" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528643105/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 198, + "original_line": 198, + "side": "RIGHT", + "in_reply_to_id": 1526807556, + "original_position": 25, + "position": 25, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528651476", + "pull_request_review_id": 1943216125, + "id": 1528651476, + "node_id": "PRRC_kwDOABII585bHV7U", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (!diagram_results.has_value()) {", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "this is what it's returning instead of a `std::nullopt`: https://github.com/bitcoin/bitcoin/pull/29242/files#diff-c065d4cd2398ad0dbcef393c5dfc53f465bf44723348892395fffd2fb3bac522R1290\r\n\r\n(we might be talking past each other)", + "created_at": "2024-03-18T14:15:55Z", + "updated_at": "2024-03-18T14:15:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528651476", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528651476" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528651476" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528651476/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 198, + "original_line": 198, + "side": "RIGHT", + "in_reply_to_id": 1526807556, + "original_position": 25, + "position": 25, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528654626", + "pull_request_review_id": 1943221493, + "id": 1528654626, + "node_id": "PRRC_kwDOABII585bHWsi", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;\n+\n+ const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (!diagram_results.has_value()) {", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Right, just discovered I missed what type this was all along. See update above.", + "created_at": "2024-03-18T14:17:59Z", + "updated_at": "2024-03-18T14:18:00Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528654626", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528654626" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528654626" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528654626/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 198, + "original_line": 198, + "side": "RIGHT", + "in_reply_to_id": 1526807556, + "original_position": 25, + "position": 25, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672383", + "pull_request_review_id": 1943248232, + "id": 1528672383, + "node_id": "PRRC_kwDOABII585bHbB_", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I probably should just be passing a reference here anyways? Changed to pass by reference", + "created_at": "2024-03-18T14:26:49Z", + "updated_at": "2024-03-18T14:26:49Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528672383", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672383" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528672383" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672383/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1526774027, + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672562", + "pull_request_review_id": 1943248552, + "id": 1528672562, + "node_id": "PRRC_kwDOABII585bHbEy", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort\n+ std::sort(old_chunks.begin(), old_chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "done", + "created_at": "2024-03-18T14:26:56Z", + "updated_at": "2024-03-18T14:26:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528672562", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672562" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528672562" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528672562/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 1336, + "side": "RIGHT", + "in_reply_to_id": 1526833187, + "original_position": 106, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528676446", + "pull_request_review_id": 1943254892, + "id": 1528676446, + "node_id": "PRRC_kwDOABII585bHcBe", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "The general advice is to pass arguments not larger than 2 pointers by value, which is the case for spans.", + "created_at": "2024-03-18T14:29:19Z", + "updated_at": "2024-03-18T14:29:19Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528676446", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528676446" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528676446" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528676446/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1526774027, + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528686305", + "pull_request_review_id": 1943273458, + "id": 1528686305, + "node_id": "PRRC_kwDOABII585bHebh", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;\n+\n+ /** Construct an IsEmpty() FeeFrac. */\n+ inline FeeFrac() noexcept : fee{0}, size{0} {}\n+\n+ /** Construct a FeeFrac with specified fee and size. */\n+ inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}\n+\n+ inline FeeFrac(const FeeFrac&) noexcept = default;\n+ inline FeeFrac& operator=(const FeeFrac&) noexcept = default;\n+\n+ /** Check if this is empty (size and fee are 0). */\n+ bool inline IsEmpty() const noexcept {\n+ return size == 0;\n+ }\n+\n+ /** Add fee and size of another FeeFrac to this one. */\n+ void inline operator+=(const FeeFrac& other) noexcept\n+ {\n+ fee += other.fee;\n+ size += other.size;\n+ }\n+\n+ /** Subtract fee and size of another FeeFrac from this one. */\n+ void inline operator-=(const FeeFrac& other) noexcept\n+ {\n+ fee -= other.fee;\n+ size -= other.size;\n+ }\n+\n+ /** Sum fee and size. */\n+ friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee + b.fee, a.size + b.size};\n+ }\n+\n+ /** Subtract both fee and size. */\n+ friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return {a.fee - b.fee, a.size - b.size};\n+ }\n+\n+ /** Check if two FeeFrac objects are equal (both same fee and same size). */\n+ friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ return a.fee == b.fee && a.size == b.size;\n+ }\n+\n+ /** Compare two FeeFracs just by feerate. */\n+ friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly lower feerate than another. */\n+ friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a < cross_b;\n+ }\n+\n+ /** Check if a FeeFrac object has strictly higher feerate than another. */\n+ friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ return cross_a > cross_b;\n+ }\n+\n+ /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */\n+ friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept\n+ {\n+ auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size);\n+ if (cross_a == cross_b) return b.size <=> a.size;\n+ return cross_a <=> cross_b;\n+ }\n+\n+ /** Swap two FeeFracs. */\n+ friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept\n+ {\n+ std::swap(a.fee, b.fee);\n+ std::swap(a.size, b.size);\n+ }\n+};\n+\n+/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */\n+std::vector BuildDiagramFromChunks(const Span chunks);", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "d2025b37cd43aa93db28a7ec637b2a6a1f936a52", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "got it, double checked, taking your suggestion to remove const from declaration instead", + "created_at": "2024-03-18T14:35:34Z", + "updated_at": "2024-03-18T14:35:34Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528686305", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528686305" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528686305" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528686305/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": null, + "original_line": 150, + "side": "RIGHT", + "in_reply_to_id": 1526774027, + "original_position": 150, + "position": null, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528732978", + "pull_request_review_id": 1943349194, + "id": 1528732978, + "node_id": "PRRC_kwDOABII585bHp0y", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "In commit \"Add FeeFrac utils\":\r\n\r\nSelf-nit: CompareFeeFrac -> FeeRateCompare", + "created_at": "2024-03-18T14:59:51Z", + "updated_at": "2024-03-18T16:34:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528732978", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528732978" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528732978" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528732978/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 34, + "original_line": 34, + "side": "RIGHT", + "original_position": 34, + "position": 34, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528740535", + "pull_request_review_id": 1943349194, + "id": 1528740535, + "node_id": "PRRC_kwDOABII585bHrq3", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "In commit \"Implement ImprovesFeerateDiagram\"\r\n\r\nNit: improve**s**", + "created_at": "2024-03-18T15:04:32Z", + "updated_at": "2024-03-18T16:34:53Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528740535", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528740535" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1528740535" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1528740535/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 193, + "original_line": 193, + "side": "RIGHT", + "original_position": 20, + "position": 20, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530231967", + "pull_request_review_id": 1945992726, + "id": 1530231967, + "node_id": "PRRC_kwDOABII585bNXyf", + "diff_hunk": "@@ -215,15 +248,119 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto grand_child_tx = add_descendants(child_tx, 1, pool);\n+ const auto entry10_grand_child = pool.GetIter(grand_child_tx->GetHash()).value();\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).value(), strprintf(\"%s has 2 descendants, max 1 allowed\", entry10_unchained->GetSharedTx()->GetHash().ToString()));\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry9_unchained, entry10_grand_child, entry11_unchained}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry10_grand_child->GetSharedTx()->GetHash().ToString()));\n+\n+ // Make a single child from two singleton parents\n+ const auto two_parent_child_tx = add_descendant_to_parents({tx11, tx12}, pool);\n+ const auto entry_two_parent_child = pool.GetIter(two_parent_child_tx->GetHash()).value();\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry11_unchained}).value(), strprintf(\"%s is not the only parent of child %s\", entry11_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry12_unchained}).value(), strprintf(\"%s is not the only parent of child %s\", entry12_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // New diagram is strictly better due to the first chunk, even though\n+ // second chunk contributes no fees\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first new chunk is better with, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 1000}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e9c5aeb11d641b8cae373452339760809625021d", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "e9c5aeb11d641b8cae373452339760809625021d could do the reciprocal checks everywhere i.e.\r\n```\r\nBOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\r\nBOOST_CHECK(std::is_gt(CompareFeerateDiagram(new_diagram, old_diagram)));\r\n\r\n...\r\nBOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\r\nBOOST_CHECK(std::is_eq(CompareFeerateDiagram(new_diagram, old_diagram)));\r\n```", + "created_at": "2024-03-19T12:00:32Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530231967", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530231967" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530231967" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530231967/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 505, + "original_start_line": 305, + "start_side": "RIGHT", + "line": 543, + "original_line": 343, + "side": "RIGHT", + "original_position": 252, + "position": 452, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530243767", + "pull_request_review_id": 1945992726, + "id": 1530243767, + "node_id": "PRRC_kwDOABII585bNaq3", + "diff_hunk": "@@ -89,58 +104,76 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n const auto tx8 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {999 * CENT});\n pool.addUnchecked(entry.Fee(high_fee).FromTx(tx8));\n \n- const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n- const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n- const auto entry3 = pool.GetIter(tx3->GetHash()).value();\n- const auto entry4 = pool.GetIter(tx4->GetHash()).value();\n- const auto entry5 = pool.GetIter(tx5->GetHash()).value();\n- const auto entry6 = pool.GetIter(tx6->GetHash()).value();\n- const auto entry7 = pool.GetIter(tx7->GetHash()).value();\n- const auto entry8 = pool.GetIter(tx8->GetHash()).value();\n-\n- BOOST_CHECK_EQUAL(entry1->GetFee(), normal_fee);\n- BOOST_CHECK_EQUAL(entry2->GetFee(), normal_fee);\n- BOOST_CHECK_EQUAL(entry3->GetFee(), low_fee);\n- BOOST_CHECK_EQUAL(entry4->GetFee(), high_fee);\n- BOOST_CHECK_EQUAL(entry5->GetFee(), low_fee);\n- BOOST_CHECK_EQUAL(entry6->GetFee(), low_fee);\n- BOOST_CHECK_EQUAL(entry7->GetFee(), high_fee);\n- BOOST_CHECK_EQUAL(entry8->GetFee(), high_fee);\n-\n- CTxMemPool::setEntries set_12_normal{entry1, entry2};\n- CTxMemPool::setEntries set_34_cpfp{entry3, entry4};\n- CTxMemPool::setEntries set_56_low{entry5, entry6};\n- CTxMemPool::setEntries all_entries{entry1, entry2, entry3, entry4, entry5, entry6, entry7, entry8};\n+ // Normal txs, will chain txns right before CheckConflictTopology test\n+ const auto tx9 = make_tx(/*inputs=*/ {m_coinbase_txns[5]}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx9));\n+ const auto tx10 = make_tx(/*inputs=*/ {m_coinbase_txns[6]}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx10));\n+\n+ // Will make these two parents of single child\n+ const auto tx11 = make_tx(/*inputs=*/ {m_coinbase_txns[7]}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx11));\n+ const auto tx12 = make_tx(/*inputs=*/ {m_coinbase_txns[8]}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx12));\n+\n+ const auto entry1_normal = pool.GetIter(tx1->GetHash()).value();\n+ const auto entry2_normal = pool.GetIter(tx2->GetHash()).value();\n+ const auto entry3_low = pool.GetIter(tx3->GetHash()).value();\n+ const auto entry4_high = pool.GetIter(tx4->GetHash()).value();\n+ const auto entry5_low = pool.GetIter(tx5->GetHash()).value();\n+ const auto entry6_low_prioritised = pool.GetIter(tx6->GetHash()).value();\n+ const auto entry7_high = pool.GetIter(tx7->GetHash()).value();\n+ const auto entry8_high = pool.GetIter(tx8->GetHash()).value();\n+ const auto entry9_unchained = pool.GetIter(tx9->GetHash()).value();\n+ const auto entry10_unchained = pool.GetIter(tx10->GetHash()).value();\n+ const auto entry11_unchained = pool.GetIter(tx11->GetHash()).value();\n+ const auto entry12_unchained = pool.GetIter(tx12->GetHash()).value();", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e9c5aeb11d641b8cae373452339760809625021d", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "e9c5aeb11d641b8cae373452339760809625021d could have been 3 commits\r\n- rename entry{1...8} to entry{1...8}\\_{normal,low,high, etc} in rbf_tests\r\n- unit tests for `CheckConflictTopology`\r\n- unit tests for `CompareFeerateDiagram`", + "created_at": "2024-03-19T12:10:40Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530243767", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530243767" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530243767" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530243767/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 119, + "original_start_line": 119, + "start_side": "RIGHT", + "line": 130, + "original_line": 130, + "side": "RIGHT", + "original_position": 80, + "position": 80, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530244386", + "pull_request_review_id": 1945992726, + "id": 1530244386, + "node_id": "PRRC_kwDOABII585bNa0i", + "diff_hunk": "@@ -215,15 +248,119 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e9c5aeb11d641b8cae373452339760809625021d", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Check the value of the string as well, i.e. \"%s has 23 descendants, max 1 allowed\"", + "created_at": "2024-03-19T12:11:14Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530244386", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530244386" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530244386" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530244386/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 264, + "original_line": 264, + "side": "RIGHT", + "original_position": 173, + "position": 173, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530252751", + "pull_request_review_id": 1945992726, + "id": 1530252751, + "node_id": "PRRC_kwDOABII585bNc3P", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "I see you've added coverage for the \"not the only parent\" case, but I don't see a test for \"not the only child\" case. Also nothing failed when I commented it out.", + "created_at": "2024-03-19T12:17:04Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530252751", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530252751" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530252751" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530252751/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 1266, + "original_start_line": 1266, + "start_side": "RIGHT", + "line": 1278, + "original_line": 1278, + "side": "RIGHT", + "in_reply_to_id": 1521609927, + "original_position": 48, + "position": 48, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530263627", + "pull_request_review_id": 1945992726, + "id": 1530263627, + "node_id": "PRRC_kwDOABII585bNfhL", + "diff_hunk": "@@ -294,6 +294,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // low feerate parent with normal feerate child\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74 This is perhaps the place to add coverage for the fact that modified feerate is used, e.g. `PrioritiseTransaction` here and check that using a `replacement_fee` between modified and base makes a difference in the result.", + "created_at": "2024-03-19T12:25:37Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530263627", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530263627" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530263627" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530263627/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 307, + "original_start_line": 307, + "start_side": "RIGHT", + "line": 308, + "original_line": 308, + "side": "RIGHT", + "original_position": 15, + "position": 217, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530265897", + "pull_request_review_id": 1945992726, + "id": 1530265897, + "node_id": "PRRC_kwDOABII585bNgEp", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "Similar to previous comment, could do a random `PrioritiseTransaction` here\r\n```\r\nif (fuzzed_data_provider.ConsumeBool()) {\r\n pool.PrioritiseTransaction(mempool_txs.back().GetHash().ToUint256(), fuzzed_data_provider.ConsumeIntegralInRange(-100000, 100000));\r\n}\r\n```", + "created_at": "2024-03-19T12:27:08Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530265897", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530265897" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530265897" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530265897/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 124, + "original_line": 124, + "side": "RIGHT", + "original_position": 84, + "position": 84, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530308029", + "pull_request_review_id": 1945992726, + "id": 1530308029, + "node_id": "PRRC_kwDOABII585bNqW9", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one.has_value());\n+ old_diagram = replace_one->first;\n+ new_diagram = replace_one->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "72959867784098137a50c34f86deca8235eef4f8\r\nNit, but this `old_diagram, new_diagram` assignment setup is\r\n- making a copies of everything\r\n- brittle / easy for the tests to bleed into each other, e.g. if you forgot to reset the variables (and, previously, if you forgot to clear them between tests)\r\n- repetitive\r\n- checking size + each element of a vector when you could just compare it to an expected vector\r\n\r\nSomething cleaner might e.g. look like:\r\n```\r\n{\r\n const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};\r\n BOOST_CHECK(replace_one.has_value());\r\n std::vector expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee, low_size)};\r\n BOOST_CHECK(replace_one->first == expected_old_diagram);\r\n std::vector expected_new_diagram{FeeFrac(0, 0), FeeFrac(0, 1)};\r\n BOOST_CHECK(replace_one->second == expected_new_diagram);\r\n}\r\n```", + "created_at": "2024-03-19T12:53:05Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530308029", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530308029" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530308029" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530308029/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 357, + "original_start_line": 357, + "start_side": "RIGHT", + "line": 369, + "original_line": 369, + "side": "RIGHT", + "original_position": 36, + "position": 36, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530455438", + "pull_request_review_id": 1945992726, + "id": 1530455438, + "node_id": "PRRC_kwDOABII585bOOWO", + "diff_hunk": "@@ -294,6 +294,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // low feerate parent with normal feerate child\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "```suggestion\r\n // With one less vB it does\r\n BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size - 1) == std::nullopt);\r\n```", + "created_at": "2024-03-19T14:12:59Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530455438", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530455438" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530455438" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530455438/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 329, + "original_line": 329, + "side": "RIGHT", + "original_position": 36, + "position": 238, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530512214", + "pull_request_review_id": 1945992726, + "id": 1530512214, + "node_id": "PRRC_kwDOABII585bOcNW", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) {\n+ child->vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};\n+ }\n+ mempool_txs.emplace_back(*child);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ }\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : mempool_txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto calc_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (calc_results.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(calc_results->first.front().size == 0);\n+ assert(calc_results->first.front().fee == 0);\n+ assert(calc_results->second.front().size == 0);\n+ assert(calc_results->second.front().fee == 0);\n+\n+ CheckDiagramConcave(calc_results->first);\n+ CheckDiagramConcave(calc_results->second);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(calc_results->first.back().fee - replaced_fee + replacement_fees == calc_results->second.back().fee);\n+ assert(calc_results->first.back().size - replaced_size + replacement_vsize == calc_results->second.back().size);\n+ }\n+\n+ // If internals report error, wrapper should too\n+ auto err_tuple{ImprovesFeerateDiagram(pool, direct_conflicts, all_conflicts, replacement_fees, replacement_vsize)};\n+ if (!calc_results.has_value()) assert(err_tuple.has_value());", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think we can be a bit more specific than this, i.e. if `!calc_results.has_value()` then `err_tuple.value().first == DiagramCheckError::UNCALCULABLE`", + "created_at": "2024-03-19T14:40:49Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530512214", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530512214" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530512214" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530512214/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 177, + "original_line": 177, + "side": "RIGHT", + "original_position": 137, + "position": 137, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530533619", + "pull_request_review_id": 1945992726, + "id": 1530533619, + "node_id": "PRRC_kwDOABII585bOhbz", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) {\n+ child->vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};\n+ }\n+ mempool_txs.emplace_back(*child);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ }\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : mempool_txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto calc_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (calc_results.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(calc_results->first.front().size == 0);\n+ assert(calc_results->first.front().fee == 0);\n+ assert(calc_results->second.front().size == 0);\n+ assert(calc_results->second.front().fee == 0);\n+\n+ CheckDiagramConcave(calc_results->first);\n+ CheckDiagramConcave(calc_results->second);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(calc_results->first.back().fee - replaced_fee + replacement_fees == calc_results->second.back().fee);\n+ assert(calc_results->first.back().size - replaced_size + replacement_vsize == calc_results->second.back().size);", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "glozow", + "id": 25183001, + "node_id": "MDQ6VXNlcjI1MTgzMDAx", + "avatar_url": "https://avatars.githubusercontent.com/u/25183001?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/glozow", + "html_url": "https://github.com/glozow", + "followers_url": "https://api.github.com/users/glozow/followers", + "following_url": "https://api.github.com/users/glozow/following{/other_user}", + "gists_url": "https://api.github.com/users/glozow/gists{/gist_id}", + "starred_url": "https://api.github.com/users/glozow/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/glozow/subscriptions", + "organizations_url": "https://api.github.com/users/glozow/orgs", + "repos_url": "https://api.github.com/users/glozow/repos", + "events_url": "https://api.github.com/users/glozow/events{/privacy}", + "received_events_url": "https://api.github.com/users/glozow/received_events", + "type": "User", + "site_admin": false + }, + "body": "This test for `ImprovesFeerateDiagram` doesn't seem very strict beyond checking NEW = OLD - CON + replacement and that internal errors = wrapper errors. For example, if I swap `!is_gt` for a `!is_eq` in `ImprovesFeerateDiagram`, this fuzzer is still happy with everything. There is coverage for that in other places, but it seems like we could be writing stronger assertions?\r\n\r\nCan we perhaps add a check that the result is consistent with what `CompareFeerateDiagram` says when comparing the diagrams returned in `calc_results`? Or some kind of sanity check that when the new diagram ends with lower fees, we should be getting `DiagramCheckError::FAILURE`?", + "created_at": "2024-03-19T14:50:00Z", + "updated_at": "2024-03-19T14:57:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530533619", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530533619" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530533619" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530533619/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 172, + "original_line": 172, + "side": "RIGHT", + "original_position": 132, + "position": 132, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530625762", + "pull_request_review_id": 1946634078, + "id": 1530625762, + "node_id": "PRRC_kwDOABII585bO37i", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "5f6ddba2635ca2100ed46560f338b64a58f61b73", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I presume you mean the multi-child case didn't trigger failure when removed? multi-parent should", + "created_at": "2024-03-19T15:34:25Z", + "updated_at": "2024-03-19T15:34:25Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530625762", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530625762" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530625762" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530625762/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 1266, + "original_start_line": 1266, + "start_side": "RIGHT", + "line": 1278, + "original_line": 1278, + "side": "RIGHT", + "in_reply_to_id": 1521609927, + "original_position": 48, + "position": 48, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530890001", + "pull_request_review_id": 1937534483, + "id": 1530890001, + "node_id": "PRRC_kwDOABII585bP4cR", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Add FeeFrac utils\" (ce8e22542ed0b4fa5794d3203207146418d59473):\r\n\r\nIs there a special reason why this is an `int64_t` instead of a `CAmount`?", + "created_at": "2024-03-19T18:28:01Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530890001", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530890001" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530890001" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530890001/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 63, + "original_line": 63, + "side": "RIGHT", + "original_position": 63, + "position": 63, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530921976", + "pull_request_review_id": 1937534483, + "id": 1530921976, + "node_id": "PRRC_kwDOABII585bQAP4", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\" (2079b80854e2595f6f696e7c13a56c7f2a7da9f4):\r\n\r\nI’m not sure I understand why there are \"No topology restrictions post-chunking\". I am guessing that this is alluding to all affected clusters at most having two transactions and therefore each having only two possible configurations: child has higher feerate and the cluster is one chunk, or child has lower feerate and the cluster has two chunks, but the chunk with the child naturally sorts after the chunk with the parent. If that’s what is being alluded to here, perhaps you could elaborate in the comment if you touch this again.\r\n\r\nAlso, I have one open question here. It is my understanding that we do not combine two transactions into one chunk if they _tie in feerate_. If we have a parent and a child that have the same feerate, and the child is smaller, would that not mean that the chunk with the child could be sorted in front of the chunk with the parent incorrectly?\r\n\r\n-----\r\n\r\nThinking more about this, I think this does not matter here, because even if the child were sorted in front of the parent, given them having the same feerate, it would result in the same feerate diagram.\r\n\r\nAlso, it seems to me that this problem could be sidestepped by chunking together a parent and a child on equal feerate _for the purpose of the diagram_, if you used `if (individual >= package) {` in line 1320 instead of `if (individual > package) {`.", + "created_at": "2024-03-19T18:51:27Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530921976", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530921976" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530921976" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530921976/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1335, + "original_line": 1335, + "side": "RIGHT", + "original_position": 105, + "position": 105, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530940913", + "pull_request_review_id": 1937534483, + "id": 1530940913, + "node_id": "PRRC_kwDOABII585bQE3x", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Add FeeFrac utils\" (ce8e22542ed0b4fa5794d3203207146418d59473):\r\n\r\nNit: I noticed that in `CalculateFeerateDiagramsForRBF(…)` you explicitly use `vsize`, but here you use `size`. Perhaps `vsize` should be used consistently? Using `vsize` for the FeeFrac member would also have the added benefit that the member name doesn’t collide with the use of `size` referring to the count of objects in the diagram.\r\n\r\n```suggestion\r\n int32_t vsize;\r\n```", + "created_at": "2024-03-19T19:04:31Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530940913", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530940913" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530940913" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530940913/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 64, + "original_line": 64, + "side": "RIGHT", + "original_position": 64, + "position": 64, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530953507", + "pull_request_review_id": 1937534483, + "id": 1530953507, + "node_id": "PRRC_kwDOABII585bQH8j", + "diff_hunk": "@@ -0,0 +1,119 @@\n+// Copyright (c) 2023 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+#include \n+\n+#include \n+#include \n+\n+#include \n+#include \n+\n+#include \n+\n+namespace {\n+\n+/** Evaluate a diagram at a specific size, returning the fee as a fraction.\n+ *\n+ * Fees in diagram cannot exceed 2^32, as the returned evaluation could overflow\n+ * the FeeFrac::fee field in the result. */\n+FeeFrac EvaluateDiagram(int32_t size, Span diagram)\n+{\n+ assert(diagram.size() > 0);\n+ unsigned not_above = 0;\n+ unsigned not_below = diagram.size() - 1;\n+ // If outside the range of diagram, extend begin/end.\n+ if (size < diagram[not_above].size) return {diagram[not_above].fee, 1};", + "path": "src/test/fuzz/feeratediagram.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4d6528a3d6bf3821c216c68f99170e2faab5d63c", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"fuzz: fuzz diagram creation and comparison\" (4d6528a3d6bf3821c216c68f99170e2faab5d63c):\r\n\r\nNit: The use of `vsize` throughout would help differentiate the mixed occurrences of `diagram.size()` and `diagram[i].size`", + "created_at": "2024-03-19T19:15:55Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530953507", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530953507" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530953507" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530953507/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 29, + "original_line": 29, + "side": "RIGHT", + "original_position": 29, + "position": 29, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530964656", + "pull_request_review_id": 1937534483, + "id": 1530964656, + "node_id": "PRRC_kwDOABII585bQKqw", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one.has_value());\n+ old_diagram = replace_one->first;\n+ new_diagram = replace_one->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+\n+ // Non-zero replacement fee/size\n+ const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one_fee.has_value());\n+ old_diagram = replace_one_fee->first;\n+ new_diagram = replace_one_fee->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};\n+ BOOST_CHECK(replace_single_chunk.has_value());\n+ old_diagram = replace_single_chunk->first;\n+ new_diagram = replace_single_chunk->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};\n+ BOOST_CHECK(replace_cpfp_child.has_value());\n+ old_diagram = replace_cpfp_child->first;\n+ new_diagram = replace_cpfp_child->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};\n+ BOOST_CHECK(!replace_too_large.has_value());\n+ BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};\n+ BOOST_CHECK(replace_two_chunks_single_cluster.has_value());\n+ old_diagram = replace_two_chunks_single_cluster->first;\n+ new_diagram = replace_two_chunks_single_cluster->second;\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+\n+ // You can have more than two direct conflicts if the there are multiple effected clusters, all of size 2 or less", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "Nit: In \"Unit tests for CalculateFeerateDiagramsForRBF\" (72959867784098137a50c34f86deca8235eef4f8):\r\n\r\n```suggestion\r\n // You can have more than two direct conflicts if the there are multiple affected clusters, all of size 2 or less\r\n```", + "created_at": "2024-03-19T19:26:26Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530964656", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530964656" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530964656" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530964656/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 448, + "original_line": 448, + "side": "RIGHT", + "original_position": 115, + "position": 115, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530980762", + "pull_request_review_id": 1937534483, + "id": 1530980762, + "node_id": "PRRC_kwDOABII585bQOma", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Unit tests for CalculateFeerateDiagramsForRBF\" (72959867784098137a50c34f86deca8235eef4f8):\r\n\r\nNit: this comment appears to make the unstated assumption that the three transactions are of similar vsize", + "created_at": "2024-03-19T19:40:51Z", + "updated_at": "2024-03-19T19:42:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530980762", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530980762" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530980762" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530980762/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 350, + "original_line": 350, + "side": "RIGHT", + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530998264", + "pull_request_review_id": 1947241589, + "id": 1530998264, + "node_id": "PRRC_kwDOABII585bQS34", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "It'd need to be `if (!(individual << package)) {`, because `>=` and `>` use size as tie breaker when comparing `FeeFrac`s. I think that's generally an improvement, actually, because size shouldn't matter here.", + "created_at": "2024-03-19T19:49:41Z", + "updated_at": "2024-03-19T19:49:41Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530998264", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530998264" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1530998264" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1530998264/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1335, + "original_line": 1335, + "side": "RIGHT", + "in_reply_to_id": 1530921976, + "original_position": 105, + "position": 105, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531012828", + "pull_request_review_id": 1947257675, + "id": 1531012828, + "node_id": "PRRC_kwDOABII585bQWbc", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "I'll answer because this is my code: I consider this class to be a low-level utility class for representing monetary fractions, without needing a dependency on consensus code.", + "created_at": "2024-03-19T19:59:03Z", + "updated_at": "2024-03-19T19:59:03Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531012828", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531012828" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531012828" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531012828/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 63, + "original_line": 63, + "side": "RIGHT", + "in_reply_to_id": 1530890001, + "original_position": 63, + "position": 63, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531014949", + "pull_request_review_id": 1947259711, + "id": 1531014949, + "node_id": "PRRC_kwDOABII585bQW8l", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "sipa", + "id": 548488, + "node_id": "MDQ6VXNlcjU0ODQ4OA==", + "avatar_url": "https://avatars.githubusercontent.com/u/548488?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sipa", + "html_url": "https://github.com/sipa", + "followers_url": "https://api.github.com/users/sipa/followers", + "following_url": "https://api.github.com/users/sipa/following{/other_user}", + "gists_url": "https://api.github.com/users/sipa/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sipa/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sipa/subscriptions", + "organizations_url": "https://api.github.com/users/sipa/orgs", + "repos_url": "https://api.github.com/users/sipa/repos", + "events_url": "https://api.github.com/users/sipa/events{/privacy}", + "received_events_url": "https://api.github.com/users/sipa/received_events", + "type": "User", + "site_admin": false + }, + "body": "Hmm, I was hoping that this class could be used in contexts where the size is WU rather than vsize too. I do agree with the confusion w.r.t. the `size()` member functions.\r\n\r\nShould they perhaps just be called `numerator` and `denominator`?", + "created_at": "2024-03-19T20:00:15Z", + "updated_at": "2024-03-19T20:00:16Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531014949", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531014949" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531014949" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531014949/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 64, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1530940913, + "original_position": 64, + "position": 64, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068001", + "pull_request_review_id": 1947329188, + "id": 1531068001, + "node_id": "PRRC_kwDOABII585bQj5h", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "> If that’s what is being alluded to here, perhaps you could elaborate in the comment if you touch this again.\r\n\r\nWill elaborate a bit on the chunk construction comments in a follow-up.\r\n\r\n> I think that's generally an improvement, actually, because size shouldn't matter here.\r\n\r\nAgreed, at a minimum I'd change to `individual >> package` to get rid of the tie-breaking behavior which is confusing to have here. Will take on a chosen change in follow-up.\r\n", + "created_at": "2024-03-19T20:32:19Z", + "updated_at": "2024-03-19T20:32:19Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531068001", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068001" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531068001" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068001/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1335, + "original_line": 1335, + "side": "RIGHT", + "in_reply_to_id": 1530921976, + "original_position": 105, + "position": 105, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068147", + "pull_request_review_id": 1947329420, + "id": 1531068147, + "node_id": "PRRC_kwDOABII585bQj7z", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "> Should they perhaps just be called numerator and denominator?\r\n\r\nI'll mull this over a bit", + "created_at": "2024-03-19T20:32:27Z", + "updated_at": "2024-03-19T20:32:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531068147", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068147" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531068147" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531068147/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 64, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1530940913, + "original_position": 64, + "position": 64, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531069109", + "pull_request_review_id": 1947330877, + "id": 1531069109, + "node_id": "PRRC_kwDOABII585bQkK1", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "murchandamus", + "id": 4060799, + "node_id": "MDQ6VXNlcjQwNjA3OTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/4060799?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/murchandamus", + "html_url": "https://github.com/murchandamus", + "followers_url": "https://api.github.com/users/murchandamus/followers", + "following_url": "https://api.github.com/users/murchandamus/following{/other_user}", + "gists_url": "https://api.github.com/users/murchandamus/gists{/gist_id}", + "starred_url": "https://api.github.com/users/murchandamus/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/murchandamus/subscriptions", + "organizations_url": "https://api.github.com/users/murchandamus/orgs", + "repos_url": "https://api.github.com/users/murchandamus/repos", + "events_url": "https://api.github.com/users/murchandamus/events{/privacy}", + "received_events_url": "https://api.github.com/users/murchandamus/received_events", + "type": "User", + "site_admin": false + }, + "body": "If it were `weight` that would also differentiate well.", + "created_at": "2024-03-19T20:33:20Z", + "updated_at": "2024-03-19T20:33:20Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531069109", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "CONTRIBUTOR", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531069109" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531069109" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531069109/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 64, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1530940913, + "original_position": 64, + "position": 64, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531076409", + "pull_request_review_id": 1947340500, + "id": 1531076409, + "node_id": "PRRC_kwDOABII585bQl85", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but\n+ * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any\n+ * other.\n+ */\n+struct FeeFrac\n+{\n+ /** Fallback version for Mul (see below).\n+ *\n+ * Separate to permit testing on platforms where it isn't actually needed.\n+ */\n+ static inline std::pair MulFallback(int64_t a, int32_t b) noexcept\n+ {\n+ // Otherwise, emulate 96-bit multiplication using two 64-bit multiplies.\n+ int64_t low = int64_t{static_cast(a)} * b;\n+ int64_t high = (a >> 32) * b;\n+ return {high + (low >> 32), static_cast(low)};\n+ }\n+\n+ // Compute a * b, returning an unspecified but totally ordered type.\n+#ifdef __SIZEOF_INT128__\n+ static inline __int128 Mul(int64_t a, int32_t b) noexcept\n+ {\n+ // If __int128 is available, use 128-bit wide multiply.\n+ return __int128{a} * b;\n+ }\n+#else\n+ static constexpr auto Mul = MulFallback;\n+#endif\n+\n+ int64_t fee;\n+ int32_t size;", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think that would be even more confusing; if we're going to change it we need it to be unit-neutral (punting for this PR)", + "created_at": "2024-03-19T20:38:26Z", + "updated_at": "2024-03-19T20:38:27Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531076409", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531076409" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531076409" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531076409/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 64, + "original_line": 64, + "side": "RIGHT", + "in_reply_to_id": 1530940913, + "original_position": 64, + "position": 64, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531848748", + "pull_request_review_id": 1948504420, + "id": 1531848748, + "node_id": "PRRC_kwDOABII585bTigs", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "willcl-ark", + "id": 6606587, + "node_id": "MDQ6VXNlcjY2MDY1ODc=", + "avatar_url": "https://avatars.githubusercontent.com/u/6606587?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/willcl-ark", + "html_url": "https://github.com/willcl-ark", + "followers_url": "https://api.github.com/users/willcl-ark/followers", + "following_url": "https://api.github.com/users/willcl-ark/following{/other_user}", + "gists_url": "https://api.github.com/users/willcl-ark/gists{/gist_id}", + "starred_url": "https://api.github.com/users/willcl-ark/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/willcl-ark/subscriptions", + "organizations_url": "https://api.github.com/users/willcl-ark/orgs", + "repos_url": "https://api.github.com/users/willcl-ark/repos", + "events_url": "https://api.github.com/users/willcl-ark/events{/privacy}", + "received_events_url": "https://api.github.com/users/willcl-ark/received_events", + "type": "User", + "site_admin": false + }, + "body": "Suhas' comment is still present.", + "created_at": "2024-03-20T10:40:36Z", + "updated_at": "2024-03-20T13:43:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531848748", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531848748" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531848748" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531848748/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 56, + "original_line": 56, + "side": "RIGHT", + "in_reply_to_id": 1499465556, + "original_position": 59, + "position": 56, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531928642", + "pull_request_review_id": 1948504420, + "id": 1531928642, + "node_id": "PRRC_kwDOABII585bT2BC", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "willcl-ark", + "id": 6606587, + "node_id": "MDQ6VXNlcjY2MDY1ODc=", + "avatar_url": "https://avatars.githubusercontent.com/u/6606587?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/willcl-ark", + "html_url": "https://github.com/willcl-ark", + "followers_url": "https://api.github.com/users/willcl-ark/followers", + "following_url": "https://api.github.com/users/willcl-ark/following{/other_user}", + "gists_url": "https://api.github.com/users/willcl-ark/gists{/gist_id}", + "starred_url": "https://api.github.com/users/willcl-ark/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/willcl-ark/subscriptions", + "organizations_url": "https://api.github.com/users/willcl-ark/orgs", + "repos_url": "https://api.github.com/users/willcl-ark/repos", + "events_url": "https://api.github.com/users/willcl-ark/events{/privacy}", + "received_events_url": "https://api.github.com/users/willcl-ark/received_events", + "type": "User", + "site_admin": false + }, + "body": "In \"Implement ImprovesFeerateDiagram\": 2079b80854e2595f6f696e7c13a56c7f2a7da9f4\r\n\r\n```cpp\r\n std::vector old_diagram, new_diagram;\r\n```\r\n\r\nThese vectors at src/policy/rbf.cpp:L194 appear to be unused and the diagrams are built inside of `CalculateFeerateDiagramsForRBF`.", + "created_at": "2024-03-20T11:33:14Z", + "updated_at": "2024-03-20T13:43:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531928642", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531928642" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1531928642" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1531928642/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 1 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 194, + "original_line": 194, + "side": "RIGHT", + "original_position": 21, + "position": 21, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537482961", + "pull_request_review_id": 1957559378, + "id": 1537482961, + "node_id": "PRRC_kwDOABII585bpCDR", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "leftovers, will remove on touchup/followup", + "created_at": "2024-03-25T12:05:59Z", + "updated_at": "2024-03-25T12:06:00Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537482961", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537482961" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537482961" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537482961/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 194, + "original_line": 194, + "side": "RIGHT", + "in_reply_to_id": 1531928642, + "original_position": 21, + "position": 21, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537484102", + "pull_request_review_id": 1957562936, + "id": 1537484102, + "node_id": "PRRC_kwDOABII585bpCVG", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "un-resolved comment(oops), will add to follow-up", + "created_at": "2024-03-25T12:07:06Z", + "updated_at": "2024-03-25T12:07:06Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537484102", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537484102" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537484102" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537484102/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 56, + "original_line": 56, + "side": "RIGHT", + "in_reply_to_id": 1499465556, + "original_position": 59, + "position": 56, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855765", + "pull_request_review_id": 1958179723, + "id": 1537855765, + "node_id": "PRRC_kwDOABII585bqdEV", + "diff_hunk": "@@ -0,0 +1,160 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#ifndef BITCOIN_UTIL_FEEFRAC_H\n+#define BITCOIN_UTIL_FEEFRAC_H\n+\n+#include \n+#include \n+#include \n+#include \n+#include \n+\n+/** Data structure storing a fee and size, ordered by increasing fee/size.\n+ *\n+ * The size of a FeeFrac cannot be zero unless the fee is also zero.\n+ *\n+ * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then\n+ * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the\n+ * following FeeFracs are in sorted order:\n+ *\n+ * - fee=0 size=1 (feerate 0)\n+ * - fee=1 size=2 (feerate 0.5)\n+ * - fee=2 size=3 (feerate 0.667...)\n+ * - fee=2 size=2 (feerate 1)\n+ * - fee=1 size=1 (feerate 1)\n+ * - fee=3 size=2 (feerate 1.5)\n+ * - fee=2 size=1 (feerate 2)\n+ * - fee=0 size=0 (undefined feerate)\n+ *\n+ * A FeeFrac is considered \"better\" if it sorts after another, by this ordering. All standard\n+ * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.\n+ *\n+ * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but", + "path": "src/util/feefrac.h", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:13:32Z", + "updated_at": "2024-03-25T16:13:32Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855765", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855765" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855765" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855765/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 34, + "original_line": 34, + "side": "RIGHT", + "in_reply_to_id": 1528732978, + "original_position": 34, + "position": 34, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855847", + "pull_request_review_id": 1958179835, + "id": 1537855847, + "node_id": "PRRC_kwDOABII585bqdFn", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:13:35Z", + "updated_at": "2024-03-25T16:13:35Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855847", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855847" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855847" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855847/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 193, + "original_line": 193, + "side": "RIGHT", + "in_reply_to_id": 1528740535, + "original_position": 20, + "position": 20, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855962", + "pull_request_review_id": 1958180007, + "id": 1537855962, + "node_id": "PRRC_kwDOABII585bqdHa", + "diff_hunk": "@@ -215,15 +248,119 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());\n+\n+ // No descendants yet\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok\n+ add_descendants(tx9, 1, pool);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);\n+\n+ // N direct conflicts; ok\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+\n+ // Add 1 descendant, still ok, even if it's considered a direct conflict as well\n+ const auto child_tx = add_descendants(tx10, 1, pool);\n+ const auto entry10_child = pool.GetIter(child_tx->GetHash()).value();\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}) == std::nullopt);\n+ BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained, entry10_child}) == std::nullopt);\n+\n+ // One more, size 3 cluster too much\n+ const auto grand_child_tx = add_descendants(child_tx, 1, pool);\n+ const auto entry10_grand_child = pool.GetIter(grand_child_tx->GetHash()).value();\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry9_unchained, entry10_unchained, entry11_unchained}).value(), strprintf(\"%s has 2 descendants, max 1 allowed\", entry10_unchained->GetSharedTx()->GetHash().ToString()));\n+ // even if direct conflict is descendent itself\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry9_unchained, entry10_grand_child, entry11_unchained}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry10_grand_child->GetSharedTx()->GetHash().ToString()));\n+\n+ // Make a single child from two singleton parents\n+ const auto two_parent_child_tx = add_descendant_to_parents({tx11, tx12}, pool);\n+ const auto entry_two_parent_child = pool.GetIter(two_parent_child_tx->GetHash()).value();\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry11_unchained}).value(), strprintf(\"%s is not the only parent of child %s\", entry11_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry12_unchained}).value(), strprintf(\"%s is not the only parent of child %s\", entry12_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n+}\n+\n+BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)\n+{\n+ // Sanity check the correctness of the feerate diagram comparison.\n+\n+ // A strictly better case.\n+ std::vector old_diagram{{FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}}};\n+ std::vector new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Incomparable diagrams\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // Strictly better but smaller size.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // New diagram is strictly better due to the first chunk, even though\n+ // second chunk contributes no fees\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Feerate of first new chunk is better with, but second chunk is worse\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 1000}};\n+\n+ BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);\n+\n+ // If we make the second chunk slightly better, the new diagram now wins.\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};\n+\n+ BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));\n+\n+ // Identical diagrams, cannot be strictly better\n+ old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+ new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};\n+\n+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e9c5aeb11d641b8cae373452339760809625021d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:13:40Z", + "updated_at": "2024-03-25T16:13:40Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855962", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855962" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537855962" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537855962/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 505, + "original_start_line": 305, + "start_side": "RIGHT", + "line": 543, + "original_line": 343, + "side": "RIGHT", + "in_reply_to_id": 1530231967, + "original_position": 252, + "position": 452, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537856017", + "pull_request_review_id": 1958180109, + "id": 1537856017, + "node_id": "PRRC_kwDOABII585bqdIR", + "diff_hunk": "@@ -215,15 +248,119 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),\n /*pool=*/ pool,\n /*iters_conflicting=*/ all_entries) == std::nullopt);\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2_normal}) == std::nullopt);\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());\n \n const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2_normal}).has_value());\n BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());\n \n const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});\n- BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);\n+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1_normal, entry3_low}) == std::nullopt);\n+\n+ // Tests for CheckConflictTopology\n+\n+ // Tx4 has 23 descendants\n+ BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e9c5aeb11d641b8cae373452339760809625021d", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:13:43Z", + "updated_at": "2024-03-25T16:13:43Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537856017", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537856017" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537856017" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537856017/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 264, + "original_line": 264, + "side": "RIGHT", + "in_reply_to_id": 1530244386, + "original_position": 173, + "position": 173, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857130", + "pull_request_review_id": 1958182075, + "id": 1537857130, + "node_id": "PRRC_kwDOABII585bqdZq", + "diff_hunk": "@@ -181,3 +183,24 @@ std::optional PaysForRBF(CAmount original_fees,\n }\n return std::nullopt;\n }\n+\n+std::optional> ImprovesFeerateDiagram(CTxMemPool& pool,\n+ const CTxMemPool::setEntries& direct_conflicts,\n+ const CTxMemPool::setEntries& all_conflicts,\n+ CAmount replacement_fees,\n+ int64_t replacement_vsize)\n+{\n+ // Require that the replacement strictly improve the mempool's feerate diagram.\n+ std::vector old_diagram, new_diagram;", + "path": "src/policy/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:33Z", + "updated_at": "2024-03-25T16:14:33Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857130", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857130" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857130" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857130/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 194, + "original_line": 194, + "side": "RIGHT", + "in_reply_to_id": 1531928642, + "original_position": 21, + "position": 21, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857210", + "pull_request_review_id": 1958182185, + "id": 1537857210, + "node_id": "PRRC_kwDOABII585bqda6", + "diff_hunk": "@@ -0,0 +1,89 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+void BuildDiagramFromUnsortedChunks(std::vector& chunks, std::vector& diagram)\n+{\n+ diagram.clear();\n+ diagram.reserve(chunks.size() + 1);\n+ // Finish by sorting the chunks we calculated, and then accumulating them.\n+ std::sort(chunks.begin(), chunks.end(), [](const FeeFrac& a, const FeeFrac& b) { return a > b; });\n+\n+ // And now build the diagram for these chunks.\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ FeeFrac& last = diagram.back();\n+ diagram.emplace_back(last.fee+chunk.fee, last.size+chunk.size);\n+ }\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4f050b23f31d32c9e46829a029e20880a9518f3a", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:36Z", + "updated_at": "2024-03-25T16:14:36Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857210", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857210" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857210" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857210/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 56, + "original_line": 56, + "side": "RIGHT", + "in_reply_to_id": 1499465556, + "original_position": 59, + "position": 56, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857284", + "pull_request_review_id": 1958182331, + "id": 1537857284, + "node_id": "PRRC_kwDOABII585bqdcE", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:39Z", + "updated_at": "2024-03-25T16:14:39Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857284", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857284" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857284" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857284/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 350, + "original_line": 350, + "side": "RIGHT", + "in_reply_to_id": 1530980762, + "original_position": 17, + "position": 17, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857338", + "pull_request_review_id": 1958182429, + "id": 1537857338, + "node_id": "PRRC_kwDOABII585bqdc6", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one.has_value());\n+ old_diagram = replace_one->first;\n+ new_diagram = replace_one->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));\n+\n+ // Non-zero replacement fee/size\n+ const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one_fee.has_value());\n+ old_diagram = replace_one_fee->first;\n+ new_diagram = replace_one_fee->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+\n+ // Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF\n+ const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx));\n+ const auto entry_high = pool.GetIter(high_tx->GetHash()).value();\n+ const auto high_size = entry_high->GetTxSize();\n+\n+ const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};\n+ BOOST_CHECK(replace_single_chunk.has_value());\n+ old_diagram = replace_single_chunk->first;\n+ new_diagram = replace_single_chunk->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+\n+ // Conflict with the 2nd tx, resulting in new diagram with three entries\n+ const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};\n+ BOOST_CHECK(replace_cpfp_child.has_value());\n+ old_diagram = replace_cpfp_child->first;\n+ new_diagram = replace_cpfp_child->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 3);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));\n+ BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));\n+\n+ // third transaction causes the topology check to fail\n+ const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(normal_tx));\n+ const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();\n+ const auto normal_size = entry_normal->GetTxSize();\n+\n+ const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};\n+ BOOST_CHECK(!replace_too_large.has_value());\n+ BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf(\"%s has 2 descendants, max 1 allowed\", low_tx->GetHash().GetHex()));\n+ old_diagram.clear();\n+ new_diagram.clear();\n+\n+ // Make a size 2 cluster that is itself two chunks; evict both txns\n+ const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(high_fee).FromTx(high_tx_2));\n+ const auto entry_high_2 = pool.GetIter(high_tx_2->GetHash()).value();\n+ const auto high_size_2 = entry_high_2->GetTxSize();\n+\n+ const auto low_tx_2 = make_tx(/*inputs=*/ {high_tx_2}, /*output_values=*/ {9 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx_2));\n+ const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();\n+ const auto low_size_2 = entry_low_2->GetTxSize();\n+\n+ const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};\n+ BOOST_CHECK(replace_two_chunks_single_cluster.has_value());\n+ old_diagram = replace_two_chunks_single_cluster->first;\n+ new_diagram = replace_two_chunks_single_cluster->second;\n+ BOOST_CHECK(old_diagram.size() == 3);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));\n+ BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));\n+\n+ // You can have more than two direct conflicts if the there are multiple effected clusters, all of size 2 or less", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:42Z", + "updated_at": "2024-03-25T16:14:42Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857338", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857338" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857338" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857338/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 448, + "original_line": 448, + "side": "RIGHT", + "in_reply_to_id": 1530964656, + "original_position": 115, + "position": 115, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857395", + "pull_request_review_id": 1958182534, + "id": 1537857395, + "node_id": "PRRC_kwDOABII585bqddz", + "diff_hunk": "@@ -0,0 +1,119 @@\n+// Copyright (c) 2023 The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+\n+#include \n+\n+#include \n+#include \n+\n+#include \n+#include \n+\n+#include \n+\n+namespace {\n+\n+/** Evaluate a diagram at a specific size, returning the fee as a fraction.\n+ *\n+ * Fees in diagram cannot exceed 2^32, as the returned evaluation could overflow\n+ * the FeeFrac::fee field in the result. */\n+FeeFrac EvaluateDiagram(int32_t size, Span diagram)\n+{\n+ assert(diagram.size() > 0);\n+ unsigned not_above = 0;\n+ unsigned not_below = diagram.size() - 1;\n+ // If outside the range of diagram, extend begin/end.\n+ if (size < diagram[not_above].size) return {diagram[not_above].fee, 1};", + "path": "src/test/fuzz/feeratediagram.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "4d6528a3d6bf3821c216c68f99170e2faab5d63c", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "leaving as is", + "created_at": "2024-03-25T16:14:45Z", + "updated_at": "2024-03-25T16:14:45Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857395", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857395" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857395" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857395/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 29, + "original_line": 29, + "side": "RIGHT", + "in_reply_to_id": 1530953507, + "original_position": 29, + "position": 29, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857474", + "pull_request_review_id": 1958182643, + "id": 1537857474, + "node_id": "PRRC_kwDOABII585bqdfC", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.\n+\n+ // OLD: Compute existing chunks from all affected clusters\n+ for (auto txiter : all_conflicts) {\n+ // Does this transaction have descendants?\n+ if (txiter->GetCountWithDescendants() > 1) {\n+ // Consider this tx when we consider the descendant.\n+ continue;\n+ }\n+ // Does this transaction have ancestors?\n+ FeeFrac individual{txiter->GetModifiedFee(), txiter->GetTxSize()};\n+ if (txiter->GetCountWithAncestors() > 1) {\n+ // We'll add chunks for either the ancestor by itself and this tx\n+ // by itself, or for a combined package.\n+ FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast(txiter->GetSizeWithAncestors())};\n+ if (individual > package) {\n+ // The individual feerate is higher than the package, and\n+ // therefore higher than the parent's fee. Chunk these\n+ // together.\n+ old_chunks.emplace_back(package);\n+ } else {\n+ // Add two points, one for the parent and one for this child.\n+ old_chunks.emplace_back(package - individual);\n+ old_chunks.emplace_back(individual);\n+ }\n+ } else {\n+ old_chunks.emplace_back(individual);\n+ }\n+ }\n+\n+ // No topology restrictions post-chunking; sort", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up with `>>` as noted", + "created_at": "2024-03-25T16:14:48Z", + "updated_at": "2024-03-25T16:14:48Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857474", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857474" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857474" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857474/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1335, + "original_line": 1335, + "side": "RIGHT", + "in_reply_to_id": 1530921976, + "original_position": 105, + "position": 105, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857551", + "pull_request_review_id": 1958182796, + "id": 1537857551, + "node_id": "PRRC_kwDOABII585bqdgP", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.\n+\n+ std::vector old_chunks;\n+ // Step 1: build the old diagram.\n+\n+ // The above clusters are all trivially linearized;\n+ // they have a strict topology of 1 or two connected transactions.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "e88d6ceff091044c8c0ec35ddae4416187b8fa43", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:52Z", + "updated_at": "2024-03-25T16:14:52Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857551", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857551" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857551" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857551/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1305, + "original_line": 1305, + "side": "RIGHT", + "in_reply_to_id": 1525381280, + "original_position": 75, + "position": 75, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857649", + "pull_request_review_id": 1958182933, + "id": 1537857649, + "node_id": "PRRC_kwDOABII585bqdhx", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) {\n+ child->vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};\n+ }\n+ mempool_txs.emplace_back(*child);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ }\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : mempool_txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto calc_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (calc_results.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(calc_results->first.front().size == 0);\n+ assert(calc_results->first.front().fee == 0);\n+ assert(calc_results->second.front().size == 0);\n+ assert(calc_results->second.front().fee == 0);\n+\n+ CheckDiagramConcave(calc_results->first);\n+ CheckDiagramConcave(calc_results->second);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(calc_results->first.back().fee - replaced_fee + replacement_fees == calc_results->second.back().fee);\n+ assert(calc_results->first.back().size - replaced_size + replacement_vsize == calc_results->second.back().size);", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I added a couple more checks where I could clearly add them in followup", + "created_at": "2024-03-25T16:14:56Z", + "updated_at": "2024-03-25T16:14:56Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857649", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857649" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857649" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857649/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 172, + "original_line": 172, + "side": "RIGHT", + "in_reply_to_id": 1530533619, + "original_position": 132, + "position": 132, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857719", + "pull_request_review_id": 1958183051, + "id": 1537857719, + "node_id": "PRRC_kwDOABII585bqdi3", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) {\n+ child->vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};\n+ }\n+ mempool_txs.emplace_back(*child);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));\n+ }\n+\n+ // Pick some transactions at random to be the direct conflicts\n+ CTxMemPool::setEntries direct_conflicts;\n+ for (auto& tx : mempool_txs) {\n+ if (fuzzed_data_provider.ConsumeBool()) {\n+ direct_conflicts.insert(*pool.GetIter(tx.GetHash()));\n+ }\n+ }\n+\n+ // Calculate all conflicts:\n+ CTxMemPool::setEntries all_conflicts;\n+ for (auto& txiter : direct_conflicts) {\n+ pool.CalculateDescendants(txiter, all_conflicts);\n+ }\n+\n+ // Calculate the feerate diagrams for a replacement.\n+ CAmount replacement_fees = ConsumeMoney(fuzzed_data_provider);\n+ int64_t replacement_vsize = fuzzed_data_provider.ConsumeIntegralInRange(1, 1000000);\n+ auto calc_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};\n+\n+ if (calc_results.has_value()) {\n+ // Sanity checks on the diagrams.\n+\n+ // Diagrams start at 0.\n+ assert(calc_results->first.front().size == 0);\n+ assert(calc_results->first.front().fee == 0);\n+ assert(calc_results->second.front().size == 0);\n+ assert(calc_results->second.front().fee == 0);\n+\n+ CheckDiagramConcave(calc_results->first);\n+ CheckDiagramConcave(calc_results->second);\n+\n+ CAmount replaced_fee{0};\n+ int64_t replaced_size{0};\n+ for (auto txiter : all_conflicts) {\n+ replaced_fee += txiter->GetModifiedFee();\n+ replaced_size += txiter->GetTxSize();\n+ }\n+ // The total fee of the new diagram should be the total fee of the old\n+ // diagram - replaced_fee + replacement_fees\n+ assert(calc_results->first.back().fee - replaced_fee + replacement_fees == calc_results->second.back().fee);\n+ assert(calc_results->first.back().size - replaced_size + replacement_vsize == calc_results->second.back().size);\n+ }\n+\n+ // If internals report error, wrapper should too\n+ auto err_tuple{ImprovesFeerateDiagram(pool, direct_conflicts, all_conflicts, replacement_fees, replacement_vsize)};\n+ if (!calc_results.has_value()) assert(err_tuple.has_value());", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:14:59Z", + "updated_at": "2024-03-25T16:14:59Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857719", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857719" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857719" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857719/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 177, + "original_line": 177, + "side": "RIGHT", + "in_reply_to_id": 1530512214, + "original_position": 137, + "position": 137, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857793", + "pull_request_review_id": 1958183166, + "id": 1537857793, + "node_id": "PRRC_kwDOABII585bqdkB", + "diff_hunk": "@@ -294,6 +294,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // low feerate parent with normal feerate child\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));\n+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});\n+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));\n+\n+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();\n+ const auto tx1_fee = entry1->GetModifiedFee();\n+ const auto tx1_size = entry1->GetTxSize();\n+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();\n+ const auto tx2_fee = entry2->GetModifiedFee();\n+ const auto tx2_size = entry2->GetTxSize();\n+\n+ // Now test ImprovesFeerateDiagram with various levels of \"package rbf\" feerates\n+\n+ // It doesn't improve itself\n+ const auto res1 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size);\n+ BOOST_CHECK(res1.has_value());\n+ BOOST_CHECK(res1.value().first == DiagramCheckError::FAILURE);\n+ BOOST_CHECK(res1.value().second == \"insufficient feerate: does not improve feerate diagram\");\n+\n+ // With one more satoshi it does\n+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);\n+", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:15:02Z", + "updated_at": "2024-03-25T16:15:02Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857793", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857793" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857793" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857793/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 329, + "original_line": 329, + "side": "RIGHT", + "in_reply_to_id": 1530455438, + "original_position": 36, + "position": 238, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857874", + "pull_request_review_id": 1958183255, + "id": 1537857874, + "node_id": "PRRC_kwDOABII585bqdlS", + "diff_hunk": "@@ -334,6 +334,164 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n BOOST_CHECK(res3.has_value());\n BOOST_CHECK(res3.value().first == DiagramCheckError::UNCALCULABLE);\n BOOST_CHECK(res3.value().second == strprintf(\"%s has 2 descendants, max 1 allowed\", tx1->GetHash().GetHex()));\n+\n+}\n+\n+BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+ const CAmount high_fee{CENT};\n+\n+ // low -> high -> medium fee transactions that would result in two chunks together\n+ const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));\n+\n+ const auto entry_low = pool.GetIter(low_tx->GetHash()).value();\n+ const auto low_size = entry_low->GetTxSize();\n+\n+ std::vector old_diagram, new_diagram;\n+\n+ // Replacement of size 1\n+ const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};\n+ BOOST_CHECK(replace_one.has_value());\n+ old_diagram = replace_one->first;\n+ new_diagram = replace_one->second;\n+ BOOST_CHECK(old_diagram.size() == 2);\n+ BOOST_CHECK(new_diagram.size() == 2);\n+ BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));\n+ BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));\n+ BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:15:04Z", + "updated_at": "2024-03-25T16:15:04Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857874", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857874" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857874" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857874/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 357, + "original_start_line": 357, + "start_side": "RIGHT", + "line": 369, + "original_line": 369, + "side": "RIGHT", + "in_reply_to_id": 1530308029, + "original_position": 36, + "position": 36, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857964", + "pull_request_review_id": 1958183367, + "id": 1537857964, + "node_id": "PRRC_kwDOABII585bqdms", + "diff_hunk": "@@ -63,3 +81,98 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)\n (void)IsRBFOptIn(tx, pool);\n }\n }\n+\n+void CheckDiagramConcave(std::vector& diagram)\n+{\n+ // Diagrams are in monotonically-decreasing feerate order.\n+ FeeFrac last_chunk = diagram.front();\n+ for (size_t i = 1; i child = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!child) return;\n+\n+ CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};\n+\n+ // Add a bunch of parent-child pairs to the mempool, and remember them.\n+ std::vector mempool_txs;\n+ size_t iter{0};\n+\n+ LOCK2(cs_main, pool.cs);\n+\n+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)\n+ {\n+ // Make sure txns only have one input, and that a unique input is given to avoid circular references\n+ std::optional parent = ConsumeDeserializable(fuzzed_data_provider, TX_WITH_WITNESS);\n+ if (!parent) {\n+ continue;\n+ }\n+ assert(iter <= g_outpoints.size());\n+ parent->vin.resize(1);\n+ parent->vin[0].prevout = g_outpoints[iter++];\n+\n+ mempool_txs.emplace_back(*parent);\n+ pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));", + "path": "src/test/fuzz/rbf.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "588a98dccc5dbb6e331f28d83a4a10a13d70eb31", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:15:08Z", + "updated_at": "2024-03-25T16:15:08Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857964", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857964" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537857964" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537857964/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 124, + "original_line": 124, + "side": "RIGHT", + "in_reply_to_id": 1530265897, + "original_position": 84, + "position": 84, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537858021", + "pull_request_review_id": 1958183477, + "id": 1537858021, + "node_id": "PRRC_kwDOABII585bqdnl", + "diff_hunk": "@@ -294,6 +294,48 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)\n BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf(\"%s has 2 ancestors, max 1 allowed\", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));\n }\n \n+BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)\n+{\n+ CTxMemPool& pool = *Assert(m_node.mempool);\n+ LOCK2(::cs_main, pool.cs);\n+ TestMemPoolEntryHelper entry;\n+\n+ const CAmount low_fee{CENT/100};\n+ const CAmount normal_fee{CENT/10};\n+\n+ // low feerate parent with normal feerate child\n+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});\n+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));", + "path": "src/test/rbf_tests.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "b767e6bd47cb0fb8f7aea3fb10c597e59a35bf74", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "opened in follow-up", + "created_at": "2024-03-25T16:15:11Z", + "updated_at": "2024-03-25T16:15:11Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537858021", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537858021" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1537858021" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1537858021/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": 307, + "original_start_line": 307, + "start_side": "RIGHT", + "line": 308, + "original_line": 308, + "side": "RIGHT", + "in_reply_to_id": 1530263627, + "original_position": 15, + "position": 217, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538124442", + "pull_request_review_id": 1958602404, + "id": 1538124442, + "node_id": "PRRC_kwDOABII585breqa", + "diff_hunk": "@@ -0,0 +1,86 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+std::vector BuildDiagramFromChunks(const Span chunks)\n+{\n+ std::vector diagram;\n+ diagram.reserve(chunks.size() + 1);\n+\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ diagram.emplace_back(diagram.back() + chunk);\n+ }\n+ return diagram;\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB\n+ const auto slope_ap = point_p - point_a;\n+ Assume(slope_ap.size > 0);\n+ std::weak_ordering cmp = std::weak_ordering::equivalent;\n+ if (done_0 || done_1) {\n+ // If a single side has no points left, act as if AB has slope tail_feerate(of 0).\n+ Assume(!(done_0 && done_1));\n+ cmp = FeeRateCompare(slope_ap, FeeFrac(0, 1));\n+ } else {\n+ // If both sides have points left, compute B, and the slope of AB explicitly.\n+ const FeeFrac& point_b = next_point(!unproc_side);\n+ const auto slope_ab = point_b - point_a;\n+ Assume(slope_ab.size >= slope_ap.size);\n+ cmp = FeeRateCompare(slope_ap, slope_ab);\n+\n+ // If B and P have the same size, B can be marked as processed (in addition to P, see\n+ // below), as we've already performed a comparison at this size.\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\n+ }\n+ // If P lies above AB, unproc_side is better in P. If P lies below AB, then !unproc_side is\n+ // better in P.\n+ if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\n+ if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\n+ ++next_index[unproc_side];\n+ } while(true);", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "Just noticed that I think we could change this to short circuit in the case where we've detected that both diagrams are \"better somewhere\" and hence incomparable, eg:\r\n\r\n```\r\n} while (!(better_somewhere[0] && better_somewhere[1]));\r\n```", + "created_at": "2024-03-25T19:24:14Z", + "updated_at": "2024-03-25T19:54:18Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1538124442", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538124442" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1538124442" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538124442/reactions", + "total_count": 2, + "+1": 2, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 80, + "original_line": 80, + "side": "RIGHT", + "original_position": 80, + "position": 80, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538151180", + "pull_request_review_id": 1958602404, + "id": 1538151180, + "node_id": "PRRC_kwDOABII585brlMM", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "sdaftuar", + "id": 7463573, + "node_id": "MDQ6VXNlcjc0NjM1NzM=", + "avatar_url": "https://avatars.githubusercontent.com/u/7463573?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sdaftuar", + "html_url": "https://github.com/sdaftuar", + "followers_url": "https://api.github.com/users/sdaftuar/followers", + "following_url": "https://api.github.com/users/sdaftuar/following{/other_user}", + "gists_url": "https://api.github.com/users/sdaftuar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sdaftuar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sdaftuar/subscriptions", + "organizations_url": "https://api.github.com/users/sdaftuar/orgs", + "repos_url": "https://api.github.com/users/sdaftuar/repos", + "events_url": "https://api.github.com/users/sdaftuar/events{/privacy}", + "received_events_url": "https://api.github.com/users/sdaftuar/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think this comment is wrong -- it should say something like:\r\n\r\n```\r\n// old diagram will consist of the ancestors and descendants of each element of \r\n// all_conflicts. every such transaction will either be at its own feerate (followed \r\n// by any descendant at its own feerate), or as a single chunk at the descendant's \r\n// ancestor feerate.\r\n```", + "created_at": "2024-03-25T19:48:49Z", + "updated_at": "2024-03-25T19:54:18Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1538151180", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538151180" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1538151180" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1538151180/reactions", + "total_count": 1, + "+1": 1, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1299, + "original_line": 1299, + "side": "RIGHT", + "original_position": 69, + "position": 69, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539148211", + "pull_request_review_id": 1960246673, + "id": 1539148211, + "node_id": "PRRC_kwDOABII585bvYmz", + "diff_hunk": "@@ -0,0 +1,86 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+std::vector BuildDiagramFromChunks(const Span chunks)\n+{\n+ std::vector diagram;\n+ diagram.reserve(chunks.size() + 1);\n+\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ diagram.emplace_back(diagram.back() + chunk);\n+ }\n+ return diagram;\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB\n+ const auto slope_ap = point_p - point_a;\n+ Assume(slope_ap.size > 0);\n+ std::weak_ordering cmp = std::weak_ordering::equivalent;\n+ if (done_0 || done_1) {\n+ // If a single side has no points left, act as if AB has slope tail_feerate(of 0).\n+ Assume(!(done_0 && done_1));\n+ cmp = FeeRateCompare(slope_ap, FeeFrac(0, 1));\n+ } else {\n+ // If both sides have points left, compute B, and the slope of AB explicitly.\n+ const FeeFrac& point_b = next_point(!unproc_side);\n+ const auto slope_ab = point_b - point_a;\n+ Assume(slope_ab.size >= slope_ap.size);\n+ cmp = FeeRateCompare(slope_ap, slope_ab);\n+\n+ // If B and P have the same size, B can be marked as processed (in addition to P, see\n+ // below), as we've already performed a comparison at this size.\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\n+ }\n+ // If P lies above AB, unproc_side is better in P. If P lies below AB, then !unproc_side is\n+ // better in P.\n+ if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\n+ if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\n+ ++next_index[unproc_side];\n+ } while(true);", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "I think slightly better is to pull the check a few lines below into the loop, just after updating the `better_somewhere` array:\r\n\r\n```\r\nif (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered;\r\n```\r\n\r\n?", + "created_at": "2024-03-26T12:40:10Z", + "updated_at": "2024-03-26T12:40:10Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539148211", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539148211" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539148211" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539148211/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 80, + "original_line": 80, + "side": "RIGHT", + "in_reply_to_id": 1538124442, + "original_position": 80, + "position": 80, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539152301", + "pull_request_review_id": 1960252643, + "id": 1539152301, + "node_id": "PRRC_kwDOABII585bvZmt", + "diff_hunk": "@@ -1238,3 +1239,131 @@ std::vector CTxMemPool::GatherClusters(const std::vector CTxMemPool::CheckConflictTopology(const setEntries& direct_conflicts)\n+{\n+ for (const auto& direct_conflict : direct_conflicts) {\n+ // Ancestor and descendant counts are inclusive of the tx itself.\n+ const auto ancestor_count{direct_conflict->GetCountWithAncestors()};\n+ const auto descendant_count{direct_conflict->GetCountWithDescendants()};\n+ const bool has_ancestor{ancestor_count > 1};\n+ const bool has_descendant{descendant_count > 1};\n+ const auto& txid_string{direct_conflict->GetSharedTx()->GetHash().ToString()};\n+ // The only allowed configurations are:\n+ // 1 ancestor and 0 descendant\n+ // 0 ancestor and 1 descendant\n+ // 0 ancestor and 0 descendant\n+ if (ancestor_count > 2) {\n+ return strprintf(\"%s has %u ancestors, max 1 allowed\", txid_string, ancestor_count - 1);\n+ } else if (descendant_count > 2) {\n+ return strprintf(\"%s has %u descendants, max 1 allowed\", txid_string, descendant_count - 1);\n+ } else if (has_ancestor && has_descendant) {\n+ return strprintf(\"%s has both ancestor and descendant, exceeding cluster limit of 2\", txid_string);\n+ }\n+ // Additionally enforce that:\n+ // If we have a child, we are its only parent.\n+ // If we have a parent, we are its only child.\n+ if (has_descendant) {\n+ const auto& our_child = direct_conflict->GetMemPoolChildrenConst().begin();\n+ if (our_child->get().GetCountWithAncestors() > 2) {\n+ return strprintf(\"%s is not the only parent of child %s\",\n+ txid_string, our_child->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ } else if (has_ancestor) {\n+ const auto& our_parent = direct_conflict->GetMemPoolParentsConst().begin();\n+ if (our_parent->get().GetCountWithDescendants() > 2) {\n+ return strprintf(\"%s is not the only child of parent %s\",\n+ txid_string, our_parent->get().GetSharedTx()->GetHash().ToString());\n+ }\n+ }\n+ }\n+ return std::nullopt;\n+}\n+\n+util::Result, std::vector>> CTxMemPool::CalculateFeerateDiagramsForRBF(CAmount replacement_fees, int64_t replacement_vsize, const setEntries& direct_conflicts, const setEntries& all_conflicts)\n+{\n+ Assume(replacement_vsize > 0);\n+\n+ auto err_string{CheckConflictTopology(direct_conflicts)};\n+ if (err_string.has_value()) {\n+ // Unsupported topology for calculating a feerate diagram\n+ return util::Error{Untranslated(err_string.value())};\n+ }\n+\n+ // new diagram will have chunks that consist of each ancestor of\n+ // direct_conflicts that is at its own fee/size, along with the replacement\n+ // tx/package at its own fee/size\n+\n+ // old diagram will consist of each element of all_conflicts either at\n+ // its own feerate (followed by any descendant at its own feerate) or as a\n+ // single chunk at its descendant's ancestor feerate.", + "path": "src/txmempool.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "2079b80854e2595f6f696e7c13a56c7f2a7da9f4", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "taken, indeed my definition missed the ancestors", + "created_at": "2024-03-26T12:42:39Z", + "updated_at": "2024-03-26T12:42:39Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539152301", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539152301" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539152301" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539152301/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 1299, + "original_line": 1299, + "side": "RIGHT", + "in_reply_to_id": 1538151180, + "original_position": 69, + "position": 69, + "subject_type": "line" + }, + { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539154260", + "pull_request_review_id": 1960255715, + "id": 1539154260, + "node_id": "PRRC_kwDOABII585bvaFU", + "diff_hunk": "@@ -0,0 +1,86 @@\n+// Copyright (c) The Bitcoin Core developers\n+// Distributed under the MIT software license, see the accompanying\n+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n+\n+#include \n+#include \n+#include \n+#include \n+\n+std::vector BuildDiagramFromChunks(const Span chunks)\n+{\n+ std::vector diagram;\n+ diagram.reserve(chunks.size() + 1);\n+\n+ diagram.emplace_back(0, 0);\n+ for (auto& chunk : chunks) {\n+ diagram.emplace_back(diagram.back() + chunk);\n+ }\n+ return diagram;\n+}\n+\n+std::partial_ordering CompareFeerateDiagram(Span dia0, Span dia1)\n+{\n+ /** Array to allow indexed access to input diagrams. */\n+ const std::array, 2> dias = {dia0, dia1};\n+ /** How many elements we have processed in each input. */\n+ size_t next_index[2] = {1, 1};\n+ /** Whether the corresponding input is strictly better than the other at least in one place. */\n+ bool better_somewhere[2] = {false, false};\n+ /** Get the first unprocessed point in diagram number dia. */\n+ const auto next_point = [&](int dia) { return dias[dia][next_index[dia]]; };\n+ /** Get the last processed point in diagram number dia. */\n+ const auto prev_point = [&](int dia) { return dias[dia][next_index[dia] - 1]; };\n+\n+ // Diagrams should be non-empty, and first elements zero in size and fee\n+ Assert(!dia0.empty() && !dia1.empty());\n+ Assert(prev_point(0).IsEmpty());\n+ Assert(prev_point(1).IsEmpty());\n+\n+ do {\n+ bool done_0 = next_index[0] == dias[0].size();\n+ bool done_1 = next_index[1] == dias[1].size();\n+ if (done_0 && done_1) break;\n+\n+ // Determine which diagram has the first unprocessed point. If a single side is finished, use the\n+ // other one. Only up to one can be done due to check above.\n+ const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;\n+\n+ // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points\n+ // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we\n+ // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,\n+ // and can thus be expressed as FeeFracs.\n+ const FeeFrac& point_p = next_point(unproc_side);\n+ const FeeFrac& point_a = prev_point(!unproc_side);\n+\n+ // Slope of AP can be negative, unlike AB\n+ const auto slope_ap = point_p - point_a;\n+ Assume(slope_ap.size > 0);\n+ std::weak_ordering cmp = std::weak_ordering::equivalent;\n+ if (done_0 || done_1) {\n+ // If a single side has no points left, act as if AB has slope tail_feerate(of 0).\n+ Assume(!(done_0 && done_1));\n+ cmp = FeeRateCompare(slope_ap, FeeFrac(0, 1));\n+ } else {\n+ // If both sides have points left, compute B, and the slope of AB explicitly.\n+ const FeeFrac& point_b = next_point(!unproc_side);\n+ const auto slope_ab = point_b - point_a;\n+ Assume(slope_ab.size >= slope_ap.size);\n+ cmp = FeeRateCompare(slope_ap, slope_ab);\n+\n+ // If B and P have the same size, B can be marked as processed (in addition to P, see\n+ // below), as we've already performed a comparison at this size.\n+ if (point_b.size == point_p.size) ++next_index[!unproc_side];\n+ }\n+ // If P lies above AB, unproc_side is better in P. If P lies below AB, then !unproc_side is\n+ // better in P.\n+ if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;\n+ if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;\n+ ++next_index[unproc_side];\n+ } while(true);", + "path": "src/util/feefrac.cpp", + "commit_id": "72959867784098137a50c34f86deca8235eef4f8", + "original_commit_id": "ce8e22542ed0b4fa5794d3203207146418d59473", + "user": { + "login": "instagibbs", + "id": 5767891, + "node_id": "MDQ6VXNlcjU3Njc4OTE=", + "avatar_url": "https://avatars.githubusercontent.com/u/5767891?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/instagibbs", + "html_url": "https://github.com/instagibbs", + "followers_url": "https://api.github.com/users/instagibbs/followers", + "following_url": "https://api.github.com/users/instagibbs/following{/other_user}", + "gists_url": "https://api.github.com/users/instagibbs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/instagibbs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/instagibbs/subscriptions", + "organizations_url": "https://api.github.com/users/instagibbs/orgs", + "repos_url": "https://api.github.com/users/instagibbs/repos", + "events_url": "https://api.github.com/users/instagibbs/events{/privacy}", + "received_events_url": "https://api.github.com/users/instagibbs/received_events", + "type": "User", + "site_admin": false + }, + "body": "e.g., https://github.com/bitcoin/bitcoin/pull/29724/commits/a9d42b9aa579f54922ffd17fdeb61e704539b92c", + "created_at": "2024-03-26T12:44:05Z", + "updated_at": "2024-03-26T12:44:05Z", + "html_url": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539154260", + "pull_request_url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242", + "author_association": "MEMBER", + "_links": { + "self": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539154260" + }, + "html": { + "href": "https://github.com/bitcoin/bitcoin/pull/29242#discussion_r1539154260" + }, + "pull_request": { + "href": "https://api.github.com/repos/bitcoin/bitcoin/pulls/29242" + } + }, + "reactions": { + "url": "https://api.github.com/repos/bitcoin/bitcoin/pulls/comments/1539154260/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "start_line": null, + "original_start_line": null, + "start_side": null, + "line": 80, + "original_line": 80, + "side": "RIGHT", + "in_reply_to_id": 1538124442, + "original_position": 80, + "position": 80, + "subject_type": "line" + } +] \ No newline at end of file diff --git a/client/fresheyes-bot/src/index.ts b/client/fresheyes-bot/src/index.ts index 064ab1a..046d321 100644 --- a/client/fresheyes-bot/src/index.ts +++ b/client/fresheyes-bot/src/index.ts @@ -1,5 +1,5 @@ import { Probot } from "probot"; -import { extractData } from "./util"; +import { extractData, groupReviewsByApprovals } from "./util"; export = (robot: Probot) => { const staging = process.env.BOT_ENV ?? ""; @@ -14,6 +14,7 @@ export = (robot: Probot) => { repo: { default_branch }, }, } = context.payload.pull_request; + console.log({ forked_pull_number }); const firstLiteral = ref.split("fresheyes")[1]; const secondLiteral = firstLiteral.split("-").slice(1, 2).join("-"); @@ -47,24 +48,51 @@ export = (robot: Probot) => { const { data } = await context.octokit.pulls.get({ owner, repo, pull_number }); const prAuthor = data.user?.login as string; + console.log({ prAuthor }); + + const fetchComments = async ({ type }: { type: "LISTREVIEWCOMMENTS" | "LISTREVIEWS" | "LISTCOMMENTS" }) => { + let comments: any[] = []; + let page = 1; + const per_page = 100; + + while (true) { + const params = { + owner, + repo, + page, + per_page, + }; + + let data: any[] = []; + + if (type === "LISTREVIEWCOMMENTS") { + // const iteratorFunction = await context.octokit.paginate(context.octokit.rest.pulls.listReviews, { + // owner: owner, + // repo: repo, + // pull_number: pull_number, + // per_page, + // }); + + data = (await context.octokit.pulls.listReviewComments({ ...params, pull_number })).data; + } else if (type === "LISTREVIEWS") { + data = (await context.octokit.pulls.listReviews({ ...params, pull_number })).data; + } else if (type === "LISTCOMMENTS") { + data = (await context.octokit.issues.listComments({ ...params, issue_number: pull_number })).data; + } else { + return { comments }; + } + + comments = comments.concat(data); + if (data.length < per_page) break; + page++; + } - const { data: reviewComments } = await context.octokit.pulls.listReviewComments({ - owner, - repo, - pull_number, - }); + return { comments }; + }; - const { data: issueComments } = await context.octokit.issues.listComments({ - owner, - repo, - issue_number: pull_number, - }); - - const { data: approvalComments } = await context.octokit.pulls.listReviews({ - owner, - repo, - pull_number, - }); + const { comments: reviewComments } = await fetchComments({ type: "LISTREVIEWCOMMENTS" }); + const { comments: approvalComments } = await fetchComments({ type: "LISTREVIEWS" }); + const { comments: issueComments } = await fetchComments({ type: "LISTCOMMENTS" }); try { if (!reviewComments && !issueComments && !approvalComments) { @@ -72,42 +100,101 @@ export = (robot: Probot) => { } const { allComments } = extractData(reviewComments, issueComments, approvalComments, prAuthor); + const reviewThreads = groupReviewsByApprovals({ reviewComments, approvalComments }); + + // console.log({ approvalComments }); + console.log({ allComments_length: allComments.length }); + console.log({ reviewThreads_length: reviewThreads.length }); + // console.log({ reviewThreads: reviewThreads }); await Promise.all( - allComments.map(async (val) => { - /** Create comments according to the time they were added **/ - if (val.key === "issue") { - await context.octokit.issues.createComment({ - owner: forked_owner, - repo: forked_repo, - issue_number: forked_pull_number, - body: val.body, - }); - } else if (val.key === "review") { - await context.octokit.pulls.createReviewComment({ - owner: forked_owner, - repo: forked_repo, - pull_number: forked_pull_number, - body: val.body, - commit_id: val.commit_id, - path: val.path, - side: val.side, - line: Number(val.line), - }); - } else if (val.key === "pull_review") { - await context.octokit.pulls.createReview({ - owner: forked_owner, - repo: forked_repo, - pull_number: forked_pull_number, - body: val.body, - commit_id: val.commit_id, - event: val.event, - }); - } else { - return; - } + reviewThreads.map(async (review) => { + const { key, values } = review; + + const reviewComments = values?.map((review) => ({ path: review.key.path, body: review.key.body })); + + // console.log({ reviewComments }); + + await context.octokit.pulls.createReview({ + owner: forked_owner, + repo: forked_repo, + pull_number: forked_pull_number, + body: key.body, + commit_id: key.commit_id, + event: key.state, + comments: reviewComments, + // comments: [{ path: valueObj.path, body: valueObj.body }], + // comments: [values?.[index].key], + }); + + console.log("CREATE REVIEW"); + + // values?.map(async (thread) => { + // const { key, values: replies } = thread; + + // await context.octokit.pulls.createReviewComment({ + // owner: forked_owner, + // repo: forked_repo, + // pull_number: forked_pull_number, + // body: key.body, + // commit_id: key.commit_id, + // path: key.path, + // side: key.side, + // line: undefined, + // // line: Number(key.line), + // }); + + // console.log("CREATE-REVIEW-COMMENT"); + + // replies?.map(async (reply) => { + // await context.octokit.pulls.createReplyForReviewComment({ + // owner: forked_owner, + // repo: forked_repo, + // pull_number: forked_pull_number, + // body: reply.body, + // comment_id: key.id, + // }); + // }); + // console.log("CREATED REPLIES FOR REVIEWS"); + // }); }) ); + + // await Promise.all( + // allComments.map(async (val) => { + // /** Create comments according to the time they were added **/ + // if (val.key === "issue") { + // await context.octokit.issues.createComment({ + // owner: forked_owner, + // repo: forked_repo, + // issue_number: forked_pull_number, + // body: val.body, + // }); + // } else if (val.key === "review") { + // await context.octokit.pulls.createReviewComment({ + // owner: forked_owner, + // repo: forked_repo, + // pull_number: forked_pull_number, + // body: val.body, + // commit_id: val.commit_id, + // path: val.path, + // side: val.side, + // line: Number(val.line), + // }); + // } else if (val.key === "pull_review") { + // await context.octokit.pulls.createReview({ + // owner: forked_owner, + // repo: forked_repo, + // pull_number: forked_pull_number, + // body: val.body, + // commit_id: val.commit_id, + // event: val.event, + // }); + // } else { + // return; + // } + // }) + // ); } catch (error) { robot.log("there seems to be an issue processing this data"); throw error; diff --git a/client/fresheyes-bot/src/util.ts b/client/fresheyes-bot/src/util.ts index d7b3c02..bf5470e 100644 --- a/client/fresheyes-bot/src/util.ts +++ b/client/fresheyes-bot/src/util.ts @@ -10,10 +10,8 @@ type Comment = { }; export function groupCommentsFn>>(data: T) { - if(!data) return { comments:[], outdatedReviews: [] } - const outdatedReviews = data - .filter((x) => x.line === null) - .map((i) => ({ ...i, outdated: true })); + if (!data) return { comments: [], outdatedReviews: [] }; + const outdatedReviews = data.filter((x) => x.line === null).map((i) => ({ ...i, outdated: true })); const comments: Record> = data .filter((f) => f.line !== null) @@ -42,102 +40,61 @@ function formatTime(arg: string) { return `${year}/${month}/${day}, ${hours}:${minutes}:${seconds} UTC`; } -export function getReviewBody>>>( - value: T -) { - if(!value) return { body: '', comment: [] as any } - const list = value - .flat() - .map((x) => ({ html_url: x.html_url, created_at: x.created_at })); +export function getReviewBody>>>(value: T) { + if (!value) return { body: "", comment: [] as any }; + const list = value.flat().map((x) => ({ html_url: x.html_url, created_at: x.created_at })); const formatString = list .map((val) => { - return `- comment link ${"`" + val.html_url + "`"} at ${formatTime( - val.created_at - )}`; + return `- comment link ${"`" + val.html_url + "`"} at ${formatTime(val.created_at)}`; }) .join("\n"); - const body = `${ - value.length === 1 ? "An author" : `${value.length} authors` - } commented here with:\n\n${formatString}.`; + const body = `${value.length === 1 ? "An author" : `${value.length} authors`} commented here with:\n\n${formatString}.`; - const comment = value - .flat() - .sort( - (a, b) => - new Date(a.created_at).getTime() - new Date(b.created_at).getTime() - )[0]; + const comment = value.flat().sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime())[0]; return { body, comment }; } export function getIssueBody>(arg: T) { - const formatString = `- comment link ${ - "`" + arg.html_url + "`" - } at ${formatTime(arg.created_at as string)}`; + const formatString = `- comment link ${"`" + arg.html_url + "`"} at ${formatTime(arg.created_at as string)}`; const outdatedComment = `This is an **OUTDATED** review comment as the original pull request may have been rebased or force-pushed\n`; - const body = `${ - arg?.outdated ? outdatedComment : "An author commented here with:" - }\n\n${formatString}.`; + const body = `${arg?.outdated ? outdatedComment : "An author commented here with:"}\n\n${formatString}.`; return { body }; } -export function generateIssueBody>>( - arg: T, - prAuthor: string -) { - if(!arg) return [] - const userLoginCompare = (item: Record, name: string) => - item?.user?.login.toLowerCase() === name.toLowerCase(); +export function generateIssueBody>>(arg: T, prAuthor: string) { + if (!arg) return []; + const userLoginCompare = (item: Record, name: string) => item?.user?.login.toLowerCase() === name.toLowerCase(); - const userTypeCompare = (item: Record, type: string) => - item?.user?.type.toLowerCase() === type.toLowerCase(); + const userTypeCompare = (item: Record, type: string) => item?.user?.type.toLowerCase() === type.toLowerCase(); - const isBitcoinBot = arg.some( - (item) => userLoginCompare(item, "DrahtBot") || userTypeCompare(item, "bot") - ); + const isBitcoinBot = arg.some((item) => userLoginCompare(item, "DrahtBot") || userTypeCompare(item, "bot")); const isAuthorPresent = arg.some((item) => userLoginCompare(item, prAuthor)); const isRegularAuthor = (item: Record) => - !userLoginCompare(item, prAuthor) && - !userLoginCompare(item, "DrahtBot") && - !userTypeCompare(item, "bot"); + !userLoginCompare(item, prAuthor) && !userLoginCompare(item, "DrahtBot") && !userTypeCompare(item, "bot"); - const authors = new Set( - arg.filter(isRegularAuthor).map((item) => item.user.login.toLowerCase()) - ).size; + const authors = new Set(arg.filter(isRegularAuthor).map((item) => item.user.login.toLowerCase())).size; const uniqueBots = new Set( arg - .filter( - (item) => - userTypeCompare(item, "bot") || - (userLoginCompare(item, "DrahtBot") && item.body.trim() !== "") - ) + .filter((item) => userTypeCompare(item, "bot") || (userLoginCompare(item, "DrahtBot") && item.body.trim() !== "")) .map((item) => item.user.login.toLowerCase()) ).size; - const nonBotCommentCount = arg.filter( - (item) => isRegularAuthor(item) && item.body.trim() !== "" - ).length; + const nonBotCommentCount = arg.filter((item) => isRegularAuthor(item) && item.body.trim() !== "").length; - const allNonEmptyCommentsCount = arg.filter( - (item) => item.body.trim() !== "" - ).length; + const allNonEmptyCommentsCount = arg.filter((item) => item.body.trim() !== "").length; const isReviewWithoutComment = nonBotCommentCount === 0 && authors >= 1; const commentText = allNonEmptyCommentsCount === 1 ? "comment" : "comments"; - const reviewersText = - isReviewWithoutComment || authors === 0 - ? "" - : authors === 1 - ? "reviewer" - : "reviewers"; + const reviewersText = isReviewWithoutComment || authors === 0 ? "" : authors === 1 ? "reviewer" : "reviewers"; const botCommentText = uniqueBots === 1 ? "1 bot" : `${uniqueBots} bots`; const botComment = isBitcoinBot @@ -148,8 +105,7 @@ export function generateIssueBody>>( : `and ${botCommentText}` : ""; - const authorText = - isReviewWithoutComment || authors === 0 ? "" : ` ${authors}`; + const authorText = isReviewWithoutComment || authors === 0 ? "" : ` ${authors}`; const issueBody = `There ${ allNonEmptyCommentsCount <= 1 ? "was" : "were" @@ -166,13 +122,8 @@ export function generateIssueBody>>( ]; } -export function getPullReviewBody>( - arg: T, - event: "APPROVE" | "REQUEST_CHANGES" | "COMMENT" -) { - const formatString = `- comment link ${ - "`" + arg.html_url + "`" - } at ${formatTime(arg.submitted_at as string)}`; +export function getPullReviewBody>(arg: T, event: "APPROVE" | "REQUEST_CHANGES" | "COMMENT") { + const formatString = `- comment link ${"`" + arg.html_url + "`"} at ${formatTime(arg.submitted_at as string)}`; let comment = ""; @@ -191,11 +142,12 @@ export function getPullReviewBody>( return { body }; } -export function extractData< - R extends Array>, - I extends Array>, - T extends Array> ->(reviews: R, issues: I, pull_reviews: T, prAuthor: string) { +export function extractData>, I extends Array>, T extends Array>>( + reviews: R, + issues: I, + pull_reviews: T, + prAuthor: string +) { const { comments, outdatedReviews } = groupCommentsFn(reviews); const extract_reviews = Object.entries(comments).map(([key, value]) => { @@ -215,11 +167,126 @@ export function extractData< const allIssues = [...issues, ...outdatedReviews, ...pull_reviews]; const extract_issues = generateIssueBody(allIssues, prAuthor); - const sortComments: Comment[] = extract_reviews.sort( - (a, b) => - new Date(a.created_at).getTime() - new Date(b.created_at).getTime() - ); + const sortComments: Comment[] = extract_reviews.sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()); const allComments: Comment[] = [...extract_issues, ...sortComments]; return { allComments }; } + +// type ReviewComment = { +// url: string; +// pull_request_review_id: number | null; +// id: number; +// node_id: string; +// diff_hunk: string; +// path: string; +// position: number; +// original_position: number; +// commit_id: string; +// original_commit_id: string; +// in_reply_to_id: number; +// user: { +// login: string; +// id: number; +// node_id: string; +// avatar_url: string; +// gravatar_id: string; +// url: string; +// html_url: string; +// followers_url: string; +// following_url: string; +// gists_url: string; +// starred_url: string; +// subscriptions_url: string; +// organizations_url: string; +// repos_url: string; +// events_url: string; +// received_events_url: string; +// type: string; +// site_admin: boolean; +// }; +// body: string; +// created_at: string | Date; +// updated_at: string | Date; +// html_url: string; +// pull_request_url: string; +// author_association: string; +// _links: { +// self: { +// href: string; +// }; +// html: { +// href: string; +// }; +// pull_request: { +// href: string; +// }; +// }; +// start_line: number; +// original_start_line: number; +// start_side: string; +// line: number; +// original_line: number; +// side: string; +// }; + +export function groupReviewsByApprovals< + R extends Partial>>, + A extends Partial>> +>({ reviewComments, approvalComments }: { reviewComments: Array; approvalComments: Array }) { + if (!approvalComments.length) { + return []; + } + + let threadBlock: Array< + Partial<{ + key: A; + values: Array }>>; + }> + > = []; + + let threadReplies: Array }>> = []; + + // sort reviewComments with in_reply_to key + const getStarterComments = reviewComments.filter((revComments) => !revComments.in_reply_to_id); + + getStarterComments.map((head_replies) => { + const replyBucket: Partial<{ key: R; values: Array }> = {}; + + const extractThreadData = reviewComments.filter((revComments) => revComments.in_reply_to_id === head_replies.id); + + replyBucket["key"] = head_replies; + replyBucket["values"] = [head_replies, ...extractThreadData]; + + threadReplies.push(replyBucket); + }); + + approvalComments.map((apprComment) => { + const thread_bucket: any = {}; + + const extractThreadData = threadReplies.filter((replyBucket) => replyBucket.key?.pull_request_review_id === apprComment.id); + + let structuredObj = {}; + + switch (apprComment.state) { + case "COMMENTED": + structuredObj = { ...apprComment, state: "COMMENT" }; + break; + case "APPROVED": + structuredObj = { ...apprComment, state: "APPROVE" }; + break; + case "CHANGES_REQUESTED": + structuredObj = { ...apprComment, state: "REQUEST_CHANGES" }; + break; + default: + break; + } + + thread_bucket["key"] = structuredObj; + thread_bucket["values"] = extractThreadData; + + threadBlock.push(thread_bucket); + }); + + return threadBlock.filter((item) => item.values?.length !== 0); +} diff --git a/client/fresheyes-web/src/app/components/form/FormSection.tsx b/client/fresheyes-web/src/app/components/form/FormSection.tsx index 7c06e75..6fb1c7d 100644 --- a/client/fresheyes-web/src/app/components/form/FormSection.tsx +++ b/client/fresheyes-web/src/app/components/form/FormSection.tsx @@ -9,7 +9,7 @@ import { checkIfAppInstalledInRepo, forkRepository } from "./bot"; import { INSTALLATION_URL } from "@/config/process"; import { ClickableOptions, CustomInput } from "./CustomComponents"; import Link from "next/link"; -import { SuccessModal } from '../modal/SuccessModal'; +import { SuccessModal } from "../modal/SuccessModal"; const FormSection = ({ username }: { username: string | null | undefined }) => { const [link, setLink] = useState(""); @@ -21,20 +21,23 @@ const FormSection = ({ username }: { username: string | null | undefined }) => { }); const [error, setError] = useState(""); const [formValues, setFormValues] = useState({ - owner: "", - repo: "", - pull_number: 0, + owner: "bitcoin", + repo: "bitcoin", + pull_number: 29242, + // owner: "", + // repo: "", + // pull_number: 0, }); const { owner, repo, pull_number } = formValues; const processPullRequest = async (e: React.FormEvent) => { - e.preventDefault() + e.preventDefault(); setLink(""); setError(""); setLoading({ loader: false, modal: false, isInstalledModal: false }); - if (pull_number === 0 || (typeof pull_number !== 'number' && pull_number === '0')) { + if (pull_number === 0 || (typeof pull_number !== "number" && pull_number === "0")) { alert("You must pass a number that is not zero"); return; } @@ -72,7 +75,10 @@ const FormSection = ({ username }: { username: string | null | undefined }) => { return (
-
+

Please enter the following details to run FreshEyes

{

Clone some of the repos below to see FreshEyes in action

- +