Skip to content

Commit

Permalink
Update deps, fix linting errors, general maintenance
Browse files Browse the repository at this point in the history
  • Loading branch information
zquestz committed Dec 21, 2024
1 parent 3b18782 commit 3237163
Show file tree
Hide file tree
Showing 18 changed files with 1,446 additions and 53 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: build
on:
push:
branches:
- master
pull_request:
branches:
- master
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: stable
- name: Install golangci-lint
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.62.2
env:
GO111MODULE: on
- name: Run goclean.sh
run: ./goclean.sh
env:
GO111MODULE: on
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
# Neutrino: Privacy-Preserving Bitcoin Cash Light Client

[![Build Status](https://travis-ci.org/gcash/neutrino.svg?branch=master)](https://travis-ci.org/gcash/neutrino)
[![Build Status](https://github.com/gcash/neutrino/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/gcash/neutrino/actions/workflows/main.yml)
[![Godoc](https://godoc.org/github.com/gcash/neutrino?status.svg)](https://godoc.org/github.com/gcash/neutrino)

Neutrino is an **experimental** Bitcoin light client written in Go. It was developed by Roasbeef and other BTC contributors as part of the broader Lightning Network project.
This repo is a port of neutrino to the Bitcoin Cash network as part of the bchd project. It uses a [new proposal](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-June/014474.html) for compact block filters to minimize bandwidth and storage use on the client side, while attempting to preserve privacy and minimize processor load on full nodes serving light clients.

## Mechanism of operation

The light client synchronizes only block headers and a chain of compact block filter headers specifying the correct filters for each block. Filters are loaded lazily and stored in the database upon request; blocks are loaded lazily and not saved. There are multiple [known major issues](https://github.com/gcash/neutrino/issues) with the client, so it is **not recommended** to use it with real money at this point.

## Usage

The client is instantiated as an object using `NewChainService` and then started. Upon start, the client sets up its database and other relevant files and connects to the p2p network. At this point, it becomes possible to query the client.

### Queries

There are various types of queries supported by the client. There are many ways to access the database, for example, to get block headers by height and hash; in addition, it's possible to get a full block from the network using `GetBlockFromNetwork` by hash. However, the most useful methods are specifically tailored to scan the blockchain for data relevant to a wallet or a smart contract platform such as a [Lightning Network node like `lnd`](https://github.com/lightningnetwork/lnd). These are described below.

#### Rescan

`Rescan` allows a wallet to scan a chain for specific TXIDs, outputs, and addresses. A start and end block may be specified along with other options. If no end block is specified, the rescan continues until stopped. If no start block is specified, the rescan begins with the latest known block. While a rescan runs, it notifies the client of each connected and disconnected block; the notifications follow the [btcjson](https://github.com/gcash/bchd/blob/master/btcjson/chainsvrwsntfns.go) format with the option to use any of the relevant notifications. It's important to note that "recvtx" and "redeemingtx" notifications are only sent when a transaction is confirmed, not when it enters the mempool; the client does not currently support accepting 0-confirmation transactions.

#### GetUtxo

`GetUtxo` allows a wallet or smart contract platform to check that a UTXO exists on the blockchain and has not been spent. It is **highly recommended** to specify a start block; otherwise, in the event that the UTXO doesn't exist on the blockchain, the client will download all the filters back to block 1 searching for it. The client scans from the tip of the chain backwards, stopping when it finds the UTXO having been either spent or created; if it finds neither, it keeps scanning backwards until it hits the specified start block or, if a start block isn't specified, the first block in the blockchain. It returns a `SpendReport` containing either a `TxOut` including the `PkScript` required to spend the output, or containing information about the spending transaction, spending input, and block height in which the spending transaction was seen.

### Stopping the client

Calling `Stop` on the `ChainService` client allows the user to stop the client; the method doesn't return until the `ChainService` is cleanly shut down.
4 changes: 3 additions & 1 deletion batch_spend_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package neutrino

import (
"bytes"

"github.com/gcash/bchd/chaincfg/chainhash"
"github.com/gcash/bchd/wire"
)
Expand Down Expand Up @@ -65,7 +66,8 @@ func (b *batchSpendReporter) NotifyUnspentAndUnfound() {
// FailRemaining will return an error to all remaining requests in the event we
// experience a critical rescan error. The error is threaded through to allow
// the syntax:
// return reporter.FailRemaining(err)
//
// return reporter.FailRemaining(err)
func (b *batchSpendReporter) FailRemaining(err error) error {
for outpoint, requests := range b.requests {
b.notifyRequests(&outpoint, requests, nil, err)
Expand Down
14 changes: 7 additions & 7 deletions blockmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ func (b *blockManager) detectBadPeers(headers map[string]*wire.MsgCFHeaders,
// other peers.
func resolveFilterMismatchFromBlock(block *wire.MsgBlock,
fType wire.FilterType, filtersFromPeers map[string]*gcs.Filter,
threshold int) ([]string, error) {
_ int) ([]string, error) {

badPeers := make(map[string]struct{})

Expand Down Expand Up @@ -1630,7 +1630,7 @@ func (b *blockManager) getCFHeadersForAllPeers(height uint32,
// Send the query to all peers and record their responses in the map.
b.server.queryAllPeers(
msg,
func(sp *ServerPeer, resp wire.Message, quit chan<- struct{},
func(sp *ServerPeer, resp wire.Message, _ chan<- struct{},
peerQuit chan<- struct{}) {
switch m := resp.(type) {
case *wire.MsgCFHeaders:
Expand Down Expand Up @@ -1668,8 +1668,8 @@ func (b *blockManager) fetchFilterFromAllPeers(
fitlerReqMsg := wire.NewMsgGetCFilters(filterType, height, &blockHash)
b.queries.queryAllPeers(
fitlerReqMsg,
func(sp *ServerPeer, resp wire.Message, quit chan<- struct{},
peerQuit chan<- struct{}) {
func(sp *ServerPeer, resp wire.Message, _ chan<- struct{},
_ chan<- struct{}) {

switch response := resp.(type) {
// We're only interested in "cfilter" messages.
Expand Down Expand Up @@ -1716,7 +1716,7 @@ func (b *blockManager) getCheckpts(lastHash *chainhash.Hash,
getCheckptMsg := wire.NewMsgGetCFCheckpt(fType, lastHash)
b.queries.queryAllPeers(
getCheckptMsg,
func(sp *ServerPeer, resp wire.Message, quit chan<- struct{},
func(sp *ServerPeer, resp wire.Message, _ chan<- struct{},
peerQuit chan<- struct{}) {
switch m := resp.(type) {
case *wire.MsgCFCheckpt:
Expand Down Expand Up @@ -2085,7 +2085,7 @@ func (b *blockManager) QueueInv(inv *wire.MsgInv, sp *ServerPeer) {
}
}

/// QueueTx adds the passed transaction message and peer to the block handling
// / QueueTx adds the passed transaction message and peer to the block handling
// queue. Responds to the done channel argument after the tx message is
// processed.
func (b *blockManager) QueueTx(tx *bchutil.Tx, sp *ServerPeer) {
Expand Down Expand Up @@ -2679,7 +2679,7 @@ func (b *blockManager) calcNextRequiredDifficulty(newBlockTime time.Time,
return 0, errors.New("unknown difficulty algorithm")
}

func (b *blockManager) calcAsertRequiredDifficulty(lastNode *headerlist.Node, anchorBlockHeight int32, anchorBlockTime int64, anchorBlockBits uint32, newBlockTime time.Time) (uint32, error) {
func (b *blockManager) calcAsertRequiredDifficulty(lastNode *headerlist.Node, _ int32, _ int64, _ uint32, newBlockTime time.Time) (uint32, error) {
// For networks that support it, allow special reduction of the
// required difficulty once too much time has elapsed without
// mining a block.
Expand Down
8 changes: 4 additions & 4 deletions blockmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func TestBlockManagerInitialInterval(t *testing.T) {
// responses.
bm.server.queryBatch = func(msgs []wire.Message,
f func(*ServerPeer, wire.Message, wire.Message) bool,
q <-chan struct{}, qo ...QueryOption) {
_ <-chan struct{}, _ ...QueryOption) {

responses, err := generateResponses(msgs, headers)
if err != nil {
Expand Down Expand Up @@ -572,7 +572,7 @@ func TestBlockManagerInvalidInterval(t *testing.T) {

bm.server.queryBatch = func(msgs []wire.Message,
f func(*ServerPeer, wire.Message, wire.Message) bool,
q <-chan struct{}, qo ...QueryOption) {
_ <-chan struct{}, _ ...QueryOption) {

responses, err := generateResponses(msgs, headers)
if err != nil {
Expand Down Expand Up @@ -718,10 +718,10 @@ type mockQueryAccess struct {
}

func (m *mockQueryAccess) queryAllPeers(
queryMsg wire.Message,
_ wire.Message,
checkResponse func(sp *ServerPeer, resp wire.Message,
quit chan<- struct{}, peerQuit chan<- struct{}),
options ...QueryOption) {
_ ...QueryOption) {

for p, resp := range m.answers {
pp, err := peer.NewOutboundPeer(&peer.Config{}, p)
Expand Down
Loading

0 comments on commit 3237163

Please sign in to comment.