payload: {"action":"created","comment":{"url":"https://api.github.com/repos/stellar/stellar-core/pulls/comments/282264245","pull_request_review_id":235311545,"id":282264245,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI4MjI2NDI0NQ==","diff_hunk":"@@ -496,68 +550,189 @@ LedgerTxn::Impl::getAllOffers()\n     return offers;\n }\n \n-std::shared_ptr<LedgerEntry const>\n-LedgerTxn::getBestOffer(Asset const& buying, Asset const& selling,\n-                        std::unordered_set<LedgerKey>& exclude)\n+bool\n+LedgerTxn::Impl::IsBetterOffer::operator()(LedgerEntry const& lhs,\n+                                           LedgerEntry const& rhs) const\n {\n-    return getImpl()->getBestOffer(buying, selling, exclude);\n+    return isBetterOffer(lhs, rhs);\n }\n \n-std::shared_ptr<LedgerEntry const>\n-LedgerTxn::Impl::getBestOffer(Asset const& buying, Asset const& selling,\n-                              std::unordered_set<LedgerKey>& exclude)\n+LedgerTxn::Impl::GetBestOffersState::GetBestOffersState(Asset const& buying,\n+                                                        Asset const& selling)\n+    : mBuying(buying), mSelling(selling)\n {\n-    auto end = mEntry.cend();\n-    auto bestOfferIter = end;\n-    if (exclude.size() + mEntry.size() > exclude.bucket_count())\n-    {\n-        // taking a best guess as a starting point for how big exclude can get\n-        // this avoids rehashing when processing transactions after a lot of\n-        // changes already occured\n-        exclude.reserve(exclude.size() + mEntry.size());\n-    }\n-    for (auto iter = mEntry.cbegin(); iter != end; ++iter)\n+}\n+\n+void\n+LedgerTxn::prepareGetBestOffer(Asset const& buying, Asset const& selling)\n+{\n+    getImpl()->prepareGetBestOffer(buying, selling);\n+}\n+\n+void\n+LedgerTxn::Impl::prepareGetBestOffer(Asset const& buying, Asset const& selling)\n+{\n+    // It is not safe to prepare the GetBestOffersState if any offers are active\n+    // because they can be modified so as to make the GetBestOffersState\n+    // inaccurate.\n+    for (auto const& kv : mActive)\n     {\n-        auto const& key = iter->first;\n-        auto const& entry = iter->second;\n-        if (key.type() != OFFER)\n+        if (kv.first.type() == OFFER)\n         {\n-            continue;\n+            throw std::runtime_error(\n+                \"Active offer found during prepareGetBestOffer\");\n         }\n+    }\n \n-        if (!exclude.insert(key).second)\n-        {\n-            continue;\n-        }\n+    std::unique_ptr<GetBestOffersState> gbos = std::move(mGetBestOffersState);\n \n-        if (!(entry && entry->data.offer().buying == buying &&\n-              entry->data.offer().selling == selling))\n-        {\n-            continue;\n-        }\n+    // The GetBestOffersState will be reset in create, erase, and load (and some\n+    // other similar functions) if it can no longer be guaranteed to be accurate\n+    // so we can accept it as accurate if it meets these conditions.\n+    if (!(gbos && gbos->mBuying == buying && gbos->mSelling == selling))\n+    {\n+        gbos = std::make_unique<GetBestOffersState>(buying, selling);\n \n-        if ((bestOfferIter == end) ||\n-            isBetterOffer(*entry, *bestOfferIter->second))\n+        for (auto const& kv : mEntry)\n         {\n-            bestOfferIter = iter;\n+            auto const& key = kv.first;\n+            if (key.type() == OFFER)\n+            {\n+                auto const& entry = kv.second;\n+                if (entry && entry->data.offer().buying == buying &&\n+                    entry->data.offer().selling == selling)\n+                {\n+                    gbos->mOffers.emplace(*entry);\n+                }\n+            }\n         }\n     }\n \n-    std::shared_ptr<LedgerEntry const> bestOffer;\n-    if (bestOfferIter != end)\n+    // Calling prepareGetBestOffer must always reset the stream to the beginning.\n+    gbos->mIter = gbos->mOffers.cbegin();\n+\n+    // At this point mGetBestOffersState = nullptr but the pending value of\n+    // mGetBestOffersState has already been computed. Therefore we can say the\n+    // following:\n+    // - If self or any parent throws an exception during prepareGetBestOffer\n+    //   then mGetBestOffersState = nullptr\n+    // - Otherwise mGetBestOffersState satisfies conditions 2a, 2b, 2c, and 2d\n+    //   from the documentation of mGetBestOffersState\n+    mParent.prepareGetBestOffer(buying, selling);\n+\n+    // Move-assignment of std::unique_ptr<...> never throws\n+    mGetBestOffersState = std::move(gbos);\n+}\n+\n+std::shared_ptr<LedgerEntry const>\n+LedgerTxn::getBestOffer(Asset const& buying, Asset const& selling,\n+                        LedgerKey const* exclude)\n+{\n+    return getImpl()->getBestOffer(buying, selling, exclude);\n+}\n+\n+std::shared_ptr<LedgerEntry const>\n+LedgerTxn::Impl::getBestOffer(Asset const& buying, Asset const& selling,\n+                              LedgerKey const* exclude)\n+{\n+    auto const& gbos = mGetBestOffersState;\n+    if (!gbos && (mChild || !mEntry.empty()))","path":"src/ledger/LedgerTxn.cpp","position":234,"original_position":234,"commit_id":"adee7d7d885ed88b2f5939b1df0ad5c16d210639","original_commit_id":"adee7d7d885ed88b2f5939b1df0ad5c16d210639","user":{"login":"jonjove","id":31668823,"node_id":"MDQ6VXNlcjMxNjY4ODIz","avatar_url":"https://avatars0.githubusercontent.com/u/31668823?v=4","gravatar_id":"","url":"https://api.github.com/users/jonjove","html_url":"https://github.com/jonjove","followers_url":"https://api.github.com/users/jonjove/followers","following_url":"https://api.github.com/users/jonjove/following{/other_user}","gists_url":"https://api.github.com/users/jonjove/gists{/gist_id}","starred_url":"https://api.github.com/users/jonjove/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonjove/subscriptions","organizations_url":"https://api.github.com/users/jonjove/orgs","repos_url":"https://api.github.com/users/jonjove/repos","events_url":"https://api.github.com/users/jonjove/events{/privacy}","received_events_url":"https://api.github.com/users/jonjove/received_events","type":"User","site_admin":false},"body":"Actually, the most efficient way to use `prepareGetBestOffer` and `getBestOffer` is to:\r\n1. Call `prepareGetBestOffer` on a `LedgerTxn`\r\n2. Open a child `LedgerTxn`\r\n3. Call `loadBestOffer` on the child (_without calling_ `prepareGetBestOffer` on the child)\r\n4. Do things other than `loadBestOffer`\r\n4. Commit the child\r\n5. Repeat steps 2-4 as necessary\r\n\r\nIndeed, this is what we do in `convertWithOffers`.\r\n\r\nWhy should we not call `prepareGetBestOffer` on the child? Because `prepareGetBestOffer` always recursively resets the streams of all parents to the beginning, so this will lead to `O(n^2)` iterations when making `O(n)` calls to `prepareGetBestOffer` followed by `getBestOffer`.\r\n\r\nWhy is it safe to not call `prepareGetBestOffer` when `!mChild && mEntry.empty()`? Because in this case there are no offers in the `LedgerTxn` so the `GetBestOfferState` won't contain anything. Note this argument only works if `prepareGetBestOffer` was already called for the parent. Technically I don't even think that the `!mChild` part is required.\r\n\r\nDespite the fact that this works, it is neither beautiful nor intuitive. Any ideas for making this part of the interface cleaner would be much appreciated.","created_at":"2019-05-08T21:54:01Z","updated_at":"2019-05-08T21:54:01Z","html_url":"https://github.com/stellar/stellar-core/pull/2089#discussion_r282264245","pull_request_url":"https://api.github.com/repos/stellar/stellar-core/pulls/2089","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/comments/282264245"},"html":{"href":"https://github.com/stellar/stellar-core/pull/2089#discussion_r282264245"},"pull_request":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/2089"}},"in_reply_to_id":282250900},"pull_request":{"url":"https://api.github.com/repos/stellar/stellar-core/pulls/2089","id":275839331,"node_id":"MDExOlB1bGxSZXF1ZXN0Mjc1ODM5MzMx","html_url":"https://github.com/stellar/stellar-core/pull/2089","diff_url":"https://github.com/stellar/stellar-core/pull/2089.diff","patch_url":"https://github.com/stellar/stellar-core/pull/2089.patch","issue_url":"https://api.github.com/repos/stellar/stellar-core/issues/2089","number":2089,"state":"open","locked":false,"title":"Optimize cross offers","user":{"login":"jonjove","id":31668823,"node_id":"MDQ6VXNlcjMxNjY4ODIz","avatar_url":"https://avatars0.githubusercontent.com/u/31668823?v=4","gravatar_id":"","url":"https://api.github.com/users/jonjove","html_url":"https://github.com/jonjove","followers_url":"https://api.github.com/users/jonjove/followers","following_url":"https://api.github.com/users/jonjove/following{/other_user}","gists_url":"https://api.github.com/users/jonjove/gists{/gist_id}","starred_url":"https://api.github.com/users/jonjove/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonjove/subscriptions","organizations_url":"https://api.github.com/users/jonjove/orgs","repos_url":"https://api.github.com/users/jonjove/repos","events_url":"https://api.github.com/users/jonjove/events{/privacy}","received_events_url":"https://api.github.com/users/jonjove/received_events","type":"User","site_admin":false},"body":"Preliminary attempt to optimize `convertWithOffers` by changing the interface of `LedgerTxn::loadBestOffer`.","created_at":"2019-05-03T20:27:25Z","updated_at":"2019-05-08T21:54:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"65d72224e1a44787c4c95578df8fbe7e0f6bc18f","assignee":null,"assignees":[],"requested_reviewers":[{"login":"graydon","id":14097,"node_id":"MDQ6VXNlcjE0MDk3","avatar_url":"https://avatars3.githubusercontent.com/u/14097?v=4","gravatar_id":"","url":"https://api.github.com/users/graydon","html_url":"https://github.com/graydon","followers_url":"https://api.github.com/users/graydon/followers","following_url":"https://api.github.com/users/graydon/following{/other_user}","gists_url":"https://api.github.com/users/graydon/gists{/gist_id}","starred_url":"https://api.github.com/users/graydon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/graydon/subscriptions","organizations_url":"https://api.github.com/users/graydon/orgs","repos_url":"https://api.github.com/users/graydon/repos","events_url":"https://api.github.com/users/graydon/events{/privacy}","received_events_url":"https://api.github.com/users/graydon/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/stellar/stellar-core/pulls/2089/commits","review_comments_url":"https://api.github.com/repos/stellar/stellar-core/pulls/2089/comments","review_comment_url":"https://api.github.com/repos/stellar/stellar-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/stellar/stellar-core/issues/2089/comments","statuses_url":"https://api.github.com/repos/stellar/stellar-core/statuses/adee7d7d885ed88b2f5939b1df0ad5c16d210639","head":{"label":"jonjove:optimize-cross-offers","ref":"optimize-cross-offers","sha":"adee7d7d885ed88b2f5939b1df0ad5c16d210639","user":{"login":"jonjove","id":31668823,"node_id":"MDQ6VXNlcjMxNjY4ODIz","avatar_url":"https://avatars0.githubusercontent.com/u/31668823?v=4","gravatar_id":"","url":"https://api.github.com/users/jonjove","html_url":"https://github.com/jonjove","followers_url":"https://api.github.com/users/jonjove/followers","following_url":"https://api.github.com/users/jonjove/following{/other_user}","gists_url":"https://api.github.com/users/jonjove/gists{/gist_id}","starred_url":"https://api.github.com/users/jonjove/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonjove/subscriptions","organizations_url":"https://api.github.com/users/jonjove/orgs","repos_url":"https://api.github.com/users/jonjove/repos","events_url":"https://api.github.com/users/jonjove/events{/privacy}","received_events_url":"https://api.github.com/users/jonjove/received_events","type":"User","site_admin":false},"repo":{"id":102531171,"node_id":"MDEwOlJlcG9zaXRvcnkxMDI1MzExNzE=","name":"stellar-core","full_name":"jonjove/stellar-core","private":false,"owner":{"login":"jonjove","id":31668823,"node_id":"MDQ6VXNlcjMxNjY4ODIz","avatar_url":"https://avatars0.githubusercontent.com/u/31668823?v=4","gravatar_id":"","url":"https://api.github.com/users/jonjove","html_url":"https://github.com/jonjove","followers_url":"https://api.github.com/users/jonjove/followers","following_url":"https://api.github.com/users/jonjove/following{/other_user}","gists_url":"https://api.github.com/users/jonjove/gists{/gist_id}","starred_url":"https://api.github.com/users/jonjove/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonjove/subscriptions","organizations_url":"https://api.github.com/users/jonjove/orgs","repos_url":"https://api.github.com/users/jonjove/repos","events_url":"https://api.github.com/users/jonjove/events{/privacy}","received_events_url":"https://api.github.com/users/jonjove/received_events","type":"User","site_admin":false},"html_url":"https://github.com/jonjove/stellar-core","description":"stellar-core is the backbone of the Stellar network. It maintains a local copy of the ledger, communicating and staying in sync with other instances of stellar-core on the network. Optionally, stellar-core can store historical records of the ledger and participate in consensus.","fork":true,"url":"https://api.github.com/repos/jonjove/stellar-core","forks_url":"https://api.github.com/repos/jonjove/stellar-core/forks","keys_url":"https://api.github.com/repos/jonjove/stellar-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jonjove/stellar-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jonjove/stellar-core/teams","hooks_url":"https://api.github.com/repos/jonjove/stellar-core/hooks","issue_events_url":"https://api.github.com/repos/jonjove/stellar-core/issues/events{/number}","events_url":"https://api.github.com/repos/jonjove/stellar-core/events","assignees_url":"https://api.github.com/repos/jonjove/stellar-core/assignees{/user}","branches_url":"https://api.github.com/repos/jonjove/stellar-core/branches{/branch}","tags_url":"https://api.github.com/repos/jonjove/stellar-core/tags","blobs_url":"https://api.github.com/repos/jonjove/stellar-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jonjove/stellar-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jonjove/stellar-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/jonjove/stellar-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jonjove/stellar-core/statuses/{sha}","languages_url":"https://api.github.com/repos/jonjove/stellar-core/languages","stargazers_url":"https://api.github.com/repos/jonjove/stellar-core/stargazers","contributors_url":"https://api.github.com/repos/jonjove/stellar-core/contributors","subscribers_url":"https://api.github.com/repos/jonjove/stellar-core/subscribers","subscription_url":"https://api.github.com/repos/jonjove/stellar-core/subscription","commits_url":"https://api.github.com/repos/jonjove/stellar-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/jonjove/stellar-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/jonjove/stellar-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/jonjove/stellar-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/jonjove/stellar-core/contents/{+path}","compare_url":"https://api.github.com/repos/jonjove/stellar-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jonjove/stellar-core/merges","archive_url":"https://api.github.com/repos/jonjove/stellar-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jonjove/stellar-core/downloads","issues_url":"https://api.github.com/repos/jonjove/stellar-core/issues{/number}","pulls_url":"https://api.github.com/repos/jonjove/stellar-core/pulls{/number}","milestones_url":"https://api.github.com/repos/jonjove/stellar-core/milestones{/number}","notifications_url":"https://api.github.com/repos/jonjove/stellar-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jonjove/stellar-core/labels{/name}","releases_url":"https://api.github.com/repos/jonjove/stellar-core/releases{/id}","deployments_url":"https://api.github.com/repos/jonjove/stellar-core/deployments","created_at":"2017-09-05T21:24:18Z","updated_at":"2018-09-10T22:11:35Z","pushed_at":"2019-05-08T19:08:47Z","git_url":"git://github.com/jonjove/stellar-core.git","ssh_url":"git@github.com:jonjove/stellar-core.git","clone_url":"https://github.com/jonjove/stellar-core.git","svn_url":"https://github.com/jonjove/stellar-core","homepage":"","size":17976,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"stellar:master","ref":"master","sha":"4977746b735187dc36f16767e21b97c81e927f19","user":{"login":"stellar","id":7386716,"node_id":"MDEyOk9yZ2FuaXphdGlvbjczODY3MTY=","avatar_url":"https://avatars3.githubusercontent.com/u/7386716?v=4","gravatar_id":"","url":"https://api.github.com/users/stellar","html_url":"https://github.com/stellar","followers_url":"https://api.github.com/users/stellar/followers","following_url":"https://api.github.com/users/stellar/following{/other_user}","gists_url":"https://api.github.com/users/stellar/gists{/gist_id}","starred_url":"https://api.github.com/users/stellar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stellar/subscriptions","organizations_url":"https://api.github.com/users/stellar/orgs","repos_url":"https://api.github.com/users/stellar/repos","events_url":"https://api.github.com/users/stellar/events{/privacy}","received_events_url":"https://api.github.com/users/stellar/received_events","type":"Organization","site_admin":false},"repo":{"id":27085821,"node_id":"MDEwOlJlcG9zaXRvcnkyNzA4NTgyMQ==","name":"stellar-core","full_name":"stellar/stellar-core","private":false,"owner":{"login":"stellar","id":7386716,"node_id":"MDEyOk9yZ2FuaXphdGlvbjczODY3MTY=","avatar_url":"https://avatars3.githubusercontent.com/u/7386716?v=4","gravatar_id":"","url":"https://api.github.com/users/stellar","html_url":"https://github.com/stellar","followers_url":"https://api.github.com/users/stellar/followers","following_url":"https://api.github.com/users/stellar/following{/other_user}","gists_url":"https://api.github.com/users/stellar/gists{/gist_id}","starred_url":"https://api.github.com/users/stellar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stellar/subscriptions","organizations_url":"https://api.github.com/users/stellar/orgs","repos_url":"https://api.github.com/users/stellar/repos","events_url":"https://api.github.com/users/stellar/events{/privacy}","received_events_url":"https://api.github.com/users/stellar/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/stellar/stellar-core","description":"stellar-core is the backbone of the Stellar network. It maintains a local copy of the ledger, communicating and staying in sync with other instances of stellar-core on the network. Optionally, stellar-core can store historical records of the ledger and participate in consensus.","fork":false,"url":"https://api.github.com/repos/stellar/stellar-core","forks_url":"https://api.github.com/repos/stellar/stellar-core/forks","keys_url":"https://api.github.com/repos/stellar/stellar-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stellar/stellar-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stellar/stellar-core/teams","hooks_url":"https://api.github.com/repos/stellar/stellar-core/hooks","issue_events_url":"https://api.github.com/repos/stellar/stellar-core/issues/events{/number}","events_url":"https://api.github.com/repos/stellar/stellar-core/events","assignees_url":"https://api.github.com/repos/stellar/stellar-core/assignees{/user}","branches_url":"https://api.github.com/repos/stellar/stellar-core/branches{/branch}","tags_url":"https://api.github.com/repos/stellar/stellar-core/tags","blobs_url":"https://api.github.com/repos/stellar/stellar-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stellar/stellar-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stellar/stellar-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/stellar/stellar-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stellar/stellar-core/statuses/{sha}","languages_url":"https://api.github.com/repos/stellar/stellar-core/languages","stargazers_url":"https://api.github.com/repos/stellar/stellar-core/stargazers","contributors_url":"https://api.github.com/repos/stellar/stellar-core/contributors","subscribers_url":"https://api.github.com/repos/stellar/stellar-core/subscribers","subscription_url":"https://api.github.com/repos/stellar/stellar-core/subscription","commits_url":"https://api.github.com/repos/stellar/stellar-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/stellar/stellar-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/stellar/stellar-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/stellar/stellar-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/stellar/stellar-core/contents/{+path}","compare_url":"https://api.github.com/repos/stellar/stellar-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stellar/stellar-core/merges","archive_url":"https://api.github.com/repos/stellar/stellar-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stellar/stellar-core/downloads","issues_url":"https://api.github.com/repos/stellar/stellar-core/issues{/number}","pulls_url":"https://api.github.com/repos/stellar/stellar-core/pulls{/number}","milestones_url":"https://api.github.com/repos/stellar/stellar-core/milestones{/number}","notifications_url":"https://api.github.com/repos/stellar/stellar-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stellar/stellar-core/labels{/name}","releases_url":"https://api.github.com/repos/stellar/stellar-core/releases{/id}","deployments_url":"https://api.github.com/repos/stellar/stellar-core/deployments","created_at":"2014-11-24T17:11:12Z","updated_at":"2019-05-08T19:33:15Z","pushed_at":"2019-05-08T21:48:25Z","git_url":"git://github.com/stellar/stellar-core.git","ssh_url":"git@github.com:stellar/stellar-core.git","clone_url":"https://github.com/stellar/stellar-core.git","svn_url":"https://github.com/stellar/stellar-core","homepage":"","size":17766,"stargazers_count":2107,"watchers_count":2107,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":637,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":131,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":637,"open_issues":131,"watchers":2107,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/2089"},"html":{"href":"https://github.com/stellar/stellar-core/pull/2089"},"issue":{"href":"https://api.github.com/repos/stellar/stellar-core/issues/2089"},"comments":{"href":"https://api.github.com/repos/stellar/stellar-core/issues/2089/comments"},"review_comments":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/2089/comments"},"review_comment":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/stellar/stellar-core/pulls/2089/commits"},"statuses":{"href":"https://api.github.com/repos/stellar/stellar-core/statuses/adee7d7d885ed88b2f5939b1df0ad5c16d210639"}},"author_association":"CONTRIBUTOR"}}
other: {"actor":{"display_login":"jonjove"}}