{"action":"created","comment":{"url":"https://api.github.com/repos/zcash/zcash/pulls/comments/60472035","id":60472035,"diff_hunk":"@@ -0,0 +1,287 @@\n+#include <stdexcept>\n+\n+#include <boost/foreach.hpp>\n+\n+#include \"zcash/IncrementalMerkleTree.hpp\"\n+#include \"crypto/sha256.h\"\n+#include \"zerocash/utils/util.h\" // TODO: remove these utilities\n+\n+namespace libzcash {\n+\n+SHA256Compress SHA256Compress::combine(const SHA256Compress& a, const SHA256Compress& b)\n+{\n+    // This is a performance optimization.\n+    if (a.IsNull() && b.IsNull()) {\n+        return a;\n+    }\n+\n+    SHA256Compress res = SHA256Compress();\n+\n+    CSHA256 hasher;\n+    hasher.Write(a.begin(), 32);\n+    hasher.Write(b.begin(), 32);\n+    hasher.FinalizeNoPadding(res.begin());\n+\n+    return res;\n+}\n+\n+\n+template <typename Hash>\n+class PathFiller {\n+private:\n+    std::deque<Hash> queue;\n+public:\n+    PathFiller() : queue() { }\n+    PathFiller(std::deque<Hash> queue) : queue(queue) { }\n+\n+    Hash next() {\n+        if (queue.size() > 0) {\n+            Hash h = queue.front();\n+            queue.pop_front();\n+\n+            return h;\n+        } else {\n+            return Hash();\n+        }\n+    }\n+};\n+\n+template<size_t Depth, typename Hash>\n+void IncrementalMerkleTree<Depth, Hash>::wfcheck() const {\n+    if (parents.size() >= Depth) {\n+        throw std::ios_base::failure(\"tree has too many parents\");\n+    }\n+}\n+\n+template<size_t Depth, typename Hash>\n+void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {\n+    if (is_complete(Depth)) {\n+        throw std::runtime_error(\"tree is full\");\n+    }\n+\n+    if (!left) {\n+        // Set the left leaf\n+        left = obj;\n+    } else if (!right) {\n+        // Set the right leaf\n+        right = obj;\n+    } else {\n+        // Combine the leaves and propagate it up the tree\n+        boost::optional<Hash> combined = Hash::combine(*left, *right);\n+\n+        // Set the left leaf to the object and make the right object none\n+        left = obj;\n+        right = boost::none;\n+\n+        // Propagate up the tree as much as needed\n+        BOOST_FOREACH(boost::optional<Hash>& parent, parents) {\n+            if (parent) {\n+                combined = Hash::combine(*parent, *combined);\n+                parent = boost::none;\n+            } else {\n+                parent = *combined;\n+                combined = boost::none;\n+                break;\n+            }\n+        }\n+\n+        if (combined) {\n+            // Create a new parent\n+            parents.push_back(combined);\n+        }\n+    }\n+}\n+\n+// This is for allowing the witness to determine if a subtree has filled\n+// to a particular depth, or for append() to ensure we're not appending\n+// to a full tree.\n+template<size_t Depth, typename Hash>\n+bool IncrementalMerkleTree<Depth, Hash>::is_complete(size_t depth) const {\n+    if (!left || !right) {\n+        return false;\n+    }\n+\n+    if (parents.size() != (depth - 1)) {\n+        return false;\n+    }\n+\n+    BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {\n+        if (!parent) {\n+            return false;\n+        }\n+    }\n+\n+    return true;\n+}\n+\n+// This finds the next \"depth\" of an unfilled subtree, given that we've filled\n+// `skip` uncles/subtrees.\n+template<size_t Depth, typename Hash>\n+size_t IncrementalMerkleTree<Depth, Hash>::next_depth(size_t skip) const {\n+    if (!left) {\n+        if (skip) { \n+            skip--;\n+        } else {\n+            return 0;\n+        }\n+    }\n+\n+    if (!right) {\n+        if (skip) { \n+            skip--;\n+        } else {\n+            return 0;\n+        }\n+    }\n+\n+    size_t d = 1;\n+\n+    BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {\n+        if (!parent) {\n+            if (skip) {\n+                skip--;\n+            } else {\n+                return d;\n+            }\n+        }\n+\n+        d++;\n+    }\n+\n+    return d + skip;\n+}\n+\n+// This calculates the root of the tree.\n+template<size_t Depth, typename Hash>\n+Hash IncrementalMerkleTree<Depth, Hash>::root(size_t depth,\n+                                              std::deque<Hash> filler_hashes) const {\n+    PathFiller<Hash> filler(filler_hashes);\n+\n+    Hash combine_left =  left  ? *left  : filler.next();\n+    Hash combine_right = right ? *right : filler.next();\n+\n+    Hash root = Hash::combine(combine_left, combine_right);\n+\n+    size_t d = 1;\n+\n+    BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {\n+        if (parent) {\n+            root = Hash::combine(*parent, root);\n+        } else {\n+            root = Hash::combine(root, filler.next());\n+        }\n+\n+        d++;\n+    }\n+\n+    // We may not have parents for ancestor trees, so we fill\n+    // the rest in here.\n+    while (d < depth) {\n+        root = Hash::combine(root, filler.next());\n+        d++;\n+    }\n+\n+    return root;\n+}\n+\n+// This constructs an authentication path into the tree in the format that the circuit\n+// wants. The caller provides `filler_hashes` to fill in the uncle subtrees.\n+template<size_t Depth, typename Hash>\n+MerklePath IncrementalMerkleTree<Depth, Hash>::path(std::deque<Hash> filler_hashes) const {\n+    if (!left) {\n+        throw std::runtime_error(\"can't create an authentication path for the beginning of the tree\");\n+    }\n+\n+    PathFiller<Hash> filler(filler_hashes);\n+\n+    std::vector<Hash> path;\n+    std::vector<bool> index;\n+\n+    if (right) {\n+        index.push_back(true);\n+        path.push_back(*left);\n+    } else {\n+        index.push_back(false);\n+        path.push_back(filler.next());\n+    }\n+\n+    size_t d = 1;\n+\n+    BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {\n+        if (parent) {\n+            index.push_back(true);\n+            path.push_back(*parent);\n+        } else {\n+            index.push_back(false);\n+            path.push_back(filler.next());\n+        }\n+\n+        d++;\n+    }\n+\n+    while (d < Depth) {\n+        index.push_back(false);\n+        path.push_back(filler.next());\n+        d++;\n+    }\n+\n+    std::vector<std::vector<bool>> merkle_path;\n+    BOOST_FOREACH(Hash b, path)\n+    {\n+        std::vector<unsigned char> hashv(b.begin(), b.end());\n+        std::vector<bool> tmp_b;\n+\n+        libzerocash::convertBytesVectorToVector(hashv, tmp_b);\n+\n+        merkle_path.push_back(tmp_b);\n+    }\n+\n+    std::reverse(merkle_path.begin(), merkle_path.end());\n+    std::reverse(index.begin(), index.end());\n+\n+    return MerklePath(merkle_path, index);\n+}\n+\n+template<size_t Depth, typename Hash>\n+std::deque<Hash> IncrementalWitness<Depth, Hash>::uncle_train() const {\n+    std::deque<Hash> uncles(filled.begin(), filled.end());\n+\n+    if (cursor) {\n+        uncles.push_back(cursor->root(cursor_depth));\n+    }\n+\n+    return uncles;\n+}\n+\n+template<size_t Depth, typename Hash>\n+void IncrementalWitness<Depth, Hash>::append(Hash obj) {\n+    if (cursor) {\n+        cursor->append(obj);\n+\n+        if (cursor->is_complete(cursor_depth)) {\n+            filled.push_back(cursor->root(cursor_depth));\n+            cursor = boost::none;\n+        }\n+    } else {\n+        cursor_depth = tree.next_depth(filled.size());\n+\n+        if (cursor_depth >= Depth) {\n+            throw std::runtime_error(\"tree is full\");\n+        }\n+\n+        if (cursor_depth == 0) {\n+            filled.push_back(obj);\n+        } else {\n+            cursor = IncrementalMerkleTree<Depth, Hash>();\n+            cursor->append(obj);\n+        }\n+    }\n+}","path":"src/zcash/IncrementalMerkleTree.cpp","position":289,"original_position":279,"commit_id":"d4450bf12b9b6795291058dff2b017d6514754a1","original_commit_id":"3a32400b876ddadd60d3b9ee300031d8fd6774c0","user":{"login":"defuse","id":4211072,"avatar_url":"https://avatars.githubusercontent.com/u/4211072?v=3","gravatar_id":"","url":"https://api.github.com/users/defuse","html_url":"https://github.com/defuse","followers_url":"https://api.github.com/users/defuse/followers","following_url":"https://api.github.com/users/defuse/following{/other_user}","gists_url":"https://api.github.com/users/defuse/gists{/gist_id}","starred_url":"https://api.github.com/users/defuse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/defuse/subscriptions","organizations_url":"https://api.github.com/users/defuse/orgs","repos_url":"https://api.github.com/users/defuse/repos","events_url":"https://api.github.com/users/defuse/events{/privacy}","received_events_url":"https://api.github.com/users/defuse/received_events","type":"User","site_admin":false},"body":"So this could be rewritten with fewer cases and without cursor being optional:\r\n\r\nConstructor:\r\n\r\n```\r\ncursor_depth = tree.getDepthOfLargestFilledTreeContainingLastElement();\r\ncursor = new tree;\r\n```\r\n\r\nAppend:\r\n\r\n```\r\n/* Special case since we don't support depth-0 trees. \r\nThis happens when the object we're witnessing is the left\r\nchild of the depth-1 tree it's in. */\r\nif (cursor_depth == 0) {\r\n    filled.push_back(obj);\r\n    /* We don't need to set cursor to a new tree here, the constructor just did it. */\r\n    return;\r\n}\r\n\r\nif (cursor->is_complete(cursor_depth)) { /* order matters here */\r\n    cursor_depth = cursor_depth + 1;\r\n    if (cursor_depth >= Depth) { /* order matters here. */\r\n        throw exception, it's full.\r\n    }\r\n    filled.push_back(cursor->root());\r\n    cursor = new tree;\r\n}\r\n\r\ncursor->append(obj);\r\n```\r\n\r\nI like @ebfull's existing code better than this alternative since this breaks so easily if you reorder any of the lines of code within a block.","created_at":"2016-04-20T19:27:23Z","updated_at":"2016-04-20T19:27:23Z","html_url":"https://github.com/zcash/zcash/pull/823#discussion_r60472035","pull_request_url":"https://api.github.com/repos/zcash/zcash/pulls/823","_links":{"self":{"href":"https://api.github.com/repos/zcash/zcash/pulls/comments/60472035"},"html":{"href":"https://github.com/zcash/zcash/pull/823#discussion_r60472035"},"pull_request":{"href":"https://api.github.com/repos/zcash/zcash/pulls/823"}}},"pull_request":{"url":"https://api.github.com/repos/zcash/zcash/pulls/823","id":65083852,"html_url":"https://github.com/zcash/zcash/pull/823","diff_url":"https://github.com/zcash/zcash/pull/823.diff","patch_url":"https://github.com/zcash/zcash/pull/823.patch","issue_url":"https://api.github.com/repos/zcash/zcash/issues/823","number":823,"state":"open","locked":false,"title":"Implement and integrate new Incremental Merkle Tree","user":{"login":"ebfull","id":3794471,"avatar_url":"https://avatars.githubusercontent.com/u/3794471?v=3","gravatar_id":"","url":"https://api.github.com/users/ebfull","html_url":"https://github.com/ebfull","followers_url":"https://api.github.com/users/ebfull/followers","following_url":"https://api.github.com/users/ebfull/following{/other_user}","gists_url":"https://api.github.com/users/ebfull/gists{/gist_id}","starred_url":"https://api.github.com/users/ebfull/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ebfull/subscriptions","organizations_url":"https://api.github.com/users/ebfull/orgs","repos_url":"https://api.github.com/users/ebfull/repos","events_url":"https://api.github.com/users/ebfull/events{/privacy}","received_events_url":"https://api.github.com/users/ebfull/received_events","type":"User","site_admin":false},"body":"This is an implementation of a new incremental merkle tree with\r\n\r\n* no memory safety issues\r\n* a more sensible internal design\r\n* better space efficiency (tree representation, witnessing)\r\n* simpler API\r\n\r\nIt is intended that this tracks the behavior of the previous tree, which it does, as verified by tests. I even wrote a little circuit for testing that all the paths work.\r\n\r\nThis PR also integrates the tree into the codebase and deprecates the old tree in almost all of our code. (I left it alone in `zerocashTest` but everything else has been changed.)\r\n\r\nThis change is compatible with the testnet but you will need to clear your *local* blockchain data out since the serialized representation of the merkle tree is now different.\r\n\r\nCloses #517, Closes #519, Closes #591, Closes #460, Closes #473","created_at":"2016-04-03T23:04:03Z","updated_at":"2016-04-20T19:27:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"19c350b962d0de565a1596f5179f55cb21a8cfab","assignee":{"login":"ebfull","id":3794471,"avatar_url":"https://avatars.githubusercontent.com/u/3794471?v=3","gravatar_id":"","url":"https://api.github.com/users/ebfull","html_url":"https://github.com/ebfull","followers_url":"https://api.github.com/users/ebfull/followers","following_url":"https://api.github.com/users/ebfull/following{/other_user}","gists_url":"https://api.github.com/users/ebfull/gists{/gist_id}","starred_url":"https://api.github.com/users/ebfull/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ebfull/subscriptions","organizations_url":"https://api.github.com/users/ebfull/orgs","repos_url":"https://api.github.com/users/ebfull/repos","events_url":"https://api.github.com/users/ebfull/events{/privacy}","received_events_url":"https://api.github.com/users/ebfull/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/zcash/zcash/pulls/823/commits","review_comments_url":"https://api.github.com/repos/zcash/zcash/pulls/823/comments","review_comment_url":"https://api.github.com/repos/zcash/zcash/pulls/comments{/number}","comments_url":"https://api.github.com/repos/zcash/zcash/issues/823/comments","statuses_url":"https://api.github.com/repos/zcash/zcash/statuses/d4450bf12b9b6795291058dff2b017d6514754a1","head":{"label":"ebfull:new-imt","ref":"new-imt","sha":"d4450bf12b9b6795291058dff2b017d6514754a1","user":{"login":"ebfull","id":3794471,"avatar_url":"https://avatars.githubusercontent.com/u/3794471?v=3","gravatar_id":"","url":"https://api.github.com/users/ebfull","html_url":"https://github.com/ebfull","followers_url":"https://api.github.com/users/ebfull/followers","following_url":"https://api.github.com/users/ebfull/following{/other_user}","gists_url":"https://api.github.com/users/ebfull/gists{/gist_id}","starred_url":"https://api.github.com/users/ebfull/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ebfull/subscriptions","organizations_url":"https://api.github.com/users/ebfull/orgs","repos_url":"https://api.github.com/users/ebfull/repos","events_url":"https://api.github.com/users/ebfull/events{/privacy}","received_events_url":"https://api.github.com/users/ebfull/received_events","type":"User","site_admin":false},"repo":{"id":52047666,"name":"zcash","full_name":"ebfull/zcash","owner":{"login":"ebfull","id":3794471,"avatar_url":"https://avatars.githubusercontent.com/u/3794471?v=3","gravatar_id":"","url":"https://api.github.com/users/ebfull","html_url":"https://github.com/ebfull","followers_url":"https://api.github.com/users/ebfull/followers","following_url":"https://api.github.com/users/ebfull/following{/other_user}","gists_url":"https://api.github.com/users/ebfull/gists{/gist_id}","starred_url":"https://api.github.com/users/ebfull/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ebfull/subscriptions","organizations_url":"https://api.github.com/users/ebfull/orgs","repos_url":"https://api.github.com/users/ebfull/repos","events_url":"https://api.github.com/users/ebfull/events{/privacy}","received_events_url":"https://api.github.com/users/ebfull/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ebfull/zcash","description":"zcash","fork":true,"url":"https://api.github.com/repos/ebfull/zcash","forks_url":"https://api.github.com/repos/ebfull/zcash/forks","keys_url":"https://api.github.com/repos/ebfull/zcash/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ebfull/zcash/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ebfull/zcash/teams","hooks_url":"https://api.github.com/repos/ebfull/zcash/hooks","issue_events_url":"https://api.github.com/repos/ebfull/zcash/issues/events{/number}","events_url":"https://api.github.com/repos/ebfull/zcash/events","assignees_url":"https://api.github.com/repos/ebfull/zcash/assignees{/user}","branches_url":"https://api.github.com/repos/ebfull/zcash/branches{/branch}","tags_url":"https://api.github.com/repos/ebfull/zcash/tags","blobs_url":"https://api.github.com/repos/ebfull/zcash/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ebfull/zcash/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ebfull/zcash/git/refs{/sha}","trees_url":"https://api.github.com/repos/ebfull/zcash/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ebfull/zcash/statuses/{sha}","languages_url":"https://api.github.com/repos/ebfull/zcash/languages","stargazers_url":"https://api.github.com/repos/ebfull/zcash/stargazers","contributors_url":"https://api.github.com/repos/ebfull/zcash/contributors","subscribers_url":"https://api.github.com/repos/ebfull/zcash/subscribers","subscription_url":"https://api.github.com/repos/ebfull/zcash/subscription","commits_url":"https://api.github.com/repos/ebfull/zcash/commits{/sha}","git_commits_url":"https://api.github.com/repos/ebfull/zcash/git/commits{/sha}","comments_url":"https://api.github.com/repos/ebfull/zcash/comments{/number}","issue_comment_url":"https://api.github.com/repos/ebfull/zcash/issues/comments{/number}","contents_url":"https://api.github.com/repos/ebfull/zcash/contents/{+path}","compare_url":"https://api.github.com/repos/ebfull/zcash/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ebfull/zcash/merges","archive_url":"https://api.github.com/repos/ebfull/zcash/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ebfull/zcash/downloads","issues_url":"https://api.github.com/repos/ebfull/zcash/issues{/number}","pulls_url":"https://api.github.com/repos/ebfull/zcash/pulls{/number}","milestones_url":"https://api.github.com/repos/ebfull/zcash/milestones{/number}","notifications_url":"https://api.github.com/repos/ebfull/zcash/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ebfull/zcash/labels{/name}","releases_url":"https://api.github.com/repos/ebfull/zcash/releases{/id}","deployments_url":"https://api.github.com/repos/ebfull/zcash/deployments","created_at":"2016-02-18T23:50:56Z","updated_at":"2016-02-18T23:50:59Z","pushed_at":"2016-04-20T02:55:07Z","git_url":"git://github.com/ebfull/zcash.git","ssh_url":"git@github.com:ebfull/zcash.git","clone_url":"https://github.com/ebfull/zcash.git","svn_url":"https://github.com/ebfull/zcash","homepage":"https://z.cash/","size":36528,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"zc.v0.11.2.latest"}},"base":{"label":"zcash:zc.v0.11.2.latest","ref":"zc.v0.11.2.latest","sha":"9b7606fb6e5e6cbbd5bb8a18d5470175606f0e85","user":{"login":"zcash","id":16122764,"avatar_url":"https://avatars.githubusercontent.com/u/16122764?v=3","gravatar_id":"","url":"https://api.github.com/users/zcash","html_url":"https://github.com/zcash","followers_url":"https://api.github.com/users/zcash/followers","following_url":"https://api.github.com/users/zcash/following{/other_user}","gists_url":"https://api.github.com/users/zcash/gists{/gist_id}","starred_url":"https://api.github.com/users/zcash/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zcash/subscriptions","organizations_url":"https://api.github.com/users/zcash/orgs","repos_url":"https://api.github.com/users/zcash/repos","events_url":"https://api.github.com/users/zcash/events{/privacy}","received_events_url":"https://api.github.com/users/zcash/received_events","type":"Organization","site_admin":false},"repo":{"id":26987049,"name":"zcash","full_name":"zcash/zcash","owner":{"login":"zcash","id":16122764,"avatar_url":"https://avatars.githubusercontent.com/u/16122764?v=3","gravatar_id":"","url":"https://api.github.com/users/zcash","html_url":"https://github.com/zcash","followers_url":"https://api.github.com/users/zcash/followers","following_url":"https://api.github.com/users/zcash/following{/other_user}","gists_url":"https://api.github.com/users/zcash/gists{/gist_id}","starred_url":"https://api.github.com/users/zcash/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zcash/subscriptions","organizations_url":"https://api.github.com/users/zcash/orgs","repos_url":"https://api.github.com/users/zcash/repos","events_url":"https://api.github.com/users/zcash/events{/privacy}","received_events_url":"https://api.github.com/users/zcash/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zcash/zcash","description":"zcash","fork":false,"url":"https://api.github.com/repos/zcash/zcash","forks_url":"https://api.github.com/repos/zcash/zcash/forks","keys_url":"https://api.github.com/repos/zcash/zcash/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zcash/zcash/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zcash/zcash/teams","hooks_url":"https://api.github.com/repos/zcash/zcash/hooks","issue_events_url":"https://api.github.com/repos/zcash/zcash/issues/events{/number}","events_url":"https://api.github.com/repos/zcash/zcash/events","assignees_url":"https://api.github.com/repos/zcash/zcash/assignees{/user}","branches_url":"https://api.github.com/repos/zcash/zcash/branches{/branch}","tags_url":"https://api.github.com/repos/zcash/zcash/tags","blobs_url":"https://api.github.com/repos/zcash/zcash/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zcash/zcash/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zcash/zcash/git/refs{/sha}","trees_url":"https://api.github.com/repos/zcash/zcash/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zcash/zcash/statuses/{sha}","languages_url":"https://api.github.com/repos/zcash/zcash/languages","stargazers_url":"https://api.github.com/repos/zcash/zcash/stargazers","contributors_url":"https://api.github.com/repos/zcash/zcash/contributors","subscribers_url":"https://api.github.com/repos/zcash/zcash/subscribers","subscription_url":"https://api.github.com/repos/zcash/zcash/subscription","commits_url":"https://api.github.com/repos/zcash/zcash/commits{/sha}","git_commits_url":"https://api.github.com/repos/zcash/zcash/git/commits{/sha}","comments_url":"https://api.github.com/repos/zcash/zcash/comments{/number}","issue_comment_url":"https://api.github.com/repos/zcash/zcash/issues/comments{/number}","contents_url":"https://api.github.com/repos/zcash/zcash/contents/{+path}","compare_url":"https://api.github.com/repos/zcash/zcash/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zcash/zcash/merges","archive_url":"https://api.github.com/repos/zcash/zcash/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zcash/zcash/downloads","issues_url":"https://api.github.com/repos/zcash/zcash/issues{/number}","pulls_url":"https://api.github.com/repos/zcash/zcash/pulls{/number}","milestones_url":"https://api.github.com/repos/zcash/zcash/milestones{/number}","notifications_url":"https://api.github.com/repos/zcash/zcash/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zcash/zcash/labels{/name}","releases_url":"https://api.github.com/repos/zcash/zcash/releases{/id}","deployments_url":"https://api.github.com/repos/zcash/zcash/deployments","created_at":"2014-11-22T03:13:10Z","updated_at":"2016-04-19T11:00:06Z","pushed_at":"2016-04-20T02:55:08Z","git_url":"git://github.com/zcash/zcash.git","ssh_url":"git@github.com:zcash/zcash.git","clone_url":"https://github.com/zcash/zcash.git","svn_url":"https://github.com/zcash/zcash","homepage":"https://z.cash/","size":41319,"stargazers_count":680,"watchers_count":680,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":68,"mirror_url":null,"open_issues_count":310,"forks":68,"open_issues":310,"watchers":680,"default_branch":"zc.v0.11.2.latest"}},"_links":{"self":{"href":"https://api.github.com/repos/zcash/zcash/pulls/823"},"html":{"href":"https://github.com/zcash/zcash/pull/823"},"issue":{"href":"https://api.github.com/repos/zcash/zcash/issues/823"},"comments":{"href":"https://api.github.com/repos/zcash/zcash/issues/823/comments"},"review_comments":{"href":"https://api.github.com/repos/zcash/zcash/pulls/823/comments"},"review_comment":{"href":"https://api.github.com/repos/zcash/zcash/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/zcash/zcash/pulls/823/commits"},"statuses":{"href":"https://api.github.com/repos/zcash/zcash/statuses/d4450bf12b9b6795291058dff2b017d6514754a1"}}}}