Compare commits

...

88 commits

Author SHA1 Message Date
Brannon King
e056f8ac23 sketching pruning; it doesn't work yet 2021-10-04 16:35:56 -04:00
Brannon King
742881a29a made payload interface 2021-10-01 23:08:59 -04:00
Brannon King
55abc9d25c made "tx" be used for both hash and raw output (like lbrycrd & bitcoin)
We want the empty tx array


use initializer to fill base result
2021-10-01 22:24:03 -04:00
Brannon King
dc230888ef interrupt initial trie build via ctrl+c 2021-10-01 11:25:32 -04:00
Brannon King
ba05456830 config: don't set ulimit on windows
Use existing file limit mechanism
2021-10-01 11:22:07 -04:00
Roy Lee
07d25ba7ce rpc: update getblock response 2021-09-28 13:23:11 -07:00
Brannon King
d884f96553 set all pebble DB's to 2k handles, set process RLimit 2021-09-28 13:23:10 -07:00
Brannon King
eb165fb359 lower flush period due to smaller block time, fixed possible data race 2021-09-24 11:00:25 -04:00
Brannon King
52f41459d5 fixed unnecessary peer disconnect 2021-09-24 10:58:55 -04:00
Roy Lee
3910319e80 [lbry] ci: separate test and lint 2021-09-14 11:43:19 -07:00
Roy Lee
db25b9b11b [lbry] ci: add golangci-lint action 2021-09-14 11:17:01 -07:00
Brannon King
6009f9048c fix bug with case folding table 2021-09-14 13:46:47 -04:00
Roy Lee
fa9239e0c5 [lbry] ci: use golangci.yml instead individual args 2021-09-13 17:00:55 -07:00
Roy Lee
edfffd979d [lbry] ci: add golangci.yml 2021-09-13 16:57:14 -07:00
Roy Lee
02f76b2e8e [lbry] ci: fix linting (gofmt) 2021-09-13 16:57:14 -07:00
Roy Lee
9ebe440325 [lbry] rpcclient: fix resource leak 2021-09-13 16:57:14 -07:00
Roy Lee
a4cc516896 [lbry] ci: fix linting (nakedret) 2021-09-13 16:57:14 -07:00
Roy Lee
690954d843 bump libcutil to v1.0.201 2021-09-11 21:49:21 -07:00
Brannon King
035ff2a799 updated go.mod 2021-09-11 20:03:18 -04:00
Brannon King
79d7e65a35 fix some BTC strings 2021-09-11 17:50:41 -04:00
Brannon King
103ab86904 fix regtest difficulty 2021-09-11 17:50:32 -04:00
Brannon King
cee79f6635 fixed issue with rollback over normalization fork 2021-09-11 17:50:32 -04:00
Brannon King
96f3d421df use newer lbcutil, rename refs for it 2021-09-10 16:51:53 -04:00
Brannon King
3a046d153c step 1 of updating module paths to not use replace 2021-09-10 16:23:04 -04:00
Roy Lee
a56581d967 [lbry] remove tests that uses internal package for now 2021-09-07 13:25:04 -07:00
eugene
3c4900275c mempool: export isDust for use in other projects
This changes isDust to IsDust so other golang projects (btcwallet
or lnd) can use the precise dust calculation used by btcd.
2021-09-07 13:25:04 -07:00
Calvin Kim
9d3279f215 rpcserverhelp: Remove extra period for gettxout--synopsis 2021-09-07 13:25:04 -07:00
Gabriel Nasr
40fe74adb8 btcjson: Update WalletCreateFundedPsbtOpts.FeeRate from *int64 to *float64 2021-09-07 13:25:04 -07:00
Brannon King
ac1fdda8a0 sanitizing readmes for lbcd 2021-08-31 15:53:55 -04:00
Brannon King
79e392b85d fixing tmp folder cleanup 2021-08-30 09:09:48 -04:00
Brannon King
5588af7d5b updated main README 2021-08-27 15:46:13 -04:00
Brannon King
83b6a8dc18 include lbcctl in release 2021-08-27 13:25:53 -04:00
Brannon King
1ba1a10e59 set release version 2021-08-27 13:04:46 -04:00
Brannon King
a51be72029 fix worker count 2021-08-27 13:04:37 -04:00
Brannon King
79987722bb fixed bug with block rollback; re-orgs should work now 2021-08-27 10:54:26 -04:00
Brannon King
1834d95b43 rollback on hash mismatch 2021-08-26 15:07:42 -04:00
Roy Lee
9c9bd3e3a5 [lbry] go module: update gopsutil to v3.21.7
v3.21.6 breaks in go 1.17
2021-08-23 21:24:37 -07:00
Brannon King
8a5e74ebe6 Disable UPnP on regtest and simnet 2021-08-23 12:43:16 -04:00
Roy Lee
7154e57d49 [lbry]: btcd: cleanup claim databases for regression test 2021-08-20 12:25:52 -04:00
Roy Lee
bf86d03f84 [lbry] claimtrie: init blockRepo with empty merkle hash at block 0 2021-08-20 12:00:51 -04:00
Brannon King
d2f8ad7657 remove symbols in release package 2021-08-19 17:57:28 -04:00
Brannon King
ca18f3e8a2 fix bad rune handling
formatting
2021-08-19 17:52:01 -04:00
Brannon King
0be18205c8 updating build scripts to not use ICU 2021-08-19 17:51:47 -04:00
Brannon King
61de064575 replaced x/text/cases with our own impl. 2021-08-19 17:51:07 -04:00
Brannon King
e4c637b02a issues found in code review 2021-08-19 17:50:43 -04:00
Brannon King
d83eaa4fed fix unexpected AppendBlock call 2021-08-19 17:50:19 -04:00
Roy Lee
c7285883a6 [lbry] mining: fix generatetoaddress 2021-08-19 16:39:53 -04:00
Brannon King
fe1ce376d8 [lbry] mining: calculate claimtrie root hash for generate RPC 2021-08-19 14:41:48 -04:00
Brannon King
d19bcd60db [lbry] brought in upnp fix from dcrd 2021-08-19 14:19:21 -04:00
Brannon King
7414ad7b54 [lbry] switched upnp param to its opposite 2021-08-19 14:19:21 -04:00
Brannon King
c8cd97fe4d [lbry] enable segwit 2021-08-19 14:19:21 -04:00
Brannon King
a06875fe46 [lbry] remove claim prefix for addr calculation 2021-08-19 14:19:21 -04:00
Brannon King
5f872b37cf [lbry] print out memory usage periodically 2021-08-19 14:19:21 -04:00
Brannon King
9af0566433 [lbry] blockchain: Consider a block with timestamp less 6 hours 'current' 2021-08-19 14:19:21 -04:00
Brannon King
aa518c59bb [lbry] rpc: update defaultMaxFeeRate from 0.1 LBC to 0.5 LBC 2021-08-19 14:19:21 -04:00
Brannon King
1402e61807 [lbry] rpc: output segwit rule 2021-08-19 14:19:21 -04:00
Brannon King
a061c31208 [lbry] rpc: add ClaimTrie root hash to GetBlockTemplate() 2021-08-19 14:19:21 -04:00
Brannon King
983e4c6000 [lbry] rpc: support claim related methods 2021-08-19 14:19:21 -04:00
Mark Beamer Jr
a310f8b598 [lbry] rpcclient: allow any chain params not specified in repo already. 2021-08-19 14:19:21 -04:00
Roy Lee
ed2c764c9d [lbry] config: support 'clmtimpl' and 'clmtheight' flags 2021-08-19 14:19:21 -04:00
Roy Lee
4b8bd4c238 [lbry] go module: update go modules
go mod init github.com/lbryio/chain
go mod edit --replace github.com/btcsuite/btcd=./
go mod edit --replace github.com/btcsuite/btcutil=github.com/lbryio/lbcutil@f93c78a8bc21
go mod tidy
2021-08-19 14:19:21 -04:00
Roy Lee
9080abc2c6 [lbry] claimtrie: import current snapshot
Sync to tip

Co-authored-by: Brannon King <countprimes@gmail.com>
2021-08-19 14:19:21 -04:00
Roy Lee
0224bf295b [lbry] blockchain: connect to ClaimTrie
Co-authored-by: Brannon King <countprimes@gmail.com>
2021-08-19 14:19:21 -04:00
Roy Lee
8e059c14d7 [lbry] FIXME: remove the tests for now to pass CI.
Some test files failed to build as the go module "replace" doesn't work
with test and internal packages yet.

The other tests need updates to the testdata.
2021-08-19 14:19:21 -04:00
Brannon King
9d0dfbe87e [lbry] log: support claimtrie entries 2021-08-19 14:19:21 -04:00
Roy Lee
62479740ae [lbry] misc: change RPC port from 8334 to 9245 2021-08-19 14:19:20 -04:00
Roy Lee
1895c9069f [lbry] txscript: recognize LBRY claim script OPCODES 2021-08-19 14:19:20 -04:00
Roy Lee
9caab1e2e1 [lbry] txscript: initial porting of claim script
Co-authored-by: Brannon King <countprimes@gmail.com>
2021-08-19 14:19:20 -04:00
Roy Lee
0a22e00498 [lbry] txscript: change MaxScriptSize from 10,000 to 20,005 2021-08-19 14:19:20 -04:00
Roy Lee
866b0cb610 [lbry] server: update client version to /btcwire:0.5.0/LBRY.GO:0.12.2/
TODO: double check if lbryd bumps the version.
2021-08-19 14:19:20 -04:00
Brannon King
3d9d9b1912 [lbry] blockchain: support force active fork deployment 2021-08-19 14:19:20 -04:00
Roy Lee
27b01f77b3 [lbry] blockchain, mempool: validate txscripts
Co-authored-by: Brannon King <countprimes@gmail.com>
2021-08-19 14:19:20 -04:00
Roy Lee
7d412b4e2f [lbry] blockchain: change Block Subsidy algorithm 2021-08-19 14:19:20 -04:00
Roy Lee
a6189cb439 [lbry] blockchain: change the difficulty adjustment algorithm.
adjusted := target + (actual - target) / 8

  max := target + (target / 2)
  min := target - (target / 8)

  if adjusted > max {
    adjusted = max
  } else if adj < min {
    adjusted = min
  }

  diffculty := lastDifficulty * adjusted / target
2021-08-19 14:19:20 -04:00
Roy Lee
1264d4581d [lbry] blockchain: make UTXO in Genesis block spendable 2021-08-19 14:19:20 -04:00
Roy Lee
ba7266c20c [lbry] blockchain, txscript: change maxScriptElementSize from 520 t0 20,000 bytes 2021-08-19 14:19:20 -04:00
Roy Lee
dce6d65452 [lbry] blockchain, wire: verify blockheaders using LBRY PoW 2021-08-19 14:19:20 -04:00
Roy Lee
43bed18649 [lbry] blockchain: change max block size to 2,000,000 2021-08-19 14:19:20 -04:00
Roy Lee
b704fef973 [lbry] wire: update protocol NetIDs 2021-08-19 14:19:20 -04:00
Roy Lee
5b72ef6719 [lbry] chaincfg: update chainparams for LBRY chain
Co-authored-by: Brannon King <countprimes@gmail.com>
Co-authored-by: Alex Grintsvayg <grin@lbry.com>
2021-08-19 14:19:20 -04:00
Roy Lee
f535c88f4a [lbry] chaincfg: setup genisis blocks 2021-08-19 14:19:20 -04:00
Roy Lee
eb3bde09f2 [lbry] chaincfg: implement LBRY PoW Hash 2021-08-19 14:19:20 -04:00
Roy Lee
c65dd82284 [lbry] add ClaimTrie to Block Header 2021-08-19 14:19:20 -04:00
Roy Lee
b7d3e11250 [lbry] misc: rename btcd to lbcd
Currently, we're only focus on the changes that are visible in
run time, such as executable name, config files/dirs, errors
and hint messages. And wire messages exchanged in network.

btc{d,ctl,wallet} lbc{d,ctl,wallet}
2021-08-19 14:17:22 -04:00
Brannon King
31ce21deb6 profile: support fgprof (flame graph) 2021-08-19 13:41:04 -04:00
Brannon King
0e5bf1c24f wire: optimize binaryFreeList handling 2021-08-19 13:41:04 -04:00
Roy Lee
61c0f0df99 gitignore: ignore IDE stuff 2021-08-19 13:41:04 -04:00
Roy Lee
82141c408c ci: Update Go toolchain to 1.16 2021-08-19 13:38:26 -04:00
352 changed files with 14240 additions and 28243 deletions

View file

@ -3,26 +3,23 @@ on: [push, pull_request]
jobs: jobs:
build: build:
name: Go CI name: Go CI
runs-on: ubuntu-latest runs-on: self-hosted
strategy: strategy:
matrix: matrix:
go: [1.14, 1.15] go: [1.16]
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

58
.github/workflows/create-release.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Create release
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
jobs:
build:
strategy:
matrix:
go: [1.16]
os: [linux, darwin, windows]
ar: [amd64, arm64]
exclude:
- go: 1.16
os: windows
ar: arm64
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout source
uses: actions/checkout@v2
- name: Build executables
env:
GOOS: ${{ matrix.os }}
GOARCH: ${{ matrix.ar }}
CGO_ENABLED: 0
run: |
go build -trimpath -ldflags="-s -w -buildid=" -v -o artifacts/ .
go build -trimpath -ldflags="-s -w -buildid=" -v -o artifacts/ ./cmd/lbcctl/
- name: SHA256 sum
run: sha256sum -b artifacts/* > artifacts/lbcd.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: lbcd-${{ matrix.os }}-${{ matrix.ar }}
path: artifacts/*
# for releases see https://trstringer.com/github-actions-create-release-upload-artifacts/
# AWS S3 support:
# - name: Upload to Amazon S3
# uses: ItsKarma/aws-cli@v1.70.0
# with:
# args: s3 sync .release s3://my-bucket-name
# env:
# # Make sure to add the secrets in the repo settings page
# # AWS_REGION is set to us-east-1 by default
# AWS_ACCESS_KEY_ID: $
# AWS_SECRET_ACCESS_KEY: $
# AWS_REGION: us-east-1

35
.github/workflows/full-sync-part-1.yml vendored Normal file
View file

@ -0,0 +1,35 @@
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.16]
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 --connect=127.0.0.1 --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

37
.github/workflows/full-sync-part-2.yml vendored Normal file
View file

@ -0,0 +1,37 @@
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.16]
steps:
- run: |
echo "Note ${{ github.event.inputs.note }}!"
- name: Set up 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 --connect=127.0.0.1 --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

57
.github/workflows/golangci-lint.yml vendored Normal file
View file

@ -0,0 +1,57 @@
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.17.0'
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

13
.gitignore vendored
View file

@ -3,6 +3,7 @@
# Databases # Databases
btcd.db btcd.db
lbcd.db
*-shm *-shm
*-wal *-wal
@ -33,6 +34,18 @@ _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

152
.golangci.yml Normal file
View file

@ -0,0 +1,152 @@
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

1230
CHANGES

File diff suppressed because it is too large Load diff

View file

@ -9,14 +9,14 @@
# docker build . -t yourregistry/btcd --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/btcsuite/btcd/tree/master/docs # https://github.com/lbryio/lbcd/tree/master/docs
# #
# 8333 Mainnet Bitcoin peer-to-peer port # 8333 Mainnet Bitcoin peer-to-peer port
# 8334 Mainet RPC port # 8334 Mainet RPC port
ARG ARCH=amd64 ARG ARCH=amd64
FROM golang:1.14-alpine3.12 AS build-container FROM golang:1.16-alpine3.14 AS build-container
ARG ARCH ARG ARCH
ENV GO111MODULE=on ENV GO111MODULE=on
@ -25,17 +25,16 @@ ADD . /app
WORKDIR /app WORKDIR /app
RUN set -ex \ RUN set -ex \
&& if [ "${ARCH}" = "amd64" ]; then export GOARCH=amd64; fi \ && if [ "${ARCH}" = "amd64" ]; then export GOARCH=amd64; fi \
&& if [ "${ARCH}" = "arm32v7" ]; then export GOARCH=arm; fi \
&& if [ "${ARCH}" = "arm64v8" ]; then export GOARCH=arm64; fi \ && if [ "${ARCH}" = "arm64v8" ]; then export GOARCH=arm64; fi \
&& echo "Compiling for $GOARCH" \ && echo "Compiling for $GOARCH" \
&& go install -v . ./cmd/... && go install -v . ./cmd/...
FROM $ARCH/alpine:3.12 FROM $ARCH/alpine:3.14
COPY --from=build-container /go/bin /bin COPY --from=build-container /go/bin /bin
VOLUME ["/root/.btcd"] VOLUME ["/root/.lbcd"]
EXPOSE 8333 8334 EXPOSE 9245 9246
ENTRYPOINT ["btcd"] ENTRYPOINT ["lbcd"]

View file

@ -1,5 +1,6 @@
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

143
README.md
View file

@ -1,121 +1,80 @@
btcd lbcd
==== ====
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions) [![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
[![Coverage Status](https://coveralls.io/repos/github/btcsuite/btcd/badge.svg?branch=master)](https://coveralls.io/github/btcsuite/btcd?branch=master) [![Coverage Status](https://coveralls.io/repos/github/lbryio/lbcd/badge.svg?branch=master)](https://coveralls.io/github/lbryio/lbcd?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/btcsuite/btcd) <!--[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd)-->
btcd is an alternative full node bitcoin implementation written in Go (golang). lbcd is a full node implementation of LBRY's blockchain written in Go (golang).
This project is currently under active development and is in a Beta state. It This project is currently under active development and is in a Beta state while we
is extremely stable and has been in production use since October 2013. ensure it matches LBRYcrd's functionality. The intention is that it properly downloads, validates, and serves the block chain using the exact
rules (including consensus bugs) for block acceptance as LBRYcrd. We have
taken great care to avoid lbcd causing a fork to the blockchain.
It properly downloads, validates, and serves the block chain using the exact Note: lbcd does *NOT* include
rules (including consensus bugs) for block acceptance as Bitcoin Core. We have wallet functionality. That functionality is provided by the
taken great care to avoid btcd causing a fork to the block chain. It includes a [lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk).
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.
It also properly relays newly mined blocks, maintains a transaction pool, and ## Security
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).
One key difference between btcd and Bitcoin Core is that btcd does *NOT* include We take security seriously. Please contact [security](mailto:security@lbry.com) regarding any security issues.
wallet functionality and this was a very intentional design decision. See the Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
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 We maintain a mailing list for notifications of upgrades, security issues,
directly with btcd. That functionality is provided by the and soft/hard forks. To join, visit https://lbry.com/forklist
[btcwallet](https://github.com/btcsuite/btcwallet) and
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
which are both under active development.
## Requirements ## Requirements
[Go](http://golang.org) 1.14 or newer. All common operating systems are supported. lbcd requires at least 8GB of RAM
and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time.
Using a fast NVMe disk is recommended.
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.
For compilation, [Go](http://golang.org) 1.16 or newer is required.
## Installation ## Installation
https://github.com/btcsuite/btcd/releases Acquire binary files from https://github.com/lbryio/lbcd/releases
#### Linux/BSD/MacOSX/POSIX - Build from Source #### To build from Source on Linux/BSD/MacOSX/POSIX:
- Install Go according to the installation instructions here: - Install Go according to its [installation instructions](http://golang.org/doc/install).
http://golang.org/doc/install - Use your favorite git tool to acquire the lbcd source.
- lbcd has no non-Go dependencies; it can be built by simply running `go build .`
- lbcctl can be built similarly:
- Ensure Go was installed properly and is a supported version: Both [GoLand](https://www.jetbrains.com/go/)
and [VS Code](https://code.visualstudio.com/docs/languages/go) IDEs are supported.
```bash ## Usage
$ go version
$ go env GOROOT GOPATH By default, data and logs are stored in `~/.lbcd/`
To enable RPC access a username and password is required. Example:
``` ```
./lbcd --notls --rpcuser=x --rpcpass=y --txindex &
NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is ./lbcctl --notls --rpcuser=x --rpcpass=y getblocktemplate
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.
- Run the following commands to obtain btcd, all dependencies, and install it:
```bash
$ cd $GOPATH/src/github.com/btcsuite/btcd
$ GO111MODULE=on go install -v . ./cmd/...
``` ```
<!-- TODO: explain how to use TLS certificates. -->
- btcd (and utilities) will now be installed in ```$GOPATH/bin```. If you did ## Contributing
not already add the bin directory to your system path during Go installation,
we recommend you do so now.
## Updating Contributions to this project are welcome, encouraged, and compensated.
The [integrated github issue tracker](https://github.com/lbryio/lbcd/issues)
#### Linux/BSD/MacOSX/POSIX - Build from Source is used for this project. All pull requests will be considered.
- Run the following commands to update btcd, all dependencies, and install it:
```bash
$ cd $GOPATH/src/github.com/btcsuite/btcd
$ git pull
$ GO111MODULE=on go install -v . ./cmd/...
```
## Getting Started
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.
#### Linux/BSD/POSIX/Source
```bash
$ ./btcd
```
## IRC
- irc.freenode.net
- channel #btcd
- [webchat](https://webchat.freenode.net/?channels=btcd)
## Issue Tracker
The [integrated github issue tracker](https://github.com/btcsuite/btcd/issues)
is used for this project.
## Documentation
The documentation is a work-in-progress. It is located in the [docs](https://github.com/btcsuite/btcd/tree/master/docs) folder.
## Release Verification
<!-- ## Release Verification
Please see our [documentation on the current build/verification Please see our [documentation on the current build/verification
process](https://github.com/btcsuite/btcd/tree/master/release) for all our process](https://github.com/lbryio/lbcd/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
btcd is licensed under the [copyfree](http://copyfree.org) ISC License. lbcd 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/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
// AddrManager provides a concurrency safe address manager for caching potential // AddrManager provides a concurrency safe address manager for caching potential

View file

@ -7,7 +7,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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/btcsuite/btcd/addrmgr" "github.com/lbryio/lbcd/addrmgr"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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

View file

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

View file

@ -7,7 +7,7 @@ package addrmgr
import ( import (
"time" "time"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
// KnownAddress tracks information about a known network address that is used // KnownAddress tracks information about a known network address that is used

View file

@ -1,114 +0,0 @@
// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package addrmgr_test
import (
"math"
"testing"
"time"
"github.com/btcsuite/btcd/addrmgr"
"github.com/btcsuite/btcd/wire"
)
func TestChance(t *testing.T) {
now := time.Unix(time.Now().Unix(), 0)
var tests = []struct {
addr *addrmgr.KnownAddress
expected float64
}{
{
//Test normal case
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
0, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
1.0,
}, {
//Test case in which lastseen < 0
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(20 * time.Second)},
0, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
1.0,
}, {
//Test case in which lastattempt < 0
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
0, time.Now().Add(30*time.Minute), time.Now(), false, 0),
1.0 * .01,
}, {
//Test case in which lastattempt < ten minutes
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
0, time.Now().Add(-5*time.Minute), time.Now(), false, 0),
1.0 * .01,
}, {
//Test case with several failed attempts.
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
2, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
1 / 1.5 / 1.5,
},
}
err := .0001
for i, test := range tests {
chance := addrmgr.TstKnownAddressChance(test.addr)
if math.Abs(test.expected-chance) >= err {
t.Errorf("case %d: got %f, expected %f", i, chance, test.expected)
}
}
}
func TestIsBad(t *testing.T) {
now := time.Unix(time.Now().Unix(), 0)
future := now.Add(35 * time.Minute)
monthOld := now.Add(-43 * time.Hour * 24)
secondsOld := now.Add(-2 * time.Second)
minutesOld := now.Add(-27 * time.Minute)
hoursOld := now.Add(-5 * time.Hour)
zeroTime := time.Time{}
futureNa := &wire.NetAddress{Timestamp: future}
minutesOldNa := &wire.NetAddress{Timestamp: minutesOld}
monthOldNa := &wire.NetAddress{Timestamp: monthOld}
currentNa := &wire.NetAddress{Timestamp: secondsOld}
//Test addresses that have been tried in the last minute.
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(futureNa, 3, secondsOld, zeroTime, false, 0)) {
t.Errorf("test case 1: addresses that have been tried in the last minute are not bad.")
}
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(monthOldNa, 3, secondsOld, zeroTime, false, 0)) {
t.Errorf("test case 2: addresses that have been tried in the last minute are not bad.")
}
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 3, secondsOld, zeroTime, false, 0)) {
t.Errorf("test case 3: addresses that have been tried in the last minute are not bad.")
}
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 3, secondsOld, monthOld, true, 0)) {
t.Errorf("test case 4: addresses that have been tried in the last minute are not bad.")
}
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 2, secondsOld, secondsOld, true, 0)) {
t.Errorf("test case 5: addresses that have been tried in the last minute are not bad.")
}
//Test address that claims to be from the future.
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(futureNa, 0, minutesOld, hoursOld, true, 0)) {
t.Errorf("test case 6: addresses that claim to be from the future are bad.")
}
//Test address that has not been seen in over a month.
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(monthOldNa, 0, minutesOld, hoursOld, true, 0)) {
t.Errorf("test case 7: addresses more than a month old are bad.")
}
//It has failed at least three times and never succeeded.
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 3, minutesOld, zeroTime, true, 0)) {
t.Errorf("test case 8: addresses that have never succeeded are bad.")
}
//It has failed ten times in the last week
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 10, minutesOld, monthOld, true, 0)) {
t.Errorf("test case 9: addresses that have not succeeded in too long are bad.")
}
//Test an address that should work.
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 2, minutesOld, hoursOld, true, 0)) {
t.Errorf("test case 10: This should be a valid address.")
}
}

View file

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

View file

@ -8,8 +8,8 @@ import (
"net" "net"
"testing" "testing"
"github.com/btcsuite/btcd/addrmgr" "github.com/lbryio/lbcd/addrmgr"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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

View file

@ -1,30 +1,9 @@
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)
Package blockchain implements bitcoin block handling and chain selection rules. ### Bitcoin Chain Processing Overview
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
@ -57,47 +36,4 @@ is by no means exhaustive:
transaction values transaction values
- 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/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// maybeAcceptBlock potentially accepts a block into the block chain and, if // maybeAcceptBlock potentially accepts a block into the block chain and, if

View file

@ -1,31 +0,0 @@
// Copyright (c) 2015 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/btcutil"
)
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
// function.
func BenchmarkIsCoinBase(b *testing.B) {
tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
IsCoinBase(tx)
}
}
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
// function.
func BenchmarkIsCoinBaseTx(b *testing.B) {
tx := Block100000.Transactions[1]
b.ResetTimer()
for i := 0; i < b.N; i++ {
IsCoinBaseTx(tx)
}
}

View file

@ -10,10 +10,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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,6 +93,7 @@ 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
@ -114,6 +115,7 @@ 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
@ -144,6 +146,7 @@ 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

@ -11,12 +11,14 @@ import (
"sync" "sync"
"time" "time"
"github.com/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcd/claimtrie"
) )
const ( const (
@ -180,6 +182,8 @@ 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
@ -571,7 +575,8 @@ 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.
if b.isCurrent() { current := 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 {
@ -579,6 +584,13 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
} }
} }
// Handle LBRY Claim Scripts
if b.claimTrie != nil {
if err := b.ParseClaimScripts(block, node, view, current); 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 {
@ -761,6 +773,12 @@ 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()
@ -1208,7 +1226,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 24 hours ago // - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
// //
// 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 {
@ -1219,13 +1237,13 @@ func (b *BlockChain) isCurrent() bool {
return false return false
} }
// Not current if the latest best block has a timestamp before 24 hours // Not current if the latest best block has a timestamp before 7 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.
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix() hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
return b.bestChain.Tip().timestamp >= minus24Hours return b.bestChain.Tip().timestamp >= hours
} }
// IsCurrent returns whether or not the chain believes it is current. Several // IsCurrent returns whether or not the chain believes it is current. Several
@ -1614,6 +1632,11 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
return headers return headers
} }
// 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.
@ -1700,6 +1723,8 @@ 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.
@ -1736,7 +1761,6 @@ 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,
@ -1745,8 +1769,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 / adjustmentFactor, minRetargetTimespan: targetTimespan - (targetTimespan / 8),
maxRetargetTimespan: targetTimespan * adjustmentFactor, maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock), blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: newBlockIndex(config.DB, params), index: newBlockIndex(config.DB, params),
hashCache: config.HashCache, hashCache: config.HashCache,
@ -1755,6 +1779,7 @@ 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
@ -1764,6 +1789,20 @@ 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
@ -1783,6 +1822,14 @@ 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,
@ -1790,3 +1837,63 @@ 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

@ -1,966 +0,0 @@
// Copyright (c) 2013-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 (
"reflect"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"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
// CalcSequenceLock method of a Chain instance. The tests exercise several
// combinations of inputs to the CalcSequenceLock function in order to ensure
// the returned SequenceLocks are correct for each test instance.
func TestCalcSequenceLock(t *testing.T) {
netParams := &chaincfg.SimNetParams
// We need to activate CSV in order to test the processing logic, so
// manually craft the block version that's used to signal the soft-fork
// activation.
csvBit := netParams.Deployments[chaincfg.DeploymentCSV].BitNumber
blockVersion := int32(0x20000000 | (uint32(1) << csvBit))
// Generate enough synthetic blocks to activate CSV.
chain := newFakeChain(netParams)
node := chain.bestChain.Tip()
blockTime := node.Header().Timestamp
numBlocksToActivate := (netParams.MinerConfirmationWindow * 3)
for i := uint32(0); i < numBlocksToActivate; i++ {
blockTime = blockTime.Add(time.Second)
node = newFakeNode(node, blockVersion, 0, blockTime)
chain.index.AddNode(node)
chain.bestChain.SetTip(node)
}
// Create a utxo view with a fake utxo for the inputs used in the
// transactions created below. This utxo is added such that it has an
// age of 4 blocks.
targetTx := btcutil.NewTx(&wire.MsgTx{
TxOut: []*wire.TxOut{{
PkScript: nil,
Value: 10,
}},
})
utxoView := NewUtxoViewpoint()
utxoView.AddTxOuts(targetTx, int32(numBlocksToActivate)-4)
utxoView.SetBestHash(&node.hash)
// Create a utxo that spends the fake utxo created above for use in the
// transactions created in the tests. It has an age of 4 blocks. Note
// that the sequence lock heights are always calculated from the same
// point of view that they were originally calculated from for a given
// utxo. That is to say, the height prior to it.
utxo := wire.OutPoint{
Hash: *targetTx.Hash(),
Index: 0,
}
prevUtxoHeight := int32(numBlocksToActivate) - 4
// Obtain the median time past from the PoV of the input created above.
// The MTP for the input is the MTP from the PoV of the block *prior*
// to the one that included it.
medianTime := node.RelativeAncestor(5).CalcPastMedianTime().Unix()
// The median time calculated from the PoV of the best block in the
// test chain. For unconfirmed inputs, this value will be used since
// the MTP will be calculated from the PoV of the yet-to-be-mined
// block.
nextMedianTime := node.CalcPastMedianTime().Unix()
nextBlockHeight := int32(numBlocksToActivate) + 1
// Add an additional transaction which will serve as our unconfirmed
// output.
unConfTx := &wire.MsgTx{
TxOut: []*wire.TxOut{{
PkScript: nil,
Value: 5,
}},
}
unConfUtxo := wire.OutPoint{
Hash: unConfTx.TxHash(),
Index: 0,
}
// Adding a utxo with a height of 0x7fffffff indicates that the output
// is currently unmined.
utxoView.AddTxOuts(btcutil.NewTx(unConfTx), 0x7fffffff)
tests := []struct {
tx *wire.MsgTx
view *UtxoViewpoint
mempool bool
want *SequenceLock
}{
// A transaction of version one should disable sequence locks
// as the new sequence number semantics only apply to
// transactions version 2 or higher.
{
tx: &wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 3),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: -1,
BlockHeight: -1,
},
},
// A transaction with a single input with max sequence number.
// This sequence number has the high bit set, so sequence locks
// should be disabled.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: wire.MaxTxInSequenceNum,
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: -1,
BlockHeight: -1,
},
},
// A transaction with a single input whose lock time is
// expressed in seconds. However, the specified lock time is
// below the required floor for time based lock times since
// they have time granularity of 512 seconds. As a result, the
// seconds lock-time should be just before the median time of
// the targeted block.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 2),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: medianTime - 1,
BlockHeight: -1,
},
},
// A transaction with a single input whose lock time is
// expressed in seconds. The number of seconds should be 1023
// seconds after the median past time of the last block in the
// chain.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 1024),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: medianTime + 1023,
BlockHeight: -1,
},
},
// A transaction with multiple inputs. The first input has a
// lock time expressed in seconds. The second input has a
// sequence lock in blocks with a value of 4. The last input
// has a sequence number with a value of 5, but has the disable
// bit set. So the first lock should be selected as it's the
// latest lock that isn't disabled.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 2560),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 4),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 5) |
wire.SequenceLockTimeDisabled,
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: prevUtxoHeight + 3,
},
},
// Transaction with a single input. The input's sequence number
// encodes a relative lock-time in blocks (3 blocks). The
// sequence lock should have a value of -1 for seconds, but a
// height of 2 meaning it can be included at height 3.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 3),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: -1,
BlockHeight: prevUtxoHeight + 2,
},
},
// A transaction with two inputs with lock times expressed in
// seconds. The selected sequence lock value for seconds should
// be the time further in the future.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 5120),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 2560),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: medianTime + (10 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: -1,
},
},
// A transaction with two inputs with lock times expressed in
// blocks. The selected sequence lock value for blocks should
// be the height further in the future, so a height of 10
// indicating it can be included at height 11.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 1),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 11),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: -1,
BlockHeight: prevUtxoHeight + 10,
},
},
// A transaction with multiple inputs. Two inputs are time
// based, and the other two are block based. The lock lying
// further into the future for both inputs should be chosen.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 2560),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(true, 6656),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 3),
}, {
PreviousOutPoint: utxo,
Sequence: LockTimeToSequence(false, 9),
}},
},
view: utxoView,
want: &SequenceLock{
Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: prevUtxoHeight + 8,
},
},
// A transaction with a single unconfirmed input. As the input
// is confirmed, the height of the input should be interpreted
// as the height of the *next* block. So, a 2 block relative
// lock means the sequence lock should be for 1 block after the
// *next* block height, indicating it can be included 2 blocks
// after that.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: unConfUtxo,
Sequence: LockTimeToSequence(false, 2),
}},
},
view: utxoView,
mempool: true,
want: &SequenceLock{
Seconds: -1,
BlockHeight: nextBlockHeight + 1,
},
},
// A transaction with a single unconfirmed input. The input has
// a time based lock, so the lock time should be based off the
// MTP of the *next* block.
{
tx: &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: unConfUtxo,
Sequence: LockTimeToSequence(true, 1024),
}},
},
view: utxoView,
mempool: true,
want: &SequenceLock{
Seconds: nextMedianTime + 1023,
BlockHeight: -1,
},
},
}
t.Logf("Running %v SequenceLock tests", len(tests))
for i, test := range tests {
utilTx := btcutil.NewTx(test.tx)
seqLock, err := chain.CalcSequenceLock(utilTx, test.view, test.mempool)
if err != nil {
t.Fatalf("test #%d, unable to calc sequence lock: %v", i, err)
}
if seqLock.Seconds != test.want.Seconds {
t.Fatalf("test #%d got %v seconds want %v seconds",
i, seqLock.Seconds, test.want.Seconds)
}
if seqLock.BlockHeight != test.want.BlockHeight {
t.Fatalf("test #%d got height of %v want height of %v ",
i, seqLock.BlockHeight, test.want.BlockHeight)
}
}
}
// nodeHashes is a convenience function that returns the hashes for all of the
// passed indexes of the provided nodes. It is used to construct expected hash
// slices in the tests.
func nodeHashes(nodes []*blockNode, indexes ...int) []chainhash.Hash {
hashes := make([]chainhash.Hash, 0, len(indexes))
for _, idx := range indexes {
hashes = append(hashes, nodes[idx].hash)
}
return hashes
}
// nodeHeaders is a convenience function that returns the headers for all of
// the passed indexes of the provided nodes. It is used to construct expected
// located headers in the tests.
func nodeHeaders(nodes []*blockNode, indexes ...int) []wire.BlockHeader {
headers := make([]wire.BlockHeader, 0, len(indexes))
for _, idx := range indexes {
headers = append(headers, nodes[idx].Header())
}
return headers
}
// TestLocateInventory ensures that locating inventory via the LocateHeaders and
// LocateBlocks functions behaves as expected.
func TestLocateInventory(t *testing.T) {
// Construct a synthetic block chain with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a
tip := tstTip
chain := newFakeChain(&chaincfg.MainNetParams)
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
branch1Nodes := chainedNodes(branch0Nodes[14], 2)
for _, node := range branch0Nodes {
chain.index.AddNode(node)
}
for _, node := range branch1Nodes {
chain.index.AddNode(node)
}
chain.bestChain.SetTip(tip(branch0Nodes))
// Create chain views for different branches of the overall chain to
// simulate a local and remote node on different parts of the chain.
localView := newChainView(tip(branch0Nodes))
remoteView := newChainView(tip(branch1Nodes))
// Create a chain view for a completely unrelated block chain to
// simulate a remote node on a totally different chain.
unrelatedBranchNodes := chainedNodes(nil, 5)
unrelatedView := newChainView(tip(unrelatedBranchNodes))
tests := []struct {
name string
locator BlockLocator // locator for requested inventory
hashStop chainhash.Hash // stop hash for locator
maxAllowed uint32 // max to locate, 0 = wire const
headers []wire.BlockHeader // expected located headers
hashes []chainhash.Hash // expected located hashes
}{
{
// Empty block locators and unknown stop hash. No
// inventory should be located.
name: "no locators, no stop",
locator: nil,
hashStop: chainhash.Hash{},
headers: nil,
hashes: nil,
},
{
// Empty block locators and stop hash in side chain.
// The expected result is the requested block.
name: "no locators, stop in side",
locator: nil,
hashStop: tip(branch1Nodes).hash,
headers: nodeHeaders(branch1Nodes, 1),
hashes: nodeHashes(branch1Nodes, 1),
},
{
// Empty block locators and stop hash in main chain.
// The expected result is the requested block.
name: "no locators, stop in main",
locator: nil,
hashStop: branch0Nodes[12].hash,
headers: nodeHeaders(branch0Nodes, 12),
hashes: nodeHashes(branch0Nodes, 12),
},
{
// Locators based on remote being on side chain and a
// stop hash local node doesn't know about. The
// expected result is the blocks after the fork point in
// the main chain and the stop hash has no effect.
name: "remote side chain, unknown stop",
locator: remoteView.BlockLocator(nil),
hashStop: chainhash.Hash{0x01},
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
},
{
// Locators based on remote being on side chain and a
// stop hash in side chain. The expected result is the
// blocks after the fork point in the main chain and the
// stop hash has no effect.
name: "remote side chain, stop in side",
locator: remoteView.BlockLocator(nil),
hashStop: tip(branch1Nodes).hash,
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
},
{
// Locators based on remote being on side chain and a
// stop hash in main chain, but before fork point. The
// expected result is the blocks after the fork point in
// the main chain and the stop hash has no effect.
name: "remote side chain, stop in main before",
locator: remoteView.BlockLocator(nil),
hashStop: branch0Nodes[13].hash,
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
},
{
// Locators based on remote being on side chain and a
// stop hash in main chain, but exactly at the fork
// point. The expected result is the blocks after the
// fork point in the main chain and the stop hash has no
// effect.
name: "remote side chain, stop in main exact",
locator: remoteView.BlockLocator(nil),
hashStop: branch0Nodes[14].hash,
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
},
{
// Locators based on remote being on side chain and a
// stop hash in main chain just after the fork point.
// The expected result is the blocks after the fork
// point in the main chain up to and including the stop
// hash.
name: "remote side chain, stop in main after",
locator: remoteView.BlockLocator(nil),
hashStop: branch0Nodes[15].hash,
headers: nodeHeaders(branch0Nodes, 15),
hashes: nodeHashes(branch0Nodes, 15),
},
{
// Locators based on remote being on side chain and a
// stop hash in main chain some time after the fork
// point. The expected result is the blocks after the
// fork point in the main chain up to and including the
// stop hash.
name: "remote side chain, stop in main after more",
locator: remoteView.BlockLocator(nil),
hashStop: branch0Nodes[16].hash,
headers: nodeHeaders(branch0Nodes, 15, 16),
hashes: nodeHashes(branch0Nodes, 15, 16),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash local node doesn't know about.
// The expected result is the blocks after the known
// point in the main chain and the stop hash has no
// effect.
name: "remote main chain past, unknown stop",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: chainhash.Hash{0x01},
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash in a side chain. The expected
// result is the blocks after the known point in the
// main chain and the stop hash has no effect.
name: "remote main chain past, stop in side",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: tip(branch1Nodes).hash,
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash in the main chain before that
// point. The expected result is the blocks after the
// known point in the main chain and the stop hash has
// no effect.
name: "remote main chain past, stop in main before",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: branch0Nodes[11].hash,
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash in the main chain exactly at that
// point. The expected result is the blocks after the
// known point in the main chain and the stop hash has
// no effect.
name: "remote main chain past, stop in main exact",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: branch0Nodes[12].hash,
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash in the main chain just after
// that point. The expected result is the blocks after
// the known point in the main chain and the stop hash
// has no effect.
name: "remote main chain past, stop in main after",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: branch0Nodes[13].hash,
headers: nodeHeaders(branch0Nodes, 13),
hashes: nodeHashes(branch0Nodes, 13),
},
{
// Locators based on remote being on main chain in the
// past and a stop hash in the main chain some time
// after that point. The expected result is the blocks
// after the known point in the main chain and the stop
// hash has no effect.
name: "remote main chain past, stop in main after more",
locator: localView.BlockLocator(branch0Nodes[12]),
hashStop: branch0Nodes[15].hash,
headers: nodeHeaders(branch0Nodes, 13, 14, 15),
hashes: nodeHashes(branch0Nodes, 13, 14, 15),
},
{
// Locators based on remote being at exactly the same
// point in the main chain and a stop hash local node
// doesn't know about. The expected result is no
// located inventory.
name: "remote main chain same, unknown stop",
locator: localView.BlockLocator(nil),
hashStop: chainhash.Hash{0x01},
headers: nil,
hashes: nil,
},
{
// Locators based on remote being at exactly the same
// point in the main chain and a stop hash at exactly
// the same point. The expected result is no located
// inventory.
name: "remote main chain same, stop same point",
locator: localView.BlockLocator(nil),
hashStop: tip(branch0Nodes).hash,
headers: nil,
hashes: nil,
},
{
// Locators from remote that don't include any blocks
// the local node knows. This would happen if the
// remote node is on a completely separate chain that
// isn't rooted with the same genesis block. The
// expected result is the blocks after the genesis
// block.
name: "remote unrelated chain",
locator: unrelatedView.BlockLocator(nil),
hashStop: chainhash.Hash{},
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
},
{
// Locators from remote for second block in main chain
// and no stop hash, but with an overridden max limit.
// The expected result is the blocks after the second
// block limited by the max.
name: "remote genesis",
locator: locatorHashes(branch0Nodes, 0),
hashStop: chainhash.Hash{},
maxAllowed: 3,
headers: nodeHeaders(branch0Nodes, 1, 2, 3),
hashes: nodeHashes(branch0Nodes, 1, 2, 3),
},
{
// Poorly formed locator.
//
// Locator from remote that only includes a single
// block on a side chain the local node knows. The
// expected result is the blocks after the genesis
// block since even though the block is known, it is on
// a side chain and there are no more locators to find
// the fork point.
name: "weak locator, single known side block",
locator: locatorHashes(branch1Nodes, 1),
hashStop: chainhash.Hash{},
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
},
{
// Poorly formed locator.
//
// Locator from remote that only includes multiple
// blocks on a side chain the local node knows however
// none in the main chain. The expected result is the
// blocks after the genesis block since even though the
// blocks are known, they are all on a side chain and
// there are no more locators to find the fork point.
name: "weak locator, multiple known side blocks",
locator: locatorHashes(branch1Nodes, 1),
hashStop: chainhash.Hash{},
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
},
{
// Poorly formed locator.
//
// Locator from remote that only includes multiple
// blocks on a side chain the local node knows however
// none in the main chain but includes a stop hash in
// the main chain. The expected result is the blocks
// after the genesis block up to the stop hash since
// even though the blocks are known, they are all on a
// side chain and there are no more locators to find the
// fork point.
name: "weak locator, multiple known side blocks, stop in main",
locator: locatorHashes(branch1Nodes, 1),
hashStop: branch0Nodes[5].hash,
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5),
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5),
},
}
for _, test := range tests {
// Ensure the expected headers are located.
var headers []wire.BlockHeader
if test.maxAllowed != 0 {
// Need to use the unexported function to override the
// max allowed for headers.
chain.chainLock.RLock()
headers = chain.locateHeaders(test.locator,
&test.hashStop, test.maxAllowed)
chain.chainLock.RUnlock()
} else {
headers = chain.LocateHeaders(test.locator,
&test.hashStop)
}
if !reflect.DeepEqual(headers, test.headers) {
t.Errorf("%s: unxpected headers -- got %v, want %v",
test.name, headers, test.headers)
continue
}
// Ensure the expected block hashes are located.
maxAllowed := uint32(wire.MaxBlocksPerMsg)
if test.maxAllowed != 0 {
maxAllowed = test.maxAllowed
}
hashes := chain.LocateBlocks(test.locator, &test.hashStop,
maxAllowed)
if !reflect.DeepEqual(hashes, test.hashes) {
t.Errorf("%s: unxpected hashes -- got %v, want %v",
test.name, hashes, test.hashes)
continue
}
}
}
// TestHeightToHashRange ensures that fetching a range of block hashes by start
// height and end hash works as expected.
func TestHeightToHashRange(t *testing.T) {
// Construct a synthetic block chain with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a -> 18a (unvalidated)
tip := tstTip
chain := newFakeChain(&chaincfg.MainNetParams)
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
branch1Nodes := chainedNodes(branch0Nodes[14], 3)
for _, node := range branch0Nodes {
chain.index.SetStatusFlags(node, statusValid)
chain.index.AddNode(node)
}
for _, node := range branch1Nodes {
if node.height < 18 {
chain.index.SetStatusFlags(node, statusValid)
}
chain.index.AddNode(node)
}
chain.bestChain.SetTip(tip(branch0Nodes))
tests := []struct {
name string
startHeight int32 // locator for requested inventory
endHash chainhash.Hash // stop hash for locator
maxResults int // max to locate, 0 = wire const
hashes []chainhash.Hash // expected located hashes
expectError bool
}{
{
name: "blocks below tip",
startHeight: 11,
endHash: branch0Nodes[14].hash,
maxResults: 10,
hashes: nodeHashes(branch0Nodes, 10, 11, 12, 13, 14),
},
{
name: "blocks on main chain",
startHeight: 15,
endHash: branch0Nodes[17].hash,
maxResults: 10,
hashes: nodeHashes(branch0Nodes, 14, 15, 16, 17),
},
{
name: "blocks on stale chain",
startHeight: 15,
endHash: branch1Nodes[1].hash,
maxResults: 10,
hashes: append(nodeHashes(branch0Nodes, 14),
nodeHashes(branch1Nodes, 0, 1)...),
},
{
name: "invalid start height",
startHeight: 19,
endHash: branch0Nodes[17].hash,
maxResults: 10,
expectError: true,
},
{
name: "too many results",
startHeight: 1,
endHash: branch0Nodes[17].hash,
maxResults: 10,
expectError: true,
},
{
name: "unvalidated block",
startHeight: 15,
endHash: branch1Nodes[2].hash,
maxResults: 10,
expectError: true,
},
}
for _, test := range tests {
hashes, err := chain.HeightToHashRange(test.startHeight, &test.endHash,
test.maxResults)
if err != nil {
if !test.expectError {
t.Errorf("%s: unexpected error: %v", test.name, err)
}
continue
}
if !reflect.DeepEqual(hashes, test.hashes) {
t.Errorf("%s: unxpected hashes -- got %v, want %v",
test.name, hashes, test.hashes)
}
}
}
// TestIntervalBlockHashes ensures that fetching block hashes at specified
// intervals by end hash works as expected.
func TestIntervalBlockHashes(t *testing.T) {
// Construct a synthetic block chain with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a -> 18a (unvalidated)
tip := tstTip
chain := newFakeChain(&chaincfg.MainNetParams)
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
branch1Nodes := chainedNodes(branch0Nodes[14], 3)
for _, node := range branch0Nodes {
chain.index.SetStatusFlags(node, statusValid)
chain.index.AddNode(node)
}
for _, node := range branch1Nodes {
if node.height < 18 {
chain.index.SetStatusFlags(node, statusValid)
}
chain.index.AddNode(node)
}
chain.bestChain.SetTip(tip(branch0Nodes))
tests := []struct {
name string
endHash chainhash.Hash
interval int
hashes []chainhash.Hash
expectError bool
}{
{
name: "blocks on main chain",
endHash: branch0Nodes[17].hash,
interval: 8,
hashes: nodeHashes(branch0Nodes, 7, 15),
},
{
name: "blocks on stale chain",
endHash: branch1Nodes[1].hash,
interval: 8,
hashes: append(nodeHashes(branch0Nodes, 7),
nodeHashes(branch1Nodes, 0)...),
},
{
name: "no results",
endHash: branch0Nodes[17].hash,
interval: 20,
hashes: []chainhash.Hash{},
},
{
name: "unvalidated block",
endHash: branch1Nodes[2].hash,
interval: 8,
expectError: true,
},
}
for _, test := range tests {
hashes, err := chain.IntervalBlockHashes(&test.endHash, test.interval)
if err != nil {
if !test.expectError {
t.Errorf("%s: unexpected error: %v", test.name, err)
}
continue
}
if !reflect.DeepEqual(hashes, test.hashes) {
t.Errorf("%s: unxpected hashes -- got %v, want %v",
test.name, hashes, test.hashes)
}
}
}

View file

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

View file

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

View file

@ -10,7 +10,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// CheckpointConfirmations is the number of blocks before the end of the current // CheckpointConfirmations is the number of blocks before the end of the current

183
blockchain/claimtrie.go Normal file
View file

@ -0,0 +1,183 @@
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()
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.DecodeClaimScript(e.pkScript)
if 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.DecodeClaimScript(txOut.PkScript)
if 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

@ -14,13 +14,13 @@ import (
"strings" "strings"
"time" "time"
"github.com/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
_ "github.com/btcsuite/btcd/database/ffldb" _ "github.com/lbryio/lbcd/database/ffldb"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
const ( const (
@ -69,7 +69,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
fi, err = os.Open(filename) fi, err = os.Open(filename)
if err != nil { if err != nil {
return return blocks, err
} }
if strings.HasSuffix(filename, ".bz2") { if strings.HasSuffix(filename, ".bz2") {
@ -107,12 +107,12 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
block, err = btcutil.NewBlockFromBytes(rbytes) block, err = btcutil.NewBlockFromBytes(rbytes)
if err != nil { if err != nil {
return return blocks, err
} }
blocks = append(blocks, block) blocks = append(blocks, block)
} }
return return blocks, err
} }
// 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/btcsuite/btcd/btcec" "github.com/lbryio/lbcd/btcec"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View file

@ -8,7 +8,7 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
) )
var ( var (
@ -159,7 +159,6 @@ 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
@ -178,7 +177,8 @@ 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 {
newTarget.Mul(newTarget, adjustmentFactor) adj := new(big.Int).Div(newTarget, big.NewInt(2))
newTarget.Add(newTarget, adj)
durationVal -= b.maxRetargetTimespan durationVal -= b.maxRetargetTimespan
} }
@ -224,47 +224,45 @@ 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 // For networks that support it, allow special reduction of the
// is not at a difficulty retarget interval. // required difficulty once too much time has elapsed without
if (lastNode.height+1)%b.blocksPerRetarget != 0 { // mining a block.
// For networks that support it, allow special reduction of the if b.chainParams.ReduceMinDifficulty {
// required difficulty once too much time has elapsed without // Return minimum difficulty when more than the desired
// mining a block. // amount of time has elapsed without mining a block.
if b.chainParams.ReduceMinDifficulty { reductionTime := int64(b.chainParams.MinDiffReductionTime /
// Return minimum difficulty when more than the desired time.Second)
// amount of time has elapsed without mining a block. allowMinTime := lastNode.timestamp + reductionTime
reductionTime := int64(b.chainParams.MinDiffReductionTime / if newBlockTime.Unix() > allowMinTime {
time.Second) return b.chainParams.PowLimitBits, nil
allowMinTime := lastNode.timestamp + reductionTime
if newBlockTime.Unix() > allowMinTime {
return b.chainParams.PowLimitBits, nil
}
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), nil
} }
// For the main network (or any unrecognized networks), simply // The block was mined within the desired timeframe, so
// return the previous block's difficulty requirements. // return the difficulty for the last block which did
return lastNode.bits, nil // not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), 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).
firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1) blocksBack := b.blocksPerRetarget
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 := actualTimespan adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
if actualTimespan < b.minRetargetTimespan { if adjustedTimespan < b.minRetargetTimespan {
adjustedTimespan = b.minRetargetTimespan adjustedTimespan = b.minRetargetTimespan
} else if actualTimespan > b.maxRetargetTimespan { } else if adjustedTimespan > b.maxRetargetTimespan {
adjustedTimespan = b.maxRetargetTimespan adjustedTimespan = b.maxRetargetTimespan
} }
@ -275,7 +273,6 @@ 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

@ -220,6 +220,10 @@ 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.
@ -267,6 +271,7 @@ 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

@ -1,107 +0,0 @@
// Copyright (c) 2014-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
import (
"fmt"
"math/big"
"os"
"path/filepath"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcutil"
)
// This example demonstrates how to create a new chain instance and use
// ProcessBlock to attempt to add a block to the chain. As the package
// overview documentation describes, this includes all of the Bitcoin consensus
// rules. This example intentionally attempts to insert a duplicate genesis
// block to illustrate how an invalid block is handled.
func ExampleBlockChain_ProcessBlock() {
// Create a new database to store the accepted blocks into. Typically
// this would be opening an existing database and would not be deleting
// and creating a new database like this, but it is done here so this is
// a complete working example and does not leave temporary files laying
// around.
dbPath := filepath.Join(os.TempDir(), "exampleprocessblock")
_ = os.RemoveAll(dbPath)
db, err := database.Create("ffldb", dbPath, chaincfg.MainNetParams.Net)
if err != nil {
fmt.Printf("Failed to create database: %v\n", err)
return
}
defer os.RemoveAll(dbPath)
defer db.Close()
// Create a new BlockChain instance using the underlying database for
// the main bitcoin network. This example does not demonstrate some
// of the other available configuration options such as specifying a
// notification callback and signature cache. Also, the caller would
// ordinarily keep a reference to the median time source and add time
// values obtained from other peers on the network so the local time is
// adjusted to be in agreement with other peers.
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: &chaincfg.MainNetParams,
TimeSource: blockchain.NewMedianTime(),
})
if err != nil {
fmt.Printf("Failed to create chain instance: %v\n", err)
return
}
// Process a block. For this example, we are going to intentionally
// cause an error by trying to process the genesis block which already
// exists.
genesisBlock := btcutil.NewBlock(chaincfg.MainNetParams.GenesisBlock)
isMainChain, isOrphan, err := chain.ProcessBlock(genesisBlock,
blockchain.BFNone)
if err != nil {
fmt.Printf("Failed to process block: %v\n", err)
return
}
fmt.Printf("Block accepted. Is it on the main chain?: %v", isMainChain)
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
// Output:
// Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
}
// This example 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.
func ExampleCompactToBig() {
// Convert the bits from block 300000 in the main block chain.
bits := uint32(419465580)
targetDifficulty := blockchain.CompactToBig(bits)
// Display it in hex.
fmt.Printf("%064x\n", targetDifficulty.Bytes())
// Output:
// 0000000000000000896c00000000000000000000000000000000000000000000
}
// This example demonstrates how to convert a target difficulty into the compact
// "bits" in a block header which represent that target difficulty .
func ExampleBigToCompact() {
// Convert the target difficulty from block 300000 in the main block
// chain to compact form.
t := "0000000000000000896c00000000000000000000000000000000000000000000"
targetDifficulty, success := new(big.Int).SetString(t, 16)
if !success {
fmt.Println("invalid target difficulty")
return
}
bits := blockchain.BigToCompact(targetDifficulty)
fmt.Println(bits)
// Output:
// 419465580
}

View file

@ -1,310 +0,0 @@
// Copyright (c) 2016 The Decred developers
// Copyright (c) 2016-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_test
import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/blockchain/fullblocktests"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
// testDbType is the database backend type to use for the tests.
testDbType = "ffldb"
// testDbRoot is the root directory used to create all test databases.
testDbRoot = "testdbs"
// blockDataNet is the expected network in the test block data.
blockDataNet = wire.MainNet
)
// filesExists returns whether or not the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// isSupportedDbType returns whether or not the passed database type is
// currently supported.
func isSupportedDbType(dbType string) bool {
supportedDrivers := database.SupportedDrivers()
for _, driver := range supportedDrivers {
if dbType == driver {
return true
}
}
return false
}
// chainSetup is used to create a new db and chain instance with the genesis
// block already inserted. In addition to the new chain instance, it returns
// a teardown function the caller should invoke when done testing to clean up.
func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain, func(), error) {
if !isSupportedDbType(testDbType) {
return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
}
// Handle memory database specially since it doesn't need the disk
// specific handling.
var db database.DB
var teardown func()
if testDbType == "memdb" {
ndb, err := database.Create(testDbType)
if err != nil {
return nil, nil, fmt.Errorf("error creating db: %v", err)
}
db = ndb
// Setup a teardown function for cleaning up. This function is
// returned to the caller to be invoked when it is done testing.
teardown = func() {
db.Close()
}
} else {
// Create the root directory for test databases.
if !fileExists(testDbRoot) {
if err := os.MkdirAll(testDbRoot, 0700); err != nil {
err := fmt.Errorf("unable to create test db "+
"root: %v", err)
return nil, nil, err
}
}
// Create a new database to store the accepted blocks into.
dbPath := filepath.Join(testDbRoot, dbName)
_ = os.RemoveAll(dbPath)
ndb, err := database.Create(testDbType, dbPath, blockDataNet)
if err != nil {
return nil, nil, fmt.Errorf("error creating db: %v", err)
}
db = ndb
// Setup a teardown function for cleaning up. This function is
// returned to the caller to be invoked when it is done testing.
teardown = func() {
db.Close()
os.RemoveAll(dbPath)
os.RemoveAll(testDbRoot)
}
}
// Copy the chain params to ensure any modifications the tests do to
// the chain parameters do not affect the global instance.
paramsCopy := *params
// Create the main chain instance.
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: &paramsCopy,
Checkpoints: nil,
TimeSource: blockchain.NewMedianTime(),
SigCache: txscript.NewSigCache(1000),
})
if err != nil {
teardown()
err := fmt.Errorf("failed to create chain instance: %v", err)
return nil, nil, err
}
return chain, teardown, nil
}
// TestFullBlocks ensures all tests generated by the fullblocktests package
// have the expected result when processed via ProcessBlock.
func TestFullBlocks(t *testing.T) {
tests, err := fullblocktests.Generate(false)
if err != nil {
t.Fatalf("failed to generate tests: %v", err)
}
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("fullblocktest",
&chaincfg.RegressionNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// testAcceptedBlock attempts to process the block in the provided test
// instance and ensures that it was accepted according to the flags
// specified in the test.
testAcceptedBlock := func(item fullblocktests.AcceptedBlock) {
blockHeight := item.Height
block := btcutil.NewBlock(item.Block)
block.SetHeight(blockHeight)
t.Logf("Testing block %s (hash %s, height %d)",
item.Name, block.Hash(), blockHeight)
isMainChain, isOrphan, err := chain.ProcessBlock(block,
blockchain.BFNone)
if err != nil {
t.Fatalf("block %q (hash %s, height %d) should "+
"have been accepted: %v", item.Name,
block.Hash(), blockHeight, err)
}
// Ensure the main chain and orphan flags match the values
// specified in the test.
if isMainChain != item.IsMainChain {
t.Fatalf("block %q (hash %s, height %d) unexpected main "+
"chain flag -- got %v, want %v", item.Name,
block.Hash(), blockHeight, isMainChain,
item.IsMainChain)
}
if isOrphan != item.IsOrphan {
t.Fatalf("block %q (hash %s, height %d) unexpected "+
"orphan flag -- got %v, want %v", item.Name,
block.Hash(), blockHeight, isOrphan,
item.IsOrphan)
}
}
// testRejectedBlock attempts to process the block in the provided test
// instance and ensures that it was rejected with the reject code
// specified in the test.
testRejectedBlock := func(item fullblocktests.RejectedBlock) {
blockHeight := item.Height
block := btcutil.NewBlock(item.Block)
block.SetHeight(blockHeight)
t.Logf("Testing block %s (hash %s, height %d)",
item.Name, block.Hash(), blockHeight)
_, _, err := chain.ProcessBlock(block, blockchain.BFNone)
if err == nil {
t.Fatalf("block %q (hash %s, height %d) should not "+
"have been accepted", item.Name, block.Hash(),
blockHeight)
}
// Ensure the error code is of the expected type and the reject
// code matches the value specified in the test instance.
rerr, ok := err.(blockchain.RuleError)
if !ok {
t.Fatalf("block %q (hash %s, height %d) returned "+
"unexpected error type -- got %T, want "+
"blockchain.RuleError", item.Name, block.Hash(),
blockHeight, err)
}
if rerr.ErrorCode != item.RejectCode {
t.Fatalf("block %q (hash %s, height %d) does not have "+
"expected reject code -- got %v, want %v",
item.Name, block.Hash(), blockHeight,
rerr.ErrorCode, item.RejectCode)
}
}
// testRejectedNonCanonicalBlock attempts to decode the block in the
// provided test instance and ensures that it failed to decode with a
// message error.
testRejectedNonCanonicalBlock := func(item fullblocktests.RejectedNonCanonicalBlock) {
headerLen := len(item.RawBlock)
if headerLen > 80 {
headerLen = 80
}
blockHash := chainhash.DoubleHashH(item.RawBlock[0:headerLen])
blockHeight := item.Height
t.Logf("Testing block %s (hash %s, height %d)", item.Name,
blockHash, blockHeight)
// Ensure there is an error due to deserializing the block.
var msgBlock wire.MsgBlock
err := msgBlock.BtcDecode(bytes.NewReader(item.RawBlock), 0, wire.BaseEncoding)
if _, ok := err.(*wire.MessageError); !ok {
t.Fatalf("block %q (hash %s, height %d) should have "+
"failed to decode", item.Name, blockHash,
blockHeight)
}
}
// testOrphanOrRejectedBlock attempts to process the block in the
// provided test instance and ensures that it was either accepted as an
// orphan or rejected with a rule violation.
testOrphanOrRejectedBlock := func(item fullblocktests.OrphanOrRejectedBlock) {
blockHeight := item.Height
block := btcutil.NewBlock(item.Block)
block.SetHeight(blockHeight)
t.Logf("Testing block %s (hash %s, height %d)",
item.Name, block.Hash(), blockHeight)
_, isOrphan, err := chain.ProcessBlock(block, blockchain.BFNone)
if err != nil {
// Ensure the error code is of the expected type.
if _, ok := err.(blockchain.RuleError); !ok {
t.Fatalf("block %q (hash %s, height %d) "+
"returned unexpected error type -- "+
"got %T, want blockchain.RuleError",
item.Name, block.Hash(), blockHeight,
err)
}
}
if !isOrphan {
t.Fatalf("block %q (hash %s, height %d) was accepted, "+
"but is not considered an orphan", item.Name,
block.Hash(), blockHeight)
}
}
// testExpectedTip ensures the current tip of the blockchain is the
// block specified in the provided test instance.
testExpectedTip := func(item fullblocktests.ExpectedTip) {
blockHeight := item.Height
block := btcutil.NewBlock(item.Block)
block.SetHeight(blockHeight)
t.Logf("Testing tip for block %s (hash %s, height %d)",
item.Name, block.Hash(), blockHeight)
// Ensure hash and height match.
best := chain.BestSnapshot()
if best.Hash != item.Block.BlockHash() ||
best.Height != blockHeight {
t.Fatalf("block %q (hash %s, height %d) should be "+
"the current tip -- got (hash %s, height %d)",
item.Name, block.Hash(), blockHeight, best.Hash,
best.Height)
}
}
for testNum, test := range tests {
for itemNum, item := range test {
switch item := item.(type) {
case fullblocktests.AcceptedBlock:
testAcceptedBlock(item)
case fullblocktests.RejectedBlock:
testRejectedBlock(item)
case fullblocktests.RejectedNonCanonicalBlock:
testRejectedNonCanonicalBlock(item)
case fullblocktests.OrphanOrRejectedBlock:
testOrphanOrRejectedBlock(item)
case fullblocktests.ExpectedTip:
testExpectedTip(item)
default:
t.Fatalf("test #%d, item #%d is not one of "+
"the supported test instance types -- "+
"got type: %T", testNum, itemNum, item)
}
}
}
}

View file

@ -1,9 +1,9 @@
fullblocktests fullblocktests
============== ==============
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions) [![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/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/fullblocktests) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/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/btcsuite/btcd/blockchain/fullblocktests $ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests
``` ```
## License ## License

View file

@ -18,24 +18,24 @@ import (
"runtime" "runtime"
"time" "time"
"github.com/btcsuite/btcd/blockchain" "github.com/lbryio/lbcd/blockchain"
"github.com/btcsuite/btcd/btcec" "github.com/lbryio/lbcd/btcec"
"github.com/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
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 = 1000000 maxBlockSize = 2000000
minCoinbaseScriptLen = 2 minCoinbaseScriptLen = 2
maxCoinbaseScriptLen = 100 maxCoinbaseScriptLen = 100
medianTimeBlocks = 11 medianTimeBlocks = 11
maxScriptElementSize = 520 maxScriptElementSize = 20000
// 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
@ -1875,7 +1875,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// //
// Comment assumptions: // Comment assumptions:
// maxBlockSigOps = 20000 // maxBlockSigOps = 20000
// maxScriptElementSize = 520 // maxScriptElementSize = 20000
// //
// [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/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
// newHashFromStr converts the passed big-endian hex string into a // newHashFromStr converts the passed big-endian hex string into a

View file

@ -1,9 +1,9 @@
indexers indexers
======== ========
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions) [![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/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/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers) [![GoDoc](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/lbryio/lbcd/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/btcsuite/btcd/blockchain/indexers $ go get -u github.com/lbryio/lbcd/blockchain/indexers
``` ```
## License ## License

View file

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

View file

@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// blockProgressLogger provides periodic logging for other services in order // blockProgressLogger provides periodic logging for other services in order

View file

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

View file

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

View file

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

View file

@ -8,11 +8,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/btcsuite/btcd/blockchain" "github.com/lbryio/lbcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
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! btcd will not work " + "are correct! lbcd will not work " +
"properly with an invalid time") "properly with an invalid time")
} }
} }

View file

@ -9,9 +9,9 @@ import (
"fmt" "fmt"
"math" "math"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
const ( const (
@ -230,8 +230,8 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error {
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", "its witness stack when only one is allowed. Height: %d",
len(coinbaseWitness)) len(coinbaseWitness), blk.Height())
return ruleError(ErrInvalidWitnessCommitment, str) return ruleError(ErrInvalidWitnessCommitment, str)
} }
witnessNonce := coinbaseWitness[0] witnessNonce := coinbaseWitness[0]

View file

@ -1,23 +0,0 @@
// Copyright (c) 2013-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/btcutil"
)
// TestMerkle tests the BuildMerkleTreeStore API.
func TestMerkle(t *testing.T) {
block := btcutil.NewBlock(&Block100000)
merkles := BuildMerkleTreeStore(block.Transactions(), false)
calculatedMerkleRoot := merkles[len(merkles)-1]
wantMerkle := &Block100000.Header.MerkleRoot
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
}
}

View file

@ -1,51 +0,0 @@
// 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/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when // BehaviorFlags is a bitmask defining tweaks to the normal behavior when

View file

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

View file

@ -1,46 +0,0 @@
// Copyright (c) 2013-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 (
"fmt"
"testing"
"github.com/btcsuite/btcd/txscript"
)
// TestCheckBlockScripts ensures that validating the all of the scripts in a
// known-good block doesn't return an error.
func TestCheckBlockScripts(t *testing.T) {
testBlockNum := 277647
blockDataFile := fmt.Sprintf("%d.dat.bz2", testBlockNum)
blocks, err := loadBlocks(blockDataFile)
if err != nil {
t.Errorf("Error loading file: %v\n", err)
return
}
if len(blocks) > 1 {
t.Errorf("The test block file must only have one block in it")
return
}
if len(blocks) == 0 {
t.Errorf("The test block file may not be empty")
return
}
storeDataFile := fmt.Sprintf("%d.utxostore.bz2", testBlockNum)
view, err := loadUtxoView(storeDataFile)
if err != nil {
t.Errorf("Error loading txstore: %v\n", err)
return
}
scriptFlags := txscript.ScriptBip16
err = checkBlockScripts(blocks[0], view, scriptFlags, nil, nil)
if err != nil {
t.Errorf("Transaction script validation failed: %v\n", err)
return
}
}

View file

@ -7,7 +7,7 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
) )
// ThresholdState define the various threshold states used when voting on // ThresholdState define the various threshold states used when voting on
@ -302,6 +302,12 @@ 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/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/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/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
const ( const (

View file

@ -7,11 +7,11 @@ package blockchain
import ( import (
"fmt" "fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/database"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// 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/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
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 = 50 * btcutil.SatoshiPerBitcoin baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
) )
var ( var (
@ -192,17 +192,44 @@ 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 {
if chainParams.SubsidyReductionInterval == 0 { h := int64(height)
return baseSubsidy if h == 0 {
return btcutil.SatoshiPerBitcoin * 4e8
}
if h <= 5100 {
return btcutil.SatoshiPerBitcoin
}
if h <= 55000 {
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
} }
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval) lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval)
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval) reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2
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. These checks are context free. // ensure it is sane.
func CheckTransactionSanity(tx *btcutil.Tx) error { func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) 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 {
@ -261,6 +288,11 @@ func CheckTransactionSanity(tx *btcutil.Tx) 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.
@ -324,7 +356,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.BlockHash() hash := header.BlockPoWHash()
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 "+
@ -515,7 +547,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) err := CheckTransactionSanity(tx, false)
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,487 +0,0 @@
// Copyright (c) 2013-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 (
"math"
"reflect"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
// works as expected in all possible combinations/scenarios.
func TestSequenceLocksActive(t *testing.T) {
seqLock := func(h int32, s int64) *SequenceLock {
return &SequenceLock{
Seconds: s,
BlockHeight: h,
}
}
tests := []struct {
seqLock *SequenceLock
blockHeight int32
mtp time.Time
want bool
}{
// Block based sequence lock with equal block height.
{seqLock: seqLock(1000, -1), blockHeight: 1001, mtp: time.Unix(9, 0), want: true},
// Time based sequence lock with mtp past the absolute time.
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(31, 0), want: true},
// Block based sequence lock with current height below seq lock block height.
{seqLock: seqLock(1000, -1), blockHeight: 90, mtp: time.Unix(9, 0), want: false},
// Time based sequence lock with current time before lock time.
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(29, 0), want: false},
// Block based sequence lock at the same height, so shouldn't yet be active.
{seqLock: seqLock(1000, -1), blockHeight: 1000, mtp: time.Unix(9, 0), want: false},
// Time based sequence lock with current time equal to lock time, so shouldn't yet be active.
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(30, 0), want: false},
}
t.Logf("Running %d sequence locks tests", len(tests))
for i, test := range tests {
got := SequenceLockActive(test.seqLock,
test.blockHeight, test.mtp)
if got != test.want {
t.Fatalf("SequenceLockActive #%d got %v want %v", i,
got, test.want)
}
}
}
// 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
// as expected.
func TestCheckBlockSanity(t *testing.T) {
powLimit := chaincfg.MainNetParams.PowLimit
block := btcutil.NewBlock(&Block100000)
timeSource := NewMedianTime()
err := CheckBlockSanity(block, powLimit, timeSource)
if err != nil {
t.Errorf("CheckBlockSanity: %v", err)
}
// Ensure a block that has a timestamp with a precision higher than one
// second fails.
timestamp := block.MsgBlock().Header.Timestamp
block.MsgBlock().Header.Timestamp = timestamp.Add(time.Nanosecond)
err = CheckBlockSanity(block, powLimit, timeSource)
if err == nil {
t.Errorf("CheckBlockSanity: error is nil when it shouldn't be")
}
}
// TestCheckSerializedHeight tests the checkSerializedHeight function with
// various serialized heights and also does negative tests to ensure errors
// and handled properly.
func TestCheckSerializedHeight(t *testing.T) {
// Create an empty coinbase template to be used in the tests below.
coinbaseOutpoint := wire.NewOutPoint(&chainhash.Hash{}, math.MaxUint32)
coinbaseTx := wire.NewMsgTx(1)
coinbaseTx.AddTxIn(wire.NewTxIn(coinbaseOutpoint, nil, nil))
// Expected rule errors.
missingHeightError := RuleError{
ErrorCode: ErrMissingCoinbaseHeight,
}
badHeightError := RuleError{
ErrorCode: ErrBadCoinbaseHeight,
}
tests := []struct {
sigScript []byte // Serialized data
wantHeight int32 // Expected height
err error // Expected error type
}{
// No serialized height length.
{[]byte{}, 0, missingHeightError},
// Serialized height length with no height bytes.
{[]byte{0x02}, 0, missingHeightError},
// Serialized height length with too few height bytes.
{[]byte{0x02, 0x4a}, 0, missingHeightError},
// Serialized height that needs 2 bytes to encode.
{[]byte{0x02, 0x4a, 0x52}, 21066, nil},
// Serialized height that needs 2 bytes to encode, but backwards
// endianness.
{[]byte{0x02, 0x4a, 0x52}, 19026, badHeightError},
// Serialized height that needs 3 bytes to encode.
{[]byte{0x03, 0x40, 0x0d, 0x03}, 200000, nil},
// Serialized height that needs 3 bytes to encode, but backwards
// endianness.
{[]byte{0x03, 0x40, 0x0d, 0x03}, 1074594560, badHeightError},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
msgTx := coinbaseTx.Copy()
msgTx.TxIn[0].SignatureScript = test.sigScript
tx := btcutil.NewTx(msgTx)
err := checkSerializedHeight(tx, test.wantHeight)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("checkSerializedHeight #%d wrong error type "+
"got: %v <%T>, want: %T", i, err, err, test.err)
continue
}
if rerr, ok := err.(RuleError); ok {
trerr := test.err.(RuleError)
if rerr.ErrorCode != trerr.ErrorCode {
t.Errorf("checkSerializedHeight #%d wrong "+
"error code got: %v, want: %v", i,
rerr.ErrorCode, trerr.ErrorCode)
continue
}
}
}
}
// Block100000 defines block 100,000 of the block chain. It is used to
// test Block operations.
var Block100000 = wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
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/btcsuite/btcd/chaincfg" "github.com/lbryio/lbcd/chaincfg"
) )
const ( const (
@ -195,6 +195,12 @@ 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/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
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 = 4000000 MaxBlockWeight = 8000000
// 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 = 1000000 MaxBlockBaseSize = 8000000
// 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

25
btcd.go
View file

@ -15,9 +15,12 @@ import (
"runtime/debug" "runtime/debug"
"runtime/pprof" "runtime/pprof"
"github.com/btcsuite/btcd/blockchain/indexers" "github.com/lbryio/lbcd/blockchain/indexers"
"github.com/btcsuite/btcd/database" "github.com/lbryio/lbcd/claimtrie/param"
"github.com/btcsuite/btcd/limits" "github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/limits"
"github.com/felixge/fgprof"
) )
const ( const (
@ -65,6 +68,7 @@ func btcdMain(serverChan chan<- *server) error {
// 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)
@ -144,6 +148,10 @@ 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)
@ -158,6 +166,10 @@ 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 {
@ -196,6 +208,13 @@ func removeRegressionDB(dbPath string) error {
} }
} }
dbPath = filepath.Join(cfg.DataDir, activeNetParams.Name, "claim_dbs")
btcdLog.Infof("Removing regression test claim databases from '%s'", dbPath)
err = os.RemoveAll(dbPath)
if err != nil {
return err
}
return nil return nil
} }

View file

@ -1,68 +1,11 @@
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)
Package btcec implements elliptic curve cryptography needed for working with 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. The btcsuite developers original is licensed signficantly diverged since then.
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

@ -8,8 +8,8 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"github.com/btcsuite/btcd/btcec" "github.com/lbryio/lbcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/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

@ -5,6 +5,7 @@
// 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
@ -17,7 +18,7 @@ import (
"log" "log"
"os" "os"
"github.com/btcsuite/btcd/btcec" "github.com/lbryio/lbcd/btcec"
) )
func main() { func main() {

View file

@ -4,6 +4,7 @@
// 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

@ -1,70 +1,8 @@
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/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/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/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/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/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/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/btcsuite/btcd/wire" "github.com/lbryio/lbcd/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

View file

@ -12,8 +12,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal // TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
@ -388,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{"0000afaf", nil}, unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil},
}, },
{ {
name: "getblockfilter optional filtertype", name: "getblockfilter optional filtertype",
@ -399,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{"0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)}, unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
}, },
{ {
name: "getblockhash", name: "getblockhash",

View file

@ -9,10 +9,10 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// GetBlockHeaderVerboseResult models the data from the getblockheader command when // GetBlockHeaderVerboseResult models the data from the getblockheader command when
@ -25,6 +25,7 @@ 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:"claimtrie,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"`
@ -65,6 +66,27 @@ type GetBlockStatsResult struct {
UTXOSizeIncrease int64 `json:"utxo_size_inc"` UTXOSizeIncrease int64 `json:"utxo_size_inc"`
} }
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"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
ClaimTrie string `json:"claimTrie,omitempty"`
TxCount int `json:"nTx"` // For backwards compatibility only
}
// GetBlockVerboseResult models the data from the getblock command when the // GetBlockVerboseResult models the data from the getblock command when the
// verbose flag is set to 1. When the verbose flag is set to 0, getblock returns a // verbose flag is set to 1. When the verbose flag is set to 0, getblock returns a
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object // hex-encoded string. When the verbose flag is set to 1, getblock returns an object
@ -72,23 +94,8 @@ type GetBlockStatsResult 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 {
Hash string `json:"hash"` GetBlockVerboseResultBase
Confirmations int64 `json:"confirmations"` Tx []string `json:"tx"`
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
@ -98,23 +105,8 @@ 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 {
Hash string `json:"hash"` GetBlockVerboseResultBase
Confirmations int64 `json:"confirmations"` Tx []TxRawResult `json:"tx"`
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.
@ -296,6 +288,10 @@ 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
@ -428,6 +424,9 @@ 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"`
} }
@ -586,6 +585,8 @@ 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

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},"sequence":4294967295}`, expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
}, },
} }

View file

@ -12,7 +12,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/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/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/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/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
) )
// TestChainSvrWsResults ensures any results that have custom marshalling // TestChainSvrWsResults ensures any results that have custom marshalling

95
btcjson/claimcmds.go Normal file
View file

@ -0,0 +1,95 @@
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"`
NormalizedName string `json:"normalizedname"`
Claims []ClaimResult `json:"claims"`
// UnclaimedSupports []SupportResult `json:"unclaimedSupports"` 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"`
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

@ -1,430 +0,0 @@
// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcjson_test
import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
)
// TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected
// methods and errors.
func TestCmdMethod(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cmd interface{}
method string
err error
}{
{
name: "unregistered type",
cmd: (*int)(nil),
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "nil pointer of registered type",
cmd: (*btcjson.GetBlockCmd)(nil),
method: "getblock",
},
{
name: "nil instance of registered type",
cmd: &btcjson.GetBlockCountCmd{},
method: "getblockcount",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
method, err := btcjson.CmdMethod(test.cmd)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
"want %T", i, test.name, err, test.err)
continue
}
if err != nil {
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code "+
"- got %v (%v), want %v", i, test.name,
gotErrorCode, err,
test.err.(btcjson.Error).ErrorCode)
continue
}
continue
}
// Ensure method matches the expected value.
if method != test.method {
t.Errorf("Test #%d (%s) mismatched method - got %v, "+
"want %v", i, test.name, method, test.method)
continue
}
}
}
// TestMethodUsageFlags tests the MethodUsage function ensure it returns the
// expected flags and errors.
func TestMethodUsageFlags(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
err error
flags btcjson.UsageFlag
}{
{
name: "unregistered type",
method: "bogusmethod",
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "getblock",
method: "getblock",
flags: 0,
},
{
name: "walletpassphrase",
method: "walletpassphrase",
flags: btcjson.UFWalletOnly,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
flags, err := btcjson.MethodUsageFlags(test.method)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
"want %T", i, test.name, err, test.err)
continue
}
if err != nil {
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code "+
"- got %v (%v), want %v", i, test.name,
gotErrorCode, err,
test.err.(btcjson.Error).ErrorCode)
continue
}
continue
}
// Ensure flags match the expected value.
if flags != test.flags {
t.Errorf("Test #%d (%s) mismatched flags - got %v, "+
"want %v", i, test.name, flags, test.flags)
continue
}
}
}
// TestMethodUsageText tests the MethodUsageText function ensure it returns the
// expected text.
func TestMethodUsageText(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
err error
expected string
}{
{
name: "unregistered type",
method: "bogusmethod",
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "getblockcount",
method: "getblockcount",
expected: "getblockcount",
},
{
name: "getblock",
method: "getblock",
expected: `getblock "hash" (verbosity=1)`,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
usage, err := btcjson.MethodUsageText(test.method)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
"want %T", i, test.name, err, test.err)
continue
}
if err != nil {
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code "+
"- got %v (%v), want %v", i, test.name,
gotErrorCode, err,
test.err.(btcjson.Error).ErrorCode)
continue
}
continue
}
// Ensure usage matches the expected value.
if usage != test.expected {
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
"want %v", i, test.name, usage, test.expected)
continue
}
// Get the usage again to exercise caching.
usage, err = btcjson.MethodUsageText(test.method)
if err != nil {
t.Errorf("Test #%d (%s) unexpected error: %v", i,
test.name, err)
continue
}
// Ensure usage still matches the expected value.
if usage != test.expected {
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
"want %v", i, test.name, usage, test.expected)
continue
}
}
}
// TestFieldUsage tests the internal fieldUsage function ensure it returns the
// expected text.
func TestFieldUsage(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field reflect.StructField
defValue *reflect.Value
expected string
}{
{
name: "jsonrpcusage tag override",
field: func() reflect.StructField {
type s struct {
Test int `jsonrpcusage:"testvalue"`
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: "testvalue",
},
{
name: "generic interface",
field: func() reflect.StructField {
type s struct {
Test interface{}
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `test`,
},
{
name: "string without default value",
field: func() reflect.StructField {
type s struct {
Test string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `"test"`,
},
{
name: "string with default value",
field: func() reflect.StructField {
type s struct {
Test string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: func() *reflect.Value {
value := "default"
rv := reflect.ValueOf(&value)
return &rv
}(),
expected: `test="default"`,
},
{
name: "array of strings",
field: func() reflect.StructField {
type s struct {
Test []string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `["test",...]`,
},
{
name: "array of strings with plural field name 1",
field: func() reflect.StructField {
type s struct {
Keys []string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `["key",...]`,
},
{
name: "array of strings with plural field name 2",
field: func() reflect.StructField {
type s struct {
Addresses []string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `["address",...]`,
},
{
name: "array of strings with plural field name 3",
field: func() reflect.StructField {
type s struct {
Capabilities []string
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `["capability",...]`,
},
{
name: "array of structs",
field: func() reflect.StructField {
type s2 struct {
Txid string
}
type s struct {
Capabilities []s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `[{"txid":"value"},...]`,
},
{
name: "array of ints",
field: func() reflect.StructField {
type s struct {
Test []int
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `[test,...]`,
},
{
name: "sub struct with jsonrpcusage tag override",
field: func() reflect.StructField {
type s2 struct {
Test string `jsonrpcusage:"testusage"`
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{testusage}`,
},
{
name: "sub struct with string",
field: func() reflect.StructField {
type s2 struct {
Txid string
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{"txid":"value"}`,
},
{
name: "sub struct with int",
field: func() reflect.StructField {
type s2 struct {
Vout int
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{"vout":n}`,
},
{
name: "sub struct with float",
field: func() reflect.StructField {
type s2 struct {
Amount float64
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{"amount":n.nnn}`,
},
{
name: "sub struct with sub struct",
field: func() reflect.StructField {
type s3 struct {
Amount float64
}
type s2 struct {
Template s3
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{"template":{"amount":n.nnn}}`,
},
{
name: "sub struct with slice",
field: func() reflect.StructField {
type s2 struct {
Capabilities []string
}
type s struct {
Test s2
}
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
}(),
defValue: nil,
expected: `{"capabilities":["capability",...]}`,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Ensure usage matches the expected value.
usage := btcjson.TstFieldUsage(test.field, test.defValue)
if usage != test.expected {
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
"want %v", i, test.name, usage, test.expected)
continue
}
}
}

View file

@ -1,593 +0,0 @@
// Copyright (c) 2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcjson_test
import (
"encoding/json"
"math"
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
)
// TestAssignField tests the assignField function handles supported combinations
// properly.
func TestAssignField(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dest interface{}
src interface{}
expected interface{}
}{
{
name: "same types",
dest: int8(0),
src: int8(100),
expected: int8(100),
},
{
name: "same types - more source pointers",
dest: int8(0),
src: func() interface{} {
i := int8(100)
return &i
}(),
expected: int8(100),
},
{
name: "same types - more dest pointers",
dest: func() interface{} {
i := int8(0)
return &i
}(),
src: int8(100),
expected: int8(100),
},
{
name: "convertible types - more source pointers",
dest: int16(0),
src: func() interface{} {
i := int8(100)
return &i
}(),
expected: int16(100),
},
{
name: "convertible types - both pointers",
dest: func() interface{} {
i := int8(0)
return &i
}(),
src: func() interface{} {
i := int16(100)
return &i
}(),
expected: int8(100),
},
{
name: "convertible types - int16 -> int8",
dest: int8(0),
src: int16(100),
expected: int8(100),
},
{
name: "convertible types - int16 -> uint8",
dest: uint8(0),
src: int16(100),
expected: uint8(100),
},
{
name: "convertible types - uint16 -> int8",
dest: int8(0),
src: uint16(100),
expected: int8(100),
},
{
name: "convertible types - uint16 -> uint8",
dest: uint8(0),
src: uint16(100),
expected: uint8(100),
},
{
name: "convertible types - float32 -> float64",
dest: float64(0),
src: float32(1.5),
expected: float64(1.5),
},
{
name: "convertible types - float64 -> float32",
dest: float32(0),
src: float64(1.5),
expected: float32(1.5),
},
{
name: "convertible types - string -> bool",
dest: false,
src: "true",
expected: true,
},
{
name: "convertible types - string -> int8",
dest: int8(0),
src: "100",
expected: int8(100),
},
{
name: "convertible types - string -> uint8",
dest: uint8(0),
src: "100",
expected: uint8(100),
},
{
name: "convertible types - string -> float32",
dest: float32(0),
src: "1.5",
expected: float32(1.5),
},
{
name: "convertible types - typecase string -> string",
dest: "",
src: func() interface{} {
type foo string
return foo("foo")
}(),
expected: "foo",
},
{
name: "convertible types - string -> array",
dest: [2]string{},
src: `["test","test2"]`,
expected: [2]string{"test", "test2"},
},
{
name: "convertible types - string -> slice",
dest: []string{},
src: `["test","test2"]`,
expected: []string{"test", "test2"},
},
{
name: "convertible types - string -> struct",
dest: struct{ A int }{},
src: `{"A":100}`,
expected: struct{ A int }{100},
},
{
name: "convertible types - string -> map",
dest: map[string]float64{},
src: `{"1Address":1.5}`,
expected: map[string]float64{"1Address": 1.5},
},
{
name: `null optional field - "null" -> *int32`,
dest: btcjson.Int32(0),
src: "null",
expected: nil,
},
{
name: `null optional field - "null" -> *string`,
dest: btcjson.String(""),
src: "null",
expected: nil,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
src := reflect.ValueOf(test.src)
err := btcjson.TstAssignField(1, "testField", dst, src)
if err != nil {
t.Errorf("Test #%d (%s) unexpected error: %v", i,
test.name, err)
continue
}
// Check case where null string is used on optional field
if dst.Kind() == reflect.Ptr && test.src == "null" {
if !dst.IsNil() {
t.Errorf("Test #%d (%s) unexpected value - got %v, "+
"want nil", i, test.name, dst.Interface())
}
continue
}
// Inidirect through to the base types to ensure their values
// are the same.
for dst.Kind() == reflect.Ptr {
dst = dst.Elem()
}
if !reflect.DeepEqual(dst.Interface(), test.expected) {
t.Errorf("Test #%d (%s) unexpected value - got %v, "+
"want %v", i, test.name, dst.Interface(),
test.expected)
continue
}
}
}
// TestAssignFieldErrors tests the assignField function error paths.
func TestAssignFieldErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dest interface{}
src interface{}
err btcjson.Error
}{
{
name: "general incompatible int -> string",
dest: "\x00",
src: int(0),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow source int -> dest int",
dest: int8(0),
src: int(128),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow source int -> dest uint",
dest: uint8(0),
src: int(256),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "int -> float",
dest: float32(0),
src: int(256),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow source uint64 -> dest int64",
dest: int64(0),
src: uint64(1 << 63),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow source uint -> dest int",
dest: int8(0),
src: uint(128),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow source uint -> dest uint",
dest: uint8(0),
src: uint(256),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "uint -> float",
dest: float32(0),
src: uint(256),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "float -> int",
dest: int(0),
src: float32(1.0),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow float64 -> float32",
dest: float32(0),
src: float64(math.MaxFloat64),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> bool",
dest: true,
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> int",
dest: int8(0),
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow string -> int",
dest: int8(0),
src: "128",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> uint",
dest: uint8(0),
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow string -> uint",
dest: uint8(0),
src: "256",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> float",
dest: float32(0),
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "overflow string -> float",
dest: float32(0),
src: "1.7976931348623157e+308",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> array",
dest: [3]int{},
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> slice",
dest: []int{},
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> struct",
dest: struct{ A int }{},
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid string -> map",
dest: map[string]int{},
src: "foo",
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
src := reflect.ValueOf(test.src)
err := btcjson.TstAssignField(1, "testField", dst, src)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
"want %T", i, test.name, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v (%v), want %v", i, test.name, gotErrorCode,
err, test.err.ErrorCode)
continue
}
}
}
// TestNewCmdErrors ensures the error paths of NewCmd behave as expected.
func TestNewCmdErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
args []interface{}
err btcjson.Error
}{
{
name: "unregistered command",
method: "boguscommand",
args: []interface{}{},
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "too few parameters to command with required + optional",
method: "getblock",
args: []interface{}{},
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
},
{
name: "too many parameters to command with no optional",
method: "getblockcount",
args: []interface{}{"123"},
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
},
{
name: "incorrect parameter type",
method: "getblock",
args: []interface{}{1},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
_, err := btcjson.NewCmd(test.method, test.args...)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
"want %T", i, test.name, err, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v (%v), want %v", i, test.name, gotErrorCode,
err, test.err.ErrorCode)
continue
}
}
}
// TestMarshalCmd tests the MarshalCmd function.
func TestMarshalCmd(t *testing.T) {
t.Parallel()
tests := []struct {
name string
id interface{}
cmd interface{}
expected string
}{
{
name: "include all parameters",
id: 1,
cmd: btcjson.NewGetNetworkHashPSCmd(btcjson.Int(100), btcjson.Int(2000)),
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[100,2000],"id":1}`,
},
{
name: "include padding null parameter",
id: 1,
cmd: btcjson.NewGetNetworkHashPSCmd(nil, btcjson.Int(2000)),
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[null,2000],"id":1}`,
},
{
name: "omit single unnecessary null parameter",
id: 1,
cmd: btcjson.NewGetNetworkHashPSCmd(btcjson.Int(100), nil),
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[100],"id":1}`,
},
{
name: "omit unnecessary null parameters",
id: 1,
cmd: btcjson.NewGetNetworkHashPSCmd(nil, nil),
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[],"id":1}`,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
bytes, err := btcjson.MarshalCmd(btcjson.RpcVersion1, test.id, test.cmd)
if err != nil {
t.Errorf("Test #%d (%s) wrong error - got %T (%v)",
i, test.name, err, err)
continue
}
marshalled := string(bytes)
if marshalled != test.expected {
t.Errorf("Test #%d (%s) mismatched marshall result - got "+
"%v, want %v", i, test.name, marshalled, test.expected)
continue
}
}
}
// TestMarshalCmdErrors tests the error paths of the MarshalCmd function.
func TestMarshalCmdErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
id interface{}
cmd interface{}
err btcjson.Error
}{
{
name: "unregistered type",
id: 1,
cmd: (*int)(nil),
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "nil instance of registered type",
id: 1,
cmd: (*btcjson.GetBlockCmd)(nil),
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "nil instance of registered type",
id: []int{0, 1},
cmd: &btcjson.GetBlockCountCmd{},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
_, err := btcjson.MarshalCmd(btcjson.RpcVersion1, test.id, test.cmd)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
"want %T", i, test.name, err, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v (%v), want %v", i, test.name, gotErrorCode,
err, test.err.ErrorCode)
continue
}
}
}
// TestUnmarshalCmdErrors tests the error paths of the UnmarshalCmd function.
func TestUnmarshalCmdErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
request btcjson.Request
err btcjson.Error
}{
{
name: "unregistered type",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "bogusmethod",
Params: nil,
ID: nil,
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "incorrect number of params",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getblockcount",
Params: []json.RawMessage{[]byte(`"bogusparam"`)},
ID: nil,
},
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
},
{
name: "invalid type for a parameter",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getblock",
Params: []json.RawMessage{[]byte("1")},
ID: nil,
},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid JSON for a parameter",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getblock",
Params: []json.RawMessage{[]byte(`"1`)},
ID: nil,
},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
_, err := btcjson.UnmarshalCmd(&test.request)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
"want %T", i, test.name, err, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v (%v), want %v", i, test.name, gotErrorCode,
err, test.err.ErrorCode)
continue
}
}
}

View file

@ -1,80 +0,0 @@
// Copyright (c) 2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcjson_test
import (
"testing"
"github.com/btcsuite/btcd/btcjson"
)
// TestErrorCodeStringer tests the stringized output for the ErrorCode type.
func TestErrorCodeStringer(t *testing.T) {
t.Parallel()
tests := []struct {
in btcjson.ErrorCode
want string
}{
{btcjson.ErrDuplicateMethod, "ErrDuplicateMethod"},
{btcjson.ErrInvalidUsageFlags, "ErrInvalidUsageFlags"},
{btcjson.ErrInvalidType, "ErrInvalidType"},
{btcjson.ErrEmbeddedType, "ErrEmbeddedType"},
{btcjson.ErrUnexportedField, "ErrUnexportedField"},
{btcjson.ErrUnsupportedFieldType, "ErrUnsupportedFieldType"},
{btcjson.ErrNonOptionalField, "ErrNonOptionalField"},
{btcjson.ErrNonOptionalDefault, "ErrNonOptionalDefault"},
{btcjson.ErrMismatchedDefault, "ErrMismatchedDefault"},
{btcjson.ErrUnregisteredMethod, "ErrUnregisteredMethod"},
{btcjson.ErrNumParams, "ErrNumParams"},
{btcjson.ErrMissingDescription, "ErrMissingDescription"},
{0xffff, "Unknown ErrorCode (65535)"},
}
// Detect additional error codes that don't have the stringer added.
if len(tests)-1 != int(btcjson.TstNumErrorCodes) {
t.Errorf("It appears an error code was added without adding an " +
"associated stringer test")
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
result := test.in.String()
if result != test.want {
t.Errorf("String #%d\n got: %s want: %s", i, result,
test.want)
continue
}
}
}
// TestError tests the error output for the Error type.
func TestError(t *testing.T) {
t.Parallel()
tests := []struct {
in btcjson.Error
want string
}{
{
btcjson.Error{Description: "some error"},
"some error",
},
{
btcjson.Error{Description: "human-readable error"},
"human-readable error",
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
result := test.in.Error()
if result != test.want {
t.Errorf("Error #%d\n got: %s want: %s", i, result,
test.want)
continue
}
}
}

View file

@ -8,7 +8,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
) )
// This example demonstrates how to create and marshal a command into a JSON-RPC // This example demonstrates how to create and marshal a command into a JSON-RPC

View file

@ -1,737 +0,0 @@
// Copyright (c) 2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcjson_test
import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
)
// TestHelpReflectInternals ensures the various help functions which deal with
// reflect types work as expected for various Go types.
func TestHelpReflectInternals(t *testing.T) {
t.Parallel()
tests := []struct {
name string
reflectType reflect.Type
indentLevel int
key string
examples []string
isComplex bool
help string
isInvalid bool
}{
{
name: "int",
reflectType: reflect.TypeOf(int(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "*int",
reflectType: reflect.TypeOf((*int)(nil)),
key: "json-type-value",
examples: []string{"n"},
help: "n (json-type-value) fdk",
isInvalid: true,
},
{
name: "int8",
reflectType: reflect.TypeOf(int8(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "int16",
reflectType: reflect.TypeOf(int16(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "int32",
reflectType: reflect.TypeOf(int32(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "int64",
reflectType: reflect.TypeOf(int64(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "uint",
reflectType: reflect.TypeOf(uint(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "uint8",
reflectType: reflect.TypeOf(uint8(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "uint16",
reflectType: reflect.TypeOf(uint16(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "uint32",
reflectType: reflect.TypeOf(uint32(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "uint64",
reflectType: reflect.TypeOf(uint64(0)),
key: "json-type-numeric",
examples: []string{"n"},
help: "n (json-type-numeric) fdk",
},
{
name: "float32",
reflectType: reflect.TypeOf(float32(0)),
key: "json-type-numeric",
examples: []string{"n.nnn"},
help: "n.nnn (json-type-numeric) fdk",
},
{
name: "float64",
reflectType: reflect.TypeOf(float64(0)),
key: "json-type-numeric",
examples: []string{"n.nnn"},
help: "n.nnn (json-type-numeric) fdk",
},
{
name: "string",
reflectType: reflect.TypeOf(""),
key: "json-type-string",
examples: []string{`"json-example-string"`},
help: "\"json-example-string\" (json-type-string) fdk",
},
{
name: "bool",
reflectType: reflect.TypeOf(true),
key: "json-type-bool",
examples: []string{"json-example-bool"},
help: "json-example-bool (json-type-bool) fdk",
},
{
name: "array of int",
reflectType: reflect.TypeOf([1]int{0}),
key: "json-type-arrayjson-type-numeric",
examples: []string{"[n,...]"},
help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
},
{
name: "slice of int",
reflectType: reflect.TypeOf([]int{0}),
key: "json-type-arrayjson-type-numeric",
examples: []string{"[n,...]"},
help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
},
{
name: "struct",
reflectType: reflect.TypeOf(struct{}{}),
key: "json-type-object",
examples: []string{"{", "}\t\t"},
isComplex: true,
help: "{\n} ",
},
{
name: "struct indent level 1",
reflectType: reflect.TypeOf(struct{ field int }{}),
indentLevel: 1,
key: "json-type-object",
examples: []string{
" \"field\": n,\t(json-type-numeric)\t-field",
" },\t\t",
},
help: "{\n" +
" \"field\": n, (json-type-numeric) -field\n" +
"} ",
isComplex: true,
},
{
name: "array of struct indent level 0",
reflectType: func() reflect.Type {
type s struct {
field int
}
return reflect.TypeOf([]s{})
}(),
key: "json-type-arrayjson-type-object",
examples: []string{
"[{",
" \"field\": n,\t(json-type-numeric)\ts-field",
"},...]",
},
help: "[{\n" +
" \"field\": n, (json-type-numeric) s-field\n" +
"},...]",
isComplex: true,
},
{
name: "array of struct indent level 1",
reflectType: func() reflect.Type {
type s struct {
field int
}
return reflect.TypeOf([]s{})
}(),
indentLevel: 1,
key: "json-type-arrayjson-type-object",
examples: []string{
" \"field\": n,\t(json-type-numeric)\ts-field",
" },...],\t\t",
},
help: "[{\n" +
" \"field\": n, (json-type-numeric) s-field\n" +
"},...]",
isComplex: true,
},
{
name: "map",
reflectType: reflect.TypeOf(map[string]string{}),
key: "json-type-object",
examples: []string{"{",
" \"fdk--key\": fdk--value, (json-type-object) fdk--desc",
" ...", "}",
},
help: "{\n" +
" \"fdk--key\": fdk--value, (json-type-object) fdk--desc\n" +
" ...\n" +
"}",
isComplex: true,
},
{
name: "complex",
reflectType: reflect.TypeOf(complex64(0)),
key: "json-type-value",
examples: []string{"json-example-unknown"},
help: "json-example-unknown (json-type-value) fdk",
isInvalid: true,
},
}
xT := func(key string) string {
return key
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Ensure the description key is the expected value.
key := btcjson.TstReflectTypeToJSONType(xT, test.reflectType)
if key != test.key {
t.Errorf("Test #%d (%s) unexpected key - got: %v, "+
"want: %v", i, test.name, key, test.key)
continue
}
// Ensure the generated example is as expected.
examples, isComplex := btcjson.TstReflectTypeToJSONExample(xT,
test.reflectType, test.indentLevel, "fdk")
if isComplex != test.isComplex {
t.Errorf("Test #%d (%s) unexpected isComplex - got: %v, "+
"want: %v", i, test.name, isComplex,
test.isComplex)
continue
}
if len(examples) != len(test.examples) {
t.Errorf("Test #%d (%s) unexpected result length - "+
"got: %v, want: %v", i, test.name, len(examples),
len(test.examples))
continue
}
for j, example := range examples {
if example != test.examples[j] {
t.Errorf("Test #%d (%s) example #%d unexpected "+
"example - got: %v, want: %v", i,
test.name, j, example, test.examples[j])
continue
}
}
// Ensure the generated result type help is as expected.
helpText := btcjson.TstResultTypeHelp(xT, test.reflectType, "fdk")
if helpText != test.help {
t.Errorf("Test #%d (%s) unexpected result help - "+
"got: %v, want: %v", i, test.name, helpText,
test.help)
continue
}
isValid := btcjson.TstIsValidResultType(test.reflectType.Kind())
if isValid != !test.isInvalid {
t.Errorf("Test #%d (%s) unexpected result type validity "+
"- got: %v", i, test.name, isValid)
continue
}
}
}
// TestResultStructHelp ensures the expected help text format is returned for
// various Go struct types.
func TestResultStructHelp(t *testing.T) {
t.Parallel()
tests := []struct {
name string
reflectType reflect.Type
expected []string
}{
{
name: "empty struct",
reflectType: func() reflect.Type {
type s struct{}
return reflect.TypeOf(s{})
}(),
expected: nil,
},
{
name: "struct with primitive field",
reflectType: func() reflect.Type {
type s struct {
field int
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"field\": n,\t(json-type-numeric)\ts-field",
},
},
{
name: "struct with primitive field and json tag",
reflectType: func() reflect.Type {
type s struct {
Field int `json:"f"`
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"f\": n,\t(json-type-numeric)\ts-f",
},
},
{
name: "struct with array of primitive field",
reflectType: func() reflect.Type {
type s struct {
field []int
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"field\": [n,...],\t(json-type-arrayjson-type-numeric)\ts-field",
},
},
{
name: "struct with sub-struct field",
reflectType: func() reflect.Type {
type s2 struct {
subField int
}
type s struct {
field s2
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"field\": {\t(json-type-object)\ts-field",
"{",
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
"}\t\t",
},
},
{
name: "struct with sub-struct field pointer",
reflectType: func() reflect.Type {
type s2 struct {
subField int
}
type s struct {
field *s2
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"field\": {\t(json-type-object)\ts-field",
"{",
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
"}\t\t",
},
},
{
name: "struct with array of structs field",
reflectType: func() reflect.Type {
type s2 struct {
subField int
}
type s struct {
field []s2
}
return reflect.TypeOf(s{})
}(),
expected: []string{
"\"field\": [{\t(json-type-arrayjson-type-object)\ts-field",
"[{",
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
"},...]",
},
},
}
xT := func(key string) string {
return key
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
results := btcjson.TstResultStructHelp(xT, test.reflectType, 0)
if len(results) != len(test.expected) {
t.Errorf("Test #%d (%s) unexpected result length - "+
"got: %v, want: %v", i, test.name, len(results),
len(test.expected))
continue
}
for j, result := range results {
if result != test.expected[j] {
t.Errorf("Test #%d (%s) result #%d unexpected "+
"result - got: %v, want: %v", i,
test.name, j, result, test.expected[j])
continue
}
}
}
}
// TestHelpArgInternals ensures the various help functions which deal with
// arguments work as expected for various argument types.
func TestHelpArgInternals(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
reflectType reflect.Type
defaults map[int]reflect.Value
help string
}{
{
name: "command with no args",
method: "test",
reflectType: func() reflect.Type {
type s struct{}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "",
},
{
name: "command with one required arg",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Field int
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. field (json-type-numeric, help-required) test-field\n",
},
{
name: "command with one optional arg, no default",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Optional *int
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. optional (json-type-numeric, help-optional) test-optional\n",
},
{
name: "command with one optional arg with default",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Optional *string
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: func() map[int]reflect.Value {
defVal := "test"
return map[int]reflect.Value{
0: reflect.ValueOf(&defVal),
}
}(),
help: "1. optional (json-type-string, help-optional, help-default=\"test\") test-optional\n",
},
{
name: "command with struct field",
method: "test",
reflectType: func() reflect.Type {
type s2 struct {
F int8
}
type s struct {
Field s2
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. field (json-type-object, help-required) test-field\n" +
"{\n" +
" \"f\": n, (json-type-numeric) s2-f\n" +
"} \n",
},
{
name: "command with map field",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Field map[string]float64
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. field (json-type-object, help-required) test-field\n" +
"{\n" +
" \"test-field--key\": test-field--value, (json-type-object) test-field--desc\n" +
" ...\n" +
"}\n",
},
{
name: "command with slice of primitives field",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Field []int64
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. field (json-type-arrayjson-type-numeric, help-required) test-field\n",
},
{
name: "command with slice of structs field",
method: "test",
reflectType: func() reflect.Type {
type s2 struct {
F int64
}
type s struct {
Field []s2
}
return reflect.TypeOf((*s)(nil))
}(),
defaults: nil,
help: "1. field (json-type-arrayjson-type-object, help-required) test-field\n" +
"[{\n" +
" \"f\": n, (json-type-numeric) s2-f\n" +
"},...]\n",
},
}
xT := func(key string) string {
return key
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
help := btcjson.TstArgHelp(xT, test.reflectType, test.defaults,
test.method)
if help != test.help {
t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
"want:\n%v", i, test.name, help, test.help)
continue
}
}
}
// TestMethodHelp ensures the method help function works as expected for various
// command structs.
func TestMethodHelp(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
reflectType reflect.Type
defaults map[int]reflect.Value
resultTypes []interface{}
help string
}{
{
name: "command with no args or results",
method: "test",
reflectType: func() reflect.Type {
type s struct{}
return reflect.TypeOf((*s)(nil))
}(),
help: "test\n\ntest--synopsis\n\n" +
"help-arguments:\nhelp-arguments-none\n\n" +
"help-result:\nhelp-result-nothing\n",
},
{
name: "command with no args and one primitive result",
method: "test",
reflectType: func() reflect.Type {
type s struct{}
return reflect.TypeOf((*s)(nil))
}(),
resultTypes: []interface{}{(*int64)(nil)},
help: "test\n\ntest--synopsis\n\n" +
"help-arguments:\nhelp-arguments-none\n\n" +
"help-result:\nn (json-type-numeric) test--result0\n",
},
{
name: "command with no args and two results",
method: "test",
reflectType: func() reflect.Type {
type s struct{}
return reflect.TypeOf((*s)(nil))
}(),
resultTypes: []interface{}{(*int64)(nil), nil},
help: "test\n\ntest--synopsis\n\n" +
"help-arguments:\nhelp-arguments-none\n\n" +
"help-result (test--condition0):\nn (json-type-numeric) test--result0\n\n" +
"help-result (test--condition1):\nhelp-result-nothing\n",
},
{
name: "command with primitive arg and no results",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Field bool
}
return reflect.TypeOf((*s)(nil))
}(),
help: "test field\n\ntest--synopsis\n\n" +
"help-arguments:\n1. field (json-type-bool, help-required) test-field\n\n" +
"help-result:\nhelp-result-nothing\n",
},
{
name: "command with primitive optional and no results",
method: "test",
reflectType: func() reflect.Type {
type s struct {
Field *bool
}
return reflect.TypeOf((*s)(nil))
}(),
help: "test (field)\n\ntest--synopsis\n\n" +
"help-arguments:\n1. field (json-type-bool, help-optional) test-field\n\n" +
"help-result:\nhelp-result-nothing\n",
},
}
xT := func(key string) string {
return key
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
help := btcjson.TestMethodHelp(xT, test.reflectType,
test.defaults, test.method, test.resultTypes)
if help != test.help {
t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
"want:\n%v", i, test.name, help, test.help)
continue
}
}
}
// TestGenerateHelpErrors ensures the GenerateHelp function returns the expected
// errors.
func TestGenerateHelpErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
resultTypes []interface{}
err btcjson.Error
}{
{
name: "unregistered command",
method: "boguscommand",
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
},
{
name: "non-pointer result type",
method: "help",
resultTypes: []interface{}{0},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid result type",
method: "help",
resultTypes: []interface{}{(*complex64)(nil)},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "missing description",
method: "help",
resultTypes: []interface{}{(*string)(nil), nil},
err: btcjson.Error{ErrorCode: btcjson.ErrMissingDescription},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
_, err := btcjson.GenerateHelp(test.method, nil,
test.resultTypes...)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
"want %T", i, test.name, err, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v (%v), want %v", i, test.name, gotErrorCode,
err, test.err.ErrorCode)
continue
}
}
}
// TestGenerateHelp performs a very basic test to ensure GenerateHelp is working
// as expected. The internal are testd much more thoroughly in other tests, so
// there is no need to add more tests here.
func TestGenerateHelp(t *testing.T) {
t.Parallel()
descs := map[string]string{
"help--synopsis": "test",
"help-command": "test",
}
help, err := btcjson.GenerateHelp("help", descs)
if err != nil {
t.Fatalf("GenerateHelp: unexpected error: %v", err)
}
wantHelp := "help (\"command\")\n\n" +
"test\n\nArguments:\n1. command (string, optional) test\n\n" +
"Result:\nNothing\n"
if help != wantHelp {
t.Fatalf("GenerateHelp: unexpected help - got\n%v\nwant\n%v",
help, wantHelp)
}
}

View file

@ -8,7 +8,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
) )
// TestHelpers tests the various helper functions which create pointers to // TestHelpers tests the various helper functions which create pointers to

View file

@ -226,8 +226,12 @@ func NewResponse(rpcVersion RPCVersion, id interface{}, marshalledResult []byte,
// JSON-RPC client. // JSON-RPC client.
func MarshalResponse(rpcVersion RPCVersion, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) { func MarshalResponse(rpcVersion RPCVersion, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) {
if !rpcVersion.IsValid() { if !rpcVersion.IsValid() {
str := fmt.Sprintf("rpcversion '%s' is invalid", rpcVersion) if rpcVersion == "" {
return nil, makeError(ErrInvalidType, str) rpcVersion = RpcVersion1
} else {
str := fmt.Sprintf("rpcversion '%s' is unsupported", rpcVersion)
return nil, makeError(ErrInvalidType, str)
}
} }
marshalledResult, err := json.Marshal(result) marshalledResult, err := json.Marshal(result)

View file

@ -9,7 +9,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
) )
// TestIsValidIDType ensures the IsValidIDType function behaves as expected. // TestIsValidIDType ensures the IsValidIDType function behaves as expected.

View file

@ -1,263 +0,0 @@
// Copyright (c) 2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcjson_test
import (
"reflect"
"sort"
"testing"
"github.com/btcsuite/btcd/btcjson"
)
// TestUsageFlagStringer tests the stringized output for the UsageFlag type.
func TestUsageFlagStringer(t *testing.T) {
t.Parallel()
tests := []struct {
in btcjson.UsageFlag
want string
}{
{0, "0x0"},
{btcjson.UFWalletOnly, "UFWalletOnly"},
{btcjson.UFWebsocketOnly, "UFWebsocketOnly"},
{btcjson.UFNotification, "UFNotification"},
{btcjson.UFWalletOnly | btcjson.UFWebsocketOnly,
"UFWalletOnly|UFWebsocketOnly"},
{btcjson.UFWalletOnly | btcjson.UFWebsocketOnly | (1 << 31),
"UFWalletOnly|UFWebsocketOnly|0x80000000"},
}
// Detect additional usage flags that don't have the stringer added.
numUsageFlags := 0
highestUsageFlagBit := btcjson.TstHighestUsageFlagBit
for highestUsageFlagBit > 1 {
numUsageFlags++
highestUsageFlagBit >>= 1
}
if len(tests)-3 != numUsageFlags {
t.Errorf("It appears a usage flag was added without adding " +
"an associated stringer test")
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
result := test.in.String()
if result != test.want {
t.Errorf("String #%d\n got: %s want: %s", i, result,
test.want)
continue
}
}
}
// TestRegisterCmdErrors ensures the RegisterCmd function returns the expected
// error when provided with invalid types.
func TestRegisterCmdErrors(t *testing.T) {
t.Parallel()
tests := []struct {
name string
method string
cmdFunc func() interface{}
flags btcjson.UsageFlag
err btcjson.Error
}{
{
name: "duplicate method",
method: "getblock",
cmdFunc: func() interface{} {
return struct{}{}
},
err: btcjson.Error{ErrorCode: btcjson.ErrDuplicateMethod},
},
{
name: "invalid usage flags",
method: "registertestcmd",
cmdFunc: func() interface{} {
return 0
},
flags: btcjson.TstHighestUsageFlagBit,
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidUsageFlags},
},
{
name: "invalid type",
method: "registertestcmd",
cmdFunc: func() interface{} {
return 0
},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "invalid type 2",
method: "registertestcmd",
cmdFunc: func() interface{} {
return &[]string{}
},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
},
{
name: "embedded field",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ int }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrEmbeddedType},
},
{
name: "unexported field",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ a int }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnexportedField},
},
{
name: "unsupported field type 1",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A **int }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "unsupported field type 2",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A chan int }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "unsupported field type 3",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A complex64 }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "unsupported field type 4",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A complex128 }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "unsupported field type 5",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A func() }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "unsupported field type 6",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct{ A interface{} }
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
},
{
name: "required after optional",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct {
A *int
B int
}
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrNonOptionalField},
},
{
name: "non-optional with default",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct {
A int `jsonrpcdefault:"1"`
}
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrNonOptionalDefault},
},
{
name: "mismatched default",
method: "registertestcmd",
cmdFunc: func() interface{} {
type test struct {
A *int `jsonrpcdefault:"1.7"`
}
return (*test)(nil)
},
err: btcjson.Error{ErrorCode: btcjson.ErrMismatchedDefault},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
err := btcjson.RegisterCmd(test.method, test.cmdFunc(),
test.flags)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("Test #%d (%s) wrong error - got %T, "+
"want %T", i, test.name, err, test.err)
continue
}
gotErrorCode := err.(btcjson.Error).ErrorCode
if gotErrorCode != test.err.ErrorCode {
t.Errorf("Test #%d (%s) mismatched error code - got "+
"%v, want %v", i, test.name, gotErrorCode,
test.err.ErrorCode)
continue
}
}
}
// TestMustRegisterCmdPanic ensures the MustRegisterCmd function panics when
// used to register an invalid type.
func TestMustRegisterCmdPanic(t *testing.T) {
t.Parallel()
// Setup a defer to catch the expected panic to ensure it actually
// paniced.
defer func() {
if err := recover(); err == nil {
t.Error("MustRegisterCmd did not panic as expected")
}
}()
// Intentionally try to register an invalid type to force a panic.
btcjson.MustRegisterCmd("panicme", 0, 0)
}
// TestRegisteredCmdMethods tests the RegisteredCmdMethods function ensure it
// works as expected.
func TestRegisteredCmdMethods(t *testing.T) {
t.Parallel()
// Ensure the registered methods are returned.
methods := btcjson.RegisteredCmdMethods()
if len(methods) == 0 {
t.Fatal("RegisteredCmdMethods: no methods")
}
// Ensure the returned methods are sorted.
sortedMethods := make([]string, len(methods))
copy(sortedMethods, methods)
sort.Strings(sortedMethods)
if !reflect.DeepEqual(sortedMethods, methods) {
t.Fatal("RegisteredCmdMethods: methods are not sorted")
}
}

View file

@ -12,7 +12,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// AddMultisigAddressCmd defines the addmutisigaddress JSON-RPC command. // AddMultisigAddressCmd defines the addmutisigaddress JSON-RPC command.
@ -1029,7 +1029,7 @@ type WalletCreateFundedPsbtOpts struct {
ChangeType *ChangeType `json:"change_type,omitempty"` ChangeType *ChangeType `json:"change_type,omitempty"`
IncludeWatching *bool `json:"includeWatching,omitempty"` IncludeWatching *bool `json:"includeWatching,omitempty"`
LockUnspents *bool `json:"lockUnspents,omitempty"` LockUnspents *bool `json:"lockUnspents,omitempty"`
FeeRate *int64 `json:"feeRate,omitempty"` FeeRate *float64 `json:"feeRate,omitempty"`
SubtractFeeFromOutputs *[]int64 `json:"subtractFeeFromOutputs,omitempty"` SubtractFeeFromOutputs *[]int64 `json:"subtractFeeFromOutputs,omitempty"`
Replaceable *bool `json:"replaceable,omitempty"` Replaceable *bool `json:"replaceable,omitempty"`
ConfTarget *int64 `json:"conf_target,omitempty"` ConfTarget *int64 `json:"conf_target,omitempty"`

View file

@ -11,8 +11,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/btcjson" "github.com/lbryio/lbcd/btcjson"
"github.com/btcsuite/btcutil" btcutil "github.com/lbryio/lbcutil"
) )
// TestWalletSvrCmds tests all of the wallet server commands marshal and // TestWalletSvrCmds tests all of the wallet server commands marshal and

View file

@ -8,7 +8,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/btcsuite/btcd/txscript" "github.com/lbryio/lbcd/txscript"
) )
// CreateWalletResult models the result of the createwallet command. // CreateWalletResult models the result of the createwallet command.

View file

@ -10,8 +10,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/txscript"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/lbryio/lbcd/txscript"
) )
// TestGetAddressInfoResult ensures that custom unmarshalling of // TestGetAddressInfoResult ensures that custom unmarshalling of

View file

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

View file

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

View file

@ -1,85 +1,8 @@
chaincfg chaincfg
======== ========
[![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/chaincfg)
Package chaincfg defines chain configuration parameters for the three standard Package chaincfg defines chain configuration parameters for the three standard
Bitcoin networks and provides the ability for callers to define their own custom LBRY networks and provides the ability for callers to define their own custom
Bitcoin networks. LBRY networks.
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 parameters for the standard Bitcoin networks or for projects needing to
define their own network.
## Sample Use
```Go
package main
import (
"flag"
"fmt"
"log"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcd/chaincfg"
)
var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network")
// By default (without -testnet), use mainnet.
var chainParams = &chaincfg.MainNetParams
func main() {
flag.Parse()
// Modify active network parameters if operating on testnet.
if *testnet {
chainParams = &chaincfg.TestNet3Params
}
// later...
// Create and print new payment address, specific to the active network.
pubKeyHash := make([]byte, 20)
addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, chainParams)
if err != nil {
log.Fatal(err)
}
fmt.Println(addr)
}
```
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/chaincfg
```
## 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 chaincfg is licensed under the [copyfree](http://copyfree.org) ISC
License.

View file

@ -1,9 +1,9 @@
chainhash chainhash
========= =========
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions) [![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/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/chaincfg/chainhash) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/chaincfg/chainhash)
======= =======
chainhash provides a generic hash type and associated functions that allows the chainhash provides a generic hash type and associated functions that allows the
@ -12,7 +12,7 @@ specific hash algorithm to be abstracted.
## Installation and Updating ## Installation and Updating
```bash ```bash
$ go get -u github.com/btcsuite/btcd/chaincfg/chainhash $ go get -u github.com/lbryio/lbcd/chaincfg/chainhash
``` ```
## GPG Verification Key ## GPG Verification Key

View file

@ -5,7 +5,12 @@
package chainhash package chainhash
import "crypto/sha256" import (
"crypto/sha256"
"crypto/sha512"
"golang.org/x/crypto/ripemd160"
)
// HashB calculates hash(b) and returns the resulting bytes. // HashB calculates hash(b) and returns the resulting bytes.
func HashB(b []byte) []byte { func HashB(b []byte) []byte {
@ -31,3 +36,26 @@ func DoubleHashH(b []byte) Hash {
first := sha256.Sum256(b) first := sha256.Sum256(b)
return Hash(sha256.Sum256(first[:])) return Hash(sha256.Sum256(first[:]))
} }
// LbryPoWHashH calculates returns the PoW Hash.
//
// doubled := SHA256(SHA256(b))
// expanded := SHA512(doubled)
// left := RIPEMD160(expanded[0:32])
// right := RIPEMD160(expanded[32:64])
// result := SHA256(SHA256(left||right))
func LbryPoWHashH(b []byte) Hash {
doubled := DoubleHashB(b)
expanded := sha512.Sum512(doubled)
r := ripemd160.New()
r.Reset()
r.Write(expanded[:sha256.Size])
left := r.Sum(nil)
r.Reset()
r.Write(expanded[sha256.Size:])
combined := r.Sum(left)
return DoubleHashH(combined)
}

View file

@ -25,8 +25,8 @@
// "fmt" // "fmt"
// "log" // "log"
// //
// "github.com/btcsuite/btcutil" // btcutil "github.com/lbryio/lbcutil"
// "github.com/btcsuite/btcd/chaincfg" // "github.com/lbryio/lbcd/chaincfg"
// ) // )
// //
// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") // var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network")

View file

@ -7,8 +7,8 @@ package chaincfg
import ( import (
"time" "time"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/lbryio/lbcd/wire"
) )
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for // genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
@ -22,33 +22,22 @@ var genesisCoinbaseTx = wire.MsgTx{
Index: 0xffffffff, Index: 0xffffffff,
}, },
SignatureScript: []byte{ SignatureScript: []byte{
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x17,
0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x74,
0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */
0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */
0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/
0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */
0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/
0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */
}, },
Sequence: 0xffffffff, Sequence: 0xffffffff,
}, },
}, },
TxOut: []*wire.TxOut{ TxOut: []*wire.TxOut{
{ {
Value: 0x12a05f200, Value: 0x8e1bc9bf040000, // 400000000 * COIN
PkScript: []byte{ PkScript: []byte{
0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ 0x76, 0xa9, 0x14, 0x34, 0x59, 0x91, 0xdb, 0xf5,
0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ 0x7b, 0xfb, 0x01, 0x4b, 0x87, 0x00, 0x6a, 0xcd,
0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ 0xfa, 0xfb, 0xfc, 0x5f, 0xe8, 0x29, 0x2f, 0x88,
0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ 0xac,
0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */
0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */
0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */
0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */
0x1d, 0x5f, 0xac, /* |._.| */
}, },
}, },
}, },
@ -58,19 +47,28 @@ var genesisCoinbaseTx = wire.MsgTx{
// genesisHash is the hash of the first block in the block chain for the main // genesisHash is the hash of the first block in the block chain for the main
// network (genesis block). // network (genesis block).
var genesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy. var genesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0x63, 0xf4, 0x34, 0x6a, 0x4d, 0xb3, 0x4f, 0xdf,
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, 0xce, 0x29, 0xa7, 0x0f, 0x5e, 0x8d, 0x11, 0xf0,
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x65, 0xf6, 0xb9, 0x16, 0x02, 0xb7, 0x03, 0x6c,
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x22, 0xf3, 0xa0, 0x3b, 0x28, 0x89, 0x9c,
}) })
// genesisMerkleRoot is the hash of the first transaction in the genesis block // genesisMerkleRoot is the hash of the first transaction in the genesis block
// for the main network. // for the main network.
var genesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy. var genesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0xcc, 0x59, 0xe5, 0x9f, 0xf9, 0x7a, 0xc0, 0x92,
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, 0xb5, 0x5e, 0x42, 0x3a, 0xa5, 0x49, 0x51, 0x51,
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0xed, 0x6f, 0xb8, 0x05, 0x70, 0xa5, 0xbb, 0x78,
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, 0xcd, 0x5b, 0xd1, 0xc3, 0x82, 0x1c, 0x21, 0xb8,
})
// genesisClaimTrie is the hash of the first transaction in the genesis block
// for the main network.
var genesisClaimTrie = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}) })
// genesisBlock defines the genesis block of the block chain which serves as the // genesisBlock defines the genesis block of the block chain which serves as the
@ -79,10 +77,11 @@ var genesisBlock = wire.MsgBlock{
Header: wire.BlockHeader{ Header: wire.BlockHeader{
Version: 1, Version: 1,
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000 PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
MerkleRoot: genesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b MerkleRoot: genesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
Nonce: 0x7c2bac1d, // 2083236893 Bits: 0x1f00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
Nonce: 0x00000507, // 1287
}, },
Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
} }
@ -90,10 +89,10 @@ var genesisBlock = wire.MsgBlock{
// regTestGenesisHash is the hash of the first block in the block chain for the // regTestGenesisHash is the hash of the first block in the block chain for the
// regression test network (genesis block). // regression test network (genesis block).
var regTestGenesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy. var regTestGenesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0x56, 0x75, 0x68, 0x69, 0x76, 0x67, 0x4f, 0x50,
0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0xa0, 0xa1, 0x95, 0x3d, 0x17, 0x2e, 0x9e, 0xcf,
0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0x4a, 0x4a, 0x62, 0x1d, 0xc9, 0xa4, 0xc3, 0x79,
0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x5d, 0xec, 0xd4, 0x99, 0x12, 0xcf, 0x3f, 0x6e,
}) })
// regTestGenesisMerkleRoot is the hash of the first transaction in the genesis // regTestGenesisMerkleRoot is the hash of the first transaction in the genesis
@ -107,10 +106,11 @@ var regTestGenesisBlock = wire.MsgBlock{
Header: wire.BlockHeader{ Header: wire.BlockHeader{
Version: 1, Version: 1,
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000 PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
MerkleRoot: regTestGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b MerkleRoot: regTestGenesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
Nonce: 2, Nonce: 1,
}, },
Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
} }
@ -135,10 +135,11 @@ var testNet3GenesisBlock = wire.MsgBlock{
Header: wire.BlockHeader{ Header: wire.BlockHeader{
Version: 1, Version: 1,
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000 PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
MerkleRoot: testNet3GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b MerkleRoot: testNet3GenesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
Nonce: 0x18aea41a, // 414098458 Bits: 0x1f00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
Nonce: 0x00000507, // 1287
}, },
Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
} }

View file

@ -1,351 +0,0 @@
// Copyright (c) 2014-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package chaincfg
import (
"bytes"
"testing"
"github.com/davecgh/go-spew/spew"
)
// TestGenesisBlock tests the genesis block of the main network for validity by
// checking the encoded bytes and hashes.
func TestGenesisBlock(t *testing.T) {
// Encode the genesis block to raw bytes.
var buf bytes.Buffer
err := MainNetParams.GenesisBlock.Serialize(&buf)
if err != nil {
t.Fatalf("TestGenesisBlock: %v", err)
}
// Ensure the encoded block matches the expected bytes.
if !bytes.Equal(buf.Bytes(), genesisBlockBytes) {
t.Fatalf("TestGenesisBlock: Genesis block does not appear valid - "+
"got %v, want %v", spew.Sdump(buf.Bytes()),
spew.Sdump(genesisBlockBytes))
}
// Check hash of the block against expected hash.
hash := MainNetParams.GenesisBlock.BlockHash()
if !MainNetParams.GenesisHash.IsEqual(&hash) {
t.Fatalf("TestGenesisBlock: Genesis block hash does not "+
"appear valid - got %v, want %v", spew.Sdump(hash),
spew.Sdump(MainNetParams.GenesisHash))
}
}
// TestRegTestGenesisBlock tests the genesis block of the regression test
// network for validity by checking the encoded bytes and hashes.
func TestRegTestGenesisBlock(t *testing.T) {
// Encode the genesis block to raw bytes.
var buf bytes.Buffer
err := RegressionNetParams.GenesisBlock.Serialize(&buf)
if err != nil {
t.Fatalf("TestRegTestGenesisBlock: %v", err)
}
// Ensure the encoded block matches the expected bytes.
if !bytes.Equal(buf.Bytes(), regTestGenesisBlockBytes) {
t.Fatalf("TestRegTestGenesisBlock: Genesis block does not "+
"appear valid - got %v, want %v",
spew.Sdump(buf.Bytes()),
spew.Sdump(regTestGenesisBlockBytes))
}
// Check hash of the block against expected hash.
hash := RegressionNetParams.GenesisBlock.BlockHash()
if !RegressionNetParams.GenesisHash.IsEqual(&hash) {
t.Fatalf("TestRegTestGenesisBlock: Genesis block hash does "+
"not appear valid - got %v, want %v", spew.Sdump(hash),
spew.Sdump(RegressionNetParams.GenesisHash))
}
}
// TestTestNet3GenesisBlock tests the genesis block of the test network (version
// 3) for validity by checking the encoded bytes and hashes.
func TestTestNet3GenesisBlock(t *testing.T) {
// Encode the genesis block to raw bytes.
var buf bytes.Buffer
err := TestNet3Params.GenesisBlock.Serialize(&buf)
if err != nil {
t.Fatalf("TestTestNet3GenesisBlock: %v", err)
}
// Ensure the encoded block matches the expected bytes.
if !bytes.Equal(buf.Bytes(), testNet3GenesisBlockBytes) {
t.Fatalf("TestTestNet3GenesisBlock: Genesis block does not "+
"appear valid - got %v, want %v",
spew.Sdump(buf.Bytes()),
spew.Sdump(testNet3GenesisBlockBytes))
}
// Check hash of the block against expected hash.
hash := TestNet3Params.GenesisBlock.BlockHash()
if !TestNet3Params.GenesisHash.IsEqual(&hash) {
t.Fatalf("TestTestNet3GenesisBlock: Genesis block hash does "+
"not appear valid - got %v, want %v", spew.Sdump(hash),
spew.Sdump(TestNet3Params.GenesisHash))
}
}
// TestSimNetGenesisBlock tests the genesis block of the simulation test network
// for validity by checking the encoded bytes and hashes.
func TestSimNetGenesisBlock(t *testing.T) {
// Encode the genesis block to raw bytes.
var buf bytes.Buffer
err := SimNetParams.GenesisBlock.Serialize(&buf)
if err != nil {
t.Fatalf("TestSimNetGenesisBlock: %v", err)
}
// Ensure the encoded block matches the expected bytes.
if !bytes.Equal(buf.Bytes(), simNetGenesisBlockBytes) {
t.Fatalf("TestSimNetGenesisBlock: Genesis block does not "+
"appear valid - got %v, want %v",
spew.Sdump(buf.Bytes()),
spew.Sdump(simNetGenesisBlockBytes))
}
// Check hash of the block against expected hash.
hash := SimNetParams.GenesisBlock.BlockHash()
if !SimNetParams.GenesisHash.IsEqual(&hash) {
t.Fatalf("TestSimNetGenesisBlock: Genesis block hash does "+
"not appear valid - got %v, want %v", spew.Sdump(hash),
spew.Sdump(SimNetParams.GenesisHash))
}
}
// TestSigNetGenesisBlock tests the genesis block of the signet test network for
// validity by checking the encoded bytes and hashes.
func TestSigNetGenesisBlock(t *testing.T) {
// Encode the genesis block to raw bytes.
var buf bytes.Buffer
err := SigNetParams.GenesisBlock.Serialize(&buf)
if err != nil {
t.Fatalf("TestSigNetGenesisBlock: %v", err)
}
// Ensure the encoded block matches the expected bytes.
if !bytes.Equal(buf.Bytes(), sigNetGenesisBlockBytes) {
t.Fatalf("TestSigNetGenesisBlock: Genesis block does not "+
"appear valid - got %v, want %v",
spew.Sdump(buf.Bytes()),
spew.Sdump(sigNetGenesisBlockBytes))
}
// Check hash of the block against expected hash.
hash := SigNetParams.GenesisBlock.BlockHash()
if !SigNetParams.GenesisHash.IsEqual(&hash) {
t.Fatalf("TestSigNetGenesisBlock: Genesis block hash does "+
"not appear valid - got %v, want %v", spew.Sdump(hash),
spew.Sdump(SigNetParams.GenesisHash))
}
}
// genesisBlockBytes are the wire encoded bytes for the genesis block of the
// main network as of protocol version 60002.
var genesisBlockBytes = []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, 0x49, /* |K.^J)._I| */
0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c, /* |......+|| */
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
}
// regTestGenesisBlockBytes are the wire encoded bytes for the genesis block of
// the regression test network as of protocol version 60002.
var regTestGenesisBlockBytes = []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */
0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
}
// testNet3GenesisBlockBytes are the wire encoded bytes for the genesis block of
// the test network (version 3) as of protocol version 60002.
var testNet3GenesisBlockBytes = []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */
0xff, 0xff, 0x00, 0x1d, 0x1a, 0xa4, 0xae, 0x18, /* |......+|| */
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
}
// simNetGenesisBlockBytes are the wire encoded bytes for the genesis block of
// the simulation test network as of protocol version 70002.
var simNetGenesisBlockBytes = []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
0x4b, 0x1e, 0x5e, 0x4a, 0x45, 0x06, 0x86, 0x53, /* |K.^J)._I| */
0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
}
// sigNetGenesisBlockBytes are the wire encoded bytes for the genesis block of
// the signet test network as of protocol version 70002.
var sigNetGenesisBlockBytes = []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |...@....| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |........| */
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |....;...| */
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |z{..z.,>| */
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |gv.a....| */
0x4b, 0x1e, 0x5e, 0x4a, 0x00, 0x8f, 0x4d, 0x5f, /* |..Q2:...| */
0xae, 0x77, 0x03, 0x1e, 0x8a, 0xd2, 0x22, 0x03, /* |K.^J..M_| */
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |.w....".| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |........| */
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..M.....| */
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |..EThe T| */
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |imes 03/| */
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* |Jan/2009| */
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* | Chancel| */
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |lor on b| */
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |rink of| */
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |second b| */
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |ailout f| */
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |or banks| */
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |........| */
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |*....CA.| */
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |g....UH'| */
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |.g..q0..| */
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |\..(.9..| */
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |yb...a..| */
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |I..?L.8.| */
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |.U......| */
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |\8M....W| */
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
}

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