{"action":"created","comment":{"url":"https://api.github.com/repos/decred/dcrd/pulls/comments/177675416","pull_request_review_id":107550079,"id":177675416,"diff_hunk":"@@ -0,0 +1,363 @@\n+// Copyright (c) 2017 The btcsuite developers\n+// Copyright (c) 2017 The Lightning Network Developers\n+// Copyright (c) 2018 The Decred developers\n+// Use of this source code is governed by an ISC\n+// license that can be found in the LICENSE file.\n+\n+package builder\n+\n+import (\n+\t\"crypto/rand\"\n+\t\"encoding/binary\"\n+\n+\t\"github.com/decred/dcrd/blockchain/stake\"\n+\t\"github.com/decred/dcrd/chaincfg/chainhash\"\n+\t\"github.com/decred/dcrd/gcs\"\n+\t\"github.com/decred/dcrd/txscript\"\n+\t\"github.com/decred/dcrd/wire\"\n+)\n+\n+// DefaultP is the default collision probability (2^-20)\n+const DefaultP = 20\n+\n+// GCSBuilder is a utility class that makes building GCS filters convenient.\n+type GCSBuilder struct {\n+\tp    uint8\n+\tkey  [gcs.KeySize]byte\n+\tdata [][]byte\n+\terr  error\n+}\n+\n+// RandomKey is a utility function that returns a cryptographically random\n+// [gcs.KeySize]byte usable as a key for a GCS filter.\n+func RandomKey() (key [gcs.KeySize]byte, err error) {\n+\t_, err = rand.Read(key[:])\n+\treturn key, err\n+}\n+\n+// DeriveKey is a utility function that derives a key from a chainhash.Hash by\n+// truncating the bytes of the hash to the appopriate key size.\n+func DeriveKey(keyHash *chainhash.Hash) (key [gcs.KeySize]byte) {\n+\tcopy(key[:], keyHash[:])\n+\treturn key\n+}\n+\n+// OutPointToFilterEntry is a utility function that derives a filter entry from\n+// a wire.OutPoint in a standardized way for use with both building and\n+// querying filters.\n+func OutPointToFilterEntry(outpoint *wire.OutPoint) []byte {\n+\t// Size of the hash plus size of int32 index\n+\tdata := make([]byte, chainhash.HashSize+4)\n+\tcopy(data[:], outpoint.Hash[:])\n+\tbinary.LittleEndian.PutUint32(data[chainhash.HashSize:], outpoint.Index)\n+\treturn data\n+}\n+\n+// Key retrieves the key with which the builder will build a filter. This is\n+// useful if the builder is created with a random initial key.\n+func (b *GCSBuilder) Key() ([gcs.KeySize]byte, error) {\n+\t// Do nothing if the builder's errored out.\n+\tif b.err != nil {\n+\t\treturn [gcs.KeySize]byte{}, b.err\n+\t}\n+\n+\treturn b.key, nil\n+}\n+\n+// SetKey sets the key with which the builder will build a filter to the passed\n+// [gcs.KeySize]byte.\n+func (b *GCSBuilder) SetKey(key *[gcs.KeySize]byte) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\tb.key = *key\n+}\n+\n+// SetKeyFromHash sets the key with which the builder will build a filter to a\n+// key derived from the passed chainhash.Hash using DeriveKey().\n+func (b *GCSBuilder) SetKeyFromHash(keyHash *chainhash.Hash) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\tcopy(b.key[:], keyHash[:])\n+}\n+\n+// SetP sets the filter's probability after calling Builder().\n+func (b *GCSBuilder) SetP(p uint8) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\t// Basic sanity check.\n+\tif p > 32 {\n+\t\tb.err = gcs.ErrPTooBig\n+\t\treturn\n+\t}\n+\n+\tb.p = p\n+}\n+\n+// Preallocate sets the estimated filter size after calling Builder() to reduce\n+// the probability of memory reallocations. If the builder has already had data\n+// added to it, Preallocate has no effect.\n+func (b *GCSBuilder) Preallocate(n uint32) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\tif len(b.data) == 0 {\n+\t\tb.data = make([][]byte, 0, n)\n+\t}\n+}\n+\n+// AddEntry adds a []byte to the list of entries to be included in the GCS\n+// filter when it's built.\n+func (b *GCSBuilder) AddEntry(data []byte) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\tb.data = append(b.data, data)\n+}\n+\n+// AddEntries adds all the []byte entries in a [][]byte to the list of entries\n+// to be included in the GCS filter when it's built.\n+func (b *GCSBuilder) AddEntries(data [][]byte) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\tb.data = append(b.data, data...)\n+}\n+\n+// AddOutPoint adds a wire.OutPoint to the list of entries to be included in\n+// the GCS filter when it's built.\n+func (b *GCSBuilder) AddOutPoint(outpoint *wire.OutPoint) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\tb.AddEntry(OutPointToFilterEntry(outpoint))\n+}\n+\n+// AddHash adds a chainhash.Hash to the list of entries to be included in the\n+// GCS filter when it's built.\n+func (b *GCSBuilder) AddHash(hash *chainhash.Hash) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\tb.AddEntry(hash[:])\n+}\n+\n+// AddScript adds all the data pushed in the script serialized as the passed\n+// []byte to the list of entries to be included in the GCS filter when it's\n+// built.\n+func (b *GCSBuilder) AddScript(script []byte) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn\n+\t}\n+\n+\t// Ignore errors and add pushed data, if any\n+\tdata, _ := txscript.PushedData(script)\n+\tif len(data) == 0 {\n+\t\treturn\n+\t}\n+\n+\tb.AddEntries(data)\n+}\n+\n+// Build returns a function which builds a GCS filter with the given parameters\n+// and data.\n+func (b *GCSBuilder) Build() (*gcs.Filter, error) {\n+\t// Do nothing if the builder's already errored out.\n+\tif b.err != nil {\n+\t\treturn nil, b.err\n+\t}\n+\n+\treturn gcs.NewFilter(b.p, b.key, b.data)\n+}\n+\n+// WithKeyPN creates a GCSBuilder with specified key and the passed probability\n+// and estimated filter size.\n+func WithKeyPN(key *[gcs.KeySize]byte, p uint8, n uint32) *GCSBuilder {\n+\tb := &GCSBuilder{}\n+\tb.SetKey(key)\n+\tb.SetP(p)\n+\tb.Preallocate(n)\n+\treturn b\n+}\n+\n+// WithKeyP creates a GCSBuilder with specified key and the passed probability.\n+// Estimated filter size is set to zero, which means more reallocations are\n+// done when building the filter.\n+func WithKeyP(key *[gcs.KeySize]byte, p uint8) *GCSBuilder {\n+\treturn WithKeyPN(key, p, 0)\n+}\n+\n+// WithKey creates a GCSBuilder with specified key. Probability is set to\n+// 20 (2^-20 collision probability). Estimated filter size is set to zero, which\n+// means more reallocations are done when building the filter.\n+func WithKey(key *[gcs.KeySize]byte) *GCSBuilder {\n+\treturn WithKeyPN(key, DefaultP, 0)\n+}\n+\n+// WithKeyHashPN creates a GCSBuilder with key derived from the specified\n+// chainhash.Hash and the passed probability and estimated filter size.\n+func WithKeyHashPN(keyHash *chainhash.Hash, p uint8, n uint32) *GCSBuilder {\n+\tkey := DeriveKey(keyHash)\n+\treturn WithKeyPN(&key, p, n)\n+}\n+\n+// WithKeyHashP creates a GCSBuilder with key derived from the specified\n+// chainhash.Hash and the passed probability. Estimated filter size is set to\n+// zero, which means more reallocations are done when building the filter.\n+func WithKeyHashP(keyHash *chainhash.Hash, p uint8) *GCSBuilder {\n+\treturn WithKeyHashPN(keyHash, p, 0)\n+}\n+\n+// WithKeyHash creates a GCSBuilder with key derived from the specified\n+// chainhash.Hash. Probability is set to 20 (2^-20 collision probability).\n+// Estimated filter size is set to zero, which means more reallocations are\n+// done when building the filter.\n+func WithKeyHash(keyHash *chainhash.Hash) *GCSBuilder {\n+\treturn WithKeyHashPN(keyHash, DefaultP, 0)\n+}\n+\n+// WithRandomKeyPN creates a GCSBuilder with a cryptographically random key and\n+// the passed probability and estimated filter size.\n+func WithRandomKeyPN(p uint8, n uint32) *GCSBuilder {\n+\tkey, err := RandomKey()\n+\tif err != nil {\n+\t\treturn &GCSBuilder{err: err}\n+\t}\n+\treturn WithKeyPN(&key, p, n)\n+}\n+\n+// WithRandomKeyP creates a GCSBuilder with a cryptographically random key and\n+// the passed probability. Estimated filter size is set to zero, which means\n+// more reallocations are done when building the filter.\n+func WithRandomKeyP(p uint8) *GCSBuilder {\n+\treturn WithRandomKeyPN(p, 0)\n+}\n+\n+// WithRandomKey creates a GCSBuilder with a cryptographically random key.\n+// Probability is set to 20 (2^-20 collision probability). Estimated filter\n+// size is set to zero, which means more reallocations are done when\n+// building the filter.\n+func WithRandomKey() *GCSBuilder {\n+\treturn WithRandomKeyPN(DefaultP, 0)\n+}\n+\n+// BuildBasicFilter builds a basic GCS filter from a block. A basic GCS filter\n+// will contain all the previous regular outpoints spent within a block, as well\n+// as the data pushes within all the outputs created within a block which can be\n+// spent by regular transactions.\n+func BuildBasicFilter(block *wire.MsgBlock) (*gcs.Filter, error) {\n+\tblockHash := block.BlockHash()\n+\tb := WithKeyHash(&blockHash)\n+\n+\t// Add \"regular\" data from stake transactions.  For each class of stake\n+\t// transaction, the following data is committed to the regular filter:\n+\t//\n+\t//   ticket purchases:\n+\t//     - all previous outpoints\n+\t//     - data pushes in change output scripts\n+\t//\n+\t//   votes:\n+\t//     - data pushes in all OP_SSGEN-tagged output scripts (all outputs\n+\t//       after the first two -- these describe the block voted on and the\n+\t//       vote choices)\n+\t//\n+\t//   revocations:\n+\t//     - data pushes in all output scripts\n+\t//\n+\t// Because change outputs are required in a ticket purchase, even when\n+\t// unused, a special case is made that excludes their commitment when the\n+\t// output value is zero (provably unspendable).\n+\tfor _, tx := range block.STransactions {\n+\t\tswitch stake.DetermineTxType(tx) {\n+\t\tcase stake.TxTypeSStx: // Ticket purchase\n+\t\t\tfor _, in := range tx.TxIn {\n+\t\t\t\tb.AddOutPoint(&in.PreviousOutPoint)\n+\t\t\t}\n+\t\t\tfor _, out := range tx.TxOut {\n+\t\t\t\tsc := txscript.GetScriptClass(out.Version, out.PkScript)\n+\t\t\t\tif sc == txscript.StakeSubChangeTy && out.Value != 0 {\n+\t\t\t\t\tb.AddScript(out.PkScript)\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\tcase stake.TxTypeSSGen: // Vote\n+\t\t\tfor _, out := range tx.TxOut {\n+\t\t\t\tsc := txscript.GetScriptClass(out.Version, out.PkScript)\n+\t\t\t\tif sc == txscript.StakeGenTy {\n+\t\t\t\t\tb.AddScript(out.PkScript)\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\tcase stake.TxTypeSSRtx: // Revocation\n+\t\t\tfor _, out := range tx.TxOut {\n+\t\t\t\tb.AddScript(out.PkScript)\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t// For regular transactions, all previous outpoints except the coinbase's\n+\t// are committed, and all data pushes from output scripts (including\n+\t// OP_RETURN pushes) are committed.\n+\tfor i, tx := range block.Transactions {\n+\t\tif i != 0 {\n+\t\t\tfor _, txIn := range tx.TxIn {\n+\t\t\t\tb.AddOutPoint(&txIn.PreviousOutPoint)\n+\t\t\t}\n+\t\t}\n+\t\tfor _, txOut := range tx.TxOut {\n+\t\t\tb.AddScript(txOut.PkScript)\n+\t\t}\n+\t}\n+\n+\treturn b.Build()\n+}\n+\n+// BuildExtFilter builds an extended GCS filter from a block. An extended filter\n+// supplements a regular basic filter by including all transaction hashes of\n+// regular and stake transactions, and adding the witness data (a.k.a. the\n+// signature script) found within every non-coinbase regular transaction.\n+func BuildExtFilter(block *wire.MsgBlock) (*gcs.Filter, error) {\n+\tblockHash := block.BlockHash()\n+\tb := WithKeyHash(&blockHash)\n+\n+\t// For each stake transaction, commit the transaction hash.\n+\tfor _, tx := range block.STransactions {","path":"gcs/builder/builder.go","position":341,"original_position":341,"commit_id":"13e9cccd7a1d26799560fbf7ba93709f4b3fa95f","original_commit_id":"13e9cccd7a1d26799560fbf7ba93709f4b3fa95f","user":{"login":"davecgh","id":2115102,"avatar_url":"https://avatars3.githubusercontent.com/u/2115102?v=4","gravatar_id":"","url":"https://api.github.com/users/davecgh","html_url":"https://github.com/davecgh","followers_url":"https://api.github.com/users/davecgh/followers","following_url":"https://api.github.com/users/davecgh/following{/other_user}","gists_url":"https://api.github.com/users/davecgh/gists{/gist_id}","starred_url":"https://api.github.com/users/davecgh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davecgh/subscriptions","organizations_url":"https://api.github.com/users/davecgh/orgs","repos_url":"https://api.github.com/users/davecgh/repos","events_url":"https://api.github.com/users/davecgh/events{/privacy}","received_events_url":"https://api.github.com/users/davecgh/received_events","type":"User","site_admin":false},"body":"Based on the intent described by the comment of the function, this appears to be missing the signature scripts for all of the stake transactions.\r\n\r\nIn the case of votes and revocations, it's the output of the ticket that is being spent (`.TxIn[1]` for votes, and `.TxIn[0]` for revocations), and in the case of tickets, it is all inputs.","created_at":"2018-03-28T08:36:13Z","updated_at":"2018-03-28T08:36:38Z","html_url":"https://github.com/decred/dcrd/pull/1151#discussion_r177675416","pull_request_url":"https://api.github.com/repos/decred/dcrd/pulls/1151","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/decred/dcrd/pulls/comments/177675416"},"html":{"href":"https://github.com/decred/dcrd/pull/1151#discussion_r177675416"},"pull_request":{"href":"https://api.github.com/repos/decred/dcrd/pulls/1151"}}},"pull_request":{"url":"https://api.github.com/repos/decred/dcrd/pulls/1151","id":174675873,"html_url":"https://github.com/decred/dcrd/pull/1151","diff_url":"https://github.com/decred/dcrd/pull/1151.diff","patch_url":"https://github.com/decred/dcrd/pull/1151.patch","issue_url":"https://api.github.com/repos/decred/dcrd/issues/1151","number":1151,"state":"open","locked":false,"title":"multi: Add initial committed filter (CF) support","user":{"login":"jrick","id":1420313,"avatar_url":"https://avatars3.githubusercontent.com/u/1420313?v=4","gravatar_id":"","url":"https://api.github.com/users/jrick","html_url":"https://github.com/jrick","followers_url":"https://api.github.com/users/jrick/followers","following_url":"https://api.github.com/users/jrick/following{/other_user}","gists_url":"https://api.github.com/users/jrick/gists{/gist_id}","starred_url":"https://api.github.com/users/jrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrick/subscriptions","organizations_url":"https://api.github.com/users/jrick/orgs","repos_url":"https://api.github.com/users/jrick/repos","events_url":"https://api.github.com/users/jrick/events{/privacy}","received_events_url":"https://api.github.com/users/jrick/received_events","type":"User","site_admin":false},"body":"This change begins the work of bringing committed filters to the\r\nnetwork consensus daemon.  Committed filters are designed to enable\r\nlight wallets without many of the privacy issues associated with\r\nserver-side bloom filtering.\r\n\r\nThe new gcs package provides the primitives for creating and matching\r\nagainst block filters.\r\n\r\nThe wire package has been updated to define a service flag for\r\nadvertising CF support and includes types for the following new\r\nmessages: cfheaders, cfilter, cftypes, getcfheaders, getcfilter,\r\ngetcftypes.\r\n\r\nFilters are committed with the P value 20 and are saved to a new\r\ndatabase index.  At first startup, the index will be created and\r\npopulated with filters and filter headers for all blocks.\r\n\r\nMultiple filter types are supported.  The regular filter commits to\r\noutput scripts and previous outpoints that any non-voting wallet will\r\nrequire access to.  Scripts and previous outpoints that can only be\r\nspent by votes and revocations are not committed.  The extended filter\r\nis a supplementary filter which commits to all transaction hashes and\r\nthe witness of each regular transaction.  Creating these filters is\r\nbased on the proposed algorithm defined by BIP0158, but the regular\r\nfilter creation has been modified to commit to \"regular\" data in stake\r\ntransactions.","created_at":"2018-03-13T14:24:11Z","updated_at":"2018-03-28T08:36:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a849a1a26c13214af09e6701ddeb87fecb1ca12a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/decred/dcrd/pulls/1151/commits","review_comments_url":"https://api.github.com/repos/decred/dcrd/pulls/1151/comments","review_comment_url":"https://api.github.com/repos/decred/dcrd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/decred/dcrd/issues/1151/comments","statuses_url":"https://api.github.com/repos/decred/dcrd/statuses/13e9cccd7a1d26799560fbf7ba93709f4b3fa95f","head":{"label":"jrick:cf","ref":"cf","sha":"13e9cccd7a1d26799560fbf7ba93709f4b3fa95f","user":{"login":"jrick","id":1420313,"avatar_url":"https://avatars3.githubusercontent.com/u/1420313?v=4","gravatar_id":"","url":"https://api.github.com/users/jrick","html_url":"https://github.com/jrick","followers_url":"https://api.github.com/users/jrick/followers","following_url":"https://api.github.com/users/jrick/following{/other_user}","gists_url":"https://api.github.com/users/jrick/gists{/gist_id}","starred_url":"https://api.github.com/users/jrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrick/subscriptions","organizations_url":"https://api.github.com/users/jrick/orgs","repos_url":"https://api.github.com/users/jrick/repos","events_url":"https://api.github.com/users/jrick/events{/privacy}","received_events_url":"https://api.github.com/users/jrick/received_events","type":"User","site_admin":false},"repo":{"id":22847143,"name":"btcd","full_name":"jrick/btcd","owner":{"login":"jrick","id":1420313,"avatar_url":"https://avatars3.githubusercontent.com/u/1420313?v=4","gravatar_id":"","url":"https://api.github.com/users/jrick","html_url":"https://github.com/jrick","followers_url":"https://api.github.com/users/jrick/followers","following_url":"https://api.github.com/users/jrick/following{/other_user}","gists_url":"https://api.github.com/users/jrick/gists{/gist_id}","starred_url":"https://api.github.com/users/jrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrick/subscriptions","organizations_url":"https://api.github.com/users/jrick/orgs","repos_url":"https://api.github.com/users/jrick/repos","events_url":"https://api.github.com/users/jrick/events{/privacy}","received_events_url":"https://api.github.com/users/jrick/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jrick/btcd","description":"An alternative full node bitcoin implementation written in Go (golang)","fork":true,"url":"https://api.github.com/repos/jrick/btcd","forks_url":"https://api.github.com/repos/jrick/btcd/forks","keys_url":"https://api.github.com/repos/jrick/btcd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jrick/btcd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jrick/btcd/teams","hooks_url":"https://api.github.com/repos/jrick/btcd/hooks","issue_events_url":"https://api.github.com/repos/jrick/btcd/issues/events{/number}","events_url":"https://api.github.com/repos/jrick/btcd/events","assignees_url":"https://api.github.com/repos/jrick/btcd/assignees{/user}","branches_url":"https://api.github.com/repos/jrick/btcd/branches{/branch}","tags_url":"https://api.github.com/repos/jrick/btcd/tags","blobs_url":"https://api.github.com/repos/jrick/btcd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jrick/btcd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jrick/btcd/git/refs{/sha}","trees_url":"https://api.github.com/repos/jrick/btcd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jrick/btcd/statuses/{sha}","languages_url":"https://api.github.com/repos/jrick/btcd/languages","stargazers_url":"https://api.github.com/repos/jrick/btcd/stargazers","contributors_url":"https://api.github.com/repos/jrick/btcd/contributors","subscribers_url":"https://api.github.com/repos/jrick/btcd/subscribers","subscription_url":"https://api.github.com/repos/jrick/btcd/subscription","commits_url":"https://api.github.com/repos/jrick/btcd/commits{/sha}","git_commits_url":"https://api.github.com/repos/jrick/btcd/git/commits{/sha}","comments_url":"https://api.github.com/repos/jrick/btcd/comments{/number}","issue_comment_url":"https://api.github.com/repos/jrick/btcd/issues/comments{/number}","contents_url":"https://api.github.com/repos/jrick/btcd/contents/{+path}","compare_url":"https://api.github.com/repos/jrick/btcd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jrick/btcd/merges","archive_url":"https://api.github.com/repos/jrick/btcd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jrick/btcd/downloads","issues_url":"https://api.github.com/repos/jrick/btcd/issues{/number}","pulls_url":"https://api.github.com/repos/jrick/btcd/pulls{/number}","milestones_url":"https://api.github.com/repos/jrick/btcd/milestones{/number}","notifications_url":"https://api.github.com/repos/jrick/btcd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jrick/btcd/labels{/name}","releases_url":"https://api.github.com/repos/jrick/btcd/releases{/id}","deployments_url":"https://api.github.com/repos/jrick/btcd/deployments","created_at":"2014-08-11T17:03:57Z","updated_at":"2016-08-11T16:56:49Z","pushed_at":"2018-03-27T23:02:31Z","git_url":"git://github.com/jrick/btcd.git","ssh_url":"git@github.com:jrick/btcd.git","clone_url":"https://github.com/jrick/btcd.git","svn_url":"https://github.com/jrick/btcd","homepage":null,"size":26927,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"isc","name":"ISC License","spdx_id":"ISC","url":"https://api.github.com/licenses/isc"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"decred:master","ref":"master","sha":"b092705295e6fcaf8bb1acf263a2d6400f863bf0","user":{"login":"decred","id":16297194,"avatar_url":"https://avatars3.githubusercontent.com/u/16297194?v=4","gravatar_id":"","url":"https://api.github.com/users/decred","html_url":"https://github.com/decred","followers_url":"https://api.github.com/users/decred/followers","following_url":"https://api.github.com/users/decred/following{/other_user}","gists_url":"https://api.github.com/users/decred/gists{/gist_id}","starred_url":"https://api.github.com/users/decred/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/decred/subscriptions","organizations_url":"https://api.github.com/users/decred/orgs","repos_url":"https://api.github.com/users/decred/repos","events_url":"https://api.github.com/users/decred/events{/privacy}","received_events_url":"https://api.github.com/users/decred/received_events","type":"Organization","site_admin":false},"repo":{"id":50457080,"name":"dcrd","full_name":"decred/dcrd","owner":{"login":"decred","id":16297194,"avatar_url":"https://avatars3.githubusercontent.com/u/16297194?v=4","gravatar_id":"","url":"https://api.github.com/users/decred","html_url":"https://github.com/decred","followers_url":"https://api.github.com/users/decred/followers","following_url":"https://api.github.com/users/decred/following{/other_user}","gists_url":"https://api.github.com/users/decred/gists{/gist_id}","starred_url":"https://api.github.com/users/decred/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/decred/subscriptions","organizations_url":"https://api.github.com/users/decred/orgs","repos_url":"https://api.github.com/users/decred/repos","events_url":"https://api.github.com/users/decred/events{/privacy}","received_events_url":"https://api.github.com/users/decred/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/decred/dcrd","description":"Decred daemon in Go (golang).","fork":true,"url":"https://api.github.com/repos/decred/dcrd","forks_url":"https://api.github.com/repos/decred/dcrd/forks","keys_url":"https://api.github.com/repos/decred/dcrd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/decred/dcrd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/decred/dcrd/teams","hooks_url":"https://api.github.com/repos/decred/dcrd/hooks","issue_events_url":"https://api.github.com/repos/decred/dcrd/issues/events{/number}","events_url":"https://api.github.com/repos/decred/dcrd/events","assignees_url":"https://api.github.com/repos/decred/dcrd/assignees{/user}","branches_url":"https://api.github.com/repos/decred/dcrd/branches{/branch}","tags_url":"https://api.github.com/repos/decred/dcrd/tags","blobs_url":"https://api.github.com/repos/decred/dcrd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/decred/dcrd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/decred/dcrd/git/refs{/sha}","trees_url":"https://api.github.com/repos/decred/dcrd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/decred/dcrd/statuses/{sha}","languages_url":"https://api.github.com/repos/decred/dcrd/languages","stargazers_url":"https://api.github.com/repos/decred/dcrd/stargazers","contributors_url":"https://api.github.com/repos/decred/dcrd/contributors","subscribers_url":"https://api.github.com/repos/decred/dcrd/subscribers","subscription_url":"https://api.github.com/repos/decred/dcrd/subscription","commits_url":"https://api.github.com/repos/decred/dcrd/commits{/sha}","git_commits_url":"https://api.github.com/repos/decred/dcrd/git/commits{/sha}","comments_url":"https://api.github.com/repos/decred/dcrd/comments{/number}","issue_comment_url":"https://api.github.com/repos/decred/dcrd/issues/comments{/number}","contents_url":"https://api.github.com/repos/decred/dcrd/contents/{+path}","compare_url":"https://api.github.com/repos/decred/dcrd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/decred/dcrd/merges","archive_url":"https://api.github.com/repos/decred/dcrd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/decred/dcrd/downloads","issues_url":"https://api.github.com/repos/decred/dcrd/issues{/number}","pulls_url":"https://api.github.com/repos/decred/dcrd/pulls{/number}","milestones_url":"https://api.github.com/repos/decred/dcrd/milestones{/number}","notifications_url":"https://api.github.com/repos/decred/dcrd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/decred/dcrd/labels{/name}","releases_url":"https://api.github.com/repos/decred/dcrd/releases{/id}","deployments_url":"https://api.github.com/repos/decred/dcrd/deployments","created_at":"2016-01-26T20:28:42Z","updated_at":"2018-03-28T02:39:29Z","pushed_at":"2018-03-28T04:46:44Z","git_url":"git://github.com/decred/dcrd.git","ssh_url":"git@github.com:decred/dcrd.git","clone_url":"https://github.com/decred/dcrd.git","svn_url":"https://github.com/decred/dcrd","homepage":"https://decred.org","size":23523,"stargazers_count":330,"watchers_count":330,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":110,"mirror_url":null,"archived":false,"open_issues_count":51,"license":{"key":"isc","name":"ISC License","spdx_id":"ISC","url":"https://api.github.com/licenses/isc"},"forks":110,"open_issues":51,"watchers":330,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/decred/dcrd/pulls/1151"},"html":{"href":"https://github.com/decred/dcrd/pull/1151"},"issue":{"href":"https://api.github.com/repos/decred/dcrd/issues/1151"},"comments":{"href":"https://api.github.com/repos/decred/dcrd/issues/1151/comments"},"review_comments":{"href":"https://api.github.com/repos/decred/dcrd/pulls/1151/comments"},"review_comment":{"href":"https://api.github.com/repos/decred/dcrd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/decred/dcrd/pulls/1151/commits"},"statuses":{"href":"https://api.github.com/repos/decred/dcrd/statuses/13e9cccd7a1d26799560fbf7ba93709f4b3fa95f"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"davecgh"}}