Compare commits

..

No commits in common. "master" and "v0.22.0-beta" have entirely different histories.

412 changed files with 13109 additions and 44877 deletions

View file

@ -1,35 +0,0 @@
name: Full Sync From 0
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
jobs:
build:
name: Go CI
runs-on: self-hosted
strategy:
matrix:
go: [1.19]
steps:
- run: |
echo "Note ${{ github.event.inputs.note }}!"
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout source
uses: actions/checkout@v2
- name: Build lbcd
run: go build .
- name: Create datadir
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
- name: Run lbcd
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

View file

@ -1,37 +0,0 @@
name: Full Sync From 814k
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
jobs:
build:
name: Go CI
runs-on: self-hosted
strategy:
matrix:
go: [1.19]
steps:
- run: |
echo "Note ${{ github.event.inputs.note }}!"
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout source
uses: actions/checkout@v2
- name: Build lbcd
run: go build .
- name: Create datadir
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
- name: Copy initial data
run: cp -r /home/lbry/lbcd_814k/* ${{env.TEMP_DATA_DIR}}
- name: Run lbcd
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

View file

@ -2,27 +2,27 @@ name: Build and Test
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
# https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/
permissions:
contents: read
name: Go CI name: Go CI
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
go: [1.19] go: [1.14, 1.15]
steps: steps:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
- name: Check out source - name: Check out source
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install Linters
run: "curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.26.0"
- name: Build - name: Build
env:
GO111MODULE: "on"
run: go build ./... run: go build ./...
- name: Test - name: Test
env:
GO111MODULE: "on"
run: | run: |
sh ./goclean.sh sh ./goclean.sh

View file

@ -1,57 +0,0 @@
name: golangci-lint
env:
# go needs absolute directories, using the $HOME variable doesn't work here.
GOCACHE: /home/runner/work/go/pkg/build
GOPATH: /home/runner/work/go
GO_VERSION: '^1.19'
on:
push:
tags:
- v*
branches:
- "*"
pull_request:
branches:
- "*"
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v2
with:
go-version: '${{ env.GO_VERSION }}'
- name: checkout source
uses: actions/checkout@v2
- name: compile code
run: go install -v ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
# Optional: if set to true then the action will use pre-installed Go.
skip-go-installation: true
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

View file

@ -1,57 +0,0 @@
name: goreleaser
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
pull_request:
push:
tags:
- '*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.19
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry docker.io
if: github.event_name != 'pull_request'
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: lbcd-${{ github.sha }}
path: |
dist/checksums.txt
dist/*.tar.gz

17
.gitignore vendored
View file

@ -3,7 +3,6 @@
# Databases # Databases
btcd.db btcd.db
lbcd.db
*-shm *-shm
*-wal *-wal
@ -34,22 +33,6 @@ _testmain.go
*.exe *.exe
.DS_Store
# Code coverage files # Code coverage files
profile.tmp profile.tmp
profile.cov profile.cov
# IDE
.idea
.vscode
# Binaries
btcd
btcctl
lbcd
lbcctl
# CI artifacts
dist
debug

View file

@ -1,152 +0,0 @@
linters-settings:
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
packages-with-error-message:
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
gci:
local-prefixes: github.com/golangci/golangci-lint
goconst:
min-len: 2
min-occurrences: 2
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
disabled-checks:
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- whyNoLint
- wrapperFunc
gocyclo:
min-complexity: 15
goimports:
local-prefixes: github.com/golangci/golangci-lint
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks:
- argument
- case
- condition
- return
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
nolintlint:
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
allow-unused: false # report any unused nolint directives
require-explanation: false # don't require an explanation for nolint directives
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
linters:
disable-all: true
enable:
- asciicheck
- bodyclose
# - deadcode
- depguard
# - dogsled
# - dupl
# - errcheck
# - exhaustive
- exportloopref
# - funlen
# - gochecknoglobals
# - gochecknoinits
# - gocognit
# - goconst
# - gocritic
# - gocyclo
# - godot
# - godox
# - goerr113
- gofmt
- goimports
# - gomnd
- goprintffuncname
# - gosec
# - gosimple
# - govet
# - ineffassign
# - interfacer
# - lll
# - maligned
# - misspell
- nakedret
# - nestif
# - noctx
# - nolintlint
# - prealloc
- rowserrcheck
# - revive
# - scopelint
# - staticcheck
# - structcheck
# - stylecheck
# - testpackage
# - typecheck
- unconvert
# - unparam
# - unused
# - varcheck
# - whitespace
# - wsl
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- gomnd
- path: pkg/golinters/errcheck.go
text: "SA1019: errCfg.Exclude is deprecated: use ExcludeFunctions instead"
- path: pkg/commands/run.go
text: "SA1019: lsc.Errcheck.Exclude is deprecated: use ExcludeFunctions instead"
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/commands/run.go
linters:
- gomnd
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/golinters/nolintlint/nolintlint.go
linters:
- gomnd
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/printers/tab.go
linters:
- gomnd
run:
skip-dirs:
- test/testdata_etc
- internal/cache
- internal/renameio
- internal/robustio

View file

@ -1,68 +0,0 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
-
main: .
id: "lbcd"
binary: "lbcd"
env:
- CGO_ENABLED=0
flags:
- -trimpath
ldflags:
- -s -w
- -buildid=
- -X github.com/lbryfoundation/lbcd/version.appTag={{ .Tag }}
targets:
- linux_amd64
- linux_arm64
- darwin_amd64
- darwin_arm64
- windows_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
-
main: ./cmd/lbcctl
id: "lbcctl"
binary: "lbcctl"
flags:
- -trimpath
ldflags:
- -s -w
- -buildid=
- -X github.com/lbryfoundation/lbcd/version.appTag={{ .Tag }}
env:
- CGO_ENABLED=0
targets:
- linux_amd64
- linux_arm64
- darwin_amd64
- darwin_arm64
- windows_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Version }}+{{ .Commit }}"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
dockers:
- use: buildx
dockerfile: Dockerfile.goreleaser
image_templates:
- "docker.io/lbryfoundation/lbcd:{{ .Tag }}"
- "docker.io/lbryfoundation/lbcd:latest"
release:
draft: true
prerelease: auto

1230
CHANGES Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,25 @@
# This Dockerfile builds lbcd from source and creates a small (55 MB) docker container based on alpine linux. # This Dockerfile builds btcd from source and creates a small (55 MB) docker container based on alpine linux.
# #
# Clone this repository and run the following command to build and tag a fresh lbcd amd64 container: # Clone this repository and run the following command to build and tag a fresh btcd amd64 container:
# #
# docker build . -t yourregistry/lbcd # docker build . -t yourregistry/btcd
# #
# You can use the following command to buid an arm64v8 container: # You can use the following command to buid an arm64v8 container:
# #
# docker build . -t yourregistry/lbcd --build-arg ARCH=arm64v8 # docker build . -t yourregistry/btcd --build-arg ARCH=arm64v8
# #
# For more information how to use this docker image visit: # For more information how to use this docker image visit:
# https://github.com/lbryio/lbcd/tree/master/docs # https://github.com/btcsuite/btcd/tree/master/docs
# #
# 9246 Mainnet LBRY peer-to-peer port # 8333 Mainnet Bitcoin peer-to-peer port
# 9245 Mainet RPC port # 8334 Mainet RPC port
ARG ARCH=amd64 ARG ARCH=amd64
FROM golang:1.19 AS build-container FROM golang:1.14-alpine3.12 AS build-container
ARG ARCH ARG ARCH
ENV GO111MODULE=on
ADD . /app ADD . /app
WORKDIR /app WORKDIR /app
@ -29,12 +30,12 @@ RUN set -ex \
&& echo "Compiling for $GOARCH" \ && echo "Compiling for $GOARCH" \
&& go install -v . ./cmd/... && go install -v . ./cmd/...
FROM $ARCH/debian:bullseye-20220418-slim FROM $ARCH/alpine:3.12
COPY --from=build-container /go/bin /bin COPY --from=build-container /go/bin /bin
VOLUME ["/root/.lbcd"] VOLUME ["/root/.btcd"]
EXPOSE 9245 9246 EXPOSE 8333 8334
ENTRYPOINT ["lbcd"] ENTRYPOINT ["btcd"]

View file

@ -1,9 +0,0 @@
FROM debian:bullseye-20220418-slim
COPY lbcd lbcctl /bin/
VOLUME ["/root/.lbcd"]
EXPOSE 9245 9246
ENTRYPOINT ["lbcd"]

View file

@ -1,6 +1,5 @@
ISC License ISC License
Copyright (c) 2021 The LBRY developers
Copyright (c) 2013-2017 The btcsuite developers Copyright (c) 2013-2017 The btcsuite developers
Copyright (c) 2015-2016 The Decred developers Copyright (c) 2015-2016 The Decred developers

364
README.md
View file

@ -1,335 +1,121 @@
# lbcd btcd
====
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions) [![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![Coverage Status](https://coveralls.io/repos/github/lbryio/lbcd/badge.svg?branch=master)](https://coveralls.io/github/lbryio/lbcd?branch=master) [![Coverage Status](https://coveralls.io/repos/github/btcsuite/btcd/badge.svg?branch=master)](https://coveralls.io/github/btcsuite/btcd?branch=master)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
<!--[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd)--> [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd)
**lbcd** is a full node implementation of LBRY's blockchain written in Go (golang). btcd is an alternative full node bitcoin implementation written in Go (golang).
Software stack developed by LBRY teams has been all migrated to **lbcd**. This project is currently under active development and is in a Beta state. It
is extremely stable and has been in production use since October 2013.
We're working with exchanges and pool oerators to migrate from **lbrycrd** to **lbcd**. It properly downloads, validates, and serves the block chain using the exact
rules (including consensus bugs) for block acceptance as Bitcoin Core. We have
taken great care to avoid btcd causing a fork to the block chain. It includes a
full block validation testing framework which contains all of the 'official'
block acceptance tests (and some additional ones) that is run on every pull
request to help ensure it properly follows consensus. Also, it passes all of
the JSON test data in the Bitcoin Core code.
If you're integrating with **lbcd+lbcwallet**, please check the Wiki for current [supported RPCs](wiki/RPC-availability). It also properly relays newly mined blocks, maintains a transaction pool, and
relays individual transactions that have not yet made it into a block. It
ensures all individual transactions admitted to the pool follow the rules
required by the block chain and also includes more strict checks which filter
transactions based on miner requirements ("standard" transactions).
Note: **lbcd** does *NOT* include wallet functionality. That functionality is provided by the One key difference between btcd and Bitcoin Core is that btcd does *NOT* include
[lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk). wallet functionality and this was a very intentional design decision. See the
blog entry [here](https://web.archive.org/web/20171125143919/https://blog.conformal.com/btcd-not-your-moms-bitcoin-daemon)
for more details. This means you can't actually make or receive payments
directly with btcd. That functionality is provided by the
[btcwallet](https://github.com/btcsuite/btcwallet) and
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
which are both under active development.
## Requirements ## Requirements
All common operating systems are supported. lbcd requires at least 8GB of RAM [Go](http://golang.org) 1.14 or newer.
and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time.
Using a fast NVMe disk is recommended.
## Installation ## Installation
Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases) https://github.com/btcsuite/btcd/releases
For compilation, [Go](http://golang.org) 1.19 or newer is required. #### Linux/BSD/MacOSX/POSIX - Build from Source
Install Go according to its [installation instructions](http://golang.org/doc/install).
``` sh - Install Go according to the installation instructions here:
# lbcd (full node) http://golang.org/doc/install
$ go install github.com/lbryio/lbcd@latest
# lbcctl (rpc client utility) - Ensure Go was installed properly and is a supported version:
$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest
```bash
$ go version
$ go env GOROOT GOPATH
``` ```
## Usage NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is
recommended that `GOPATH` is set to a directory in your home directory such as
`~/goprojects` to avoid write permission issues. It is also recommended to add
`$GOPATH/bin` to your `PATH` at this point.
Default application folder `${LBCDDIR}`: - Run the following commands to obtain btcd, all dependencies, and install it:
- Linux: `~/.lbcd/` ```bash
- MacOS: `/Users/<username>/Library/Application Support/Lbcd/` $ cd $GOPATH/src/github.com/btcsuite/btcd
$ GO111MODULE=on go install -v . ./cmd/...
### Start the **lbcd**
``` sh
./lbcd
``` ```
**lbcd** loads config file at `"${LBCDDIR}/lbcd.conf"`. - btcd (and utilities) will now be installed in ```$GOPATH/bin```. If you did
not already add the bin directory to your system path during Go installation,
we recommend you do so now.
If no config is found, it creates a [default one](sample-lbcd.conf), which includes all available options with default settings except randomly generated *RPC credentials* (see below). ## Updating
### RPC server #### Linux/BSD/MacOSX/POSIX - Build from Source
RPC credentials (`rpcuser` and `rpcpass`) is required to enable RPC server. It can be specify in the `"${LBCDDIR}/lbcd.conf"`, using command line options: - Run the following commands to update btcd, all dependencies, and install it:
``` sh ```bash
./lbcd --rpcuser=rpcuser --rpcpass=rpcpass $ cd $GOPATH/src/github.com/btcsuite/btcd
$ git pull
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on 0.0.0.0:9245 $ GO111MODULE=on go install -v . ./cmd/...
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on [::]:9245
``` ```
### Working with TLS (Default) ## Getting Started
By default, **lbcd** runs RPC server with TLS enabled, and generates the `rpc.cert` and `rpc.key` under `${LBCDDIR}`, if not exist already. btcd has several configuration options available to tweak how it runs, but all
of the basic operations described in the intro section work with zero
configuration.
To interact with the RPC server, a client has to either specify the `rpc.cert`, or disable the certification verification for TLS. #### Linux/BSD/POSIX/Source
Interact with **lbcd** RPC using `lbcctl` ```bash
$ ./btcd
``` sh
$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount
# or disable the certificate verification
$ ./lbcctl --skipverify getblockcount
1200062
``` ```
Interact with **lbcd** RPC using `curl` ## IRC
``` sh - irc.freenode.net
$ curl --user rpcuser:rpcpass \ - channel #btcd
--cacert "${LBCDDIR}/rpc.cert" \ - [webchat](https://webchat.freenode.net/?channels=btcd)
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
https://127.0.0.1:9245/
# or disable the certificate verification ## Issue Tracker
$ curl --user rpcuser:rpcpass \
--insecure \
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
https://127.0.0.1:9245/
```
``` json The [integrated github issue tracker](https://github.com/btcsuite/btcd/issues)
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"} is used for this project.
```
### Working without TLS ## Documentation
TLS can be disabled using the `--notls` option: The documentation is a work-in-progress. It is located in the [docs](https://github.com/btcsuite/btcd/tree/master/docs) folder.
``` sh ## Release Verification
$ ./lbcd --notls
```
``` sh
$ ./lbcctl --notls getblockcount
1200062
```
``` sh
$ curl --user rpcuser:rpcpass \
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:9245/
```
``` json
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}
```
## Using Snapshots (optional)
[Snapshots](https://snapshots.lbry.com/blockchain/) are created bi-weekly to help new users catch up current block height.
The snapshots are archived and compressed in [zstd](https://facebook.github.io/zstd/) format for it's compression ratio and speed.
Download the snapshot, and uncompress it:
``` sh
time curl -O https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst
zstd -d --stdout lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | tar xf - -C "${LBCDDIR}"
```
If preferred, a user can download and uncompress the snapshot on the fly:
By the time the download is finished, the snapshots should be almost uncompressed already.
``` sh
mkdir -p "${LBCDDIR}"
time curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | zstd -d --stdout | tar xf - -C "${LBCDDIR}"
# % Total % Received % Xferd Average Speed Time Time Time Current
# Dload Upload Total Spent Left Speed
# 100 64.9G 100 64.9G 0 0 37.0M 0 0:29:49 0:29:49 --:--:-- 33.0M
#
# real 29m49.962s
# user 6m53.710s
# sys 8m56.545s
```
## Working with RPCs
Using `lbcctl -l` to list available RPCs:
``` sh
$ lbcctl -l
Chain Server Commands:
addnode "addr" "add|remove|onetry"
createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)
debuglevel "levelspec"
decoderawtransaction "hextx"
decodescript "hexscript"
deriveaddresses "descriptor" ({"value":value})
fundrawtransaction "hextx" {"changeaddress":changeaddress,"changeposition":changeposition,"changetype":changetype,"includewatching":includewatching,"lockunspents":lockunspents,"feerate":feerate,"subtractfeefromoutputs":[subtractfeefromoutput,...],"replaceable":replaceable,"conftarget":conftarget,"estimatemode":estimatemode} (iswitness)
generate numblocks
[skipped]
Wallet Server Commands (--wallet):
addmultisigaddress nrequired ["key",...] ("account")
addwitnessaddress "address"
backupwallet "destination"
createmultisig nrequired ["key",...]
createnewaccount "account"
createwallet "walletname" (disableprivatekeys=false blank=false passphrase="" avoidreuse=false)
dumpprivkey "address"
dumpwallet "filename"
encryptwallet "passphrase"
estimatefee numblocks
estimatepriority numblocks
estimatesmartfee conftarget (estimatemode="CONSERVATIVE")
getaccount "address"
getaccountaddress "account"
getaddressesbyaccount "account"
[skipped]
```
Using `lbcctl help rpcname` to show the RPC spec:
``` sh
$ lbcctl help getblock
getblock "hash" (verbosity=1)
Returns information about a block given its hash.
Arguments:
1. hash (string, required) The hash of the block
2. verbosity (numeric, optional, default=1) Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2)
Result (verbosity=0):
"value" (string) Hex-encoded bytes of the serialized block
Result (verbosity=1):
{
"getblockverboseresultbase": { (object)
"hash": "value", (string) The hash of the block (same as provided)
"confirmations": n, (numeric) The number of confirmations
"strippedsize": n, (numeric) The size of the block without witness data
"size": n, (numeric) The size of the block
"weight": n, (numeric) The weight of the block
"height": n, (numeric) The height of the block in the block chain
"version": n, (numeric) The block version
"versionHex": "value", (string) The block version in hexadecimal
"merkleroot": "value", (string) Root hash of the merkle tree
"time": n, (numeric) The block time in seconds since 1 Jan 1970 GMT
"mediantime": n, (numeric) The median block time in seconds since 1 Jan 1970 GMT
"nonce": n, (numeric) The block nonce
"bits": "value", (string) The bits which represent the block difficulty
"difficulty": n.nnn, (numeric) The proof-of-work difficulty as a multiple of the minimum difficulty
"chainwork": "value", (string) Expected number of hashes required to produce the chain up to this block (in hex)
"previousblockhash": "value", (string) The hash of the previous block
"nextblockhash": "value", (string) The hash of the next block (only if there is one)
"nameclaimroot": "value", (string) Root hash of the claim trie
"nTx": n, (numeric) The number of transactions (aka, count of TX)
},
"tx": ["value",...], (array of string) The transaction hashes (only when verbosity=1)
}
```
## **lbcd** & **lbcwallet**
*Wallet* related functianlities and RPCs are provided by a separate programe - [**lbcwallet**](https://github.com/lbryio/lbcwallet).
Once setup, lbcwallet can serve wallet related RPCs as well as proxy lbcd RPCs to an assocated lbcd now.
It's sufficient for user to connect just the **lbcwallet** instead of both.
``` mermaid
sequenceDiagram
actor C as lbcctl
participant W as lbcwallet (port: 9244)
participant D as lbcd (port: 9245)
rect rgb(200,200,200)
Note over C,D: lbcctl getblockcount
C ->>+ D: getblockcount
D -->>- C: response
end
rect rgb(200,200,200)
Note over C,W: lbcctl --wallet balance
C ->>+ W: getbalance
W -->>- C: response
end
rect rgb(200,200,200)
Note over C,D: lbcctl --wallet getblockcount (lbcd RPC service proxied by lbcwallet)
C ->>+ W: getblockcount
W ->>+ D: getblockcount
D -->>- W: response
W -->>- C: response
end
```
While **lbcd** can run standalone as a full node, **lbcwallet** requires an associated **lbcd** instance for scanning and sync'ing block data.
``` mermaid
sequenceDiagram
participant W as lbcwallet (RPC port: 9244)
participant D as lbcd (RPC port: 9245, P2P port: 9246)
participant D2 as other lbcd node(s) (P2P port: 9246)
rect rgb(200,200,200)
Note over W,D: Asynchronous websocket notifications
W ->> D: subscribe to notifications
D -->> W: notification
D -->> W: notification
end
rect rgb(200,200,200)
Note over W,D: lbcd RPCs
W ->>+ D: getblockheader
D ->>- W: response
end
rect rgb(200,200,200)
Note over D,D2: P2P messages over port 9246
D -->> D2: P2P message
D2 -->> D: P2P message
end
```
## Data integrity
**lbcd** is not immune to data loss. It expects a clean shutdown via SIGINT or
SIGTERM. SIGKILL, immediate VM kills, and sudden power loss can cause data
corruption, thus requiring chain resynchronization for recovery.
## Security
We take security seriously. Please contact [security](mailto:security@lbry.com) regarding any security issues.
Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
We maintain a mailing list for notifications of upgrades, security issues,
and soft/hard forks. To join, visit [fork list](https://lbry.com/forklist)
## Contributing
Contributions to this project are welcome, encouraged, and compensated.
The [integrated github issue tracker](https://github.com/lbryio/lbcd/issues)
is used for this project. All pull requests will be considered.
<!-- ## Release Verification
Please see our [documentation on the current build/verification Please see our [documentation on the current build/verification
process](https://github.com/lbryio/lbcd/tree/master/release) for all our process](https://github.com/btcsuite/btcd/tree/master/release) for all our
releases for information on how to verify the integrity of published releases releases for information on how to verify the integrity of published releases
using our reproducible build system. using our reproducible build system.
-->
## License ## License
lbcd is licensed under the [copyfree](http://copyfree.org) ISC License. btcd is licensed under the [copyfree](http://copyfree.org) ISC License.

View file

@ -23,8 +23,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// AddrManager provides a concurrency safe address manager for caching potential // AddrManager provides a concurrency safe address manager for caching potential
@ -45,7 +45,7 @@ type AddrManager struct {
nTried int nTried int
nNew int nNew int
lamtx sync.Mutex lamtx sync.Mutex
localAddresses map[string]*LocalAddress localAddresses map[string]*localAddress
version int version int
} }
@ -69,9 +69,9 @@ type serializedAddrManager struct {
TriedBuckets [triedBucketCount][]string TriedBuckets [triedBucketCount][]string
} }
type LocalAddress struct { type localAddress struct {
NA *wire.NetAddress na *wire.NetAddress
Score AddressPriority score AddressPriority
} }
// AddressPriority type is used to describe the hierarchy of local address // AddressPriority type is used to describe the hierarchy of local address
@ -176,9 +176,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
// TODO: only update addresses periodically. // TODO: only update addresses periodically.
// Update the last seen time and services. // Update the last seen time and services.
// note that to prevent causing excess garbage on getaddr // note that to prevent causing excess garbage on getaddr
// messages the netaddresses in addrmanager are *immutable*, // messages the netaddresses in addrmaanger are *immutable*,
// if we need to change them then we replace the pointer with a // if we need to change them then we replace the pointer with a
// new copy so that we don't have to copy every NA for getaddr. // new copy so that we don't have to copy every na for getaddr.
if netAddr.Timestamp.After(ka.na.Timestamp) || if netAddr.Timestamp.After(ka.na.Timestamp) ||
(ka.na.Services&netAddr.Services) != (ka.na.Services&netAddr.Services) !=
netAddr.Services { netAddr.Services {
@ -186,9 +186,7 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
naCopy := *ka.na naCopy := *ka.na
naCopy.Timestamp = netAddr.Timestamp naCopy.Timestamp = netAddr.Timestamp
naCopy.AddService(netAddr.Services) naCopy.AddService(netAddr.Services)
ka.mtx.Lock()
ka.na = &naCopy ka.na = &naCopy
ka.mtx.Unlock()
} }
// If already in tried, we have nothing to do here. // If already in tried, we have nothing to do here.
@ -755,7 +753,7 @@ func (a *AddrManager) HostToNetAddress(host string, port uint16, services wire.S
// the relevant .onion address. // the relevant .onion address.
func ipString(na *wire.NetAddress) string { func ipString(na *wire.NetAddress) string {
if IsOnionCatTor(na) { if IsOnionCatTor(na) {
// We know now that NA.IP is long enough. // We know now that na.IP is long enough.
base32 := base32.StdEncoding.EncodeToString(na.IP[6:]) base32 := base32.StdEncoding.EncodeToString(na.IP[6:])
return strings.ToLower(base32) + ".onion" return strings.ToLower(base32) + ".onion"
} }
@ -859,11 +857,8 @@ func (a *AddrManager) Attempt(addr *wire.NetAddress) {
return return
} }
// set last tried time to now // set last tried time to now
now := time.Now()
ka.mtx.Lock()
ka.attempts++ ka.attempts++
ka.lastattempt = now ka.lastattempt = time.Now()
ka.mtx.Unlock()
} }
// Connected Marks the given address as currently connected and working at the // Connected Marks the given address as currently connected and working at the
@ -882,12 +877,10 @@ func (a *AddrManager) Connected(addr *wire.NetAddress) {
// so. // so.
now := time.Now() now := time.Now()
if now.After(ka.na.Timestamp.Add(time.Minute * 20)) { if now.After(ka.na.Timestamp.Add(time.Minute * 20)) {
// ka.NA is immutable, so replace it. // ka.na is immutable, so replace it.
naCopy := *ka.na naCopy := *ka.na
naCopy.Timestamp = time.Now() naCopy.Timestamp = time.Now()
ka.mtx.Lock()
ka.na = &naCopy ka.na = &naCopy
ka.mtx.Unlock()
} }
} }
@ -906,13 +899,11 @@ func (a *AddrManager) Good(addr *wire.NetAddress) {
// ka.Timestamp is not updated here to avoid leaking information // ka.Timestamp is not updated here to avoid leaking information
// about currently connected peers. // about currently connected peers.
now := time.Now() now := time.Now()
ka.mtx.Lock()
ka.lastsuccess = now ka.lastsuccess = now
ka.lastattempt = now ka.lastattempt = now
ka.attempts = 0 ka.attempts = 0
ka.mtx.Unlock() // tried and refs synchronized via a.mtx
// move to tried set, optionally evicting other addresses if need. // move to tried set, optionally evicting other addresses if neeed.
if ka.tried { if ka.tried {
return return
} }
@ -994,16 +985,14 @@ func (a *AddrManager) SetServices(addr *wire.NetAddress, services wire.ServiceFl
// Update the services if needed. // Update the services if needed.
if ka.na.Services != services { if ka.na.Services != services {
// ka.NA is immutable, so replace it. // ka.na is immutable, so replace it.
naCopy := *ka.na naCopy := *ka.na
naCopy.Services = services naCopy.Services = services
ka.mtx.Lock()
ka.na = &naCopy ka.na = &naCopy
ka.mtx.Unlock()
} }
} }
// AddLocalAddress adds NA to the list of known local addresses to advertise // AddLocalAddress adds na to the list of known local addresses to advertise
// with the given priority. // with the given priority.
func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error { func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error {
if !IsRoutable(na) { if !IsRoutable(na) {
@ -1015,13 +1004,13 @@ func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPrior
key := NetAddressKey(na) key := NetAddressKey(na)
la, ok := a.localAddresses[key] la, ok := a.localAddresses[key]
if !ok || la.Score < priority { if !ok || la.score < priority {
if ok { if ok {
la.Score = priority + 1 la.score = priority + 1
} else { } else {
a.localAddresses[key] = &LocalAddress{ a.localAddresses[key] = &localAddress{
NA: na, na: na,
Score: priority, score: priority,
} }
} }
} }
@ -1117,12 +1106,12 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
var bestscore AddressPriority var bestscore AddressPriority
var bestAddress *wire.NetAddress var bestAddress *wire.NetAddress
for _, la := range a.localAddresses { for _, la := range a.localAddresses {
reach := getReachabilityFrom(la.NA, remoteAddr) reach := getReachabilityFrom(la.na, remoteAddr)
if reach > bestreach || if reach > bestreach ||
(reach == bestreach && la.Score > bestscore) { (reach == bestreach && la.score > bestscore) {
bestreach = reach bestreach = reach
bestscore = la.Score bestscore = la.score
bestAddress = la.NA bestAddress = la.na
} }
} }
if bestAddress != nil { if bestAddress != nil {
@ -1146,15 +1135,6 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
return bestAddress return bestAddress
} }
// LocalAddresses returns the list of local addresses for our node.
func (a *AddrManager) LocalAddresses() []*LocalAddress {
var addrs []*LocalAddress
for _, addr := range a.localAddresses {
addrs = append(addrs, addr)
}
return addrs
}
// New returns a new bitcoin address manager. // New returns a new bitcoin address manager.
// Use Start to begin processing asynchronous address updates. // Use Start to begin processing asynchronous address updates.
func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager { func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
@ -1163,7 +1143,7 @@ func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager
lookupFunc: lookupFunc, lookupFunc: lookupFunc,
rand: rand.New(rand.NewSource(time.Now().UnixNano())), rand: rand.New(rand.NewSource(time.Now().UnixNano())),
quit: make(chan struct{}), quit: make(chan struct{}),
localAddresses: make(map[string]*LocalAddress), localAddresses: make(map[string]*localAddress),
version: serialisationVersion, version: serialisationVersion,
} }
am.reset() am.reset()

View file

@ -7,7 +7,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address. // randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.

View file

@ -12,8 +12,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/lbryio/lbcd/addrmgr" "github.com/btcsuite/btcd/addrmgr"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// naTest is used to describe a test to be performed against the NetAddressKey // naTest is used to describe a test to be performed against the NetAddressKey
@ -34,61 +34,61 @@ var someIP = "173.194.115.66"
func addNaTests() { func addNaTests() {
// IPv4 // IPv4
// Localhost // Localhost
addNaTest("127.0.0.1", 9244, "127.0.0.1:9244") addNaTest("127.0.0.1", 8333, "127.0.0.1:8333")
addNaTest("127.0.0.1", 9245, "127.0.0.1:9245") addNaTest("127.0.0.1", 8334, "127.0.0.1:8334")
// Class A // Class A
addNaTest("1.0.0.1", 9244, "1.0.0.1:9244") addNaTest("1.0.0.1", 8333, "1.0.0.1:8333")
addNaTest("2.2.2.2", 9245, "2.2.2.2:9245") addNaTest("2.2.2.2", 8334, "2.2.2.2:8334")
addNaTest("27.253.252.251", 9246, "27.253.252.251:9246") addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
addNaTest("123.3.2.1", 9247, "123.3.2.1:9247") addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
// Private Class A // Private Class A
addNaTest("10.0.0.1", 9244, "10.0.0.1:9244") addNaTest("10.0.0.1", 8333, "10.0.0.1:8333")
addNaTest("10.1.1.1", 9245, "10.1.1.1:9245") addNaTest("10.1.1.1", 8334, "10.1.1.1:8334")
addNaTest("10.2.2.2", 9246, "10.2.2.2:9246") addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
addNaTest("10.10.10.10", 9247, "10.10.10.10:9247") addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
// Class B // Class B
addNaTest("128.0.0.1", 9244, "128.0.0.1:9244") addNaTest("128.0.0.1", 8333, "128.0.0.1:8333")
addNaTest("129.1.1.1", 9245, "129.1.1.1:9245") addNaTest("129.1.1.1", 8334, "129.1.1.1:8334")
addNaTest("180.2.2.2", 9246, "180.2.2.2:9246") addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
addNaTest("191.10.10.10", 9247, "191.10.10.10:9247") addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
// Private Class B // Private Class B
addNaTest("172.16.0.1", 9244, "172.16.0.1:9244") addNaTest("172.16.0.1", 8333, "172.16.0.1:8333")
addNaTest("172.16.1.1", 9245, "172.16.1.1:9245") addNaTest("172.16.1.1", 8334, "172.16.1.1:8334")
addNaTest("172.16.2.2", 9246, "172.16.2.2:9246") addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
addNaTest("172.16.172.172", 9247, "172.16.172.172:9247") addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
// Class C // Class C
addNaTest("193.0.0.1", 9244, "193.0.0.1:9244") addNaTest("193.0.0.1", 8333, "193.0.0.1:8333")
addNaTest("200.1.1.1", 9245, "200.1.1.1:9245") addNaTest("200.1.1.1", 8334, "200.1.1.1:8334")
addNaTest("205.2.2.2", 9246, "205.2.2.2:9246") addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
addNaTest("223.10.10.10", 9247, "223.10.10.10:9247") addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
// Private Class C // Private Class C
addNaTest("192.168.0.1", 9244, "192.168.0.1:9244") addNaTest("192.168.0.1", 8333, "192.168.0.1:8333")
addNaTest("192.168.1.1", 9245, "192.168.1.1:9245") addNaTest("192.168.1.1", 8334, "192.168.1.1:8334")
addNaTest("192.168.2.2", 9246, "192.168.2.2:9246") addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
addNaTest("192.168.192.192", 9247, "192.168.192.192:9247") addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
// IPv6 // IPv6
// Localhost // Localhost
addNaTest("::1", 9244, "[::1]:9244") addNaTest("::1", 8333, "[::1]:8333")
addNaTest("fe80::1", 9245, "[fe80::1]:9245") addNaTest("fe80::1", 8334, "[fe80::1]:8334")
// Link-local // Link-local
addNaTest("fe80::1:1", 9244, "[fe80::1:1]:9244") addNaTest("fe80::1:1", 8333, "[fe80::1:1]:8333")
addNaTest("fe91::2:2", 9245, "[fe91::2:2]:9245") addNaTest("fe91::2:2", 8334, "[fe91::2:2]:8334")
addNaTest("fea2::3:3", 9246, "[fea2::3:3]:9246") addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
addNaTest("feb3::4:4", 9247, "[feb3::4:4]:9247") addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
// Site-local // Site-local
addNaTest("fec0::1:1", 9244, "[fec0::1:1]:9244") addNaTest("fec0::1:1", 8333, "[fec0::1:1]:8333")
addNaTest("fed1::2:2", 9245, "[fed1::2:2]:9245") addNaTest("fed1::2:2", 8334, "[fed1::2:2]:8334")
addNaTest("fee2::3:3", 9246, "[fee2::3:3]:9246") addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
addNaTest("fef3::4:4", 9247, "[fef3::4:4]:9247") addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
} }
func addNaTest(ip string, port uint16, want string) { func addNaTest(ip string, port uint16, want string) {
@ -119,7 +119,7 @@ func TestAddAddressByIP(t *testing.T) {
err error err error
}{ }{
{ {
someIP + ":9244", someIP + ":8333",
nil, nil,
}, },
{ {
@ -127,7 +127,7 @@ func TestAddAddressByIP(t *testing.T) {
addrErr, addrErr,
}, },
{ {
someIP[:12] + ":9244", someIP[:12] + ":8333",
fmtErr, fmtErr,
}, },
{ {
@ -212,7 +212,7 @@ func TestAttempt(t *testing.T) {
n := addrmgr.New("testattempt", lookupFunc) n := addrmgr.New("testattempt", lookupFunc)
// Add a new address and get it // Add a new address and get it
err := n.AddAddressByIP(someIP + ":9244") err := n.AddAddressByIP(someIP + ":8333")
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }
@ -234,7 +234,7 @@ func TestConnected(t *testing.T) {
n := addrmgr.New("testconnected", lookupFunc) n := addrmgr.New("testconnected", lookupFunc)
// Add a new address and get it // Add a new address and get it
err := n.AddAddressByIP(someIP + ":9244") err := n.AddAddressByIP(someIP + ":8333")
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }
@ -261,14 +261,14 @@ func TestNeedMoreAddresses(t *testing.T) {
var err error var err error
for i := 0; i < addrsToAdd; i++ { for i := 0; i < addrsToAdd; i++ {
s := fmt.Sprintf("%d.%d.173.147:9244", i/128+60, i%128+60) s := fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60)
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork) addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
if err != nil { if err != nil {
t.Errorf("Failed to turn %s into an address: %v", s, err) t.Errorf("Failed to turn %s into an address: %v", s, err)
} }
} }
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0) srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
n.AddAddresses(addrs, srcAddr) n.AddAddresses(addrs, srcAddr)
numAddrs := n.NumAddresses() numAddrs := n.NumAddresses()
@ -289,14 +289,14 @@ func TestGood(t *testing.T) {
var err error var err error
for i := 0; i < addrsToAdd; i++ { for i := 0; i < addrsToAdd; i++ {
s := fmt.Sprintf("%d.173.147.%d:9244", i/64+60, i%64+60) s := fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60)
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork) addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
if err != nil { if err != nil {
t.Errorf("Failed to turn %s into an address: %v", s, err) t.Errorf("Failed to turn %s into an address: %v", s, err)
} }
} }
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0) srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
n.AddAddresses(addrs, srcAddr) n.AddAddresses(addrs, srcAddr)
for _, addr := range addrs { for _, addr := range addrs {
@ -323,7 +323,7 @@ func TestGetAddress(t *testing.T) {
} }
// Add a new address and get it // Add a new address and get it
err := n.AddAddressByIP(someIP + ":9244") err := n.AddAddressByIP(someIP + ":8333")
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }

View file

@ -5,7 +5,7 @@
/* /*
Package addrmgr implements concurrency safe Bitcoin address manager. Package addrmgr implements concurrency safe Bitcoin address manager.
# Address Manager Overview Address Manager Overview
In order maintain the peer-to-peer Bitcoin network, there needs to be a source In order maintain the peer-to-peer Bitcoin network, there needs to be a source
of addresses to connect to as nodes come and go. The Bitcoin protocol provides of addresses to connect to as nodes come and go. The Bitcoin protocol provides

View file

@ -7,7 +7,7 @@ package addrmgr
import ( import (
"time" "time"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
func TstKnownAddressIsBad(ka *KnownAddress) bool { func TstKnownAddressIsBad(ka *KnownAddress) bool {

View file

@ -5,16 +5,14 @@
package addrmgr package addrmgr
import ( import (
"sync"
"time" "time"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// KnownAddress tracks information about a known network address that is used // KnownAddress tracks information about a known network address that is used
// to determine how viable an address is. // to determine how viable an address is.
type KnownAddress struct { type KnownAddress struct {
mtx sync.RWMutex // na and lastattempt
na *wire.NetAddress na *wire.NetAddress
srcAddr *wire.NetAddress srcAddr *wire.NetAddress
attempts int attempts int
@ -27,28 +25,19 @@ type KnownAddress struct {
// NetAddress returns the underlying wire.NetAddress associated with the // NetAddress returns the underlying wire.NetAddress associated with the
// known address. // known address.
func (ka *KnownAddress) NetAddress() *wire.NetAddress { func (ka *KnownAddress) NetAddress() *wire.NetAddress {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.na return ka.na
} }
// LastAttempt returns the last time the known address was attempted. // LastAttempt returns the last time the known address was attempted.
func (ka *KnownAddress) LastAttempt() time.Time { func (ka *KnownAddress) LastAttempt() time.Time {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.lastattempt return ka.lastattempt
} }
// Services returns the services supported by the peer with the known address. // Services returns the services supported by the peer with the known address.
func (ka *KnownAddress) Services() wire.ServiceFlag { func (ka *KnownAddress) Services() wire.ServiceFlag {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.na.Services return ka.na.Services
} }
// The unexported methods, chance and isBad, are used from within AddrManager
// where KnownAddress field access is synchronized via it's own Mutex.
// chance returns the selection probability for a known address. The priority // chance returns the selection probability for a known address. The priority
// depends upon how recently the address has been seen, how recently it was last // depends upon how recently the address has been seen, how recently it was last
// attempted and how often attempts to connect to it have failed. // attempted and how often attempts to connect to it have failed.

View file

@ -9,8 +9,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/lbryio/lbcd/addrmgr" "github.com/btcsuite/btcd/addrmgr"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
func TestChance(t *testing.T) { func TestChance(t *testing.T) {

View file

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"net" "net"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
var ( var (

View file

@ -8,8 +8,8 @@ import (
"net" "net"
"testing" "testing"
"github.com/lbryio/lbcd/addrmgr" "github.com/btcsuite/btcd/addrmgr"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// TestIPTypes ensures the various functions which determine the type of an IP // TestIPTypes ensures the various functions which determine the type of an IP
@ -39,7 +39,7 @@ func TestIPTypes(t *testing.T) {
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
local, valid, routable bool) ipTest { local, valid, routable bool) ipTest {
nip := net.ParseIP(ip) nip := net.ParseIP(ip)
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork) na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380, test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable} rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
return test return test
@ -192,7 +192,7 @@ func TestGroupKey(t *testing.T) {
for i, test := range tests { for i, test := range tests {
nip := net.ParseIP(test.ip) nip := net.ParseIP(test.ip)
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork) na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
if key := addrmgr.GroupKey(&na); key != test.expected { if key := addrmgr.GroupKey(&na); key != test.expected {
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+ t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
"- got '%s', want '%s'", i, test.name, "- got '%s', want '%s'", i, test.name,

View file

@ -1,9 +1,30 @@
blockchain blockchain
========== ==========
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain)
### Bitcoin Chain Processing Overview Package blockchain implements bitcoin block handling and chain selection rules.
The test coverage is currently only around 60%, but will be increasing over
time. See `test_coverage.txt` for the gocov coverage report. Alternatively, if
you are running a POSIX OS, you can run the `cov_report.sh` script for a
real-time report. Package blockchain is licensed under the liberal ISC license.
There is an associated blog post about the release of this package
[here](https://blog.conformal.com/btcchain-the-bitcoin-chain-package-from-bctd/).
This package has intentionally been designed so it can be used as a standalone
package for any projects needing to handle processing of blocks into the bitcoin
block chain.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/blockchain
```
## Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of series of validation rules. The following list serves as a general outline of
@ -37,3 +58,46 @@ is by no means exhaustive:
- Run the transaction scripts to verify the spender is allowed to spend the - Run the transaction scripts to verify the spender is allowed to spend the
coins coins
- Insert the block into the block database - Insert the block into the block database
## Examples
* [ProcessBlock Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BlockChain-ProcessBlock)
Demonstrates how to create a new chain instance and use ProcessBlock to
attempt to add a block to the chain. This example intentionally
attempts to insert a duplicate genesis block to illustrate how an invalid
block is handled.
* [CompactToBig Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-CompactToBig)
Demonstrates how to convert the compact "bits" in a block header which
represent the target difficulty to a big integer and display it using the
typical hex notation.
* [BigToCompact Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BigToCompact)
Demonstrates how to convert a target difficulty into the
compact "bits" in a block header which represent that target difficulty.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package blockchain is licensed under the [copyfree](http://copyfree.org) ISC
License.

View file

@ -7,8 +7,8 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// maybeAcceptBlock potentially accepts a block into the block chain and, if // maybeAcceptBlock potentially accepts a block into the block chain and, if
@ -84,11 +84,9 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
// Notify the caller that the new block was accepted into the block // Notify the caller that the new block was accepted into the block
// chain. The caller would typically want to react by relaying the // chain. The caller would typically want to react by relaying the
// inventory to other peers. // inventory to other peers.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockAccepted, block) b.sendNotification(NTBlockAccepted, block)
b.chainLock.Lock()
return isMainChain, nil return isMainChain, nil
} }

View file

@ -6,12 +6,14 @@ package blockchain
import ( import (
"testing" "testing"
"github.com/btcsuite/btcutil"
) )
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase // BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
// function. // function.
func BenchmarkIsCoinBase(b *testing.B) { func BenchmarkIsCoinBase(b *testing.B) {
tx, _ := GetBlock100000().Tx(1) tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
IsCoinBase(tx) IsCoinBase(tx)
@ -21,9 +23,9 @@ func BenchmarkIsCoinBase(b *testing.B) {
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx // BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
// function. // function.
func BenchmarkIsCoinBaseTx(b *testing.B) { func BenchmarkIsCoinBaseTx(b *testing.B) {
tx, _ := GetBlock100000().Tx(1) tx := Block100000.Transactions[1]
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
IsCoinBaseTx(tx.MsgTx()) IsCoinBaseTx(tx)
} }
} }

View file

@ -10,10 +10,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// blockStatus is a bit field representing the validation state of the block. // blockStatus is a bit field representing the validation state of the block.
@ -93,7 +93,6 @@ type blockNode struct {
nonce uint32 nonce uint32
timestamp int64 timestamp int64
merkleRoot chainhash.Hash merkleRoot chainhash.Hash
claimTrie chainhash.Hash
// status is a bitfield representing the validation state of the block. The // status is a bitfield representing the validation state of the block. The
// status field, unlike the other fields, may be written to and so should // status field, unlike the other fields, may be written to and so should
@ -115,7 +114,6 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
nonce: blockHeader.Nonce, nonce: blockHeader.Nonce,
timestamp: blockHeader.Timestamp.Unix(), timestamp: blockHeader.Timestamp.Unix(),
merkleRoot: blockHeader.MerkleRoot, merkleRoot: blockHeader.MerkleRoot,
claimTrie: blockHeader.ClaimTrie,
} }
if parent != nil { if parent != nil {
node.parent = parent node.parent = parent
@ -146,7 +144,6 @@ func (node *blockNode) Header() wire.BlockHeader {
Version: node.version, Version: node.version,
PrevBlock: *prevHash, PrevBlock: *prevHash,
MerkleRoot: node.merkleRoot, MerkleRoot: node.merkleRoot,
ClaimTrie: node.claimTrie,
Timestamp: time.Unix(node.timestamp, 0), Timestamp: time.Unix(node.timestamp, 0),
Bits: node.bits, Bits: node.bits,
Nonce: node.nonce, Nonce: node.nonce,

View file

@ -8,18 +8,15 @@ package blockchain
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"math/big"
"sync" "sync"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/claimtrie"
) )
const ( const (
@ -37,7 +34,6 @@ const (
// from the block being located. // from the block being located.
// //
// For example, assume a block chain with a side chain as depicted below: // For example, assume a block chain with a side chain as depicted below:
//
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18 // genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a // \-> 16a -> 17a
// //
@ -118,12 +114,6 @@ type BlockChain struct {
// fields in this struct below this point. // fields in this struct below this point.
chainLock sync.RWMutex chainLock sync.RWMutex
// notificationSendLock helps us only process one block at a time.
// It's definitely a hack. DCRD has much better structure in this regard.
// Without this you will get an error if you invalidate a block and then generate more right after.
// Taken from https://github.com/gcash/bchd/pull/308
notificationSendLock sync.Mutex
// These fields are related to the memory block index. They both have // These fields are related to the memory block index. They both have
// their own locks, however they are often also protected by the chain // their own locks, however they are often also protected by the chain
// lock to help prevent logic races when blocks are being processed. // lock to help prevent logic races when blocks are being processed.
@ -190,8 +180,6 @@ type BlockChain struct {
// certain blockchain events. // certain blockchain events.
notificationsLock sync.RWMutex notificationsLock sync.RWMutex
notifications []NotificationCallback notifications []NotificationCallback
claimTrie *claimtrie.ClaimTrie
} }
// HaveBlock returns whether or not the chain instance has the block represented // HaveBlock returns whether or not the chain instance has the block represented
@ -207,15 +195,6 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
return exists || b.IsKnownOrphan(hash), nil return exists || b.IsKnownOrphan(hash), nil
} }
// GetWarnings returns a bool for whether unknownRules
// has been warned.
func (b *BlockChain) GetWarnings() bool {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
return b.unknownRulesWarned
}
// IsKnownOrphan returns whether the passed hash is currently a known orphan. // IsKnownOrphan returns whether the passed hash is currently a known orphan.
// Keep in mind that only a limited number of orphans are held onto for a // Keep in mind that only a limited number of orphans are held onto for a
// limited amount of time, so this function must not be used as an absolute // limited amount of time, so this function must not be used as an absolute
@ -489,7 +468,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView
// LockTimeToSequence converts the passed relative locktime to a sequence // LockTimeToSequence converts the passed relative locktime to a sequence
// number in accordance to BIP-68. // number in accordance to BIP-68.
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki // See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
// - (Compatibility) // * (Compatibility)
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 { func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
// If we're expressing the relative lock time in blocks, then the // If we're expressing the relative lock time in blocks, then the
// corresponding sequence number is simply the desired input age. // corresponding sequence number is simply the desired input age.
@ -592,8 +571,7 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
} }
// No warnings about unknown rules until the chain is current. // No warnings about unknown rules until the chain is current.
current := b.isCurrent() if b.isCurrent() {
if current {
// Warn if any unknown new rules are either about to activate or // Warn if any unknown new rules are either about to activate or
// have already been activated. // have already been activated.
if err := b.warnUnknownRuleActivations(node); err != nil { if err := b.warnUnknownRuleActivations(node); err != nil {
@ -601,14 +579,6 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
} }
} }
// Handle LBRY Claim Scripts
if b.claimTrie != nil {
shouldFlush := current && b.chainParams.Net != wire.TestNet
if err := b.ParseClaimScripts(block, node, view, shouldFlush); err != nil {
return ruleError(ErrBadClaimTrie, err.Error())
}
}
// Write any block status changes to DB before updating best state. // Write any block status changes to DB before updating best state.
err := b.index.flushToDB() err := b.index.flushToDB()
if err != nil { if err != nil {
@ -691,11 +661,9 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
// Notify the caller that the block was connected to the main chain. // Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as // The caller would typically want to react with actions such as
// updating wallets. // updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockConnected, block) b.sendNotification(NTBlockConnected, block)
b.chainLock.Lock()
return nil return nil
} }
@ -793,12 +761,6 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
return err return err
} }
if b.claimTrie != nil {
if err = b.claimTrie.ResetHeight(node.parent.height); err != nil {
return err
}
}
// Prune fully spent entries and mark all entries in the view unmodified // Prune fully spent entries and mark all entries in the view unmodified
// now that the modifications have been committed to the database. // now that the modifications have been committed to the database.
view.commit() view.commit()
@ -818,11 +780,9 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
// Notify the caller that the block was disconnected from the main // Notify the caller that the block was disconnected from the main
// chain. The caller would typically want to react with actions such as // chain. The caller would typically want to react with actions such as
// updating wallets. // updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockDisconnected, block) b.sendNotification(NTBlockDisconnected, block)
b.chainLock.Lock()
return nil return nil
} }
@ -1006,7 +966,6 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
err = b.checkConnectBlock(n, block, view, nil) err = b.checkConnectBlock(n, block, view, nil)
if err != nil { if err != nil {
if _, ok := err.(RuleError); ok { if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(n, statusValid)
b.index.SetStatusFlags(n, statusValidateFailed) b.index.SetStatusFlags(n, statusValidateFailed)
for de := e.Next(); de != nil; de = de.Next() { for de := e.Next(); de != nil; de = de.Next() {
dn := de.Value.(*blockNode) dn := de.Value.(*blockNode)
@ -1144,7 +1103,6 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
if err == nil { if err == nil {
b.index.SetStatusFlags(node, statusValid) b.index.SetStatusFlags(node, statusValid)
} else if _, ok := err.(RuleError); ok { } else if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(node, statusValid)
b.index.SetStatusFlags(node, statusValidateFailed) b.index.SetStatusFlags(node, statusValidateFailed)
} else { } else {
return false, err return false, err
@ -1179,7 +1137,6 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
// that status of the block as invalid and flush the // that status of the block as invalid and flush the
// index state to disk before returning with the error. // index state to disk before returning with the error.
if _, ok := err.(RuleError); ok { if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(node, statusValid)
b.index.SetStatusFlags( b.index.SetStatusFlags(
node, statusValidateFailed, node, statusValidateFailed,
) )
@ -1251,7 +1208,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
// factors are used to guess, but the key factors that allow the chain to // factors are used to guess, but the key factors that allow the chain to
// believe it is current are: // believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled) // - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin) // - Latest block has a timestamp newer than 24 hours ago
// //
// This function MUST be called with the chain state lock held (for reads). // This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) isCurrent() bool { func (b *BlockChain) isCurrent() bool {
@ -1262,13 +1219,13 @@ func (b *BlockChain) isCurrent() bool {
return false return false
} }
// Not current if the latest best block has a timestamp before 7 hours // Not current if the latest best block has a timestamp before 24 hours
// ago. // ago.
// //
// The chain appears to be current if none of the checks reported // The chain appears to be current if none of the checks reported
// otherwise. // otherwise.
hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix() minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
return b.bestChain.Tip().timestamp >= hours return b.bestChain.Tip().timestamp >= minus24Hours
} }
// IsCurrent returns whether or not the chain believes it is current. Several // IsCurrent returns whether or not the chain believes it is current. Several
@ -1375,57 +1332,6 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro
return &node.hash, nil return &node.hash, nil
} }
// BlockAttributes desribes a Block in relation to others on the main chain.
type BlockAttributes struct {
Height int32
Confirmations int32
MedianTime time.Time
ChainWork *big.Int
PrevHash *chainhash.Hash
NextHash *chainhash.Hash
}
// BlockAttributesByHash returns BlockAttributes for the block with the given hash
// relative to other blocks in the main chain. A BestState snapshot describing
// the main chain is also returned for convenience.
//
// This function is safe for concurrent access.
func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) (
attrs *BlockAttributes, best *BestState, err error) {
best = b.BestSnapshot()
node := b.index.LookupNode(hash)
if node == nil {
str := fmt.Sprintf("block %s not found", hash)
return nil, best, errNotInMainChain(str)
}
attrs = &BlockAttributes{
Height: node.height,
Confirmations: 1 + best.Height - node.height,
MedianTime: node.CalcPastMedianTime(),
ChainWork: node.workSum,
}
if !b.bestChain.Contains(node) {
attrs.Confirmations = -1
}
// Populate prev block hash if there is one.
if node.height > 0 {
attrs.PrevHash = prevHash
}
// Populate next block hash if there is one.
if node.height < best.Height {
nextHash, err := b.BlockHashByHeight(node.height + 1)
if err != nil {
return nil, best, err
}
attrs.NextHash = nextHash
}
return attrs, best, nil
}
// HeightRange returns a range of block hashes for the given start and end // HeightRange returns a range of block hashes for the given start and end
// heights. It is inclusive of the start height and exclusive of the end // heights. It is inclusive of the start height and exclusive of the end
// height. The end height will be limited to the current main chain height. // height. The end height will be limited to the current main chain height.
@ -1708,121 +1614,6 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
return headers return headers
} }
// InvalidateBlock takes a block hash and invalidates it.
//
// This function is safe for concurrent access.
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.invalidateBlock(hash)
}
// invalidateBlock takes a block hash and invalidates it.
func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
node := b.index.LookupNode(hash)
if node == nil {
err := fmt.Errorf("block %s is not known", hash)
return err
}
// No need to invalidate if its already invalid.
if node.status.KnownInvalid() {
err := fmt.Errorf("block %s is already invalid", hash)
return err
}
if node.parent == nil {
err := fmt.Errorf("block %s has no parent", hash)
return err
}
b.index.SetStatusFlags(node, statusValidateFailed)
b.index.UnsetStatusFlags(node, statusValid)
detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
err := b.reorganizeChain(detachNodes, attachNodes)
if err != nil {
return err
}
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
n := e.Value.(*blockNode)
b.index.SetStatusFlags(n, statusInvalidAncestor)
b.index.UnsetStatusFlags(n, statusValid)
}
if writeErr := b.index.flushToDB(); writeErr != nil {
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
}
return nil
}
// ReconsiderBlock takes a block hash and allows it to be revalidated.
//
// This function is safe for concurrent access.
func (b *BlockChain) ReconsiderBlock(hash *chainhash.Hash) error {
return b.reconsiderBlock(hash)
}
// reconsiderBlock takes a block hash and allows it to be revalidated.
func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
node := b.index.LookupNode(hash)
if node == nil {
err := fmt.Errorf("block %s is not known", hash)
return err
}
// No need to reconsider, it is already valid.
if node.status.KnownValid() && !node.status.KnownInvalid() { // second clause works around old bug
err := fmt.Errorf("block %s is already valid", hash)
return err
}
// Keep a reference to the first node in the chain of invalid
// blocks so we can reprocess after status flags are updated.
firstNode := node
// Find previous node to the point where the blocks are valid again.
for n := node; n.status.KnownInvalid(); n = n.parent {
b.index.UnsetStatusFlags(n, statusInvalidAncestor)
b.index.UnsetStatusFlags(n, statusValidateFailed)
firstNode = n
}
// do we need an rlock on chainstate for this section?
var blk *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
var err error
blk, err = dbFetchBlockByNode(dbTx, firstNode)
return err
})
if err != nil {
return err
}
// Process it all again. This will take care of the
// orphans as well.
_, _, err = b.ProcessBlock(blk, BFNoDupBlockCheck)
if err != nil {
return err
}
if writeErr := b.index.flushToDB(); writeErr != nil {
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
}
return nil
}
// ClaimTrie returns the claimTrie associated wit hthe chain.
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
return b.claimTrie
}
// IndexManager provides a generic interface that the is called when blocks are // IndexManager provides a generic interface that the is called when blocks are
// connected and disconnected to and from the tip of the main chain for the // connected and disconnected to and from the tip of the main chain for the
// purpose of supporting optional indexes. // purpose of supporting optional indexes.
@ -1909,8 +1700,6 @@ type Config struct {
// This field can be nil if the caller is not interested in using a // This field can be nil if the caller is not interested in using a
// signature cache. // signature cache.
HashCache *txscript.HashCache HashCache *txscript.HashCache
ClaimTrie *claimtrie.ClaimTrie
} }
// New returns a BlockChain instance using the provided configuration details. // New returns a BlockChain instance using the provided configuration details.
@ -1947,6 +1736,7 @@ func New(config *Config) (*BlockChain, error) {
params := config.ChainParams params := config.ChainParams
targetTimespan := int64(params.TargetTimespan / time.Second) targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second) targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{ b := BlockChain{
checkpoints: config.Checkpoints, checkpoints: config.Checkpoints,
checkpointsByHeight: checkpointsByHeight, checkpointsByHeight: checkpointsByHeight,
@ -1955,8 +1745,8 @@ func New(config *Config) (*BlockChain, error) {
timeSource: config.TimeSource, timeSource: config.TimeSource,
sigCache: config.SigCache, sigCache: config.SigCache,
indexManager: config.IndexManager, indexManager: config.IndexManager,
minRetargetTimespan: targetTimespan - (targetTimespan / 8), minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan + (targetTimespan / 2), maxRetargetTimespan: targetTimespan * adjustmentFactor,
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock), blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: newBlockIndex(config.DB, params), index: newBlockIndex(config.DB, params),
hashCache: config.HashCache, hashCache: config.HashCache,
@ -1965,7 +1755,6 @@ func New(config *Config) (*BlockChain, error) {
prevOrphans: make(map[chainhash.Hash][]*orphanBlock), prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
warningCaches: newThresholdCaches(vbNumBits), warningCaches: newThresholdCaches(vbNumBits),
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments), deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
claimTrie: config.ClaimTrie,
} }
// Initialize the chain state from the passed database. When the db // Initialize the chain state from the passed database. When the db
@ -1975,20 +1764,6 @@ func New(config *Config) (*BlockChain, error) {
return nil, err return nil, err
} }
// Helper function to insert the output in genesis block in to the
// transaction database.
fn := func(dbTx database.Tx) error {
genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock)
view := NewUtxoViewpoint()
if err := view.connectTransactions(genesisBlock, nil); err != nil {
return err
}
return dbPutUtxoView(dbTx, view)
}
if err := b.db.Update(fn); err != nil {
return nil, err
}
// Perform any upgrades to the various chain-specific buckets as needed. // Perform any upgrades to the various chain-specific buckets as needed.
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil { if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
return nil, err return nil, err
@ -2008,14 +1783,6 @@ func New(config *Config) (*BlockChain, error) {
return nil, err return nil, err
} }
if b.claimTrie != nil {
err := rebuildMissingClaimTrieData(&b, config.Interrupt)
if err != nil {
b.claimTrie.Close()
return nil, err
}
}
bestNode := b.bestChain.Tip() bestNode := b.bestChain.Tip()
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)", log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns, bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
@ -2023,63 +1790,3 @@ func New(config *Config) (*BlockChain, error) {
return &b, nil return &b, nil
} }
func rebuildMissingClaimTrieData(b *BlockChain, done <-chan struct{}) error {
target := b.bestChain.Height()
if b.claimTrie.Height() == target {
return nil
}
if b.claimTrie.Height() > target {
return b.claimTrie.ResetHeight(target)
}
start := time.Now()
lastReport := time.Now()
// TODO: move this view inside the loop (or recreate it every 5 sec.)
// as accumulating all inputs has potential to use a huge amount of RAM
// but we need to get the spent inputs working for that to be possible
view := NewUtxoViewpoint()
for h := int32(0); h < target; h++ {
select {
case <-done:
return fmt.Errorf("rebuild unfinished at height %d", b.claimTrie.Height())
default:
}
n := b.bestChain.NodeByHeight(h + 1)
var block *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
var err error
block, err = dbFetchBlockByNode(dbTx, n)
return err
})
if err != nil {
return err
}
err = view.fetchInputUtxos(b.db, block)
if err != nil {
return err
}
err = view.connectTransactions(block, nil)
if err != nil {
return err
}
if h >= b.claimTrie.Height() {
err = b.ParseClaimScripts(block, n, view, false)
if err != nil {
return err
}
}
if time.Since(lastReport) > time.Second*5 {
lastReport = time.Now()
log.Infof("Rebuilding claim trie data to %d. At: %d", target, h)
}
}
log.Infof("Completed rebuilding claim trie data to %d. Took %s ",
b.claimTrie.Height(), time.Since(start))
return nil
}

View file

@ -9,12 +9,108 @@ import (
"testing" "testing"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// TestHaveBlock tests the HaveBlock API to ensure proper functionality.
func TestHaveBlock(t *testing.T) {
// Load up blocks such that there is a side chain.
// (genesis block) -> 1 -> 2 -> 3 -> 4
// \-> 3a
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_3A.dat.bz2",
}
var blocks []*btcutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Errorf("Error loading file: %v\n", err)
return
}
blocks = append(blocks, blockTmp...)
}
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("haveblock",
&chaincfg.MainNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// Since we're not dealing with the real block chain, set the coinbase
// maturity to 1.
chain.TstSetCoinbaseMaturity(1)
for i := 1; i < len(blocks); i++ {
_, isOrphan, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return
}
if isOrphan {
t.Errorf("ProcessBlock incorrectly returned block %v "+
"is an orphan\n", i)
return
}
}
// Insert an orphan block.
_, isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000),
BFNone)
if err != nil {
t.Errorf("Unable to process block: %v", err)
return
}
if !isOrphan {
t.Errorf("ProcessBlock indicated block is an not orphan when " +
"it should be\n")
return
}
tests := []struct {
hash string
want bool
}{
// Genesis block should be present (in the main chain).
{hash: chaincfg.MainNetParams.GenesisHash.String(), want: true},
// Block 3a should be present (on a side chain).
{hash: "00000000474284d20067a4d33f6a02284e6ef70764a3a26d6a5b9df52ef663dd", want: true},
// Block 100000 should be present (as an orphan).
{hash: "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506", want: true},
// Random hashes should not be available.
{hash: "123", want: false},
}
for i, test := range tests {
hash, err := chainhash.NewHashFromStr(test.hash)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
continue
}
result, err := chain.HaveBlock(hash)
if err != nil {
t.Errorf("HaveBlock #%d unexpected error: %v", i, err)
return
}
if result != test.want {
t.Errorf("HaveBlock #%d got %v want %v", i, result,
test.want)
continue
}
}
}
// TestCalcSequenceLock tests the LockTimeToSequence function, and the // TestCalcSequenceLock tests the LockTimeToSequence function, and the
// CalcSequenceLock method of a Chain instance. The tests exercise several // CalcSequenceLock method of a Chain instance. The tests exercise several
// combinations of inputs to the CalcSequenceLock function in order to ensure // combinations of inputs to the CalcSequenceLock function in order to ensure

View file

@ -12,10 +12,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (

View file

@ -11,8 +11,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work // TestErrNotInMainChain ensures the functions related to errNotInMainChain work

View file

@ -1,123 +0,0 @@
package blockchain
import (
"sort"
"strings"
btcutil "github.com/lbryio/lbcutil"
)
type ChainTip struct { // duplicate of btcjson.GetChainTipsResult to avoid circular reference
Height int64
Hash string
BranchLen int64
Status string
}
// nodeHeightSorter implements sort.Interface to allow a slice of nodes to
// be sorted by height in ascending order.
type nodeHeightSorter []ChainTip
// Len returns the number of nodes in the slice. It is part of the
// sort.Interface implementation.
func (s nodeHeightSorter) Len() int {
return len(s)
}
// Swap swaps the nodes at the passed indices. It is part of the
// sort.Interface implementation.
func (s nodeHeightSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Less returns whether the node with index i should sort before the node with
// index j. It is part of the sort.Interface implementation.
func (s nodeHeightSorter) Less(i, j int) bool {
// To ensure stable order when the heights are the same, fall back to
// sorting based on hash.
if s[i].Height == s[j].Height {
return strings.Compare(s[i].Hash, s[j].Hash) < 0
}
return s[i].Height < s[j].Height
}
// ChainTips returns information, in JSON-RPC format, about all the currently
// known chain tips in the block index.
func (b *BlockChain) ChainTips() []ChainTip {
// we need our current tip
// we also need all of our orphans that aren't in the prevOrphans
var results []ChainTip
tip := b.bestChain.Tip()
results = append(results, ChainTip{
Height: int64(tip.height),
Hash: tip.hash.String(),
BranchLen: 0,
Status: "active",
})
b.orphanLock.RLock()
defer b.orphanLock.RUnlock()
notInBestChain := func(block *btcutil.Block) bool {
node := b.bestChain.NodeByHeight(block.Height())
if node == nil {
return false
}
return node.hash.IsEqual(block.Hash())
}
for hash, orphan := range b.orphans {
if len(b.prevOrphans[hash]) > 0 {
continue
}
fork := orphan.block
for fork != nil && notInBestChain(fork) {
fork = b.orphans[*fork.Hash()].block
}
result := ChainTip{
Height: int64(orphan.block.Height()),
Hash: hash.String(),
BranchLen: int64(orphan.block.Height() - fork.Height()),
}
// Determine the status of the chain tip.
//
// active:
// The current best chain tip.
//
// invalid:
// The block or one of its ancestors is invalid.
//
// headers-only:
// The block or one of its ancestors does not have the full block data
// available which also means the block can't be validated or
// connected.
//
// valid-fork:
// The block is fully validated which implies it was probably part of
// main chain at one point and was reorganized.
//
// valid-headers:
// The full block data is available and the header is valid, but the
// block was never validated which implies it was probably never part
// of the main chain.
tipStatus := b.index.LookupNode(&hash).status
if tipStatus.KnownInvalid() {
result.Status = "invalid"
} else if !tipStatus.HaveData() {
result.Status = "headers-only"
} else if tipStatus.KnownValid() {
result.Status = "valid-fork"
} else {
result.Status = "valid-headers"
}
results = append(results, result)
}
// Generate the results sorted by descending height.
sort.Sort(sort.Reverse(nodeHeightSorter(results)))
return results
}

View file

@ -36,12 +36,10 @@ func fastLog2Floor(n uint32) uint8 {
// for comparing chains. // for comparing chains.
// //
// For example, assume a block chain with a side chain as depicted below: // For example, assume a block chain with a side chain as depicted below:
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 // genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a // \-> 4a -> 5a -> 6a
// //
// The chain view for the branch ending in 6a consists of: // The chain view for the branch ending in 6a consists of:
//
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a // genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
type chainView struct { type chainView struct {
mtx sync.Mutex mtx sync.Mutex
@ -260,13 +258,11 @@ func (c *chainView) next(node *blockNode) *blockNode {
// view. // view.
// //
// For example, assume a block chain with a side chain as depicted below: // For example, assume a block chain with a side chain as depicted below:
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 // genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a // \-> 4a -> 5a -> 6a
// //
// Further, assume the view is for the longer chain depicted above. That is to // Further, assume the view is for the longer chain depicted above. That is to
// say it consists of: // say it consists of:
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 // genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// //
// Invoking this function with block node 5 would return block node 6 while // Invoking this function with block node 5 would return block node 6 while
@ -325,13 +321,11 @@ func (c *chainView) findFork(node *blockNode) *blockNode {
// the chain view. It will return nil if there is no common block. // the chain view. It will return nil if there is no common block.
// //
// For example, assume a block chain with a side chain as depicted below: // For example, assume a block chain with a side chain as depicted below:
//
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8 // genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
// \-> 6a -> 7a // \-> 6a -> 7a
// //
// Further, assume the view is for the longer chain depicted above. That is to // Further, assume the view is for the longer chain depicted above. That is to
// say it consists of: // say it consists of:
//
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8. // genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
// //
// Invoking this function with block node 7a would return block node 5 while // Invoking this function with block node 7a would return block node 5 while

View file

@ -10,7 +10,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// testNoncePrng provides a deterministic prng for the nonce in generated fake // testNoncePrng provides a deterministic prng for the nonce in generated fake

View file

@ -8,10 +8,10 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// CheckpointConfirmations is the number of blocks before the end of the current // CheckpointConfirmations is the number of blocks before the end of the current
@ -172,8 +172,7 @@ func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
func isNonstandardTransaction(tx *btcutil.Tx) bool { func isNonstandardTransaction(tx *btcutil.Tx) bool {
// Check all of the output public key scripts for non-standard scripts. // Check all of the output public key scripts for non-standard scripts.
for _, txOut := range tx.MsgTx().TxOut { for _, txOut := range tx.MsgTx().TxOut {
stripped := txscript.StripClaimScriptPrefix(txOut.PkScript) scriptClass := txscript.GetScriptClass(txOut.PkScript)
scriptClass := txscript.GetScriptClass(stripped)
if scriptClass == txscript.NonStandardTy { if scriptClass == txscript.NonStandardTy {
return true return true
} }

View file

@ -1,183 +0,0 @@
package blockchain
import (
"bytes"
"fmt"
"github.com/pkg/errors"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcd/claimtrie"
"github.com/lbryio/lbcd/claimtrie/change"
"github.com/lbryio/lbcd/claimtrie/node"
"github.com/lbryio/lbcd/claimtrie/normalization"
)
func (b *BlockChain) SetClaimtrieHeader(block *btcutil.Block, view *UtxoViewpoint) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
err := b.ParseClaimScripts(block, nil, view, false)
if err != nil {
return errors.Wrapf(err, "in parse claim scripts")
}
block.MsgBlock().Header.ClaimTrie = *b.claimTrie.MerkleHash()
err = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
return errors.Wrapf(err, "in reset height")
}
func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view *UtxoViewpoint, shouldFlush bool) error {
ht := block.Height()
for _, tx := range block.Transactions() {
h := handler{ht, tx, view, map[string][]byte{}}
if err := h.handleTxIns(b.claimTrie); err != nil {
return err
}
if err := h.handleTxOuts(b.claimTrie); err != nil {
return err
}
}
err := b.claimTrie.AppendBlock(bn == nil)
if err != nil {
return errors.Wrapf(err, "in append block")
}
if shouldFlush {
b.claimTrie.FlushToDisk()
}
hash := b.claimTrie.MerkleHash()
if bn != nil && bn.claimTrie != *hash {
// undo our AppendBlock call as we've decided that our interpretation of the block data is incorrect,
// or that the person who made the block assembled the pieces incorrectly.
_ = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
return errors.Errorf("height: %d, computed hash: %s != header's ClaimTrie: %s", ht, *hash, bn.claimTrie)
}
return nil
}
type handler struct {
ht int32
tx *btcutil.Tx
view *UtxoViewpoint
spent map[string][]byte
}
func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error {
if IsCoinBase(h.tx) {
return nil
}
for _, txIn := range h.tx.MsgTx().TxIn {
op := txIn.PreviousOutPoint
e := h.view.LookupEntry(op)
if e == nil {
return errors.Errorf("missing input in view for %s", op.String())
}
cs, err := txscript.ExtractClaimScript(e.pkScript)
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
continue
}
if err != nil {
return err
}
var id change.ClaimID
name := cs.Name // name of the previous one (that we're now spending)
switch cs.Opcode {
case txscript.OP_CLAIMNAME: // OP code from previous transaction
id = change.NewClaimID(op) // claimID of the previous item now being spent
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
err = ct.SpendClaim(name, op, id)
case txscript.OP_UPDATECLAIM:
copy(id[:], cs.ClaimID)
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
err = ct.SpendClaim(name, op, id)
case txscript.OP_SUPPORTCLAIM:
copy(id[:], cs.ClaimID)
err = ct.SpendSupport(name, op, id)
}
if err != nil {
return errors.Wrapf(err, "handleTxIns")
}
}
return nil
}
func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error {
for i, txOut := range h.tx.MsgTx().TxOut {
op := *wire.NewOutPoint(h.tx.Hash(), uint32(i))
cs, err := txscript.ExtractClaimScript(txOut.PkScript)
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
continue
}
if err != nil {
return err
}
var id change.ClaimID
name := cs.Name
amt := txOut.Value
switch cs.Opcode {
case txscript.OP_CLAIMNAME:
id = change.NewClaimID(op)
err = ct.AddClaim(name, op, id, amt)
case txscript.OP_SUPPORTCLAIM:
copy(id[:], cs.ClaimID)
err = ct.AddSupport(name, op, amt, id)
case txscript.OP_UPDATECLAIM:
// old code wouldn't run the update if name or claimID didn't match existing data
// that was a safety feature, but it should have rejected the transaction instead
// TODO: reject transactions with invalid update commands
copy(id[:], cs.ClaimID)
normName := normalization.NormalizeIfNecessary(name, ct.Height())
if !bytes.Equal(h.spent[id.Key()], normName) {
node.LogOnce(fmt.Sprintf("Invalid update operation: name or ID mismatch at %d for: %s, %s",
ct.Height(), normName, id.String()))
continue
}
delete(h.spent, id.Key())
err = ct.UpdateClaim(name, op, amt, id)
}
if err != nil {
return errors.Wrapf(err, "handleTxOuts")
}
}
return nil
}
func (b *BlockChain) GetNamesChangedInBlock(height int32) ([]string, error) {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
return b.claimTrie.NamesChangedInBlock(height)
}
func (b *BlockChain) GetClaimsForName(height int32, name string) (string, *node.Node, error) {
normalizedName := normalization.NormalizeIfNecessary([]byte(name), height)
b.chainLock.RLock()
defer b.chainLock.RUnlock()
n, err := b.claimTrie.NodeAt(height, normalizedName)
if err != nil {
return string(normalizedName), nil, err
}
if n == nil {
return string(normalizedName), nil, fmt.Errorf("name does not exist at height %d: %s", height, name)
}
n.SortClaimsByBid()
return string(normalizedName), n, nil
}

View file

@ -5,7 +5,6 @@
package blockchain package blockchain
import ( import (
"bytes"
"compress/bzip2" "compress/bzip2"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
@ -15,13 +14,13 @@ import (
"strings" "strings"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
_ "github.com/lbryio/lbcd/database/ffldb" _ "github.com/btcsuite/btcd/database/ffldb"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (
@ -64,13 +63,13 @@ func isSupportedDbType(dbType string) bool {
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) { func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
filename = filepath.Join("testdata/", filename) filename = filepath.Join("testdata/", filename)
var network = 0xd9b4bef9 // bitcoin's network ID var network = wire.MainNet
var dr io.Reader var dr io.Reader
var fi io.ReadCloser var fi io.ReadCloser
fi, err = os.Open(filename) fi, err = os.Open(filename)
if err != nil { if err != nil {
return blocks, err return
} }
if strings.HasSuffix(filename, ".bz2") { if strings.HasSuffix(filename, ".bz2") {
@ -96,7 +95,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
break break
} }
if rintbuf != uint32(network) { if rintbuf != uint32(network) {
continue break
} }
err = binary.Read(dr, binary.LittleEndian, &rintbuf) err = binary.Read(dr, binary.LittleEndian, &rintbuf)
blocklen := rintbuf blocklen := rintbuf
@ -106,20 +105,14 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
// read block // read block
dr.Read(rbytes) dr.Read(rbytes)
// inject claimtrie:
tail := make([]byte, len(rbytes)-68)
copy(tail, rbytes[68:])
rbytes = append(rbytes[:68], bytes.Repeat([]byte{23}, chainhash.HashSize)...)
rbytes = append(rbytes, tail...)
block, err = btcutil.NewBlockFromBytes(rbytes) block, err = btcutil.NewBlockFromBytes(rbytes)
if err != nil { if err != nil {
return blocks, err return
} }
blocks = append(blocks, block) blocks = append(blocks, block)
} }
return blocks, err return
} }
// chainSetup is used to create a new db and chain instance with the genesis // chainSetup is used to create a new db and chain instance with the genesis

View file

@ -5,8 +5,8 @@
package blockchain package blockchain
import ( import (
"github.com/lbryio/lbcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View file

@ -8,7 +8,7 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
) )
var ( var (
@ -42,11 +42,9 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
// Like IEEE754 floating point, there are three basic components: the sign, // Like IEEE754 floating point, there are three basic components: the sign,
// the exponent, and the mantissa. They are broken out as follows: // the exponent, and the mantissa. They are broken out as follows:
// //
// - the most significant 8 bits represent the unsigned base 256 exponent // * the most significant 8 bits represent the unsigned base 256 exponent
// // * bit 23 (the 24th bit) represents the sign bit
// - bit 23 (the 24th bit) represents the sign bit // * the least significant 23 bits represent the mantissa
//
// - the least significant 23 bits represent the mantissa
// //
// ------------------------------------------------- // -------------------------------------------------
// | Exponent | Sign | Mantissa | // | Exponent | Sign | Mantissa |
@ -55,7 +53,6 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
// ------------------------------------------------- // -------------------------------------------------
// //
// The formula to calculate N is: // The formula to calculate N is:
//
// N = (-1^sign) * mantissa * 256^(exponent-3) // N = (-1^sign) * mantissa * 256^(exponent-3)
// //
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers // This compact form is only used in bitcoin to encode unsigned 256-bit numbers
@ -162,6 +159,7 @@ func CalcWork(bits uint32) *big.Int {
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 { func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below. // Convert types used in the calculations below.
durationVal := int64(duration / time.Second) durationVal := int64(duration / time.Second)
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
// The test network rules allow minimum difficulty blocks after more // The test network rules allow minimum difficulty blocks after more
// than twice the desired amount of time needed to generate a block has // than twice the desired amount of time needed to generate a block has
@ -180,8 +178,7 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
// multiplied by the max adjustment factor. // multiplied by the max adjustment factor.
newTarget := CompactToBig(bits) newTarget := CompactToBig(bits)
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 { for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
adj := new(big.Int).Div(newTarget, big.NewInt(2)) newTarget.Mul(newTarget, adjustmentFactor)
newTarget.Add(newTarget, adj)
durationVal -= b.maxRetargetTimespan durationVal -= b.maxRetargetTimespan
} }
@ -227,6 +224,9 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
return b.chainParams.PowLimitBits, nil return b.chainParams.PowLimitBits, nil
} }
// Return the previous block's difficulty requirements if this block
// is not at a difficulty retarget interval.
if (lastNode.height+1)%b.blocksPerRetarget != 0 {
// For networks that support it, allow special reduction of the // For networks that support it, allow special reduction of the
// required difficulty once too much time has elapsed without // required difficulty once too much time has elapsed without
// mining a block. // mining a block.
@ -246,26 +246,25 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
return b.findPrevTestNetDifficulty(lastNode), nil return b.findPrevTestNetDifficulty(lastNode), nil
} }
// For the main network (or any unrecognized networks), simply
// return the previous block's difficulty requirements.
return lastNode.bits, nil
}
// Get the block node at the previous retarget (targetTimespan days // Get the block node at the previous retarget (targetTimespan days
// worth of blocks). // worth of blocks).
blocksBack := b.blocksPerRetarget firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1)
if blocksBack > lastNode.height {
blocksBack = lastNode.height
}
firstNode := lastNode.RelativeAncestor(blocksBack)
if firstNode == nil { if firstNode == nil {
return 0, AssertError("unable to obtain previous retarget block") return 0, AssertError("unable to obtain previous retarget block")
} }
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
// Limit the amount of adjustment that can occur to the previous // Limit the amount of adjustment that can occur to the previous
// difficulty. // difficulty.
actualTimespan := lastNode.timestamp - firstNode.timestamp actualTimespan := lastNode.timestamp - firstNode.timestamp
adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8 adjustedTimespan := actualTimespan
if adjustedTimespan < b.minRetargetTimespan { if actualTimespan < b.minRetargetTimespan {
adjustedTimespan = b.minRetargetTimespan adjustedTimespan = b.minRetargetTimespan
} else if adjustedTimespan > b.maxRetargetTimespan { } else if actualTimespan > b.maxRetargetTimespan {
adjustedTimespan = b.maxRetargetTimespan adjustedTimespan = b.maxRetargetTimespan
} }
@ -276,6 +275,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// result. // result.
oldTarget := CompactToBig(lastNode.bits) oldTarget := CompactToBig(lastNode.bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan)) newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
newTarget.Div(newTarget, big.NewInt(targetTimeSpan)) newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
// Limit new value to the proof of work limit. // Limit new value to the proof of work limit.

View file

@ -26,7 +26,7 @@ caller a high level of flexibility in how they want to react to certain events
such as orphan blocks which need their parents requested and newly connected such as orphan blocks which need their parents requested and newly connected
main chain blocks which might result in wallet updates. main chain blocks which might result in wallet updates.
# Bitcoin Chain Processing Overview Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of series of validation rules. The following list serves as a general outline of
@ -61,7 +61,7 @@ is by no means exhaustive:
coins coins
- Insert the block into the block database - Insert the block into the block database
# Errors Errors
Errors returned by this package are either the raw errors provided by underlying Errors returned by this package are either the raw errors provided by underlying
calls or of type blockchain.RuleError. This allows the caller to differentiate calls or of type blockchain.RuleError. This allows the caller to differentiate
@ -70,7 +70,7 @@ violations through type assertions. In addition, callers can programmatically
determine the specific rule violation by examining the ErrorCode field of the determine the specific rule violation by examining the ErrorCode field of the
type asserted blockchain.RuleError. type asserted blockchain.RuleError.
# Bitcoin Improvement Proposals Bitcoin Improvement Proposals
This package includes spec changes outlined by the following BIPs: This package includes spec changes outlined by the following BIPs:

View file

@ -220,10 +220,6 @@ const (
// current chain tip. This is not a block validation rule, but is required // current chain tip. This is not a block validation rule, but is required
// for block proposals submitted via getblocktemplate RPC. // for block proposals submitted via getblocktemplate RPC.
ErrPrevBlockNotBest ErrPrevBlockNotBest
// ErrBadClaimTrie indicates the calculated ClaimTrie root does not match
// the expected value.
ErrBadClaimTrie
) )
// Map of ErrorCode values back to their constant names for pretty printing. // Map of ErrorCode values back to their constant names for pretty printing.
@ -271,7 +267,6 @@ var errorCodeStrings = map[ErrorCode]string{
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown", ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock", ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
ErrPrevBlockNotBest: "ErrPrevBlockNotBest", ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
ErrBadClaimTrie: "ErrBadClaimTrie",
} }
// String returns the ErrorCode as a human-readable name. // String returns the ErrorCode as a human-readable name.

View file

@ -10,11 +10,11 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
_ "github.com/lbryio/lbcd/database/ffldb" _ "github.com/btcsuite/btcd/database/ffldb"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// This example demonstrates how to create a new chain instance and use // This example demonstrates how to create a new chain instance and use
@ -69,7 +69,7 @@ func ExampleBlockChain_ProcessBlock() {
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan) fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
// Output: // Output:
// Failed to process block: already have block 9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463 // Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
} }
// This example demonstrates how to convert the compact "bits" in a block header // This example demonstrates how to convert the compact "bits" in a block header

View file

@ -12,15 +12,15 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/blockchain/fullblocktests" "github.com/btcsuite/btcd/blockchain/fullblocktests"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
_ "github.com/lbryio/lbcd/database/ffldb" _ "github.com/btcsuite/btcd/database/ffldb"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (
@ -139,7 +139,7 @@ func TestFullBlocks(t *testing.T) {
// Create a new database and chain instance to run tests against. // Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("fullblocktest", chain, teardownFunc, err := chainSetup("fullblocktest",
fullblocktests.FbRegressionNetParams) &chaincfg.RegressionNetParams)
if err != nil { if err != nil {
t.Errorf("Failed to setup chain instance: %v", err) t.Errorf("Failed to setup chain instance: %v", err)
return return

View file

@ -1,9 +1,9 @@
fullblocktests fullblocktests
============== ==============
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions) [![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/fullblocktests) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/fullblocktests)
Package fullblocktests provides a set of full block tests to be used for testing Package fullblocktests provides a set of full block tests to be used for testing
the consensus validation rules. The tests are intended to be flexible enough to the consensus validation rules. The tests are intended to be flexible enough to
@ -20,7 +20,7 @@ of blocks that exercise the consensus validation rules.
## Installation and Updating ## Installation and Updating
```bash ```bash
$ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests $ go get -u github.com/btcsuite/btcd/blockchain/fullblocktests
``` ```
## License ## License

View file

@ -18,24 +18,24 @@ import (
"runtime" "runtime"
"time" "time"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (
// Intentionally defined here rather than using constants from codebase // Intentionally defined here rather than using constants from codebase
// to ensure consensus changes are detected. // to ensure consensus changes are detected.
maxBlockSigOps = 20000 maxBlockSigOps = 20000
maxBlockSize = 8000000 maxBlockSize = 1000000
minCoinbaseScriptLen = 2 minCoinbaseScriptLen = 2
maxCoinbaseScriptLen = 100 maxCoinbaseScriptLen = 100
medianTimeBlocks = 11 medianTimeBlocks = 11
maxScriptElementSize = 20000 maxScriptElementSize = 520
// numLargeReorgBlocks is the number of blocks to use in the large block // numLargeReorgBlocks is the number of blocks to use in the large block
// reorg test (when enabled). This is the equivalent of 1 week's worth // reorg test (when enabled). This is the equivalent of 1 week's worth
@ -342,8 +342,10 @@ func solveBlock(header *wire.BlockHeader) bool {
return return
default: default:
hdr.Nonce = i hdr.Nonce = i
hash := hdr.BlockPoWHash() hash := hdr.BlockHash()
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 { if blockchain.HashToBig(&hash).Cmp(
targetDifficulty) <= 0 {
results <- sbResult{true, i} results <- sbResult{true, i}
return return
} }
@ -809,7 +811,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Create a test generator instance initialized with the genesis block // Create a test generator instance initialized with the genesis block
// as the tip. // as the tip.
g, err := makeTestGenerator(FbRegressionNetParams) g, err := makeTestGenerator(regressionNetParams)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1442,7 +1444,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Keep incrementing the nonce until the hash treated as // Keep incrementing the nonce until the hash treated as
// a uint256 is higher than the limit. // a uint256 is higher than the limit.
b46.Header.Nonce++ b46.Header.Nonce++
blockHash := b46.Header.BlockPoWHash() blockHash := b46.BlockHash()
hashNum := blockchain.HashToBig(&blockHash) hashNum := blockchain.HashToBig(&blockHash)
if hashNum.Cmp(g.params.PowLimit) >= 0 { if hashNum.Cmp(g.params.PowLimit) >= 0 {
break break
@ -1873,7 +1875,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// //
// Comment assumptions: // Comment assumptions:
// maxBlockSigOps = 20000 // maxBlockSigOps = 20000
// maxScriptElementSize = 20000 // maxScriptElementSize = 520
// //
// [0-19999] : OP_CHECKSIG // [0-19999] : OP_CHECKSIG
// [20000] : OP_PUSHDATA4 // [20000] : OP_PUSHDATA4

View file

@ -9,9 +9,9 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// newHashFromStr converts the passed big-endian hex string into a // newHashFromStr converts the passed big-endian hex string into a
@ -54,7 +54,6 @@ var (
Version: 1, Version: 1,
PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"), PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"),
MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"), MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"),
ClaimTrie: chainhash.Hash{1}, // EmptyTrieHash
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
Nonce: 2, Nonce: 2,
@ -84,25 +83,23 @@ var (
LockTime: 0, LockTime: 0,
}}, }},
} }
regTestGenesisBlockHash = regTestGenesisBlock.BlockHash()
) )
// FbRegressionNetParams defines the network parameters for the regression test // regressionNetParams defines the network parameters for the regression test
// network. // network.
// //
// NOTE: The test generator intentionally does not use the existing definitions // NOTE: The test generator intentionally does not use the existing definitions
// in the chaincfg package since the intent is to be able to generate known // in the chaincfg package since the intent is to be able to generate known
// good tests which exercise that code. Using the chaincfg parameters would // good tests which exercise that code. Using the chaincfg parameters would
// allow them to change out from under the tests potentially invalidating them. // allow them to change out from under the tests potentially invalidating them.
var FbRegressionNetParams = &chaincfg.Params{ var regressionNetParams = &chaincfg.Params{
Name: "regtest", Name: "regtest",
Net: wire.TestNet, Net: wire.TestNet,
DefaultPort: "18444", DefaultPort: "18444",
// Chain parameters // Chain parameters
GenesisBlock: &regTestGenesisBlock, GenesisBlock: &regTestGenesisBlock,
GenesisHash: &regTestGenesisBlockHash, GenesisHash: newHashFromStr("5bec7567af40504e0994db3b573c186fffcc4edefe096ff2e58d00523bd7e8a6"),
PowLimit: regressionPowLimit, PowLimit: regressionPowLimit,
PowLimitBits: 0x207fffff, PowLimitBits: 0x207fffff,
CoinbaseMaturity: 100, CoinbaseMaturity: 100,
@ -116,7 +113,6 @@ var FbRegressionNetParams = &chaincfg.Params{
ReduceMinDifficulty: true, ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2 MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true, GenerateSupported: true,
MinerConfirmationWindow: 1,
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints: nil, Checkpoints: nil,

View file

@ -1,9 +1,9 @@
indexers indexers
======== ========
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions) [![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers) [![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers)
Package indexers implements optional block chain indexes. Package indexers implements optional block chain indexes.
@ -23,7 +23,7 @@ via an RPC interface.
## Installation ## Installation
```bash ```bash
$ go get -u github.com/lbryio/lbcd/blockchain/indexers $ go get -u github.com/btcsuite/btcd/blockchain/indexers
``` ```
## License ## License

View file

@ -9,13 +9,13 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (

View file

@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// addrIndexBucket provides a mock address index database bucket by implementing // addrIndexBucket provides a mock address index database bucket by implementing

View file

@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// blockProgressLogger provides periodic logging for other services in order // blockProgressLogger provides periodic logging for other services in order
@ -27,7 +27,6 @@ type blockProgressLogger struct {
// newBlockProgressLogger returns a new block progress logger. // newBlockProgressLogger returns a new block progress logger.
// The progress message is templated as follows: // The progress message is templated as follows:
//
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} // {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) // ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger { func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {

View file

@ -7,14 +7,14 @@ package indexers
import ( import (
"errors" "errors"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
"github.com/lbryio/lbcutil/gcs" "github.com/btcsuite/btcutil/gcs"
"github.com/lbryio/lbcutil/gcs/builder" "github.com/btcsuite/btcutil/gcs/builder"
) )
const ( const (

View file

@ -11,9 +11,9 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
var ( var (

View file

@ -8,11 +8,11 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
var ( var (

View file

@ -8,11 +8,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/lbryio/lbcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (

View file

@ -183,7 +183,7 @@ func (m *medianTime) AddTimeSample(sourceID string, timeVal time.Time) {
// Warn if none of the time samples are close. // Warn if none of the time samples are close.
if !remoteHasCloseTime { if !remoteHasCloseTime {
log.Warnf("Please check your date and time " + log.Warnf("Please check your date and time " +
"are correct! lbcd will not work " + "are correct! btcd will not work " +
"properly with an invalid time") "properly with an invalid time")
} }
} }

View file

@ -9,10 +9,9 @@ import (
"fmt" "fmt"
"math" "math"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcutil"
btcutil "github.com/lbryio/lbcutil"
) )
const ( const (
@ -228,25 +227,11 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error {
// coinbase transaction MUST have exactly one witness element within // coinbase transaction MUST have exactly one witness element within
// its witness data and that element must be exactly // its witness data and that element must be exactly
// CoinbaseWitnessDataLen bytes. // CoinbaseWitnessDataLen bytes.
//
// Some popular pool software, for example yiimp, uses pre-BIP0141
// coinbase struture. In this case, we don't just accept it, but also
// turn it into post-BIP0141 format.
if len(coinbaseTx.MsgTx().TxIn[0].Witness) == 0 {
log.Infof("pre-BIP0141 coinbase transaction detected. Height: %d", blk.Height())
var witnessNonce [CoinbaseWitnessDataLen]byte
coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
blk.MsgBlock().Transactions[0].TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
// Clear cached serialized block.
blk.SetBytes(nil)
}
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
if len(coinbaseWitness) != 1 { if len(coinbaseWitness) != 1 {
str := fmt.Sprintf("the coinbase transaction has %d items in "+ str := fmt.Sprintf("the coinbase transaction has %d items in "+
"its witness stack when only one is allowed. Height: %d", "its witness stack when only one is allowed",
len(coinbaseWitness), blk.Height()) len(coinbaseWitness))
return ruleError(ErrInvalidWitnessCommitment, str) return ruleError(ErrInvalidWitnessCommitment, str)
} }
witnessNonce := coinbaseWitness[0] witnessNonce := coinbaseWitness[0]

View file

@ -6,14 +6,16 @@ package blockchain
import ( import (
"testing" "testing"
"github.com/btcsuite/btcutil"
) )
// TestMerkle tests the BuildMerkleTreeStore API. // TestMerkle tests the BuildMerkleTreeStore API.
func TestMerkle(t *testing.T) { func TestMerkle(t *testing.T) {
block := GetBlock100000() block := btcutil.NewBlock(&Block100000)
merkles := BuildMerkleTreeStore(block.Transactions(), false) merkles := BuildMerkleTreeStore(block.Transactions(), false)
calculatedMerkleRoot := merkles[len(merkles)-1] calculatedMerkleRoot := merkles[len(merkles)-1]
wantMerkle := block.MsgBlock().Header.MerkleRoot wantMerkle := &Block100000.Header.MerkleRoot
if !wantMerkle.IsEqual(calculatedMerkleRoot) { if !wantMerkle.IsEqual(calculatedMerkleRoot) {
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+ t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
"got %v, want %v", calculatedMerkleRoot, wantMerkle) "got %v, want %v", calculatedMerkleRoot, wantMerkle)

View file

@ -0,0 +1,51 @@
// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/chaincfg"
)
// TestNotifications ensures that notification callbacks are fired on events.
func TestNotifications(t *testing.T) {
blocks, err := loadBlocks("blk_0_to_4.dat.bz2")
if err != nil {
t.Fatalf("Error loading file: %v\n", err)
}
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("notifications",
&chaincfg.MainNetParams)
if err != nil {
t.Fatalf("Failed to setup chain instance: %v", err)
}
defer teardownFunc()
notificationCount := 0
callback := func(notification *Notification) {
if notification.Type == NTBlockAccepted {
notificationCount++
}
}
// Register callback multiple times then assert it is called that many
// times.
const numSubscribers = 3
for i := 0; i < numSubscribers; i++ {
chain.Subscribe(callback)
}
_, _, err = chain.ProcessBlock(blocks[1], BFNone)
if err != nil {
t.Fatalf("ProcessBlock fail on block 1: %v\n", err)
}
if notificationCount != numSubscribers {
t.Fatalf("Expected notification callback to be executed %d "+
"times, found %d", numSubscribers, notificationCount)
}
}

View file

@ -8,9 +8,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when // BehaviorFlags is a bitmask defining tweaks to the normal behavior when
@ -29,10 +29,6 @@ const (
// not be performed. // not be performed.
BFNoPoWCheck BFNoPoWCheck
// BFNoDupBlockCheck signals if the block should skip existence
// checks.
BFNoDupBlockCheck
// BFNone is a convenience value to specifically indicate no flags. // BFNone is a convenience value to specifically indicate no flags.
BFNone BehaviorFlags = 0 BFNone BehaviorFlags = 0
) )
@ -152,7 +148,6 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
blockHash := block.Hash() blockHash := block.Hash()
log.Tracef("Processing block %v", blockHash) log.Tracef("Processing block %v", blockHash)
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
// The block must not already exist in the main chain or side chains. // The block must not already exist in the main chain or side chains.
exists, err := b.blockExists(blockHash) exists, err := b.blockExists(blockHash)
if err != nil { if err != nil {
@ -168,10 +163,9 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
str := fmt.Sprintf("already have block (orphan) %v", blockHash) str := fmt.Sprintf("already have block (orphan) %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str) return false, false, ruleError(ErrDuplicateBlock, str)
} }
}
// Perform preliminary sanity checks on the block and its transactions. // Perform preliminary sanity checks on the block and its transactions.
err := checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags) err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }

View file

@ -10,9 +10,9 @@ import (
"runtime" "runtime"
"time" "time"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// txValidateItem holds a transaction along with which input to validate. // txValidateItem holds a transaction along with which input to validate.

View file

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
) )
// TestCheckBlockScripts ensures that validating the all of the scripts in a // TestCheckBlockScripts ensures that validating the all of the scripts in a

BIN
blockchain/testdata/blk_0_to_4.dat.bz2 vendored Normal file

Binary file not shown.

BIN
blockchain/testdata/blk_3A.dat.bz2 vendored Normal file

Binary file not shown.

BIN
blockchain/testdata/blk_4A.dat.bz2 vendored Normal file

Binary file not shown.

BIN
blockchain/testdata/blk_5A.dat.bz2 vendored Normal file

Binary file not shown.

180
blockchain/testdata/reorgtest.hex vendored Normal file
View file

@ -0,0 +1,180 @@
File path: reorgTest/blk_0_to_4.dat
Block 0:
f9beb4d9
1d010000
01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 3ba3edfd 7a7b12b2 7ac72c3e 67768f61 7fc81bc3 888a5132 3a9fb8aa
4b1e5e4a 29ab5f49 ffff001d 1dac2b7c
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff4d04ff ff001d01 04455468 65205469 6d657320 30332f4a
616e2f32 30303920 4368616e 63656c6c 6f72206f 6e206272 696e6b20 6f662073
65636f6e 64206261 696c6f75 7420666f 72206261 6e6b73ff ffffff01 00f2052a
01000000 43410467 8afdb0fe 55482719 67f1a671 30b7105c d6a828e0 3909a679
62e0ea1f 61deb649 f6bc3f4c ef38c4f3 5504e51e c112de5c 384df7ba 0b8d578a
4c702b6b f11d5fac 00000000
Block 1:
f9beb4d9
d4000000
01000000 6fe28c0a b6f1b372 c1a6a246 ae63f74f 931e8365 e15a089c 68d61900
00000000 3bbd67ad e98fbbb7 0718cd80 f9e9acf9 3b5fae91 7bb2b41d 4c3bb82c
77725ca5 81ad5f49 ffff001d 44e69904
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04722f 2e2bffff ffff0100 f2052a01 00000043 41046868
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
000000
Block 2:
f9beb4d9
95010000
01000000 13ca7940 4c11c63e ca906bbd f190b751 2872b857 1b5143ae e8cb5737
00000000 fc07c983 d7391736 0aeda657 29d0d4d3 2533eb84 76ee9d64 aa27538f
9b4fc00a d9af5f49 ffff001d 630bea22
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04eb96 14e5ffff ffff0100 f2052a01 00000043 41046868
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 3dde52c6 5e339f45 7fe1015e 70eed208
872eb71e dd484c07 206b190e cb2ec3f8 02210011 c78dcfd0 3d43fa63 61242a33
6291ba2a 8c1ef5bc d5472126 2468f2bf 8dee4d01 ffffffff 0200ca9a 3b000000
001976a9 14cb2abd e8bccacc 32e893df 3a054b9e f7f227a4 ce88ac00 286bee00
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
00
Block 3:
f9beb4d9
96020000
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
00000000 4806fe80 bf85931b 882ea645 77ca5a03 22bb8af2 3f277b20 55f160cd
972c8e8b 31b25f49 ffff001d e8f0c653
03
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff044abd 8159ffff ffff0100 f2052a01 00000043 4104b95c
249d84f4 17e3e395 a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c
a5e56c90 f340988d 3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ac00
000000
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77000000 008c4930 46022100 b08b922a c4bde411 1c229f92 9fe6eb6a
50161f98 1f4cf47e a9214d35 bf74d380 022100d2 f6640327 e677a1e1 cc474991
b9a48ba5 bd1e0c94 d1c8df49 f7b0193b 7ea4fa01 4104b95c 249d84f4 17e3e395
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
Block 4:
f9beb4d9
73010000
01000000 5da36499 06f35e09 9be42a1d 87b6dd42 11bc1400 6c220694 0807eaae
00000000 48eeeaed 2d9d8522 e6201173 743823fd 4b87cd8a ca8e6408 ec75ca38
302c2ff0 89b45f49 ffff001d 00530839
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04d41d 2213ffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000
File path: reorgTest/blk_3A.dat
Block 3A:
f9beb4d9
96020000
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
00000000 5a15f573 1177a353 bdca7aab 20e16624 dfe90adc 70accadc 68016732
302c20a7 31b25f49 ffff001d 6a901440
03
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04ad1b e7d5ffff ffff0100 f2052a01 00000043 4104ed83
704c95d8 29046f1a c2780621 1132102c 34e9ac7f fa1b7111 0658e5b9 d1bdedc4
16f5cefc 1db0625c d0c75de8 192d2b59 2d7e3b00 bcfb4a0e 860d880f d1fcac00
000000
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77000000 008c4930 46022100 9cc67ddd aa6f592a 6b2babd4 d6ff954f
25a784cf 4fe4bb13 afb9f49b 08955119 022100a2 d99545b7 94080757 fcf2b563
f2e91287 86332f46 0ec6b90f f085fb28 41a69701 4104b95c 249d84f4 17e3e395
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
00
File path: reorgTest/blk_4A.dat
Block 4A:
f9beb4d9
d4000000
01000000 aae77468 2205667d 4f413a58 47cc8fe8 9795f1d5 645d5b24 1daf3c92
00000000 361c9cde a09637a0 d0c05c3b 4e7a5d91 9edb184a 0a4c7633 d92e2ddd
f04cb854 89b45f49 ffff001d 9e9aa1e8
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff0401b8 f3eaffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
File path: reorgTest/blk_5A.dat
Block 5A:
f9beb4d9
73010000
01000000 ebc7d0de 9c31a71b 7f41d275 2c080ba4 11e1854b d45cb2cf 8c1e4624
00000000 a607774b 79b8eb50 b52a5a32 c1754281 ec67f626 9561df28 57d1fe6a
ea82c696 e1b65f49 ffff001d 4a263577
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff049971 0c7dffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000

View file

@ -7,7 +7,7 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
) )
// ThresholdState define the various threshold states used when voting on // ThresholdState define the various threshold states used when voting on
@ -302,12 +302,6 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
} }
deployment := &b.chainParams.Deployments[deploymentID] deployment := &b.chainParams.Deployments[deploymentID]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
return ThresholdActive, nil
}
checker := deploymentChecker{deployment: deployment, chain: b} checker := deploymentChecker{deployment: deployment, chain: b}
cache := &b.deploymentCaches[deploymentID] cache := &b.deploymentCaches[deploymentID]

View file

@ -7,7 +7,7 @@ package blockchain
import ( import (
"testing" "testing"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
) )
// TestThresholdStateStringer tests the stringized output for the // TestThresholdStateStringer tests the stringized output for the

View file

@ -11,9 +11,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
const ( const (
@ -244,7 +244,6 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
// compressed script []byte variable // compressed script []byte variable
// //
// The serialized header code format is: // The serialized header code format is:
//
// bit 0 - containing transaction is a coinbase // bit 0 - containing transaction is a coinbase
// bit 1 - output zero is unspent // bit 1 - output zero is unspent
// bit 2 - output one is unspent // bit 2 - output one is unspent

View file

@ -7,11 +7,11 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// txoFlags is a bitmask defining additional information and state for a // txoFlags is a bitmask defining additional information and state for a

View file

@ -11,11 +11,11 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (
@ -40,7 +40,7 @@ const (
// baseSubsidy is the starting subsidy amount for mined blocks. This // baseSubsidy is the starting subsidy amount for mined blocks. This
// value is halved every SubsidyHalvingInterval blocks. // value is halved every SubsidyHalvingInterval blocks.
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
) )
var ( var (
@ -192,44 +192,17 @@ func isBIP0030Node(node *blockNode) bool {
// At the target block generation rate for the main network, this is // At the target block generation rate for the main network, this is
// approximately every 4 years. // approximately every 4 years.
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 { func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
h := int64(height) if chainParams.SubsidyReductionInterval == 0 {
if h == 0 { return baseSubsidy
return btcutil.SatoshiPerBitcoin * 4e8
}
if h <= 5100 {
return btcutil.SatoshiPerBitcoin
}
if h <= 55000 {
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
} }
lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval) // Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2 return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
for !withinLevelBounds(reduction, lv) {
if ((reduction*reduction + reduction) >> 1) > lv {
reduction--
} else {
reduction++
}
}
subsidyReduction := btcutil.SatoshiPerBitcoin * reduction
if subsidyReduction >= baseSubsidy {
return 0
}
return baseSubsidy - subsidyReduction
}
func withinLevelBounds(reduction int64, lv int64) bool {
if ((reduction*reduction + reduction) >> 1) > lv {
return false
}
reduction++
return ((reduction*reduction + reduction) >> 1) > lv
} }
// CheckTransactionSanity performs some preliminary checks on a transaction to // CheckTransactionSanity performs some preliminary checks on a transaction to
// ensure it is sane. // ensure it is sane. These checks are context free.
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error { func CheckTransactionSanity(tx *btcutil.Tx) error {
// A transaction must have at least one input. // A transaction must have at least one input.
msgTx := tx.MsgTx() msgTx := tx.MsgTx()
if len(msgTx.TxIn) == 0 { if len(msgTx.TxIn) == 0 {
@ -288,11 +261,6 @@ func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
btcutil.MaxSatoshi) btcutil.MaxSatoshi)
return ruleError(ErrBadTxOutValue, str) return ruleError(ErrBadTxOutValue, str)
} }
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
if err != nil {
return ruleError(ErrBadTxOutValue, err.Error())
}
} }
// Check for duplicate transaction inputs. // Check for duplicate transaction inputs.
@ -356,7 +324,7 @@ func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags Behavio
// to avoid proof of work checks is set. // to avoid proof of work checks is set.
if flags&BFNoPoWCheck != BFNoPoWCheck { if flags&BFNoPoWCheck != BFNoPoWCheck {
// The block hash must be less than the claimed target. // The block hash must be less than the claimed target.
hash := header.BlockPoWHash() hash := header.BlockHash()
hashNum := HashToBig(&hash) hashNum := HashToBig(&hash)
if hashNum.Cmp(target) > 0 { if hashNum.Cmp(target) > 0 {
str := fmt.Sprintf("block hash of %064x is higher than "+ str := fmt.Sprintf("block hash of %064x is higher than "+
@ -547,7 +515,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
// Do some preliminary checks on each transaction to ensure they are // Do some preliminary checks on each transaction to ensure they are
// sane before continuing. // sane before continuing.
for _, tx := range transactions { for _, tx := range transactions {
err := CheckTransactionSanity(tx, false) err := CheckTransactionSanity(tx)
if err != nil { if err != nil {
return err return err
} }

View file

@ -5,16 +5,15 @@
package blockchain package blockchain
import ( import (
"encoding/hex"
"math" "math"
"reflect" "reflect"
"testing" "testing"
"time" "time"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it // TestSequenceLocksActive tests the SequenceLockActive function to ensure it
@ -64,11 +63,96 @@ func TestSequenceLocksActive(t *testing.T) {
} }
} }
// TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to
// ensure it fails.
func TestCheckConnectBlockTemplate(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("checkconnectblocktemplate",
&chaincfg.MainNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// Since we're not dealing with the real block chain, set the coinbase
// maturity to 1.
chain.TstSetCoinbaseMaturity(1)
// Load up blocks such that there is a side chain.
// (genesis block) -> 1 -> 2 -> 3 -> 4
// \-> 3a
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_3A.dat.bz2",
}
var blocks []*btcutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Fatalf("Error loading file: %v\n", err)
}
blocks = append(blocks, blockTmp...)
}
for i := 1; i <= 3; i++ {
isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
"processing block %d: %v", i, err)
}
if !isMainChain {
t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
"to main chain", i)
}
}
// Block 3 should fail to connect since it's already inserted.
err = chain.CheckConnectBlockTemplate(blocks[3])
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 3")
}
// Block 4 should connect successfully to tip of chain.
err = chain.CheckConnectBlockTemplate(blocks[4])
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
"block 4: %v", err)
}
// Block 3a should fail to connect since does not build on chain tip.
err = chain.CheckConnectBlockTemplate(blocks[5])
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 3a")
}
// Block 4 should connect even if proof of work is invalid.
invalidPowBlock := *blocks[4].MsgBlock()
invalidPowBlock.Header.Nonce++
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidPowBlock))
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
"block 4 with bad nonce: %v", err)
}
// Invalid block building on chain tip should fail to connect.
invalidBlock := *blocks[4].MsgBlock()
invalidBlock.Header.Bits--
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidBlock))
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 4 with invalid difficulty bits")
}
}
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works // TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
// as expected. // as expected.
func TestCheckBlockSanity(t *testing.T) { func TestCheckBlockSanity(t *testing.T) {
powLimit := chaincfg.MainNetParams.PowLimit powLimit := chaincfg.MainNetParams.PowLimit
block := GetBlock100000() block := btcutil.NewBlock(&Block100000)
timeSource := NewMedianTime() timeSource := NewMedianTime()
err := CheckBlockSanity(block, powLimit, timeSource) err := CheckBlockSanity(block, powLimit, timeSource)
if err != nil { if err != nil {
@ -150,12 +234,254 @@ func TestCheckSerializedHeight(t *testing.T) {
} }
} }
var block100000Hex = "0000002024cbdc8644ee3983e66b003a0733891c069ca74c114c034c7b3e2e7ad7a12cd67e95e0555c0e056f6f2af538268ff9d21b420e529750d08eacb25c40f1322936637109b8a051157604c1c163cd39237687f6244b4e6d2b3a94e9d816babaecbb10c56058c811041b2b9c43000701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2003a086010410c56058081011314abf0100000d2f6e6f64655374726174756d2f000000000180354a6e0a0000001976a914b5e74e7cc9e1f480a6599895c92aab1401f870f188ac000000000100000002f1b75decc2c1c59c2178852822de412f574ad9796b65ac9092a79630d8109aaf000000006a47304402202f78ed3bf8dcadb6c17e289cd06e9c96b02c6f23aa1f446a4a7896a31cfd1e4702202862261e2eb59475ac91092c620b3cac5a831372bafc446d5ee450866040b532012103db4f3785354d84311fab7624c52784a61e3046d8f364463d327bdd96281b5b90feffffff987ee6b4bf95548d01e443683261dd0ffdcb2eb335b2f7119df0d41b60756b92010000006a47304402200c422c7560b6418d45443138bb957ec44eb293a639f4b2235a622205ca6cac370220759f15d5dc2543fd1aef80104c93427fcb025847bf895669025d1d82c62fbf6801210201864b998db5436990a0029fc3fb153c09e8c2689214b91c8ed68784995c8da0feffffff022bccfedd000000001976a914738f16132942a01d00cb9699bd058c4925aada3288ac1f4d030c000000001976a914c4292e757f5ff6a27c2f0a87d3a4aea5e46c275a88ac9f86010001000000015fbb26ad6d818186032baeef4d3f475dfe165c6da2d93411b8ec5f9f523cf1a4000000006a4730440220356999ad5a9f6f09b676f17dd4a2617a0af234722d68a50edc3768c983c0623d022056b4e5531608aeb0205fde9c44f741158da3bba1f4c3788c9fe79d36d43ea355012103509893a2a7c765d49ac9ff70126cb1af54871d70baba2c7e39ec9b4096289a9bfeffffff02389332fa080000001976a914f85e054405fbcedc2341cf8bf41ea989090587a288acf9321a41000000001976a914e85e90c048fdfbe1c2117a7132856ff4b39b470188ac9f86010001000000013508189b9bb61ac2aa536b905447b58f6c58c17cdef305240f566caa689d760a010000006a4730440220669a2b86e5abe58bae54829d3c271669540a9ad965c2fb79e8cc1fb609c0b60002202f958403d979138075cb53d8cb5ff6bb14e18d66dfdb6701c7d43a8ceeed0fa80121029935a602205a3fb72446064f3bc3a55ab9cd2e3459bf2ffdf80a48ab029d4b42feffffff02523c2f13000000001976a914c5b2ae398496f0f9ceaf81b83c28a27ddc890e3588ac211958f2000000001976a914ac65f1d16e5a2af37408b5d65406000a7ea143ca88ac9f8601000100000001bdd724322c555a21d5eb62d4aadbdc051663bcd4ec03f8d9005992f299783c21000000006a47304402205448141a2a788f73310025123bd24f5bee01dd8f48f18d7abc62d7c26465008902207ab46e6ddf6ba416decf3fbb97b6946a1428ea0a7c25a55cab47c47110d8e9ce0121029d6ff3b1235f2a08560b23dd4a08b14cc415b544801b885365736ea8ab1d3470feffffff029d104ccf000000001976a914999d5b0e3d5efcf601c711127b91841afbf5c37a88ace5c5a07f070000001976a9144aade372298eb387da9b6ac69d215a213e822f3f88ac9f86010001000000011658304d4ce796cd450228a10fdf647c6ea42295c9f5e1663df11481af1c884d010000006b483045022100a35d5d3ccde85b41559047d976ae6210b8e6ba5653c53aae1adc90048de0761002200d6bd6ebc6d73f97855f435c6fd595009ee71d23bb34870ab83ad53f67eeb22b012102d2f681ebfd1a570416d602986a47ca4254d8dedf2935b3f8c2ba55dcee8e98f4feffffff025ee913e6020000001976a91468076c9380d3c6b468ad1d6109c36770fb181e8f88acb165394f000000001976a9147ae970e81b3657cbb59df26517e372165807be0088ac9f86010001000000018f285109f78524a88ff328a4f94de2ac03224c50984b11c68adda192e8f78efa010000006b483045022100d77f2ac32dd6a3015f02f7115a13f617c57952fc5d53a33a87dc3fc00ffe1864022006455f74cff864b10424e445c530a59243f86d309dc92c5010ec5709e38471ab012102fdac7335b41edcd2846fc7e2166bb48312ee583ed6ff70fb5c27bcb2addaad86feffffff028b7a6d5c000000001976a914c65106d2e7ea4ec6aa8aa30ba4d11cfd1143123388ac5934c228000000001976a914d1c4d190b07edb972b91f33c36c6568b80358dd488ac9f860100" // Block100000 defines block 100,000 of the block chain. It is used to
// GetBlock100000 defines block 100,000 of the block chain. It is used to
// test Block operations. // test Block operations.
func GetBlock100000() *btcutil.Block { var Block100000 = wire.MsgBlock{
var block100000Bytes, _ = hex.DecodeString(block100000Hex) Header: wire.BlockHeader{
var results, _ = btcutil.NewBlockFromBytes(block100000Bytes) Version: 1,
return results PrevBlock: chainhash.Hash([32]byte{ // Make go vet happy.
0x50, 0x12, 0x01, 0x19, 0x17, 0x2a, 0x61, 0x04,
0x21, 0xa6, 0xc3, 0x01, 0x1d, 0xd3, 0x30, 0xd9,
0xdf, 0x07, 0xb6, 0x36, 0x16, 0xc2, 0xcc, 0x1f,
0x1c, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
}), // 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
MerkleRoot: chainhash.Hash([32]byte{ // Make go vet happy.
0x66, 0x57, 0xa9, 0x25, 0x2a, 0xac, 0xd5, 0xc0,
0xb2, 0x94, 0x09, 0x96, 0xec, 0xff, 0x95, 0x22,
0x28, 0xc3, 0x06, 0x7c, 0xc3, 0x8d, 0x48, 0x85,
0xef, 0xb5, 0xa4, 0xac, 0x42, 0x47, 0xe9, 0xf3,
}), // f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
Timestamp: time.Unix(1293623863, 0), // 2010-12-29 11:57:43 +0000 UTC
Bits: 0x1b04864c, // 453281356
Nonce: 0x10572b0f, // 274148111
},
Transactions: []*wire.MsgTx{
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0xffffffff,
},
SignatureScript: []byte{
0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x12a05f200, // 5000000000
PkScript: []byte{
0x41, // OP_DATA_65
0x04, 0x1b, 0x0e, 0x8c, 0x25, 0x67, 0xc1, 0x25,
0x36, 0xaa, 0x13, 0x35, 0x7b, 0x79, 0xa0, 0x73,
0xdc, 0x44, 0x44, 0xac, 0xb8, 0x3c, 0x4e, 0xc7,
0xa0, 0xe2, 0xf9, 0x9d, 0xd7, 0x45, 0x75, 0x16,
0xc5, 0x81, 0x72, 0x42, 0xda, 0x79, 0x69, 0x24,
0xca, 0x4e, 0x99, 0x94, 0x7d, 0x08, 0x7f, 0xed,
0xf9, 0xce, 0x46, 0x7c, 0xb9, 0xf7, 0xc6, 0x28,
0x70, 0x78, 0xf8, 0x01, 0xdf, 0x27, 0x6f, 0xdf,
0x84, // 65-byte signature
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
0xd3, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x2123e300, // 556000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
0xf7, 0xf5, 0x8b, 0x32,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
{
Value: 0x108e20f00, // 4444000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
0x52, 0xde, 0x3d, 0x7c,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
Index: 1,
},
SignatureScript: []byte{
0x47, // OP_DATA_71
0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
0x41, // OP_DATA_65
0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
0x0f, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
0xad, 0xbe, 0x7e, 0x10,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
{
Value: 0x11d260c0, // 299000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
0xb3, 0x40, 0x9c, 0xd9,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
0xbb, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
0xf2, 0xeb, 0x9e, 0xe0,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
},
} }

View file

@ -7,7 +7,7 @@ package blockchain
import ( import (
"math" "math"
"github.com/lbryio/lbcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
) )
const ( const (
@ -195,12 +195,6 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
expectedVersion := uint32(vbTopBits) expectedVersion := uint32(vbTopBits)
for id := 0; id < len(b.chainParams.Deployments); id++ { for id := 0; id < len(b.chainParams.Deployments); id++ {
deployment := &b.chainParams.Deployments[id] deployment := &b.chainParams.Deployments[id]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
continue
}
cache := &b.deploymentCaches[id] cache := &b.deploymentCaches[id]
checker := deploymentChecker{deployment: deployment, chain: b} checker := deploymentChecker{deployment: deployment, chain: b}
state, err := b.thresholdState(prevNode, checker, cache) state, err := b.thresholdState(prevNode, checker, cache)

View file

@ -7,9 +7,9 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/lbryio/lbcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
const ( const (
@ -20,11 +20,11 @@ const (
// weight of a "base" byte is 4, while the weight of a witness byte is // weight of a "base" byte is 4, while the weight of a witness byte is
// 1. As a result, for a block to be valid, the BlockWeight MUST be // 1. As a result, for a block to be valid, the BlockWeight MUST be
// less than, or equal to MaxBlockWeight. // less than, or equal to MaxBlockWeight.
MaxBlockWeight = 8000000 MaxBlockWeight = 4000000
// MaxBlockBaseSize is the maximum number of bytes within a block // MaxBlockBaseSize is the maximum number of bytes within a block
// which can be allocated to non-witness data. // which can be allocated to non-witness data.
MaxBlockBaseSize = 8000000 MaxBlockBaseSize = 1000000
// MaxBlockSigOpsCost is the maximum number of signature operations // MaxBlockSigOpsCost is the maximum number of signature operations
// allowed for a block. It is calculated via a weighted algorithm which // allowed for a block. It is calculated via a weighted algorithm which

View file

@ -15,13 +15,9 @@ import (
"runtime/debug" "runtime/debug"
"runtime/pprof" "runtime/pprof"
"github.com/lbryio/lbcd/blockchain/indexers" "github.com/btcsuite/btcd/blockchain/indexers"
"github.com/lbryio/lbcd/claimtrie/param" "github.com/btcsuite/btcd/database"
"github.com/lbryio/lbcd/database" "github.com/btcsuite/btcd/limits"
"github.com/lbryio/lbcd/limits"
"github.com/lbryio/lbcd/version"
"github.com/felixge/fgprof"
) )
const ( const (
@ -65,11 +61,10 @@ func btcdMain(serverChan chan<- *server) error {
defer btcdLog.Info("Shutdown complete") defer btcdLog.Info("Shutdown complete")
// Show version at startup. // Show version at startup.
btcdLog.Infof("Version %s", version.Full()) btcdLog.Infof("Version %s", version())
// Enable http profiling server if requested. // Enable http profiling server if requested.
if cfg.Profile != "" { if cfg.Profile != "" {
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
go func() { go func() {
listenAddr := net.JoinHostPort("", cfg.Profile) listenAddr := net.JoinHostPort("", cfg.Profile)
btcdLog.Infof("Profile server listening on %s", listenAddr) btcdLog.Infof("Profile server listening on %s", listenAddr)
@ -92,25 +87,6 @@ func btcdMain(serverChan chan<- *server) error {
defer pprof.StopCPUProfile() defer pprof.StopCPUProfile()
} }
// Write memory profile if requested.
if cfg.MemProfile != "" {
f, err := os.Create(cfg.MemProfile + ".heap")
if err != nil {
btcdLog.Errorf("Unable to create mem profile: %v", err)
return err
}
defer f.Close()
defer pprof.Lookup("heap").WriteTo(f, 0)
f, err = os.Create(cfg.MemProfile + ".allocs")
if err != nil {
btcdLog.Errorf("Unable to create mem profile: %v", err)
return err
}
defer f.Close()
defer pprof.Lookup("allocs").WriteTo(f, 0)
}
// Perform upgrades to btcd as new versions require it. // Perform upgrades to btcd as new versions require it.
if err := doUpgrades(); err != nil { if err := doUpgrades(); err != nil {
btcdLog.Errorf("%v", err) btcdLog.Errorf("%v", err)
@ -168,10 +144,6 @@ func btcdMain(serverChan chan<- *server) error {
return nil return nil
} }
param.SetNetwork(activeNetParams.Params.Net) // prep the claimtrie params
go logMemoryUsage()
// Create server and start it. // Create server and start it.
server, err := newServer(cfg.Listeners, cfg.AgentBlacklist, server, err := newServer(cfg.Listeners, cfg.AgentBlacklist,
cfg.AgentWhitelist, db, activeNetParams.Params, interrupt) cfg.AgentWhitelist, db, activeNetParams.Params, interrupt)
@ -186,10 +158,6 @@ func btcdMain(serverChan chan<- *server) error {
server.Stop() server.Stop()
server.WaitForShutdown() server.WaitForShutdown()
srvrLog.Infof("Server shutdown complete") srvrLog.Infof("Server shutdown complete")
// TODO: tie into the sync manager for shutdown instead
if ct := server.chain.ClaimTrie(); ct != nil {
ct.Close()
}
}() }()
server.Start() server.Start()
if serverChan != nil { if serverChan != nil {
@ -203,6 +171,34 @@ func btcdMain(serverChan chan<- *server) error {
return nil return nil
} }
// removeRegressionDB removes the existing regression test database if running
// in regression test mode and it already exists.
func removeRegressionDB(dbPath string) error {
// Don't do anything if not in regression test mode.
if !cfg.RegressionTest {
return nil
}
// Remove the old regression test database if it already exists.
fi, err := os.Stat(dbPath)
if err == nil {
btcdLog.Infof("Removing regression test database from '%s'", dbPath)
if fi.IsDir() {
err := os.RemoveAll(dbPath)
if err != nil {
return err
}
} else {
err := os.Remove(dbPath)
if err != nil {
return err
}
}
}
return nil
}
// dbPath returns the path to the block database given a database type. // dbPath returns the path to the block database given a database type.
func blockDbPath(dbType string) string { func blockDbPath(dbType string) string {
// The database name is based on the database type. // The database name is based on the database type.
@ -269,6 +265,11 @@ func loadBlockDB() (database.DB, error) {
// The database name is based on the database type. // The database name is based on the database type.
dbPath := blockDbPath(cfg.DbType) dbPath := blockDbPath(cfg.DbType)
// The regression test is special in that it needs a clean database for
// each run, so remove it now if it already exists.
removeRegressionDB(dbPath)
btcdLog.Infof("Loading block database from '%s'", dbPath) btcdLog.Infof("Loading block database from '%s'", dbPath)
db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net) db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net)
if err != nil { if err != nil {
@ -300,9 +301,7 @@ func main() {
// limits the garbage collector from excessively overallocating during // limits the garbage collector from excessively overallocating during
// bursts. This value was arrived at with the help of profiling live // bursts. This value was arrived at with the help of profiling live
// usage. // usage.
if _, ok := os.LookupEnv("GOGC"); !ok {
debug.SetGCPercent(10) debug.SetGCPercent(10)
}
// Up some limits. // Up some limits.
if err := limits.SetLimits(); err != nil { if err := limits.SetLimits(); err != nil {

View file

@ -1,11 +1,68 @@
btcec btcec
===== =====
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/btcec?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/btcec)
btcec implements elliptic curve cryptography needed for working with Package btcec implements elliptic curve cryptography needed for working with
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
standard crypto/ecdsa packages provided with go. A comprehensive suite of test standard crypto/ecdsa packages provided with go. A comprehensive suite of test
is provided to ensure proper functionality. Package btcec was originally based is provided to ensure proper functionality. Package btcec was originally based
on work from ThePiachu which is licensed under the same terms as Go, but it has on work from ThePiachu which is licensed under the same terms as Go, but it has
signficantly diverged since then. signficantly diverged since then. The btcsuite developers original is licensed
under the liberal ISC license.
Although this package was primarily written for btcd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use secp256k1 elliptic curve cryptography.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/btcec
```
## Examples
* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first
parsed form raw bytes and serializing the generated signature.
* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes.
* [Encryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
Demonstrates encrypting a message for a public key that is first parsed from
raw bytes, then decrypting it using the corresponding private key.
* [Decryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
Demonstrates decrypting a message using a private key that is first parsed
from raw bytes.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
except for btcec.go and btcec_test.go which is under the same license as Go.

View file

@ -527,7 +527,7 @@ type baseMultTest struct {
x, y string x, y string
} }
// TODO: add more test vectors //TODO: add more test vectors
var s256BaseMultTests = []baseMultTest{ var s256BaseMultTests = []baseMultTest{
{ {
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522", "AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522",
@ -556,7 +556,7 @@ var s256BaseMultTests = []baseMultTest{
}, },
} }
// TODO: test different curves as well? //TODO: test different curves as well?
func TestBaseMult(t *testing.T) { func TestBaseMult(t *testing.T) {
s256 := S256() s256 := S256()
for i, e := range s256BaseMultTests { for i, e := range s256BaseMultTests {

View file

@ -8,8 +8,8 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/lbryio/lbcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
) )
// This example demonstrates signing a message with a secp256k1 private key that // This example demonstrates signing a message with a secp256k1 private key that

View file

@ -125,7 +125,6 @@ var (
// the arithmetic needed for elliptic curve operations. // the arithmetic needed for elliptic curve operations.
// //
// The following depicts the internal representation: // The following depicts the internal representation:
//
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// | n[9] | n[8] | ... | n[0] | // | n[9] | n[8] | ... | n[0] |
// | 32 bits available | 32 bits available | ... | 32 bits available | // | 32 bits available | 32 bits available | ... | 32 bits available |
@ -135,14 +134,12 @@ var (
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// //
// For example, consider the number 2^49 + 1. It would be represented as: // For example, consider the number 2^49 + 1. It would be represented as:
//
// n[0] = 1 // n[0] = 1
// n[1] = 2^23 // n[1] = 2^23
// n[2..9] = 0 // n[2..9] = 0
// //
// The full 256-bit value is then calculated by looping i from 9..0 and // The full 256-bit value is then calculated by looping i from 9..0 and
// doing sum(n[i] * 2^(26i)) like so: // doing sum(n[i] * 2^(26i)) like so:
//
// n[9] * 2^(26*9) = 0 * 2^234 = 0 // n[9] * 2^(26*9) = 0 * 2^234 = 0
// n[8] * 2^(26*8) = 0 * 2^208 = 0 // n[8] * 2^(26*8) = 0 * 2^208 = 0
// ... // ...

View file

@ -5,7 +5,6 @@
// This file is ignored during the regular build due to the following build tag. // This file is ignored during the regular build due to the following build tag.
// It is called by go generate and used to automatically generate pre-computed // It is called by go generate and used to automatically generate pre-computed
// tables used to accelerate operations. // tables used to accelerate operations.
//go:build ignore
// +build ignore // +build ignore
package main package main
@ -18,7 +17,7 @@ import (
"log" "log"
"os" "os"
"github.com/lbryio/lbcd/btcec" "github.com/btcsuite/btcd/btcec"
) )
func main() { func main() {

View file

@ -4,7 +4,6 @@
// This file is ignored during the regular build due to the following build tag. // This file is ignored during the regular build due to the following build tag.
// This build tag is set during go generate. // This build tag is set during go generate.
//go:build gensecp256k1
// +build gensecp256k1 // +build gensecp256k1
package btcec package btcec

View file

@ -12,7 +12,7 @@ import (
"strings" "strings"
) )
//go:rm -f gensecp256k1.go; generate go run -tags gensecp256k1 genprecomps.go //go:generate go run -tags gensecp256k1 genprecomps.go
// loadS256BytePoints decompresses and deserializes the pre-computed byte points // loadS256BytePoints decompresses and deserializes the pre-computed byte points
// used to accelerate scalar base multiplication for the secp256k1 curve. This // used to accelerate scalar base multiplication for the secp256k1 curve. This

View file

@ -353,10 +353,6 @@ func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
// step to prevent the jacobian conversion back and forth. // step to prevent the jacobian conversion back and forth.
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy) Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
if Qx.Sign() == 0 && Qy.Sign() == 0 {
return nil, errors.New("point (Qx, Qy) equals the point at infinity")
}
return &PublicKey{ return &PublicKey{
Curve: curve, Curve: curve,
X: Qx, X: Qx,

View file

@ -549,12 +549,6 @@ var recoveryTests = []struct {
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
err: fmt.Errorf("invalid square root"), err: fmt.Errorf("invalid square root"),
}, },
{
// Point at infinity recovered
msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"),
},
{ {
// Low R and S values. // Low R and S values.
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f", msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",

View file

@ -1,8 +1,70 @@
btcjson btcjson
======= =======
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson)
Package btcjson implements concrete types for marshalling to and from the Package btcjson implements concrete types for marshalling to and from the
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
proper functionality. proper functionality.
Although this package was primarily written for the btcsuite, it has
intentionally been designed so it can be used as a standalone package for any
projects needing to marshal to and from bitcoin JSON-RPC requests and responses.
Note that although it's possible to use this package directly to implement an
RPC client, it is not recommended since it is only intended as an infrastructure
package. Instead, RPC clients should use the
[btcrpcclient](https://github.com/btcsuite/btcrpcclient) package which provides
a full blown RPC client with many features such as automatic connection
management, websocket support, automatic notification re-registration on
reconnect, and conversion from the raw underlying RPC types (strings, floats,
ints, etc) to higher-level types with many nice and useful properties.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/btcjson
```
## Examples
* [Marshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalCmd)
Demonstrates how to create and marshal a command into a JSON-RPC request.
* [Unmarshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-UnmarshalCmd)
Demonstrates how to unmarshal a JSON-RPC request and then unmarshal the
concrete request into a concrete command.
* [Marshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalResponse)
Demonstrates how to marshal a JSON-RPC response.
* [Unmarshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-package--UnmarshalResponse)
Demonstrates how to unmarshal a JSON-RPC response and then unmarshal the
result field in the response to a concrete type.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcjson is licensed under the [copyfree](http://copyfree.org) ISC
License.

View file

@ -12,7 +12,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal // TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal

View file

@ -9,7 +9,7 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestBtcdExtCustomResults ensures any results that have custom marshalling // TestBtcdExtCustomResults ensures any results that have custom marshalling

View file

@ -11,7 +11,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and // TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and

View file

@ -13,7 +13,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the // AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
@ -48,15 +48,6 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd {
} }
} }
// ClearBannedCmd defines the clearbanned JSON-RPC command.
type ClearBannedCmd struct{}
// NewClearBannedCmd returns a new instance which can be used to issue an clearbanned
// JSON-RPC command.
func NewClearBannedCmd() *ClearBannedCmd {
return &ClearBannedCmd{}
}
// TransactionInput represents the inputs to a transaction. Specifically a // TransactionInput represents the inputs to a transaction. Specifically a
// transaction hash and output number pair. // transaction hash and output number pair.
type TransactionInput struct { type TransactionInput struct {
@ -67,7 +58,7 @@ type TransactionInput struct {
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command. // CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
type CreateRawTransactionCmd struct { type CreateRawTransactionCmd struct {
Inputs []TransactionInput Inputs []TransactionInput
Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"` Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
LockTime *int64 LockTime *int64
} }
@ -76,7 +67,7 @@ type CreateRawTransactionCmd struct {
// //
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent, // Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
// both gets interpreted as the empty slice. // both gets interpreted as the empty slice.
func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{}, func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
lockTime *int64) *CreateRawTransactionCmd { lockTime *int64) *CreateRawTransactionCmd {
// to make sure we're serializing this to the empty list and not null, we // to make sure we're serializing this to the empty list and not null, we
// explicitly initialize the list // explicitly initialize the list
@ -85,7 +76,7 @@ func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]in
} }
return &CreateRawTransactionCmd{ return &CreateRawTransactionCmd{
Inputs: inputs, Inputs: inputs,
Outputs: outputs, Amounts: amounts,
LockTime: lockTime, LockTime: lockTime,
} }
} }
@ -659,7 +650,7 @@ func NewGetRawMempoolCmd(verbose *bool) *GetRawMempoolCmd {
// Core even though it really should be a bool. // Core even though it really should be a bool.
type GetRawTransactionCmd struct { type GetRawTransactionCmd struct {
Txid string Txid string
Verbose *bool `jsonrpcdefault:"false"` Verbose *int `jsonrpcdefault:"0"`
} }
// NewGetRawTransactionCmd returns a new instance which can be used to issue a // NewGetRawTransactionCmd returns a new instance which can be used to issue a
@ -667,7 +658,7 @@ type GetRawTransactionCmd struct {
// //
// The parameters which are pointers indicate they are optional. Passing nil // The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value. // for optional parameters will use the default value.
func NewGetRawTransactionCmd(txHash string, verbose *bool) *GetRawTransactionCmd { func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd {
return &GetRawTransactionCmd{ return &GetRawTransactionCmd{
Txid: txHash, Txid: txHash,
Verbose: verbose, Verbose: verbose,
@ -766,15 +757,6 @@ func NewInvalidateBlockCmd(blockHash string) *InvalidateBlockCmd {
} }
} }
// ListBannedCmd defines the listbanned JSON-RPC command.
type ListBannedCmd struct{}
// NewListBannedCmd returns a new instance which can be used to issue a listbanned
// JSON-RPC command.
func NewListBannedCmd() *ListBannedCmd {
return &ListBannedCmd{}
}
// PingCmd defines the ping JSON-RPC command. // PingCmd defines the ping JSON-RPC command.
type PingCmd struct{} type PingCmd struct{}
@ -921,39 +903,6 @@ func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTr
} }
} }
// SetBanSubCmd defines the type used in the setban JSON-RPC command for the
// sub command field.
type SetBanSubCmd string
const (
// SBAdd indicates the specified host should be added as a persistent
// peer.
SBAdd SetBanSubCmd = "add"
// SBRemove indicates the specified peer should be removed.
SBRemove SetBanSubCmd = "remove"
)
// SetBanCmd defines the setban JSON-RPC command.
type SetBanCmd struct {
Addr string
SubCmd SetBanSubCmd `jsonrpcusage:"\"add|remove\""`
BanTime *int `jsonrpcdefault:"0"`
Absolute *bool `jsonrpcdefault:"false"`
}
// NewSetBanCmd returns a new instance which can be used to issue an setban
// JSON-RPC command.
func NewSetBanCmd(addr string, subCmd SetBanSubCmd, banTime *int,
absolute *bool) *SetBanCmd {
return &SetBanCmd{
Addr: addr,
SubCmd: subCmd,
BanTime: banTime,
Absolute: absolute,
}
}
// SetGenerateCmd defines the setgenerate JSON-RPC command. // SetGenerateCmd defines the setgenerate JSON-RPC command.
type SetGenerateCmd struct { type SetGenerateCmd struct {
Generate bool Generate bool
@ -1131,9 +1080,6 @@ func init() {
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags) MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags) MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags) MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags)
MustRegisterCmd("setban", (*SetBanCmd)(nil), flags)
MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags)
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags) MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags) MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags) MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)

View file

@ -12,8 +12,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
) )
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal // TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
@ -52,13 +52,13 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{ txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1}, {Txid: "123", Vout: 1},
} }
txOutputs := map[string]interface{}{"456": .0123} amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil) return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
}, },
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{ unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}}, Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"456": .0123}, Amounts: map[string]float64{"456": .0123},
}, },
}, },
{ {
@ -67,13 +67,13 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`) return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`)
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
txOutputs := map[string]interface{}{"456": .0123} amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(nil, txOutputs, nil) return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil)
}, },
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{ unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{}, Inputs: []btcjson.TransactionInput{},
Outputs: map[string]interface{}{"456": .0123}, Amounts: map[string]float64{"456": .0123},
}, },
}, },
{ {
@ -86,35 +86,16 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{ txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1}, {Txid: "123", Vout: 1},
} }
txOutputs := map[string]interface{}{"456": .0123} amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333)) return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
}, },
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{ unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}}, Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"456": .0123}, Amounts: map[string]float64{"456": .0123},
LockTime: btcjson.Int64(12312333333), LockTime: btcjson.Int64(12312333333),
}, },
}, },
{
name: "createrawtransaction with data",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
`{"data":"6a134920616d204672616374616c456e6372797074"}`)
},
staticCmd: func() interface{} {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
},
},
{ {
name: "fundrawtransaction - empty opts", name: "fundrawtransaction - empty opts",
newCmd: func() (i interface{}, e error) { newCmd: func() (i interface{}, e error) {
@ -407,7 +388,7 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewGetBlockFilterCmd("0000afaf", nil) return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
}, },
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`,
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil}, unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", nil},
}, },
{ {
name: "getblockfilter optional filtertype", name: "getblockfilter optional filtertype",
@ -418,7 +399,7 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)) return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
}, },
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`,
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)}, unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
}, },
{ {
name: "getblockhash", name: "getblockhash",
@ -891,21 +872,21 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{ unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123", Txid: "123",
Verbose: btcjson.Bool(false), Verbose: btcjson.Int(0),
}, },
}, },
{ {
name: "getrawtransaction optional", name: "getrawtransaction optional",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getrawtransaction", "123", true) return btcjson.NewCmd("getrawtransaction", "123", 1)
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
return btcjson.NewGetRawTransactionCmd("123", btcjson.Bool(true)) return btcjson.NewGetRawTransactionCmd("123", btcjson.Int(1))
}, },
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",true],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{ unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123", Txid: "123",
Verbose: btcjson.Bool(true), Verbose: btcjson.Int(1),
}, },
}, },
{ {

View file

@ -9,10 +9,10 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire" "github.com/btcsuite/btcd/wire"
btcutil "github.com/lbryio/lbcutil" "github.com/btcsuite/btcutil"
) )
// GetBlockHeaderVerboseResult models the data from the getblockheader command when // GetBlockHeaderVerboseResult models the data from the getblockheader command when
@ -25,7 +25,6 @@ type GetBlockHeaderVerboseResult struct {
Version int32 `json:"version"` Version int32 `json:"version"`
VersionHex string `json:"versionHex"` VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"` MerkleRoot string `json:"merkleroot"`
ClaimTrie string `json:"nameclaimroot,omitempty"`
Time int64 `json:"time"` Time int64 `json:"time"`
Nonce uint64 `json:"nonce"` Nonce uint64 `json:"nonce"`
Bits string `json:"bits"` Bits string `json:"bits"`
@ -35,60 +34,35 @@ type GetBlockHeaderVerboseResult struct {
} }
// GetBlockStatsResult models the data from the getblockstats command. // GetBlockStatsResult models the data from the getblockstats command.
// Pointers are used instead of values to allow for optional fields.
type GetBlockStatsResult struct { type GetBlockStatsResult struct {
AverageFee *int64 `json:"avgfee,omitempty"` AverageFee int64 `json:"avgfee"`
AverageFeeRate *int64 `json:"avgfeerate,omitempty"` AverageFeeRate int64 `json:"avgfeerate"`
AverageTxSize *int64 `json:"avgtxsize,omitempty"` AverageTxSize int64 `json:"avgtxsize"`
FeeratePercentiles *[]int64 `json:"feerate_percentiles,omitempty"` FeeratePercentiles []int64 `json:"feerate_percentiles"`
Hash *string `json:"blockhash,omitempty"` Hash string `json:"blockhash"`
Height *int64 `json:"height,omitempty"`
Ins *int64 `json:"ins,omitempty"`
MaxFee *int64 `json:"maxfee,omitempty"`
MaxFeeRate *int64 `json:"maxfeerate,omitempty"`
MaxTxSize *int64 `json:"maxtxsize,omitempty"`
MedianFee *int64 `json:"medianfee,omitempty"`
MedianTime *int64 `json:"mediantime,omitempty"`
MedianTxSize *int64 `json:"mediantxsize,omitempty"`
MinFee *int64 `json:"minfee,omitempty"`
MinFeeRate *int64 `json:"minfeerate,omitempty"`
MinTxSize *int64 `json:"mintxsize,omitempty"`
Outs *int64 `json:"outs,omitempty"`
SegWitTotalSize *int64 `json:"swtotal_size,omitempty"`
SegWitTotalWeight *int64 `json:"swtotal_weight,omitempty"`
SegWitTxs *int64 `json:"swtxs,omitempty"`
Subsidy *int64 `json:"subsidy,omitempty"`
Time *int64 `json:"time,omitempty"`
TotalOut *int64 `json:"total_out,omitempty"`
TotalSize *int64 `json:"total_size,omitempty"`
TotalWeight *int64 `json:"total_weight,omitempty"`
TotalFee *int64 `json:"totalfee,omitempty"`
Txs *int64 `json:"txs,omitempty"`
UTXOIncrease *int64 `json:"utxo_increase,omitempty"`
UTXOSizeIncrease *int64 `json:"utxo_size_inc,omitempty"`
}
type GetBlockVerboseResultBase struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"` Height int64 `json:"height"`
Version int32 `json:"version"` Ins int64 `json:"ins"`
VersionHex string `json:"versionHex"` MaxFee int64 `json:"maxfee"`
MerkleRoot string `json:"merkleroot"` MaxFeeRate int64 `json:"maxfeerate"`
Time int64 `json:"time"` MaxTxSize int64 `json:"maxtxsize"`
MedianFee int64 `json:"medianfee"`
MedianTime int64 `json:"mediantime"` MedianTime int64 `json:"mediantime"`
Nonce uint32 `json:"nonce"` MedianTxSize int64 `json:"mediantxsize"`
Bits string `json:"bits"` MinFee int64 `json:"minfee"`
Difficulty float64 `json:"difficulty"` MinFeeRate int64 `json:"minfeerate"`
ChainWork string `json:"chainwork"` MinTxSize int64 `json:"mintxsize"`
PreviousHash string `json:"previousblockhash,omitempty"` Outs int64 `json:"outs"`
NextHash string `json:"nextblockhash,omitempty"` SegWitTotalSize int64 `json:"swtotal_size"`
SegWitTotalWeight int64 `json:"swtotal_weight"`
ClaimTrie string `json:"nameclaimroot,omitempty"` SegWitTxs int64 `json:"swtxs"`
TxCount int `json:"nTx"` // For backwards compatibility only Subsidy int64 `json:"subsidy"`
Time int64 `json:"time"`
TotalOut int64 `json:"total_out"`
TotalSize int64 `json:"total_size"`
TotalWeight int64 `json:"total_weight"`
Txs int64 `json:"txs"`
UTXOIncrease int64 `json:"utxo_increase"`
UTXOSizeIncrease int64 `json:"utxo_size_inc"`
} }
// GetBlockVerboseResult models the data from the getblock command when the // GetBlockVerboseResult models the data from the getblock command when the
@ -98,8 +72,23 @@ type GetBlockVerboseResultBase struct {
// getblock returns an object whose tx field is an array of raw transactions. // getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseTxResult to unmarshal data received from passing verbose=2 to getblock. // Use GetBlockVerboseTxResult to unmarshal data received from passing verbose=2 to getblock.
type GetBlockVerboseResult struct { type GetBlockVerboseResult struct {
GetBlockVerboseResultBase Hash string `json:"hash"`
Tx []string `json:"tx"` Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []string `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"` // Note: this field is always empty when verbose != 2.
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
} }
// GetBlockVerboseTxResult models the data from the getblock command when the // GetBlockVerboseTxResult models the data from the getblock command when the
@ -109,8 +98,23 @@ type GetBlockVerboseResult struct {
// getblock returns an object whose tx field is an array of raw transactions. // getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock. // Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
type GetBlockVerboseTxResult struct { type GetBlockVerboseTxResult struct {
GetBlockVerboseResultBase Hash string `json:"hash"`
Tx []TxRawResult `json:"tx"` Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []TxRawResult `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"` // Deprecated: removed in Bitcoin Core
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
} }
// GetChainTxStatsResult models the data from the getchaintxstats command. // GetChainTxStatsResult models the data from the getchaintxstats command.
@ -292,10 +296,6 @@ type GetBlockTemplateResult struct {
// Block proposal from BIP 0023. // Block proposal from BIP 0023.
Capabilities []string `json:"capabilities,omitempty"` Capabilities []string `json:"capabilities,omitempty"`
RejectReasion string `json:"reject-reason,omitempty"` RejectReasion string `json:"reject-reason,omitempty"`
ClaimTrieHash string `json:"claimtrie"`
Rules []string `json:"rules,omitempty"`
} }
// GetMempoolEntryResult models the data returned from the getmempoolentry's // GetMempoolEntryResult models the data returned from the getmempoolentry's
@ -327,27 +327,13 @@ type GetMempoolEntryResult struct {
WTxId string `json:"wtxid"` WTxId string `json:"wtxid"`
Fees MempoolFees `json:"fees"` Fees MempoolFees `json:"fees"`
Depends []string `json:"depends"` Depends []string `json:"depends"`
SpentBy []string `json:"spentby"`
}
// GetChainTipsResult models the data returns from the getchaintips command.
type GetChainTipsResult struct {
Height int64 `json:"height"`
Hash string `json:"hash"`
BranchLen int64 `json:"branchlen"`
Status string `json:"status"`
} }
// GetMempoolInfoResult models the data returned from the getmempoolinfo // GetMempoolInfoResult models the data returned from the getmempoolinfo
// command. // command.
type GetMempoolInfoResult struct { type GetMempoolInfoResult struct {
Size int64 `json:"size"` // Current tx count Size int64 `json:"size"`
Bytes int64 `json:"bytes"` // Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted Bytes int64 `json:"bytes"`
Usage int64 `json:"usage"` // Total memory usage for the mempool
TotalFee float64 `json:"total_fee"` // Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction
MemPoolMinFee float64 `json:"mempoolminfee"` // Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee
MinRelayTxFee float64 `json:"minrelaytxfee"` // Current minimum relay fee for transactions
UnbroadcastCount int64 `json:"unbroadcastcount"` // Current number of transactions that haven't passed initial broadcast yet
} }
// NetworksResult models the networks data from the getnetworkinfo command. // NetworksResult models the networks data from the getnetworkinfo command.
@ -442,9 +428,6 @@ type ScriptPubKeyResult struct {
Hex string `json:"hex,omitempty"` Hex string `json:"hex,omitempty"`
ReqSigs int32 `json:"reqSigs,omitempty"` ReqSigs int32 `json:"reqSigs,omitempty"`
Type string `json:"type"` Type string `json:"type"`
SubType string `json:"subtype"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
Addresses []string `json:"addresses,omitempty"` Addresses []string `json:"addresses,omitempty"`
} }
@ -603,8 +586,6 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
type PrevOut struct { type PrevOut struct {
Addresses []string `json:"addresses,omitempty"` Addresses []string `json:"addresses,omitempty"`
Value float64 `json:"value"` Value float64 `json:"value"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
} }
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction // VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
@ -723,15 +704,6 @@ type InfoChainResult struct {
Errors string `json:"errors"` Errors string `json:"errors"`
} }
// ListBannedResult models the data returned from the listbanned command.
type ListBannedResult struct {
Address string `json:"address"`
BanCreated int64 `json:"ban_created"`
BannedUntil int64 `json:"banned_until"`
BanDuration int64 `json:"ban_duration"`
TimeRemaining int64 `json:"time_remaining"`
}
// TxRawResult models the data from the getrawtransaction command. // TxRawResult models the data from the getrawtransaction command.
type TxRawResult struct { type TxRawResult struct {
Hex string `json:"hex"` Hex string `json:"hex"`

View file

@ -9,10 +9,10 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/lbryio/lbcd/btcjson"
"github.com/lbryio/lbcd/chaincfg/chainhash"
btcutil "github.com/lbryio/lbcutil"
) )
// TestChainSvrCustomResults ensures any results that have custom marshalling // TestChainSvrCustomResults ensures any results that have custom marshalling
@ -70,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
}, },
Sequence: 4294967295, Sequence: 4294967295,
}, },
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`, expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
}, },
} }

View file

@ -12,7 +12,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands // TestChainSvrWsCmds tests all of the chain server websocket-specific commands

View file

@ -12,7 +12,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestChainSvrWsNtfns tests all of the chain server websocket-specific // TestChainSvrWsNtfns tests all of the chain server websocket-specific

View file

@ -9,7 +9,7 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestChainSvrWsResults ensures any results that have custom marshalling // TestChainSvrWsResults ensures any results that have custom marshalling

View file

@ -1,97 +0,0 @@
package btcjson
func init() {
// No special flags for commands in this file.
flags := UsageFlag(0)
MustRegisterCmd("getchangesinblock", (*GetChangesInBlockCmd)(nil), flags)
MustRegisterCmd("getclaimsforname", (*GetClaimsForNameCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebyid", (*GetClaimsForNameByIDCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)
}
// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
// optional inputs have to be at the bottom of the struct
// optional outputs require ",omitempty"
// traditional bitcoin fields are all lowercase
type GetChangesInBlockCmd struct {
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
}
type GetChangesInBlockResult struct {
Hash string `json:"hash"`
Height int32 `json:"height"`
Names []string `json:"names"`
}
type GetClaimsForNameCmd struct {
Name string `json:"name"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameByIDCmd struct {
Name string `json:"name"`
PartialClaimIDs []string `json:"partialclaimids"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameByBidCmd struct {
Name string `json:"name"`
Bids []int32 `json:"bids"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameBySeqCmd struct {
Name string `json:"name"`
Sequences []int32 `json:"sequences" jsonrpcusage:"[sequence,...]"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameResult struct {
Hash string `json:"hash"`
Height int32 `json:"height"`
LastTakeoverHeight int32 `json:"lasttakeoverheight"`
NormalizedName string `json:"normalizedname"`
Claims []ClaimResult `json:"claims"`
// UnclaimedSupports []SupportResult `json:"supportswithoutclaim"` how would this work with other constraints?
}
type SupportResult struct {
TXID string `json:"txid"`
N uint32 `json:"n"`
Height int32 `json:"height"`
ValidAtHeight int32 `json:"validatheight"`
Amount int64 `json:"amount"`
Address string `json:"address,omitempty"`
Value string `json:"value,omitempty"`
}
type ClaimResult struct {
ClaimID string `json:"claimid"`
TXID string `json:"txid"`
N uint32 `json:"n"`
Bid int32 `json:"bid"`
Sequence int32 `json:"sequence"`
Height int32 `json:"height"`
ValidAtHeight int32 `json:"validatheight"`
Amount int64 `json:"amount"`
EffectiveAmount int64 `json:"effectiveamount"`
Supports []SupportResult `json:"supports,omitempty"`
Address string `json:"address,omitempty"`
Value string `json:"value,omitempty"`
}
type GetNormalizedCmd struct {
Name string `json:"name"`
}
type GetNormalizedResult struct {
NormalizedName string `json:"normalizedname"`
}

View file

@ -8,7 +8,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected // TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected

View file

@ -134,16 +134,6 @@ func UnmarshalCmd(r *Request) (interface{}, error) {
// Unmarshal the parameter into the struct field. // Unmarshal the parameter into the struct field.
concreteVal := rvf.Addr().Interface() concreteVal := rvf.Addr().Interface()
if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil { if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil {
// Parse Integer into Bool for compatibility with lbrycrd.
if rvf.Kind() == reflect.Ptr &&
rvf.Elem().Type().Kind() == reflect.Bool {
boolInt, errBoolInt := strconv.Atoi(string(r.Params[i]))
if errBoolInt == nil {
rvf.Elem().SetBool(boolInt != 0)
continue
}
}
// The most common error is the wrong type, so // The most common error is the wrong type, so
// explicitly detect that error and make it nicer. // explicitly detect that error and make it nicer.
fieldName := strings.ToLower(rt.Field(i).Name) fieldName := strings.ToLower(rt.Field(i).Name)

View file

@ -10,7 +10,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestAssignField tests the assignField function handles supported combinations // TestAssignField tests the assignField function handles supported combinations
@ -557,7 +557,7 @@ func TestUnmarshalCmdErrors(t *testing.T) {
request: btcjson.Request{ request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1, Jsonrpc: btcjson.RpcVersion1,
Method: "getblock", Method: "getblock",
Params: []json.RawMessage{[]byte("1.0")}, Params: []json.RawMessage{[]byte("1")},
ID: nil, ID: nil,
}, },
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType}, err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
@ -591,84 +591,3 @@ func TestUnmarshalCmdErrors(t *testing.T) {
} }
} }
} }
// TestUnmarshalCmdBoolParams tests the parsing of boolean paramers of the UnmarshalCmd function.
func TestUnmarshalCmdBoolParams(t *testing.T) {
t.Parallel()
txid := []byte(`"ab91c149aff2b37a4a1856e9935ea623c973f47886d032ed7511ad8ca37855bb"`)
tests := []struct {
name string
request btcjson.Request
expect bool
}{
{
name: "parse true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("true")},
ID: nil,
},
expect: true,
},
{
name: "parse false",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("false")},
ID: nil,
},
expect: false,
},
{
name: "parse integer 0 to false",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("0")},
ID: nil,
},
expect: false,
},
{
name: "parse integer 1 to true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("1")},
ID: nil,
},
expect: true,
},
{
name: "parse integer 100 to true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("100")},
ID: nil,
},
expect: true,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
cmd, err := btcjson.UnmarshalCmd(&test.request)
if err != nil {
t.Errorf("Test #%d (%s) error - got %T (%v)", i, test.name,
err, err)
continue
}
cc := cmd.(*btcjson.GetRawTransactionCmd)
verbose := *cc.Verbose
if verbose != test.expect {
t.Errorf("Test #%d (%s) got %t, want %v", i, test.name,
verbose, test.expect)
continue
}
}
}

View file

@ -5,7 +5,7 @@
/* /*
Package btcjson provides primitives for working with the bitcoin JSON-RPC API. Package btcjson provides primitives for working with the bitcoin JSON-RPC API.
# Overview Overview
When communicating via the JSON-RPC protocol, all of the commands need to be When communicating via the JSON-RPC protocol, all of the commands need to be
marshalled to and from the the wire in the appropriate format. This package marshalled to and from the the wire in the appropriate format. This package
@ -14,7 +14,7 @@ provides data structures and primitives to ease this process.
In addition, it also provides some additional features such as custom command In addition, it also provides some additional features such as custom command
registration, command categorization, and reflection-based help generation. registration, command categorization, and reflection-based help generation.
# JSON-RPC Protocol Overview JSON-RPC Protocol Overview
This information is not necessary in order to use this package, but it does This information is not necessary in order to use this package, but it does
provide some intuition into what the marshalling and unmarshalling that is provide some intuition into what the marshalling and unmarshalling that is
@ -47,7 +47,7 @@ with it) doesn't always follow the spec and will sometimes return an error
string in the result field with a null error for certain commands. However, string in the result field with a null error for certain commands. However,
for the most part, the error field will be set as described on failure. for the most part, the error field will be set as described on failure.
# Marshalling and Unmarshalling Marshalling and Unmarshalling
Based upon the discussion above, it should be easy to see how the types of this Based upon the discussion above, it should be easy to see how the types of this
package map into the required parts of the protocol package map into the required parts of the protocol
@ -63,8 +63,8 @@ MarshalResponse functions are provided. They return the raw bytes ready to be
sent across the wire. sent across the wire.
Unmarshalling a received Request object is a two step process: Unmarshalling a received Request object is a two step process:
1. Unmarshal the raw bytes into a Request struct instance via json.Unmarshal 1) Unmarshal the raw bytes into a Request struct instance via json.Unmarshal
2. Use UnmarshalCmd on the Result field of the unmarshalled Request to create 2) Use UnmarshalCmd on the Result field of the unmarshalled Request to create
a concrete command or notification instance with all struct fields set a concrete command or notification instance with all struct fields set
accordingly accordingly
@ -72,14 +72,14 @@ This approach is used since it provides the caller with access to the additional
fields in the request that are not part of the command such as the ID. fields in the request that are not part of the command such as the ID.
Unmarshalling a received Response object is also a two step process: Unmarshalling a received Response object is also a two step process:
1. Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal 1) Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal
2. Depending on the ID, unmarshal the Result field of the unmarshalled 2) Depending on the ID, unmarshal the Result field of the unmarshalled
Response to create a concrete type instance Response to create a concrete type instance
As above, this approach is used since it provides the caller with access to the As above, this approach is used since it provides the caller with access to the
fields in the response such as the ID and Error. fields in the response such as the ID and Error.
# Command Creation Command Creation
This package provides two approaches for creating a new command. This first, This package provides two approaches for creating a new command. This first,
and preferred, method is to use one of the New<Foo>Cmd functions. This allows and preferred, method is to use one of the New<Foo>Cmd functions. This allows
@ -93,7 +93,7 @@ obviously, run-time which means any mistakes won't be found until the code is
actually executed. However, it is quite useful for user-supplied commands actually executed. However, it is quite useful for user-supplied commands
that are intentionally dynamic. that are intentionally dynamic.
# Custom Command Registration Custom Command Registration
The command handling of this package is built around the concept of registered The command handling of this package is built around the concept of registered
commands. This is true for the wide variety of commands already provided by the commands. This is true for the wide variety of commands already provided by the
@ -104,7 +104,7 @@ function for this purpose.
A list of all registered methods can be obtained with the RegisteredCmdMethods A list of all registered methods can be obtained with the RegisteredCmdMethods
function. function.
# Command Inspection Command Inspection
All registered commands are registered with flags that identify information such All registered commands are registered with flags that identify information such
as whether the command applies to a chain server, wallet server, or is a as whether the command applies to a chain server, wallet server, or is a
@ -112,7 +112,7 @@ notification along with the method name to use. These flags can be obtained
with the MethodUsageFlags flags, and the method can be obtained with the with the MethodUsageFlags flags, and the method can be obtained with the
CmdMethod function. CmdMethod function.
# Help Generation Help Generation
To facilitate providing consistent help to users of the RPC server, this package To facilitate providing consistent help to users of the RPC server, this package
exposes the GenerateHelp and function which uses reflection on registered exposes the GenerateHelp and function which uses reflection on registered
@ -122,7 +122,7 @@ generate the final help text.
In addition, the MethodUsageText function is provided to generate consistent In addition, the MethodUsageText function is provided to generate consistent
one-line usage for registered commands and notifications using reflection. one-line usage for registered commands and notifications using reflection.
# Errors Errors
There are 2 distinct type of errors supported by this package: There are 2 distinct type of errors supported by this package:

View file

@ -7,7 +7,7 @@ package btcjson_test
import ( import (
"testing" "testing"
"github.com/lbryio/lbcd/btcjson" "github.com/btcsuite/btcd/btcjson"
) )
// TestErrorCodeStringer tests the stringized output for the ErrorCode type. // TestErrorCodeStringer tests the stringized output for the ErrorCode type.

Some files were not shown because too many files have changed in this diff Show more