Compare commits
269 commits
pruned_ram
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
a0ff51b84a | ||
|
4c39a9842c | ||
|
f513fca6a7 | ||
|
6728bf4b08 | ||
|
979d643594 | ||
|
cbc4d489e8 | ||
|
987a533423 | ||
|
6bc9a2b4dd | ||
|
9bcd3d0591 | ||
|
2adfcd211d | ||
|
81ec217899 | ||
|
5acfa4c81b | ||
|
c5193e74ac | ||
|
8a80f0683a | ||
|
5d7a219e35 | ||
|
2d04d31894 | ||
|
ce37025d5a | ||
|
98e5771989 | ||
|
ff324e0fdb | ||
|
be0d7de8da | ||
|
fcfb2af76f | ||
|
78bed14956 | ||
|
fdedbf86f8 | ||
|
a9351b3e3a | ||
|
e323751218 | ||
|
66c8567a27 | ||
|
6b0e7592c6 | ||
|
05f52c11a1 | ||
|
ea63a44c7b | ||
|
daa3137dc4 | ||
|
b147fe2a5b | ||
|
7f9fe4b970 | ||
|
eefb1260eb | ||
|
a8a44aa988 | ||
|
abb1b8b388 | ||
|
13e31d033a | ||
|
5499a2c1b3 | ||
|
fae4063046 | ||
|
8d1005706b | ||
|
bb93a49349 | ||
|
d5922cd725 | ||
|
3a179a0eee | ||
|
ca9b4e5529 | ||
|
2b7f065855 | ||
|
b859832907 | ||
|
70852905e0 | ||
|
5f7b1f1b4f | ||
|
0241e18f42 | ||
|
b06df3d750 | ||
|
15191b7ede | ||
|
92a7a2087a | ||
|
8f95946b17 | ||
|
5d5f53c8d8 | ||
|
6e36118193 | ||
|
e48200f53a | ||
|
4a8d390a06 | ||
|
aef4e45bd7 | ||
|
0375a6d38b | ||
|
2cfa235a33 | ||
|
7ee3d7d26b | ||
|
d4cddda35c | ||
|
76e482bb73 | ||
|
badb894e3a | ||
|
3cb961257c | ||
|
bf7a513006 | ||
|
7c5a2c6f58 | ||
|
3662f316ab | ||
|
43d3086ce1 | ||
|
7513046f70 | ||
|
d126d0c10e | ||
|
324c443c64 | ||
|
d99883a620 | ||
|
a7f971f404 | ||
|
239d681f28 | ||
|
d35a82412f | ||
|
2bd6e4c3a9 | ||
|
b4623ef2dd | ||
|
4dd4505706 | ||
|
1b823c055f | ||
|
a07bb527df | ||
|
d6a6b53551 | ||
|
fe1637c223 | ||
|
6c2a3d8bcf | ||
|
2add30af9a | ||
|
b8b2bd1584 | ||
|
f3e1c96de9 | ||
|
0a0e79bc41 | ||
|
023aa5d6b0 | ||
|
de2a548207 | ||
|
568544961f | ||
|
8c984993a8 | ||
|
6c0360fa42 | ||
|
d20a2e53b4 | ||
|
29f64f9dcf | ||
|
e0870db24e | ||
|
6784830246 | ||
|
405897fa38 | ||
|
64884458f9 | ||
|
5537ebbf0c | ||
|
1ea849d509 | ||
|
73d8f4762f | ||
|
81862c664e | ||
|
5116f45617 | ||
|
3d8f36a505 | ||
|
096dd3ff75 | ||
|
fb3ef35189 | ||
|
3111601ac9 | ||
|
e7d8637cc5 | ||
|
9d70ff6f6d | ||
|
6834591d52 | ||
|
0c5f94420a | ||
|
6828cf5e36 | ||
|
45627c7a6a | ||
|
aae5b24bb0 | ||
|
ba22414cc1 | ||
|
78d780263b | ||
|
61a18152e9 | ||
|
2b28dfa528 | ||
|
7657419b22 | ||
|
33328a3e93 | ||
|
44dd82a9f5 | ||
|
93481d7f3a | ||
|
4eb4dfa670 | ||
|
8ff0f3787e | ||
|
4a987b068d | ||
|
767a375816 | ||
|
e63ede0311 | ||
|
4bfd69e23d | ||
|
b2d0ae301e | ||
|
03989a91d9 | ||
|
9f479837c1 | ||
|
3dc91f1295 | ||
|
cbac056756 | ||
|
ba3ca3b77e | ||
|
21ad6495b6 | ||
|
dba1eb7261 | ||
|
31d3d9debc | ||
|
abe121ea6e | ||
|
2c3c4db198 | ||
|
a8ad257660 | ||
|
40dab558f6 | ||
|
42310f6948 | ||
|
7358671e83 | ||
|
6f3f4c1b8c | ||
|
4bbfd2413c | ||
|
849873675f | ||
|
82e02951dc | ||
|
08a53b25fb | ||
|
8588536586 | ||
|
e84398d21e | ||
|
b40859ff00 | ||
|
9d1d6d59a6 | ||
|
64aeab7882 | ||
|
aa1014c87b | ||
|
bd07a2580e | ||
|
b871286f98 | ||
|
6198f45307 | ||
|
07e1369839 | ||
|
e610deb203 | ||
|
804327d22c | ||
|
e928eeb5ce | ||
|
25206b9565 | ||
|
1e3b85cd60 | ||
|
90b8c2cb51 | ||
|
f5d78e8b10 | ||
|
5283e30bfc | ||
|
b8e25c397c | ||
|
21ed801540 | ||
|
13dbfa3d87 | ||
|
f8978f5804 | ||
|
a3166c8d9b | ||
|
ad01d080d9 | ||
|
76131529f2 | ||
|
1936f28d33 | ||
|
67168099d3 | ||
|
37f9cdd115 | ||
|
a3c39034b8 | ||
|
45bdd26ac3 | ||
|
8a4da7690d | ||
|
dcbff6a507 | ||
|
9b541ad169 | ||
|
9dec01adf4 | ||
|
e4c9d283b5 | ||
|
96c8bc1e93 | ||
|
767dae7adf | ||
|
76fcfbaa1f | ||
|
ef4e561119 | ||
|
afb68c4ea2 | ||
|
e063742295 | ||
|
e0cafeb4ca | ||
|
ea7b0e3816 | ||
|
e9a777d84e | ||
|
ded9b8c506 | ||
|
0edfee87d6 | ||
|
6e0abb61bd | ||
|
918278a251 | ||
|
9cfaf49024 | ||
|
b5e58f4a8d | ||
|
461335437a | ||
|
c52f41a5af | ||
|
cb4018a1d4 | ||
|
b1544cd4a9 | ||
|
1f25921172 | ||
|
cfb6bc9399 | ||
|
c85458bc7c | ||
|
603c2e3b2b | ||
|
9ac8abd519 | ||
|
aa5a1d1648 | ||
|
43e2a2acb2 | ||
|
83442d60bf | ||
|
b607be0852 | ||
|
8de1bc3ecc | ||
|
873339c5bc | ||
|
c7218b2622 | ||
|
f1ab6cc7cb | ||
|
2674b2926b | ||
|
c0b2b10241 | ||
|
1814b48565 | ||
|
814f0bae89 | ||
|
90e7a42585 | ||
|
b4f144ad8c | ||
|
4878db49cf | ||
|
44c6be3d4e | ||
|
b3dd941a77 | ||
|
4d8edfe6d9 | ||
|
38ade2c48f | ||
|
02ddaf29fd | ||
|
2b5edd2b5e | ||
|
6be04a8e43 | ||
|
3bdeaa46bf | ||
|
67e2cbe374 | ||
|
a6244b516d | ||
|
69aefa65e6 | ||
|
e7228a2e5f | ||
|
eb03d84098 | ||
|
c4da180d4f | ||
|
5d18558bc6 | ||
|
28eaf3492d | ||
|
8c68575331 | ||
|
45de22d457 | ||
|
a02b71bcf9 | ||
|
18aa1a59df | ||
|
07c1a9343d | ||
|
ce08988514 | ||
|
94bb41664b | ||
|
ac002d6422 | ||
|
fc5b1a817c | ||
|
b2784102f4 | ||
|
42f4b4025c | ||
|
cc7327c194 | ||
|
65e986844e | ||
|
31791ba4dc | ||
|
c56a053fdf | ||
|
d590f3f77d | ||
|
a148fa797a | ||
|
e3449998be | ||
|
e98a1a1b4c | ||
|
4caf037c52 | ||
|
bca4298ada | ||
|
f8e6854197 | ||
|
7ae5b74dee | ||
|
5e6736aad5 | ||
|
73f7eac903 | ||
|
3e2d8464f1 | ||
|
f9d72f05a4 | ||
|
f5a1fb9965 | ||
|
b3e6bd6161 | ||
|
86a17263b0 | ||
|
505915dc3f |
412 changed files with 44890 additions and 13122 deletions
|
@ -2,27 +2,27 @@ name: Build and Test
|
|||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
# https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/
|
||||
permissions:
|
||||
contents: read
|
||||
name: Go CI
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.14, 1.15]
|
||||
go: [1.19]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Check out source
|
||||
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
|
||||
env:
|
||||
GO111MODULE: "on"
|
||||
run: go build ./...
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
GO111MODULE: "on"
|
||||
run: |
|
||||
sh ./goclean.sh
|
||||
|
35
.github/workflows/full-sync-part-1.yml
vendored
Normal file
35
.github/workflows/full-sync-part-1.yml
vendored
Normal 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.19]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Note ${{ github.event.inputs.note }}!"
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2
|
||||
- name: Build lbcd
|
||||
run: go build .
|
||||
- name: Create datadir
|
||||
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
|
||||
- name: Run lbcd
|
||||
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
|
||||
- name: Remove datadir
|
||||
if: always()
|
||||
run: rm -rf ${{env.TEMP_DATA_DIR}}
|
37
.github/workflows/full-sync-part-2.yml
vendored
Normal file
37
.github/workflows/full-sync-part-2.yml
vendored
Normal 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.19]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Note ${{ github.event.inputs.note }}!"
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2
|
||||
- name: Build lbcd
|
||||
run: go build .
|
||||
- name: Create datadir
|
||||
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
|
||||
- name: Copy initial data
|
||||
run: cp -r /home/lbry/lbcd_814k/* ${{env.TEMP_DATA_DIR}}
|
||||
- name: Run lbcd
|
||||
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
|
||||
- name: Remove datadir
|
||||
if: always()
|
||||
run: rm -rf ${{env.TEMP_DATA_DIR}}
|
57
.github/workflows/golangci-lint.yml
vendored
Normal file
57
.github/workflows/golangci-lint.yml
vendored
Normal 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.19'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '${{ env.GO_VERSION }}'
|
||||
|
||||
- name: checkout source
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: compile code
|
||||
run: go install -v ./...
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||
version: latest
|
||||
|
||||
# Optional: working directory, useful for monorepos
|
||||
# working-directory: somedir
|
||||
|
||||
# Optional: golangci-lint command line arguments.
|
||||
# args: --issues-exit-code=0
|
||||
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
# only-new-issues: true
|
||||
|
||||
# Optional: if set to true then the action will use pre-installed Go.
|
||||
skip-go-installation: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||
# skip-pkg-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||
# skip-build-cache: true
|
57
.github/workflows/release.yml
vendored
Normal file
57
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
name: goreleaser
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
note:
|
||||
description: 'Note'
|
||||
required: false
|
||||
default: ''
|
||||
pull_request:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry docker.io
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lbcd-${{ github.sha }}
|
||||
path: |
|
||||
dist/checksums.txt
|
||||
dist/*.tar.gz
|
17
.gitignore
vendored
17
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Databases
|
||||
btcd.db
|
||||
lbcd.db
|
||||
*-shm
|
||||
*-wal
|
||||
|
||||
|
@ -33,6 +34,22 @@ _testmain.go
|
|||
|
||||
*.exe
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Code coverage files
|
||||
profile.tmp
|
||||
profile.cov
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Binaries
|
||||
btcd
|
||||
btcctl
|
||||
lbcd
|
||||
lbcctl
|
||||
|
||||
# CI artifacts
|
||||
dist
|
||||
debug
|
||||
|
|
152
.golangci.yml
Normal file
152
.golangci.yml
Normal 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
|
68
.goreleaser.yml
Normal file
68
.goreleaser.yml
Normal file
|
@ -0,0 +1,68 @@
|
|||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
# you may remove this if you don't need go generate
|
||||
- go generate ./...
|
||||
builds:
|
||||
-
|
||||
main: .
|
||||
id: "lbcd"
|
||||
binary: "lbcd"
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -buildid=
|
||||
- -X github.com/lbryio/lbcd/version.appTag={{ .Tag }}
|
||||
targets:
|
||||
- linux_amd64
|
||||
- linux_arm64
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- windows_amd64
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
-
|
||||
main: ./cmd/lbcctl
|
||||
id: "lbcctl"
|
||||
binary: "lbcctl"
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -buildid=
|
||||
- -X github.com/lbryio/lbcd/version.appTag={{ .Tag }}
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
targets:
|
||||
- linux_amd64
|
||||
- linux_arm64
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- windows_amd64
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}+{{ .Commit }}"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
|
||||
dockers:
|
||||
- use: buildx
|
||||
dockerfile: Dockerfile.goreleaser
|
||||
image_templates:
|
||||
- "docker.io/lbry/lbcd:{{ .Tag }}"
|
||||
- "docker.io/lbry/lbcd:latest"
|
||||
|
||||
release:
|
||||
draft: true
|
||||
prerelease: auto
|
25
Dockerfile
25
Dockerfile
|
@ -1,25 +1,24 @@
|
|||
# This Dockerfile builds btcd from source and creates a small (55 MB) docker container based on alpine linux.
|
||||
# This Dockerfile builds lbcd from source and creates a small (55 MB) docker container based on alpine linux.
|
||||
#
|
||||
# Clone this repository and run the following command to build and tag a fresh btcd amd64 container:
|
||||
# Clone this repository and run the following command to build and tag a fresh lbcd amd64 container:
|
||||
#
|
||||
# docker build . -t yourregistry/btcd
|
||||
# docker build . -t yourregistry/lbcd
|
||||
#
|
||||
# You can use the following command to buid an arm64v8 container:
|
||||
#
|
||||
# docker build . -t yourregistry/btcd --build-arg ARCH=arm64v8
|
||||
# docker build . -t yourregistry/lbcd --build-arg ARCH=arm64v8
|
||||
#
|
||||
# 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
|
||||
# 8334 Mainet RPC port
|
||||
# 9246 Mainnet LBRY peer-to-peer port
|
||||
# 9245 Mainet RPC port
|
||||
|
||||
ARG ARCH=amd64
|
||||
|
||||
FROM golang:1.14-alpine3.12 AS build-container
|
||||
FROM golang:1.19 AS build-container
|
||||
|
||||
ARG ARCH
|
||||
ENV GO111MODULE=on
|
||||
|
||||
ADD . /app
|
||||
WORKDIR /app
|
||||
|
@ -30,12 +29,12 @@ RUN set -ex \
|
|||
&& echo "Compiling for $GOARCH" \
|
||||
&& go install -v . ./cmd/...
|
||||
|
||||
FROM $ARCH/alpine:3.12
|
||||
FROM $ARCH/debian:bullseye-20220418-slim
|
||||
|
||||
COPY --from=build-container /go/bin /bin
|
||||
|
||||
VOLUME ["/root/.btcd"]
|
||||
VOLUME ["/root/.lbcd"]
|
||||
|
||||
EXPOSE 8333 8334
|
||||
EXPOSE 9245 9246
|
||||
|
||||
ENTRYPOINT ["btcd"]
|
||||
ENTRYPOINT ["lbcd"]
|
||||
|
|
9
Dockerfile.goreleaser
Normal file
9
Dockerfile.goreleaser
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM debian:bullseye-20220418-slim
|
||||
|
||||
COPY lbcd lbcctl /bin/
|
||||
|
||||
VOLUME ["/root/.lbcd"]
|
||||
|
||||
EXPOSE 9245 9246
|
||||
|
||||
ENTRYPOINT ["lbcd"]
|
1
LICENSE
1
LICENSE
|
@ -1,5 +1,6 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2021 The LBRY developers
|
||||
Copyright (c) 2013-2017 The btcsuite developers
|
||||
Copyright (c) 2015-2016 The Decred developers
|
||||
|
||||
|
|
364
README.md
364
README.md
|
@ -1,121 +1,335 @@
|
|||
btcd
|
||||
====
|
||||
# lbcd
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/btcsuite/btcd/badge.svg?branch=master)](https://coveralls.io/github/btcsuite/btcd?branch=master)
|
||||
[![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/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)
|
||||
[![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
|
||||
is extremely stable and has been in production use since October 2013.
|
||||
Software stack developed by LBRY teams has been all migrated to **lbcd**.
|
||||
|
||||
It properly downloads, validates, and serves the block chain using the exact
|
||||
rules (including consensus bugs) for block acceptance as Bitcoin Core. We have
|
||||
taken great care to avoid btcd causing a fork to the block chain. It includes a
|
||||
full block validation testing framework which contains all of the 'official'
|
||||
block acceptance tests (and some additional ones) that is run on every pull
|
||||
request to help ensure it properly follows consensus. Also, it passes all of
|
||||
the JSON test data in the Bitcoin Core code.
|
||||
We're working with exchanges and pool oerators to migrate from **lbrycrd** to **lbcd**.
|
||||
|
||||
It also properly relays newly mined blocks, maintains a transaction pool, and
|
||||
relays individual transactions that have not yet made it into a block. It
|
||||
ensures all individual transactions admitted to the pool follow the rules
|
||||
required by the block chain and also includes more strict checks which filter
|
||||
transactions based on miner requirements ("standard" transactions).
|
||||
If you're integrating with **lbcd+lbcwallet**, please check the Wiki for current [supported RPCs](wiki/RPC-availability).
|
||||
|
||||
One key difference between btcd and Bitcoin Core is that btcd does *NOT* include
|
||||
wallet functionality and this was a very intentional design decision. See the
|
||||
blog entry [here](https://web.archive.org/web/20171125143919/https://blog.conformal.com/btcd-not-your-moms-bitcoin-daemon)
|
||||
for more details. This means you can't actually make or receive payments
|
||||
directly with btcd. That functionality is provided by the
|
||||
[btcwallet](https://github.com/btcsuite/btcwallet) and
|
||||
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
|
||||
which are both under active development.
|
||||
Note: **lbcd** does *NOT* include wallet functionality. That functionality is provided by the
|
||||
[lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk).
|
||||
|
||||
## 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.
|
||||
|
||||
## Installation
|
||||
|
||||
https://github.com/btcsuite/btcd/releases
|
||||
Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases)
|
||||
|
||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
||||
For compilation, [Go](http://golang.org) 1.19 or newer is required.
|
||||
Install Go according to its [installation instructions](http://golang.org/doc/install).
|
||||
|
||||
- Install Go according to the installation instructions here:
|
||||
http://golang.org/doc/install
|
||||
``` sh
|
||||
# lbcd (full node)
|
||||
$ go install github.com/lbryio/lbcd@latest
|
||||
|
||||
- Ensure Go was installed properly and is a supported version:
|
||||
|
||||
```bash
|
||||
$ go version
|
||||
$ go env GOROOT GOPATH
|
||||
# lbcctl (rpc client utility)
|
||||
$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest
|
||||
```
|
||||
|
||||
NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is
|
||||
recommended that `GOPATH` is set to a directory in your home directory such as
|
||||
`~/goprojects` to avoid write permission issues. It is also recommended to add
|
||||
`$GOPATH/bin` to your `PATH` at this point.
|
||||
## Usage
|
||||
|
||||
- Run the following commands to obtain btcd, all dependencies, and install it:
|
||||
Default application folder `${LBCDDIR}`:
|
||||
|
||||
```bash
|
||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
||||
$ GO111MODULE=on go install -v . ./cmd/...
|
||||
- Linux: `~/.lbcd/`
|
||||
- MacOS: `/Users/<username>/Library/Application Support/Lbcd/`
|
||||
|
||||
### Start the **lbcd**
|
||||
|
||||
``` sh
|
||||
./lbcd
|
||||
```
|
||||
|
||||
- btcd (and utilities) will now be installed in ```$GOPATH/bin```. If you did
|
||||
not already add the bin directory to your system path during Go installation,
|
||||
we recommend you do so now.
|
||||
**lbcd** loads config file at `"${LBCDDIR}/lbcd.conf"`.
|
||||
|
||||
## Updating
|
||||
If no config is found, it creates a [default one](sample-lbcd.conf), which includes all available options with default settings except randomly generated *RPC credentials* (see below).
|
||||
|
||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
||||
### RPC server
|
||||
|
||||
- Run the following commands to update btcd, all dependencies, and install it:
|
||||
RPC credentials (`rpcuser` and `rpcpass`) is required to enable RPC server. It can be specify in the `"${LBCDDIR}/lbcd.conf"`, using command line options:
|
||||
|
||||
```bash
|
||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
||||
$ git pull
|
||||
$ GO111MODULE=on go install -v . ./cmd/...
|
||||
``` sh
|
||||
./lbcd --rpcuser=rpcuser --rpcpass=rpcpass
|
||||
|
||||
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on 0.0.0.0:9245
|
||||
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on [::]:9245
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
### Working with TLS (Default)
|
||||
|
||||
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.
|
||||
By default, **lbcd** runs RPC server with TLS enabled, and generates the `rpc.cert` and `rpc.key` under `${LBCDDIR}`, if not exist already.
|
||||
|
||||
#### Linux/BSD/POSIX/Source
|
||||
To interact with the RPC server, a client has to either specify the `rpc.cert`, or disable the certification verification for TLS.
|
||||
|
||||
```bash
|
||||
$ ./btcd
|
||||
Interact with **lbcd** RPC using `lbcctl`
|
||||
|
||||
``` sh
|
||||
$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount
|
||||
|
||||
# or disable the certificate verification
|
||||
$ ./lbcctl --skipverify getblockcount
|
||||
|
||||
1200062
|
||||
```
|
||||
|
||||
## IRC
|
||||
Interact with **lbcd** RPC using `curl`
|
||||
|
||||
- irc.freenode.net
|
||||
- channel #btcd
|
||||
- [webchat](https://webchat.freenode.net/?channels=btcd)
|
||||
``` sh
|
||||
$ curl --user rpcuser:rpcpass \
|
||||
--cacert "${LBCDDIR}/rpc.cert" \
|
||||
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
|
||||
-H 'content-type: text/plain;' \
|
||||
https://127.0.0.1:9245/
|
||||
|
||||
## Issue Tracker
|
||||
# or disable the certificate verification
|
||||
$ curl --user rpcuser:rpcpass \
|
||||
--insecure \
|
||||
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
|
||||
-H 'content-type: text/plain;' \
|
||||
https://127.0.0.1:9245/
|
||||
```
|
||||
|
||||
The [integrated github issue tracker](https://github.com/btcsuite/btcd/issues)
|
||||
is used for this project.
|
||||
``` json
|
||||
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
### Working without TLS
|
||||
|
||||
The documentation is a work-in-progress. It is located in the [docs](https://github.com/btcsuite/btcd/tree/master/docs) folder.
|
||||
TLS can be disabled using the `--notls` option:
|
||||
|
||||
## Release Verification
|
||||
``` sh
|
||||
$ ./lbcd --notls
|
||||
```
|
||||
|
||||
``` sh
|
||||
$ ./lbcctl --notls getblockcount
|
||||
|
||||
1200062
|
||||
```
|
||||
|
||||
``` sh
|
||||
$ curl --user rpcuser:rpcpass \
|
||||
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
|
||||
-H 'content-type: text/plain;' \
|
||||
http://127.0.0.1:9245/
|
||||
```
|
||||
|
||||
``` json
|
||||
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}
|
||||
```
|
||||
|
||||
## Using Snapshots (optional)
|
||||
|
||||
[Snapshots](https://snapshots.lbry.com/blockchain/) are created bi-weekly to help new users catch up current block height.
|
||||
|
||||
The snapshots are archived and compressed in [zstd](https://facebook.github.io/zstd/) format for it's compression ratio and speed.
|
||||
|
||||
Download the snapshot, and uncompress it:
|
||||
|
||||
``` sh
|
||||
time curl -O https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst
|
||||
zstd -d --stdout lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | tar xf - -C "${LBCDDIR}"
|
||||
```
|
||||
|
||||
If preferred, a user can download and uncompress the snapshot on the fly:
|
||||
By the time the download is finished, the snapshots should be almost uncompressed already.
|
||||
|
||||
``` sh
|
||||
mkdir -p "${LBCDDIR}"
|
||||
|
||||
time curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | zstd -d --stdout | tar xf - -C "${LBCDDIR}"
|
||||
|
||||
# % Total % Received % Xferd Average Speed Time Time Time Current
|
||||
# Dload Upload Total Spent Left Speed
|
||||
# 100 64.9G 100 64.9G 0 0 37.0M 0 0:29:49 0:29:49 --:--:-- 33.0M
|
||||
#
|
||||
# real 29m49.962s
|
||||
# user 6m53.710s
|
||||
# sys 8m56.545s
|
||||
```
|
||||
|
||||
## Working with RPCs
|
||||
|
||||
Using `lbcctl -l` to list available RPCs:
|
||||
|
||||
``` sh
|
||||
$ lbcctl -l
|
||||
|
||||
Chain Server Commands:
|
||||
addnode "addr" "add|remove|onetry"
|
||||
createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)
|
||||
debuglevel "levelspec"
|
||||
decoderawtransaction "hextx"
|
||||
decodescript "hexscript"
|
||||
deriveaddresses "descriptor" ({"value":value})
|
||||
fundrawtransaction "hextx" {"changeaddress":changeaddress,"changeposition":changeposition,"changetype":changetype,"includewatching":includewatching,"lockunspents":lockunspents,"feerate":feerate,"subtractfeefromoutputs":[subtractfeefromoutput,...],"replaceable":replaceable,"conftarget":conftarget,"estimatemode":estimatemode} (iswitness)
|
||||
generate numblocks
|
||||
|
||||
[skipped]
|
||||
|
||||
Wallet Server Commands (--wallet):
|
||||
addmultisigaddress nrequired ["key",...] ("account")
|
||||
addwitnessaddress "address"
|
||||
backupwallet "destination"
|
||||
createmultisig nrequired ["key",...]
|
||||
createnewaccount "account"
|
||||
createwallet "walletname" (disableprivatekeys=false blank=false passphrase="" avoidreuse=false)
|
||||
dumpprivkey "address"
|
||||
dumpwallet "filename"
|
||||
encryptwallet "passphrase"
|
||||
estimatefee numblocks
|
||||
estimatepriority numblocks
|
||||
estimatesmartfee conftarget (estimatemode="CONSERVATIVE")
|
||||
getaccount "address"
|
||||
getaccountaddress "account"
|
||||
getaddressesbyaccount "account"
|
||||
|
||||
[skipped]
|
||||
```
|
||||
|
||||
Using `lbcctl help rpcname` to show the RPC spec:
|
||||
|
||||
``` sh
|
||||
$ lbcctl help getblock
|
||||
|
||||
getblock "hash" (verbosity=1)
|
||||
|
||||
Returns information about a block given its hash.
|
||||
|
||||
Arguments:
|
||||
1. hash (string, required) The hash of the block
|
||||
2. verbosity (numeric, optional, default=1) Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2)
|
||||
|
||||
Result (verbosity=0):
|
||||
"value" (string) Hex-encoded bytes of the serialized block
|
||||
|
||||
Result (verbosity=1):
|
||||
{
|
||||
"getblockverboseresultbase": { (object)
|
||||
"hash": "value", (string) The hash of the block (same as provided)
|
||||
"confirmations": n, (numeric) The number of confirmations
|
||||
"strippedsize": n, (numeric) The size of the block without witness data
|
||||
"size": n, (numeric) The size of the block
|
||||
"weight": n, (numeric) The weight of the block
|
||||
"height": n, (numeric) The height of the block in the block chain
|
||||
"version": n, (numeric) The block version
|
||||
"versionHex": "value", (string) The block version in hexadecimal
|
||||
"merkleroot": "value", (string) Root hash of the merkle tree
|
||||
"time": n, (numeric) The block time in seconds since 1 Jan 1970 GMT
|
||||
"mediantime": n, (numeric) The median block time in seconds since 1 Jan 1970 GMT
|
||||
"nonce": n, (numeric) The block nonce
|
||||
"bits": "value", (string) The bits which represent the block difficulty
|
||||
"difficulty": n.nnn, (numeric) The proof-of-work difficulty as a multiple of the minimum difficulty
|
||||
"chainwork": "value", (string) Expected number of hashes required to produce the chain up to this block (in hex)
|
||||
"previousblockhash": "value", (string) The hash of the previous block
|
||||
"nextblockhash": "value", (string) The hash of the next block (only if there is one)
|
||||
"nameclaimroot": "value", (string) Root hash of the claim trie
|
||||
"nTx": n, (numeric) The number of transactions (aka, count of TX)
|
||||
},
|
||||
"tx": ["value",...], (array of string) The transaction hashes (only when verbosity=1)
|
||||
}
|
||||
```
|
||||
|
||||
## **lbcd** & **lbcwallet**
|
||||
|
||||
*Wallet* related functianlities and RPCs are provided by a separate programe - [**lbcwallet**](https://github.com/lbryio/lbcwallet).
|
||||
|
||||
Once setup, lbcwallet can serve wallet related RPCs as well as proxy lbcd RPCs to an assocated lbcd now.
|
||||
It's sufficient for user to connect just the **lbcwallet** instead of both.
|
||||
|
||||
``` mermaid
|
||||
sequenceDiagram
|
||||
actor C as lbcctl
|
||||
participant W as lbcwallet (port: 9244)
|
||||
participant D as lbcd (port: 9245)
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over C,D: lbcctl getblockcount
|
||||
C ->>+ D: getblockcount
|
||||
D -->>- C: response
|
||||
end
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over C,W: lbcctl --wallet balance
|
||||
C ->>+ W: getbalance
|
||||
W -->>- C: response
|
||||
end
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over C,D: lbcctl --wallet getblockcount (lbcd RPC service proxied by lbcwallet)
|
||||
C ->>+ W: getblockcount
|
||||
W ->>+ D: getblockcount
|
||||
D -->>- W: response
|
||||
W -->>- C: response
|
||||
end
|
||||
```
|
||||
|
||||
While **lbcd** can run standalone as a full node, **lbcwallet** requires an associated **lbcd** instance for scanning and sync'ing block data.
|
||||
|
||||
``` mermaid
|
||||
sequenceDiagram
|
||||
participant W as lbcwallet (RPC port: 9244)
|
||||
participant D as lbcd (RPC port: 9245, P2P port: 9246)
|
||||
participant D2 as other lbcd node(s) (P2P port: 9246)
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over W,D: Asynchronous websocket notifications
|
||||
W ->> D: subscribe to notifications
|
||||
D -->> W: notification
|
||||
D -->> W: notification
|
||||
end
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over W,D: lbcd RPCs
|
||||
W ->>+ D: getblockheader
|
||||
D ->>- W: response
|
||||
end
|
||||
|
||||
rect rgb(200,200,200)
|
||||
Note over D,D2: P2P messages over port 9246
|
||||
D -->> D2: P2P message
|
||||
D2 -->> D: P2P message
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
## Data integrity
|
||||
|
||||
**lbcd** is not immune to data loss. It expects a clean shutdown via SIGINT or
|
||||
SIGTERM. SIGKILL, immediate VM kills, and sudden power loss can cause data
|
||||
corruption, thus requiring chain resynchronization for recovery.
|
||||
|
||||
## Security
|
||||
|
||||
We take security seriously. Please contact [security](mailto:security@lbry.com) regarding any security issues.
|
||||
Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
|
||||
|
||||
We maintain a mailing list for notifications of upgrades, security issues,
|
||||
and soft/hard forks. To join, visit [fork list](https://lbry.com/forklist)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to this project are welcome, encouraged, and compensated.
|
||||
The [integrated github issue tracker](https://github.com/lbryio/lbcd/issues)
|
||||
is used for this project. All pull requests will be considered.
|
||||
|
||||
<!-- ## Release Verification
|
||||
Please see our [documentation on the current build/verification
|
||||
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
|
||||
using our reproducible build system.
|
||||
-->
|
||||
|
||||
## License
|
||||
|
||||
btcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||
lbcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||
|
|
|
@ -23,8 +23,8 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// AddrManager provides a concurrency safe address manager for caching potential
|
||||
|
@ -45,7 +45,7 @@ type AddrManager struct {
|
|||
nTried int
|
||||
nNew int
|
||||
lamtx sync.Mutex
|
||||
localAddresses map[string]*localAddress
|
||||
localAddresses map[string]*LocalAddress
|
||||
version int
|
||||
}
|
||||
|
||||
|
@ -69,9 +69,9 @@ type serializedAddrManager struct {
|
|||
TriedBuckets [triedBucketCount][]string
|
||||
}
|
||||
|
||||
type localAddress struct {
|
||||
na *wire.NetAddress
|
||||
score AddressPriority
|
||||
type LocalAddress struct {
|
||||
NA *wire.NetAddress
|
||||
Score AddressPriority
|
||||
}
|
||||
|
||||
// AddressPriority type is used to describe the hierarchy of local address
|
||||
|
@ -176,9 +176,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
|
|||
// TODO: only update addresses periodically.
|
||||
// Update the last seen time and services.
|
||||
// note that to prevent causing excess garbage on getaddr
|
||||
// messages the netaddresses in addrmaanger are *immutable*,
|
||||
// messages the netaddresses in addrmanager are *immutable*,
|
||||
// if we need to change them then we replace the pointer with a
|
||||
// new copy so that we don't have to copy every na for getaddr.
|
||||
// new copy so that we don't have to copy every NA for getaddr.
|
||||
if netAddr.Timestamp.After(ka.na.Timestamp) ||
|
||||
(ka.na.Services&netAddr.Services) !=
|
||||
netAddr.Services {
|
||||
|
@ -186,7 +186,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
|
|||
naCopy := *ka.na
|
||||
naCopy.Timestamp = netAddr.Timestamp
|
||||
naCopy.AddService(netAddr.Services)
|
||||
ka.mtx.Lock()
|
||||
ka.na = &naCopy
|
||||
ka.mtx.Unlock()
|
||||
}
|
||||
|
||||
// If already in tried, we have nothing to do here.
|
||||
|
@ -753,7 +755,7 @@ func (a *AddrManager) HostToNetAddress(host string, port uint16, services wire.S
|
|||
// the relevant .onion address.
|
||||
func ipString(na *wire.NetAddress) string {
|
||||
if IsOnionCatTor(na) {
|
||||
// We know now that na.IP is long enough.
|
||||
// We know now that NA.IP is long enough.
|
||||
base32 := base32.StdEncoding.EncodeToString(na.IP[6:])
|
||||
return strings.ToLower(base32) + ".onion"
|
||||
}
|
||||
|
@ -857,8 +859,11 @@ func (a *AddrManager) Attempt(addr *wire.NetAddress) {
|
|||
return
|
||||
}
|
||||
// set last tried time to now
|
||||
now := time.Now()
|
||||
ka.mtx.Lock()
|
||||
ka.attempts++
|
||||
ka.lastattempt = time.Now()
|
||||
ka.lastattempt = now
|
||||
ka.mtx.Unlock()
|
||||
}
|
||||
|
||||
// Connected Marks the given address as currently connected and working at the
|
||||
|
@ -877,10 +882,12 @@ func (a *AddrManager) Connected(addr *wire.NetAddress) {
|
|||
// so.
|
||||
now := time.Now()
|
||||
if now.After(ka.na.Timestamp.Add(time.Minute * 20)) {
|
||||
// ka.na is immutable, so replace it.
|
||||
// ka.NA is immutable, so replace it.
|
||||
naCopy := *ka.na
|
||||
naCopy.Timestamp = time.Now()
|
||||
ka.mtx.Lock()
|
||||
ka.na = &naCopy
|
||||
ka.mtx.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,11 +906,13 @@ func (a *AddrManager) Good(addr *wire.NetAddress) {
|
|||
// ka.Timestamp is not updated here to avoid leaking information
|
||||
// about currently connected peers.
|
||||
now := time.Now()
|
||||
ka.mtx.Lock()
|
||||
ka.lastsuccess = now
|
||||
ka.lastattempt = now
|
||||
ka.attempts = 0
|
||||
ka.mtx.Unlock() // tried and refs synchronized via a.mtx
|
||||
|
||||
// move to tried set, optionally evicting other addresses if neeed.
|
||||
// move to tried set, optionally evicting other addresses if need.
|
||||
if ka.tried {
|
||||
return
|
||||
}
|
||||
|
@ -985,14 +994,16 @@ func (a *AddrManager) SetServices(addr *wire.NetAddress, services wire.ServiceFl
|
|||
|
||||
// Update the services if needed.
|
||||
if ka.na.Services != services {
|
||||
// ka.na is immutable, so replace it.
|
||||
// ka.NA is immutable, so replace it.
|
||||
naCopy := *ka.na
|
||||
naCopy.Services = services
|
||||
ka.mtx.Lock()
|
||||
ka.na = &naCopy
|
||||
ka.mtx.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// AddLocalAddress adds na to the list of known local addresses to advertise
|
||||
// AddLocalAddress adds NA to the list of known local addresses to advertise
|
||||
// with the given priority.
|
||||
func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error {
|
||||
if !IsRoutable(na) {
|
||||
|
@ -1004,13 +1015,13 @@ func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPrior
|
|||
|
||||
key := NetAddressKey(na)
|
||||
la, ok := a.localAddresses[key]
|
||||
if !ok || la.score < priority {
|
||||
if !ok || la.Score < priority {
|
||||
if ok {
|
||||
la.score = priority + 1
|
||||
la.Score = priority + 1
|
||||
} else {
|
||||
a.localAddresses[key] = &localAddress{
|
||||
na: na,
|
||||
score: priority,
|
||||
a.localAddresses[key] = &LocalAddress{
|
||||
NA: na,
|
||||
Score: priority,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1106,12 +1117,12 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
|
|||
var bestscore AddressPriority
|
||||
var bestAddress *wire.NetAddress
|
||||
for _, la := range a.localAddresses {
|
||||
reach := getReachabilityFrom(la.na, remoteAddr)
|
||||
reach := getReachabilityFrom(la.NA, remoteAddr)
|
||||
if reach > bestreach ||
|
||||
(reach == bestreach && la.score > bestscore) {
|
||||
(reach == bestreach && la.Score > bestscore) {
|
||||
bestreach = reach
|
||||
bestscore = la.score
|
||||
bestAddress = la.na
|
||||
bestscore = la.Score
|
||||
bestAddress = la.NA
|
||||
}
|
||||
}
|
||||
if bestAddress != nil {
|
||||
|
@ -1135,6 +1146,15 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
|
|||
return bestAddress
|
||||
}
|
||||
|
||||
// LocalAddresses returns the list of local addresses for our node.
|
||||
func (a *AddrManager) LocalAddresses() []*LocalAddress {
|
||||
var addrs []*LocalAddress
|
||||
for _, addr := range a.localAddresses {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// New returns a new bitcoin address manager.
|
||||
// Use Start to begin processing asynchronous address updates.
|
||||
func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
|
||||
|
@ -1143,7 +1163,7 @@ func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager
|
|||
lookupFunc: lookupFunc,
|
||||
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
quit: make(chan struct{}),
|
||||
localAddresses: make(map[string]*localAddress),
|
||||
localAddresses: make(map[string]*LocalAddress),
|
||||
version: serialisationVersion,
|
||||
}
|
||||
am.reset()
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/addrmgr"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// naTest is used to describe a test to be performed against the NetAddressKey
|
||||
|
@ -34,61 +34,61 @@ var someIP = "173.194.115.66"
|
|||
func addNaTests() {
|
||||
// IPv4
|
||||
// Localhost
|
||||
addNaTest("127.0.0.1", 8333, "127.0.0.1:8333")
|
||||
addNaTest("127.0.0.1", 8334, "127.0.0.1:8334")
|
||||
addNaTest("127.0.0.1", 9244, "127.0.0.1:9244")
|
||||
addNaTest("127.0.0.1", 9245, "127.0.0.1:9245")
|
||||
|
||||
// Class A
|
||||
addNaTest("1.0.0.1", 8333, "1.0.0.1:8333")
|
||||
addNaTest("2.2.2.2", 8334, "2.2.2.2:8334")
|
||||
addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
|
||||
addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
|
||||
addNaTest("1.0.0.1", 9244, "1.0.0.1:9244")
|
||||
addNaTest("2.2.2.2", 9245, "2.2.2.2:9245")
|
||||
addNaTest("27.253.252.251", 9246, "27.253.252.251:9246")
|
||||
addNaTest("123.3.2.1", 9247, "123.3.2.1:9247")
|
||||
|
||||
// Private Class A
|
||||
addNaTest("10.0.0.1", 8333, "10.0.0.1:8333")
|
||||
addNaTest("10.1.1.1", 8334, "10.1.1.1:8334")
|
||||
addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
|
||||
addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
|
||||
addNaTest("10.0.0.1", 9244, "10.0.0.1:9244")
|
||||
addNaTest("10.1.1.1", 9245, "10.1.1.1:9245")
|
||||
addNaTest("10.2.2.2", 9246, "10.2.2.2:9246")
|
||||
addNaTest("10.10.10.10", 9247, "10.10.10.10:9247")
|
||||
|
||||
// Class B
|
||||
addNaTest("128.0.0.1", 8333, "128.0.0.1:8333")
|
||||
addNaTest("129.1.1.1", 8334, "129.1.1.1:8334")
|
||||
addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
|
||||
addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
|
||||
addNaTest("128.0.0.1", 9244, "128.0.0.1:9244")
|
||||
addNaTest("129.1.1.1", 9245, "129.1.1.1:9245")
|
||||
addNaTest("180.2.2.2", 9246, "180.2.2.2:9246")
|
||||
addNaTest("191.10.10.10", 9247, "191.10.10.10:9247")
|
||||
|
||||
// Private Class B
|
||||
addNaTest("172.16.0.1", 8333, "172.16.0.1:8333")
|
||||
addNaTest("172.16.1.1", 8334, "172.16.1.1:8334")
|
||||
addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
|
||||
addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
|
||||
addNaTest("172.16.0.1", 9244, "172.16.0.1:9244")
|
||||
addNaTest("172.16.1.1", 9245, "172.16.1.1:9245")
|
||||
addNaTest("172.16.2.2", 9246, "172.16.2.2:9246")
|
||||
addNaTest("172.16.172.172", 9247, "172.16.172.172:9247")
|
||||
|
||||
// Class C
|
||||
addNaTest("193.0.0.1", 8333, "193.0.0.1:8333")
|
||||
addNaTest("200.1.1.1", 8334, "200.1.1.1:8334")
|
||||
addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
|
||||
addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
|
||||
addNaTest("193.0.0.1", 9244, "193.0.0.1:9244")
|
||||
addNaTest("200.1.1.1", 9245, "200.1.1.1:9245")
|
||||
addNaTest("205.2.2.2", 9246, "205.2.2.2:9246")
|
||||
addNaTest("223.10.10.10", 9247, "223.10.10.10:9247")
|
||||
|
||||
// Private Class C
|
||||
addNaTest("192.168.0.1", 8333, "192.168.0.1:8333")
|
||||
addNaTest("192.168.1.1", 8334, "192.168.1.1:8334")
|
||||
addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
|
||||
addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
|
||||
addNaTest("192.168.0.1", 9244, "192.168.0.1:9244")
|
||||
addNaTest("192.168.1.1", 9245, "192.168.1.1:9245")
|
||||
addNaTest("192.168.2.2", 9246, "192.168.2.2:9246")
|
||||
addNaTest("192.168.192.192", 9247, "192.168.192.192:9247")
|
||||
|
||||
// IPv6
|
||||
// Localhost
|
||||
addNaTest("::1", 8333, "[::1]:8333")
|
||||
addNaTest("fe80::1", 8334, "[fe80::1]:8334")
|
||||
addNaTest("::1", 9244, "[::1]:9244")
|
||||
addNaTest("fe80::1", 9245, "[fe80::1]:9245")
|
||||
|
||||
// Link-local
|
||||
addNaTest("fe80::1:1", 8333, "[fe80::1:1]:8333")
|
||||
addNaTest("fe91::2:2", 8334, "[fe91::2:2]:8334")
|
||||
addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
|
||||
addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
|
||||
addNaTest("fe80::1:1", 9244, "[fe80::1:1]:9244")
|
||||
addNaTest("fe91::2:2", 9245, "[fe91::2:2]:9245")
|
||||
addNaTest("fea2::3:3", 9246, "[fea2::3:3]:9246")
|
||||
addNaTest("feb3::4:4", 9247, "[feb3::4:4]:9247")
|
||||
|
||||
// Site-local
|
||||
addNaTest("fec0::1:1", 8333, "[fec0::1:1]:8333")
|
||||
addNaTest("fed1::2:2", 8334, "[fed1::2:2]:8334")
|
||||
addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
|
||||
addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
|
||||
addNaTest("fec0::1:1", 9244, "[fec0::1:1]:9244")
|
||||
addNaTest("fed1::2:2", 9245, "[fed1::2:2]:9245")
|
||||
addNaTest("fee2::3:3", 9246, "[fee2::3:3]:9246")
|
||||
addNaTest("fef3::4:4", 9247, "[fef3::4:4]:9247")
|
||||
}
|
||||
|
||||
func addNaTest(ip string, port uint16, want string) {
|
||||
|
@ -119,7 +119,7 @@ func TestAddAddressByIP(t *testing.T) {
|
|||
err error
|
||||
}{
|
||||
{
|
||||
someIP + ":8333",
|
||||
someIP + ":9244",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ func TestAddAddressByIP(t *testing.T) {
|
|||
addrErr,
|
||||
},
|
||||
{
|
||||
someIP[:12] + ":8333",
|
||||
someIP[:12] + ":9244",
|
||||
fmtErr,
|
||||
},
|
||||
{
|
||||
|
@ -212,7 +212,7 @@ func TestAttempt(t *testing.T) {
|
|||
n := addrmgr.New("testattempt", lookupFunc)
|
||||
|
||||
// Add a new address and get it
|
||||
err := n.AddAddressByIP(someIP + ":8333")
|
||||
err := n.AddAddressByIP(someIP + ":9244")
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ func TestConnected(t *testing.T) {
|
|||
n := addrmgr.New("testconnected", lookupFunc)
|
||||
|
||||
// Add a new address and get it
|
||||
err := n.AddAddressByIP(someIP + ":8333")
|
||||
err := n.AddAddressByIP(someIP + ":9244")
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
|
@ -261,14 +261,14 @@ func TestNeedMoreAddresses(t *testing.T) {
|
|||
|
||||
var err error
|
||||
for i := 0; i < addrsToAdd; i++ {
|
||||
s := fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60)
|
||||
s := fmt.Sprintf("%d.%d.173.147:9244", i/128+60, i%128+60)
|
||||
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
||||
}
|
||||
}
|
||||
|
||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
|
||||
|
||||
n.AddAddresses(addrs, srcAddr)
|
||||
numAddrs := n.NumAddresses()
|
||||
|
@ -289,14 +289,14 @@ func TestGood(t *testing.T) {
|
|||
|
||||
var err error
|
||||
for i := 0; i < addrsToAdd; i++ {
|
||||
s := fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60)
|
||||
s := fmt.Sprintf("%d.173.147.%d:9244", i/64+60, i%64+60)
|
||||
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
||||
}
|
||||
}
|
||||
|
||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
|
||||
|
||||
n.AddAddresses(addrs, srcAddr)
|
||||
for _, addr := range addrs {
|
||||
|
@ -323,7 +323,7 @@ func TestGetAddress(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add a new address and get it
|
||||
err := n.AddAddressByIP(someIP + ":8333")
|
||||
err := n.AddAddressByIP(someIP + ":9244")
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
/*
|
||||
Package addrmgr implements concurrency safe Bitcoin address manager.
|
||||
|
||||
Address Manager Overview
|
||||
# Address Manager Overview
|
||||
|
||||
In order maintain the peer-to-peer Bitcoin network, there needs to be a source
|
||||
of addresses to connect to as nodes come and go. The Bitcoin protocol provides
|
||||
|
|
|
@ -7,7 +7,7 @@ package addrmgr
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
func TstKnownAddressIsBad(ka *KnownAddress) bool {
|
||||
|
|
|
@ -5,14 +5,16 @@
|
|||
package addrmgr
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// KnownAddress tracks information about a known network address that is used
|
||||
// to determine how viable an address is.
|
||||
type KnownAddress struct {
|
||||
mtx sync.RWMutex // na and lastattempt
|
||||
na *wire.NetAddress
|
||||
srcAddr *wire.NetAddress
|
||||
attempts int
|
||||
|
@ -25,19 +27,28 @@ type KnownAddress struct {
|
|||
// NetAddress returns the underlying wire.NetAddress associated with the
|
||||
// known address.
|
||||
func (ka *KnownAddress) NetAddress() *wire.NetAddress {
|
||||
ka.mtx.RLock()
|
||||
defer ka.mtx.RUnlock()
|
||||
return ka.na
|
||||
}
|
||||
|
||||
// LastAttempt returns the last time the known address was attempted.
|
||||
func (ka *KnownAddress) LastAttempt() time.Time {
|
||||
ka.mtx.RLock()
|
||||
defer ka.mtx.RUnlock()
|
||||
return ka.lastattempt
|
||||
}
|
||||
|
||||
// Services returns the services supported by the peer with the known address.
|
||||
func (ka *KnownAddress) Services() wire.ServiceFlag {
|
||||
ka.mtx.RLock()
|
||||
defer ka.mtx.RUnlock()
|
||||
return ka.na.Services
|
||||
}
|
||||
|
||||
// The unexported methods, chance and isBad, are used from within AddrManager
|
||||
// where KnownAddress field access is synchronized via it's own Mutex.
|
||||
|
||||
// chance returns the selection probability for a known address. The priority
|
||||
// depends upon how recently the address has been seen, how recently it was last
|
||||
// attempted and how often attempts to connect to it have failed.
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/addrmgr"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
func TestChance(t *testing.T) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/addrmgr"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestIPTypes ensures the various functions which determine the type of an IP
|
||||
|
@ -39,7 +39,7 @@ func TestIPTypes(t *testing.T) {
|
|||
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
|
||||
local, valid, routable bool) ipTest {
|
||||
nip := net.ParseIP(ip)
|
||||
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
|
||||
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
|
||||
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
|
||||
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
|
||||
return test
|
||||
|
@ -192,7 +192,7 @@ func TestGroupKey(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
nip := net.ParseIP(test.ip)
|
||||
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
|
||||
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
|
||||
if key := addrmgr.GroupKey(&na); key != test.expected {
|
||||
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
|
||||
"- got '%s', want '%s'", i, test.name,
|
||||
|
|
|
@ -1,30 +1,9 @@
|
|||
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)
|
||||
[![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.
|
||||
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
|
||||
### Bitcoin Chain Processing Overview
|
||||
|
||||
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
|
||||
|
@ -57,47 +36,4 @@ is by no means exhaustive:
|
|||
transaction values
|
||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||
coins
|
||||
- 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.
|
||||
- Insert the block into the block database
|
|
@ -7,8 +7,8 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// maybeAcceptBlock potentially accepts a block into the block chain and, if
|
||||
|
@ -84,9 +84,11 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
|
|||
// Notify the caller that the new block was accepted into the block
|
||||
// chain. The caller would typically want to react by relaying the
|
||||
// inventory to other peers.
|
||||
b.notificationSendLock.Lock()
|
||||
defer b.notificationSendLock.Unlock()
|
||||
b.chainLock.Unlock()
|
||||
defer b.chainLock.Lock()
|
||||
b.sendNotification(NTBlockAccepted, block)
|
||||
b.chainLock.Lock()
|
||||
|
||||
return isMainChain, nil
|
||||
}
|
||||
|
|
|
@ -6,14 +6,12 @@ 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)
|
||||
tx, _ := GetBlock100000().Tx(1)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsCoinBase(tx)
|
||||
|
@ -23,9 +21,9 @@ func BenchmarkIsCoinBase(b *testing.B) {
|
|||
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
|
||||
// function.
|
||||
func BenchmarkIsCoinBaseTx(b *testing.B) {
|
||||
tx := Block100000.Transactions[1]
|
||||
tx, _ := GetBlock100000().Tx(1)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsCoinBaseTx(tx)
|
||||
IsCoinBaseTx(tx.MsgTx())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// blockStatus is a bit field representing the validation state of the block.
|
||||
|
@ -93,6 +93,7 @@ type blockNode struct {
|
|||
nonce uint32
|
||||
timestamp int64
|
||||
merkleRoot chainhash.Hash
|
||||
claimTrie chainhash.Hash
|
||||
|
||||
// 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
|
||||
|
@ -114,6 +115,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
|
|||
nonce: blockHeader.Nonce,
|
||||
timestamp: blockHeader.Timestamp.Unix(),
|
||||
merkleRoot: blockHeader.MerkleRoot,
|
||||
claimTrie: blockHeader.ClaimTrie,
|
||||
}
|
||||
if parent != nil {
|
||||
node.parent = parent
|
||||
|
@ -144,6 +146,7 @@ func (node *blockNode) Header() wire.BlockHeader {
|
|||
Version: node.version,
|
||||
PrevBlock: *prevHash,
|
||||
MerkleRoot: node.merkleRoot,
|
||||
ClaimTrie: node.claimTrie,
|
||||
Timestamp: time.Unix(node.timestamp, 0),
|
||||
Bits: node.bits,
|
||||
Nonce: node.nonce,
|
||||
|
|
|
@ -8,15 +8,18 @@ package blockchain
|
|||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
|
||||
"github.com/lbryio/lbcd/claimtrie"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -34,8 +37,9 @@ const (
|
|||
// from the block being located.
|
||||
//
|
||||
// For example, assume a block chain with a side chain as depicted below:
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
// \-> 16a -> 17a
|
||||
//
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
// \-> 16a -> 17a
|
||||
//
|
||||
// The block locator for block 17a would be the hashes of blocks:
|
||||
// [17a 16a 15 14 13 12 11 10 9 8 7 6 4 genesis]
|
||||
|
@ -114,6 +118,12 @@ type BlockChain struct {
|
|||
// fields in this struct below this point.
|
||||
chainLock sync.RWMutex
|
||||
|
||||
// notificationSendLock helps us only process one block at a time.
|
||||
// It's definitely a hack. DCRD has much better structure in this regard.
|
||||
// Without this you will get an error if you invalidate a block and then generate more right after.
|
||||
// Taken from https://github.com/gcash/bchd/pull/308
|
||||
notificationSendLock sync.Mutex
|
||||
|
||||
// These fields are related to the memory block index. They both have
|
||||
// their own locks, however they are often also protected by the chain
|
||||
// lock to help prevent logic races when blocks are being processed.
|
||||
|
@ -180,6 +190,8 @@ type BlockChain struct {
|
|||
// certain blockchain events.
|
||||
notificationsLock sync.RWMutex
|
||||
notifications []NotificationCallback
|
||||
|
||||
claimTrie *claimtrie.ClaimTrie
|
||||
}
|
||||
|
||||
// HaveBlock returns whether or not the chain instance has the block represented
|
||||
|
@ -195,6 +207,15 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
|
|||
return exists || b.IsKnownOrphan(hash), nil
|
||||
}
|
||||
|
||||
// GetWarnings returns a bool for whether unknownRules
|
||||
// has been warned.
|
||||
func (b *BlockChain) GetWarnings() bool {
|
||||
b.chainLock.RLock()
|
||||
defer b.chainLock.RUnlock()
|
||||
|
||||
return b.unknownRulesWarned
|
||||
}
|
||||
|
||||
// IsKnownOrphan returns whether the passed hash is currently a known orphan.
|
||||
// Keep in mind that only a limited number of orphans are held onto for a
|
||||
// limited amount of time, so this function must not be used as an absolute
|
||||
|
@ -468,7 +489,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView
|
|||
// LockTimeToSequence converts the passed relative locktime to a sequence
|
||||
// number in accordance to BIP-68.
|
||||
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
|
||||
// * (Compatibility)
|
||||
// - (Compatibility)
|
||||
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
|
||||
// If we're expressing the relative lock time in blocks, then the
|
||||
// corresponding sequence number is simply the desired input age.
|
||||
|
@ -571,7 +592,8 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
|||
}
|
||||
|
||||
// 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
|
||||
// have already been activated.
|
||||
if err := b.warnUnknownRuleActivations(node); err != nil {
|
||||
|
@ -579,6 +601,14 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
|||
}
|
||||
}
|
||||
|
||||
// Handle LBRY Claim Scripts
|
||||
if b.claimTrie != nil {
|
||||
shouldFlush := current && b.chainParams.Net != wire.TestNet
|
||||
if err := b.ParseClaimScripts(block, node, view, shouldFlush); err != nil {
|
||||
return ruleError(ErrBadClaimTrie, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Write any block status changes to DB before updating best state.
|
||||
err := b.index.flushToDB()
|
||||
if err != nil {
|
||||
|
@ -661,9 +691,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
|||
// Notify the caller that the block was connected to the main chain.
|
||||
// The caller would typically want to react with actions such as
|
||||
// updating wallets.
|
||||
b.notificationSendLock.Lock()
|
||||
defer b.notificationSendLock.Unlock()
|
||||
b.chainLock.Unlock()
|
||||
defer b.chainLock.Lock()
|
||||
b.sendNotification(NTBlockConnected, block)
|
||||
b.chainLock.Lock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -761,6 +793,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
|||
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
|
||||
// now that the modifications have been committed to the database.
|
||||
view.commit()
|
||||
|
@ -780,9 +818,11 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
|||
// Notify the caller that the block was disconnected from the main
|
||||
// chain. The caller would typically want to react with actions such as
|
||||
// updating wallets.
|
||||
b.notificationSendLock.Lock()
|
||||
defer b.notificationSendLock.Unlock()
|
||||
b.chainLock.Unlock()
|
||||
defer b.chainLock.Lock()
|
||||
b.sendNotification(NTBlockDisconnected, block)
|
||||
b.chainLock.Lock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -966,6 +1006,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
|
|||
err = b.checkConnectBlock(n, block, view, nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(RuleError); ok {
|
||||
b.index.UnsetStatusFlags(n, statusValid)
|
||||
b.index.SetStatusFlags(n, statusValidateFailed)
|
||||
for de := e.Next(); de != nil; de = de.Next() {
|
||||
dn := de.Value.(*blockNode)
|
||||
|
@ -1067,8 +1108,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
|
|||
// a reorganization to become the main chain).
|
||||
//
|
||||
// The flags modify the behavior of this function as follows:
|
||||
// - BFFastAdd: Avoids several expensive transaction validation operations.
|
||||
// This is useful when using checkpoints.
|
||||
// - BFFastAdd: Avoids several expensive transaction validation operations.
|
||||
// This is useful when using checkpoints.
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for writes).
|
||||
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) {
|
||||
|
@ -1103,6 +1144,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
|||
if err == nil {
|
||||
b.index.SetStatusFlags(node, statusValid)
|
||||
} else if _, ok := err.(RuleError); ok {
|
||||
b.index.UnsetStatusFlags(node, statusValid)
|
||||
b.index.SetStatusFlags(node, statusValidateFailed)
|
||||
} else {
|
||||
return false, err
|
||||
|
@ -1137,6 +1179,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
|||
// that status of the block as invalid and flush the
|
||||
// index state to disk before returning with the error.
|
||||
if _, ok := err.(RuleError); ok {
|
||||
b.index.UnsetStatusFlags(node, statusValid)
|
||||
b.index.SetStatusFlags(
|
||||
node, statusValidateFailed,
|
||||
)
|
||||
|
@ -1207,8 +1250,8 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
|||
// isCurrent returns whether or not the chain believes it is current. Several
|
||||
// factors are used to guess, but the key factors that allow the chain to
|
||||
// believe it is current are:
|
||||
// - Latest block height is after the latest checkpoint (if enabled)
|
||||
// - Latest block has a timestamp newer than 24 hours ago
|
||||
// - Latest block height is after the latest checkpoint (if enabled)
|
||||
// - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for reads).
|
||||
func (b *BlockChain) isCurrent() bool {
|
||||
|
@ -1219,20 +1262,20 @@ func (b *BlockChain) isCurrent() bool {
|
|||
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.
|
||||
//
|
||||
// The chain appears to be current if none of the checks reported
|
||||
// otherwise.
|
||||
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
|
||||
return b.bestChain.Tip().timestamp >= minus24Hours
|
||||
hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
|
||||
return b.bestChain.Tip().timestamp >= hours
|
||||
}
|
||||
|
||||
// IsCurrent returns whether or not the chain believes it is current. Several
|
||||
// factors are used to guess, but the key factors that allow the chain to
|
||||
// believe it is current are:
|
||||
// - Latest block height is after the latest checkpoint (if enabled)
|
||||
// - Latest block has a timestamp newer than 24 hours ago
|
||||
// - Latest block height is after the latest checkpoint (if enabled)
|
||||
// - Latest block has a timestamp newer than 24 hours ago
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) IsCurrent() bool {
|
||||
|
@ -1332,6 +1375,57 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro
|
|||
return &node.hash, nil
|
||||
}
|
||||
|
||||
// BlockAttributes desribes a Block in relation to others on the main chain.
|
||||
type BlockAttributes struct {
|
||||
Height int32
|
||||
Confirmations int32
|
||||
MedianTime time.Time
|
||||
ChainWork *big.Int
|
||||
PrevHash *chainhash.Hash
|
||||
NextHash *chainhash.Hash
|
||||
}
|
||||
|
||||
// BlockAttributesByHash returns BlockAttributes for the block with the given hash
|
||||
// relative to other blocks in the main chain. A BestState snapshot describing
|
||||
// the main chain is also returned for convenience.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) (
|
||||
attrs *BlockAttributes, best *BestState, err error) {
|
||||
best = b.BestSnapshot()
|
||||
node := b.index.LookupNode(hash)
|
||||
if node == nil {
|
||||
str := fmt.Sprintf("block %s not found", hash)
|
||||
return nil, best, errNotInMainChain(str)
|
||||
}
|
||||
|
||||
attrs = &BlockAttributes{
|
||||
Height: node.height,
|
||||
Confirmations: 1 + best.Height - node.height,
|
||||
MedianTime: node.CalcPastMedianTime(),
|
||||
ChainWork: node.workSum,
|
||||
}
|
||||
if !b.bestChain.Contains(node) {
|
||||
attrs.Confirmations = -1
|
||||
}
|
||||
|
||||
// Populate prev block hash if there is one.
|
||||
if node.height > 0 {
|
||||
attrs.PrevHash = prevHash
|
||||
}
|
||||
|
||||
// Populate next block hash if there is one.
|
||||
if node.height < best.Height {
|
||||
nextHash, err := b.BlockHashByHeight(node.height + 1)
|
||||
if err != nil {
|
||||
return nil, best, err
|
||||
}
|
||||
attrs.NextHash = nextHash
|
||||
}
|
||||
|
||||
return attrs, best, nil
|
||||
}
|
||||
|
||||
// HeightRange returns a range of block hashes for the given start and end
|
||||
// heights. It is inclusive of the start height and exclusive of the end
|
||||
// height. The end height will be limited to the current main chain height.
|
||||
|
@ -1467,11 +1561,11 @@ func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int,
|
|||
//
|
||||
// In addition, there are two special cases:
|
||||
//
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that block, so it will either return the node associated with the stop hash
|
||||
// if it is known, or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, nodes starting
|
||||
// after the genesis block will be returned
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that block, so it will either return the node associated with the stop hash
|
||||
// if it is known, or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, nodes starting
|
||||
// after the genesis block will be returned
|
||||
//
|
||||
// This is primarily a helper function for the locateBlocks and locateHeaders
|
||||
// functions.
|
||||
|
@ -1555,11 +1649,11 @@ func (b *BlockChain) locateBlocks(locator BlockLocator, hashStop *chainhash.Hash
|
|||
//
|
||||
// In addition, there are two special cases:
|
||||
//
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that block, so it will either return the stop hash itself if it is known,
|
||||
// or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, hashes starting
|
||||
// after the genesis block will be returned
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that block, so it will either return the stop hash itself if it is known,
|
||||
// or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, hashes starting
|
||||
// after the genesis block will be returned
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash {
|
||||
|
@ -1600,11 +1694,11 @@ func (b *BlockChain) locateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
|||
//
|
||||
// In addition, there are two special cases:
|
||||
//
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that header, so it will either return the header for the stop hash itself
|
||||
// if it is known, or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, headers starting
|
||||
// after the genesis block will be returned
|
||||
// - When no locators are provided, the stop hash is treated as a request for
|
||||
// that header, so it will either return the header for the stop hash itself
|
||||
// if it is known, or nil if it is unknown
|
||||
// - When locators are provided, but none of them are known, headers starting
|
||||
// after the genesis block will be returned
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader {
|
||||
|
@ -1614,6 +1708,121 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
|||
return headers
|
||||
}
|
||||
|
||||
// InvalidateBlock takes a block hash and invalidates it.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
|
||||
b.chainLock.Lock()
|
||||
defer b.chainLock.Unlock()
|
||||
return b.invalidateBlock(hash)
|
||||
}
|
||||
|
||||
// invalidateBlock takes a block hash and invalidates it.
|
||||
func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
|
||||
node := b.index.LookupNode(hash)
|
||||
if node == nil {
|
||||
err := fmt.Errorf("block %s is not known", hash)
|
||||
return err
|
||||
}
|
||||
|
||||
// No need to invalidate if its already invalid.
|
||||
if node.status.KnownInvalid() {
|
||||
err := fmt.Errorf("block %s is already invalid", hash)
|
||||
return err
|
||||
}
|
||||
|
||||
if node.parent == nil {
|
||||
err := fmt.Errorf("block %s has no parent", hash)
|
||||
return err
|
||||
}
|
||||
|
||||
b.index.SetStatusFlags(node, statusValidateFailed)
|
||||
b.index.UnsetStatusFlags(node, statusValid)
|
||||
|
||||
detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
|
||||
|
||||
err := b.reorganizeChain(detachNodes, attachNodes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
|
||||
n := e.Value.(*blockNode)
|
||||
|
||||
b.index.SetStatusFlags(n, statusInvalidAncestor)
|
||||
b.index.UnsetStatusFlags(n, statusValid)
|
||||
}
|
||||
|
||||
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReconsiderBlock takes a block hash and allows it to be revalidated.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (b *BlockChain) ReconsiderBlock(hash *chainhash.Hash) error {
|
||||
return b.reconsiderBlock(hash)
|
||||
}
|
||||
|
||||
// reconsiderBlock takes a block hash and allows it to be revalidated.
|
||||
func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
|
||||
node := b.index.LookupNode(hash)
|
||||
if node == nil {
|
||||
err := fmt.Errorf("block %s is not known", hash)
|
||||
return err
|
||||
}
|
||||
|
||||
// No need to reconsider, it is already valid.
|
||||
if node.status.KnownValid() && !node.status.KnownInvalid() { // second clause works around old bug
|
||||
err := fmt.Errorf("block %s is already valid", hash)
|
||||
return err
|
||||
}
|
||||
|
||||
// Keep a reference to the first node in the chain of invalid
|
||||
// blocks so we can reprocess after status flags are updated.
|
||||
firstNode := node
|
||||
|
||||
// Find previous node to the point where the blocks are valid again.
|
||||
for n := node; n.status.KnownInvalid(); n = n.parent {
|
||||
b.index.UnsetStatusFlags(n, statusInvalidAncestor)
|
||||
b.index.UnsetStatusFlags(n, statusValidateFailed)
|
||||
|
||||
firstNode = n
|
||||
}
|
||||
|
||||
// do we need an rlock on chainstate for this section?
|
||||
var blk *btcutil.Block
|
||||
err := b.db.View(func(dbTx database.Tx) error {
|
||||
var err error
|
||||
blk, err = dbFetchBlockByNode(dbTx, firstNode)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process it all again. This will take care of the
|
||||
// orphans as well.
|
||||
_, _, err = b.ProcessBlock(blk, BFNoDupBlockCheck)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClaimTrie returns the claimTrie associated wit hthe chain.
|
||||
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
||||
return b.claimTrie
|
||||
}
|
||||
|
||||
// IndexManager provides a generic interface that the is called when blocks are
|
||||
// connected and disconnected to and from the tip of the main chain for the
|
||||
// purpose of supporting optional indexes.
|
||||
|
@ -1700,6 +1909,8 @@ type Config struct {
|
|||
// This field can be nil if the caller is not interested in using a
|
||||
// signature cache.
|
||||
HashCache *txscript.HashCache
|
||||
|
||||
ClaimTrie *claimtrie.ClaimTrie
|
||||
}
|
||||
|
||||
// New returns a BlockChain instance using the provided configuration details.
|
||||
|
@ -1736,7 +1947,6 @@ func New(config *Config) (*BlockChain, error) {
|
|||
params := config.ChainParams
|
||||
targetTimespan := int64(params.TargetTimespan / time.Second)
|
||||
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
|
||||
adjustmentFactor := params.RetargetAdjustmentFactor
|
||||
b := BlockChain{
|
||||
checkpoints: config.Checkpoints,
|
||||
checkpointsByHeight: checkpointsByHeight,
|
||||
|
@ -1745,8 +1955,8 @@ func New(config *Config) (*BlockChain, error) {
|
|||
timeSource: config.TimeSource,
|
||||
sigCache: config.SigCache,
|
||||
indexManager: config.IndexManager,
|
||||
minRetargetTimespan: targetTimespan / adjustmentFactor,
|
||||
maxRetargetTimespan: targetTimespan * adjustmentFactor,
|
||||
minRetargetTimespan: targetTimespan - (targetTimespan / 8),
|
||||
maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
|
||||
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
||||
index: newBlockIndex(config.DB, params),
|
||||
hashCache: config.HashCache,
|
||||
|
@ -1755,6 +1965,7 @@ func New(config *Config) (*BlockChain, error) {
|
|||
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
||||
warningCaches: newThresholdCaches(vbNumBits),
|
||||
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
|
||||
claimTrie: config.ClaimTrie,
|
||||
}
|
||||
|
||||
// Initialize the chain state from the passed database. When the db
|
||||
|
@ -1764,6 +1975,20 @@ func New(config *Config) (*BlockChain, error) {
|
|||
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.
|
||||
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
|
||||
return nil, err
|
||||
|
@ -1783,6 +2008,14 @@ func New(config *Config) (*BlockChain, error) {
|
|||
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()
|
||||
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
|
||||
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
|
||||
|
@ -1790,3 +2023,63 @@ func New(config *Config) (*BlockChain, error) {
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -9,108 +9,12 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work
|
||||
|
|
123
blockchain/chainquery.go
Normal file
123
blockchain/chainquery.go
Normal file
|
@ -0,0 +1,123 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
type ChainTip struct { // duplicate of btcjson.GetChainTipsResult to avoid circular reference
|
||||
Height int64
|
||||
Hash string
|
||||
BranchLen int64
|
||||
Status string
|
||||
}
|
||||
|
||||
// nodeHeightSorter implements sort.Interface to allow a slice of nodes to
|
||||
// be sorted by height in ascending order.
|
||||
type nodeHeightSorter []ChainTip
|
||||
|
||||
// Len returns the number of nodes in the slice. It is part of the
|
||||
// sort.Interface implementation.
|
||||
func (s nodeHeightSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// Swap swaps the nodes at the passed indices. It is part of the
|
||||
// sort.Interface implementation.
|
||||
func (s nodeHeightSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Less returns whether the node with index i should sort before the node with
|
||||
// index j. It is part of the sort.Interface implementation.
|
||||
func (s nodeHeightSorter) Less(i, j int) bool {
|
||||
// To ensure stable order when the heights are the same, fall back to
|
||||
// sorting based on hash.
|
||||
if s[i].Height == s[j].Height {
|
||||
return strings.Compare(s[i].Hash, s[j].Hash) < 0
|
||||
}
|
||||
return s[i].Height < s[j].Height
|
||||
}
|
||||
|
||||
// ChainTips returns information, in JSON-RPC format, about all the currently
|
||||
// known chain tips in the block index.
|
||||
func (b *BlockChain) ChainTips() []ChainTip {
|
||||
// we need our current tip
|
||||
// we also need all of our orphans that aren't in the prevOrphans
|
||||
var results []ChainTip
|
||||
|
||||
tip := b.bestChain.Tip()
|
||||
results = append(results, ChainTip{
|
||||
Height: int64(tip.height),
|
||||
Hash: tip.hash.String(),
|
||||
BranchLen: 0,
|
||||
Status: "active",
|
||||
})
|
||||
|
||||
b.orphanLock.RLock()
|
||||
defer b.orphanLock.RUnlock()
|
||||
|
||||
notInBestChain := func(block *btcutil.Block) bool {
|
||||
node := b.bestChain.NodeByHeight(block.Height())
|
||||
if node == nil {
|
||||
return false
|
||||
}
|
||||
return node.hash.IsEqual(block.Hash())
|
||||
}
|
||||
|
||||
for hash, orphan := range b.orphans {
|
||||
if len(b.prevOrphans[hash]) > 0 {
|
||||
continue
|
||||
}
|
||||
fork := orphan.block
|
||||
for fork != nil && notInBestChain(fork) {
|
||||
fork = b.orphans[*fork.Hash()].block
|
||||
}
|
||||
|
||||
result := ChainTip{
|
||||
Height: int64(orphan.block.Height()),
|
||||
Hash: hash.String(),
|
||||
BranchLen: int64(orphan.block.Height() - fork.Height()),
|
||||
}
|
||||
|
||||
// Determine the status of the chain tip.
|
||||
//
|
||||
// active:
|
||||
// The current best chain tip.
|
||||
//
|
||||
// invalid:
|
||||
// The block or one of its ancestors is invalid.
|
||||
//
|
||||
// headers-only:
|
||||
// The block or one of its ancestors does not have the full block data
|
||||
// available which also means the block can't be validated or
|
||||
// connected.
|
||||
//
|
||||
// valid-fork:
|
||||
// The block is fully validated which implies it was probably part of
|
||||
// main chain at one point and was reorganized.
|
||||
//
|
||||
// valid-headers:
|
||||
// The full block data is available and the header is valid, but the
|
||||
// block was never validated which implies it was probably never part
|
||||
// of the main chain.
|
||||
tipStatus := b.index.LookupNode(&hash).status
|
||||
if tipStatus.KnownInvalid() {
|
||||
result.Status = "invalid"
|
||||
} else if !tipStatus.HaveData() {
|
||||
result.Status = "headers-only"
|
||||
} else if tipStatus.KnownValid() {
|
||||
result.Status = "valid-fork"
|
||||
} else {
|
||||
result.Status = "valid-headers"
|
||||
}
|
||||
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
// Generate the results sorted by descending height.
|
||||
sort.Sort(sort.Reverse(nodeHeightSorter(results)))
|
||||
return results
|
||||
}
|
|
@ -36,11 +36,13 @@ func fastLog2Floor(n uint32) uint8 {
|
|||
// for comparing chains.
|
||||
//
|
||||
// For example, assume a block chain with a side chain as depicted below:
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 4a -> 5a -> 6a
|
||||
//
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 4a -> 5a -> 6a
|
||||
//
|
||||
// The chain view for the branch ending in 6a consists of:
|
||||
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
|
||||
//
|
||||
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
|
||||
type chainView struct {
|
||||
mtx sync.Mutex
|
||||
nodes []*blockNode
|
||||
|
@ -258,12 +260,14 @@ func (c *chainView) next(node *blockNode) *blockNode {
|
|||
// view.
|
||||
//
|
||||
// For example, assume a block chain with a side chain as depicted below:
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 4a -> 5a -> 6a
|
||||
//
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 4a -> 5a -> 6a
|
||||
//
|
||||
// Further, assume the view is for the longer chain depicted above. That is to
|
||||
// say it consists of:
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
//
|
||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||
//
|
||||
// Invoking this function with block node 5 would return block node 6 while
|
||||
// invoking it with block node 5a would return nil since that node is not part
|
||||
|
@ -321,12 +325,14 @@ func (c *chainView) findFork(node *blockNode) *blockNode {
|
|||
// the chain view. It will return nil if there is no common block.
|
||||
//
|
||||
// For example, assume a block chain with a side chain as depicted below:
|
||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 6a -> 7a
|
||||
//
|
||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
|
||||
// \-> 6a -> 7a
|
||||
//
|
||||
// Further, assume the view is for the longer chain depicted above. That is to
|
||||
// say it consists of:
|
||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
|
||||
//
|
||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
|
||||
//
|
||||
// Invoking this function with block node 7a would return block node 5 while
|
||||
// invoking it with block node 7 would return itself since it is already part of
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// testNoncePrng provides a deterministic prng for the nonce in generated fake
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// CheckpointConfirmations is the number of blocks before the end of the current
|
||||
|
@ -172,7 +172,8 @@ func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
|
|||
func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
||||
// Check all of the output public key scripts for non-standard scripts.
|
||||
for _, txOut := range tx.MsgTx().TxOut {
|
||||
scriptClass := txscript.GetScriptClass(txOut.PkScript)
|
||||
stripped := txscript.StripClaimScriptPrefix(txOut.PkScript)
|
||||
scriptClass := txscript.GetScriptClass(stripped)
|
||||
if scriptClass == txscript.NonStandardTy {
|
||||
return true
|
||||
}
|
||||
|
@ -184,14 +185,14 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
|||
// checkpoint candidate.
|
||||
//
|
||||
// The factors used to determine a good checkpoint are:
|
||||
// - The block must be in the main chain
|
||||
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
|
||||
// current end of the main chain
|
||||
// - The timestamps for the blocks before and after the checkpoint must have
|
||||
// timestamps which are also before and after the checkpoint, respectively
|
||||
// (due to the median time allowance this is not always the case)
|
||||
// - The block must not contain any strange transaction such as those with
|
||||
// nonstandard scripts
|
||||
// - The block must be in the main chain
|
||||
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
|
||||
// current end of the main chain
|
||||
// - The timestamps for the blocks before and after the checkpoint must have
|
||||
// timestamps which are also before and after the checkpoint, respectively
|
||||
// (due to the median time allowance this is not always the case)
|
||||
// - The block must not contain any strange transaction such as those with
|
||||
// nonstandard scripts
|
||||
//
|
||||
// The intent is that candidates are reviewed by a developer to make the final
|
||||
// decision and then manually added to the list of checkpoints for a network.
|
||||
|
|
183
blockchain/claimtrie.go
Normal file
183
blockchain/claimtrie.go
Normal 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(bn == nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "in append block")
|
||||
}
|
||||
|
||||
if shouldFlush {
|
||||
b.claimTrie.FlushToDisk()
|
||||
}
|
||||
|
||||
hash := b.claimTrie.MerkleHash()
|
||||
if bn != nil && bn.claimTrie != *hash {
|
||||
// undo our AppendBlock call as we've decided that our interpretation of the block data is incorrect,
|
||||
// or that the person who made the block assembled the pieces incorrectly.
|
||||
_ = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
|
||||
return errors.Errorf("height: %d, computed hash: %s != header's ClaimTrie: %s", ht, *hash, bn.claimTrie)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
ht int32
|
||||
tx *btcutil.Tx
|
||||
view *UtxoViewpoint
|
||||
spent map[string][]byte
|
||||
}
|
||||
|
||||
func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error {
|
||||
if IsCoinBase(h.tx) {
|
||||
return nil
|
||||
}
|
||||
for _, txIn := range h.tx.MsgTx().TxIn {
|
||||
op := txIn.PreviousOutPoint
|
||||
e := h.view.LookupEntry(op)
|
||||
if e == nil {
|
||||
return errors.Errorf("missing input in view for %s", op.String())
|
||||
}
|
||||
cs, err := txscript.ExtractClaimScript(e.pkScript)
|
||||
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id change.ClaimID
|
||||
name := cs.Name // name of the previous one (that we're now spending)
|
||||
|
||||
switch cs.Opcode {
|
||||
case txscript.OP_CLAIMNAME: // OP code from previous transaction
|
||||
id = change.NewClaimID(op) // claimID of the previous item now being spent
|
||||
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
err = ct.SpendClaim(name, op, id)
|
||||
case txscript.OP_UPDATECLAIM:
|
||||
copy(id[:], cs.ClaimID)
|
||||
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
err = ct.SpendClaim(name, op, id)
|
||||
case txscript.OP_SUPPORTCLAIM:
|
||||
copy(id[:], cs.ClaimID)
|
||||
err = ct.SpendSupport(name, op, id)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "handleTxIns")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error {
|
||||
for i, txOut := range h.tx.MsgTx().TxOut {
|
||||
op := *wire.NewOutPoint(h.tx.Hash(), uint32(i))
|
||||
cs, err := txscript.ExtractClaimScript(txOut.PkScript)
|
||||
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id change.ClaimID
|
||||
name := cs.Name
|
||||
amt := txOut.Value
|
||||
|
||||
switch cs.Opcode {
|
||||
case txscript.OP_CLAIMNAME:
|
||||
id = change.NewClaimID(op)
|
||||
err = ct.AddClaim(name, op, id, amt)
|
||||
case txscript.OP_SUPPORTCLAIM:
|
||||
copy(id[:], cs.ClaimID)
|
||||
err = ct.AddSupport(name, op, amt, id)
|
||||
case txscript.OP_UPDATECLAIM:
|
||||
// old code wouldn't run the update if name or claimID didn't match existing data
|
||||
// that was a safety feature, but it should have rejected the transaction instead
|
||||
// TODO: reject transactions with invalid update commands
|
||||
copy(id[:], cs.ClaimID)
|
||||
normName := normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
if !bytes.Equal(h.spent[id.Key()], normName) {
|
||||
node.LogOnce(fmt.Sprintf("Invalid update operation: name or ID mismatch at %d for: %s, %s",
|
||||
ct.Height(), normName, id.String()))
|
||||
continue
|
||||
}
|
||||
|
||||
delete(h.spent, id.Key())
|
||||
err = ct.UpdateClaim(name, op, amt, id)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "handleTxOuts")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BlockChain) GetNamesChangedInBlock(height int32) ([]string, error) {
|
||||
b.chainLock.RLock()
|
||||
defer b.chainLock.RUnlock()
|
||||
|
||||
return b.claimTrie.NamesChangedInBlock(height)
|
||||
}
|
||||
|
||||
func (b *BlockChain) GetClaimsForName(height int32, name string) (string, *node.Node, error) {
|
||||
|
||||
normalizedName := normalization.NormalizeIfNecessary([]byte(name), height)
|
||||
|
||||
b.chainLock.RLock()
|
||||
defer b.chainLock.RUnlock()
|
||||
|
||||
n, err := b.claimTrie.NodeAt(height, normalizedName)
|
||||
if err != nil {
|
||||
return string(normalizedName), nil, err
|
||||
}
|
||||
|
||||
if n == nil {
|
||||
return string(normalizedName), nil, fmt.Errorf("name does not exist at height %d: %s", height, name)
|
||||
}
|
||||
|
||||
n.SortClaimsByBid()
|
||||
return string(normalizedName), n, nil
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
@ -14,13 +15,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -63,13 +64,13 @@ func isSupportedDbType(dbType string) bool {
|
|||
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
||||
filename = filepath.Join("testdata/", filename)
|
||||
|
||||
var network = wire.MainNet
|
||||
var network = 0xd9b4bef9 // bitcoin's network ID
|
||||
var dr io.Reader
|
||||
var fi io.ReadCloser
|
||||
|
||||
fi, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
|
||||
if strings.HasSuffix(filename, ".bz2") {
|
||||
|
@ -95,7 +96,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
|||
break
|
||||
}
|
||||
if rintbuf != uint32(network) {
|
||||
break
|
||||
continue
|
||||
}
|
||||
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
|
||||
blocklen := rintbuf
|
||||
|
@ -105,14 +106,20 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
|||
// read block
|
||||
dr.Read(rbytes)
|
||||
|
||||
// inject claimtrie:
|
||||
tail := make([]byte, len(rbytes)-68)
|
||||
copy(tail, rbytes[68:])
|
||||
rbytes = append(rbytes[:68], bytes.Repeat([]byte{23}, chainhash.HashSize)...)
|
||||
rbytes = append(rbytes, tail...)
|
||||
|
||||
block, err = btcutil.NewBlockFromBytes(rbytes)
|
||||
if err != nil {
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
|
||||
// chainSetup is used to create a new db and chain instance with the genesis
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -42,18 +42,21 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
|
|||
// Like IEEE754 floating point, there are three basic components: the sign,
|
||||
// the exponent, and the mantissa. They are broken out as follows:
|
||||
//
|
||||
// * the most significant 8 bits represent the unsigned base 256 exponent
|
||||
// * bit 23 (the 24th bit) represents the sign bit
|
||||
// * the least significant 23 bits represent the mantissa
|
||||
// - the most significant 8 bits represent the unsigned base 256 exponent
|
||||
//
|
||||
// -------------------------------------------------
|
||||
// | Exponent | Sign | Mantissa |
|
||||
// -------------------------------------------------
|
||||
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
||||
// -------------------------------------------------
|
||||
// - bit 23 (the 24th bit) represents the sign bit
|
||||
//
|
||||
// - the least significant 23 bits represent the mantissa
|
||||
//
|
||||
// -------------------------------------------------
|
||||
// | Exponent | Sign | Mantissa |
|
||||
// -------------------------------------------------
|
||||
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
||||
// -------------------------------------------------
|
||||
//
|
||||
// The formula to calculate N is:
|
||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
//
|
||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
//
|
||||
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers
|
||||
// which represent difficulty targets, thus there really is not a need for a
|
||||
|
@ -159,7 +162,6 @@ func CalcWork(bits uint32) *big.Int {
|
|||
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
|
||||
// Convert types used in the calculations below.
|
||||
durationVal := int64(duration / time.Second)
|
||||
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
|
||||
|
||||
// The test network rules allow minimum difficulty blocks after more
|
||||
// than twice the desired amount of time needed to generate a block has
|
||||
|
@ -178,7 +180,8 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
|
|||
// multiplied by the max adjustment factor.
|
||||
newTarget := CompactToBig(bits)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -224,47 +227,45 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
|||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// Return the previous block's difficulty requirements if this block
|
||||
// is not at a difficulty retarget interval.
|
||||
if (lastNode.height+1)%b.blocksPerRetarget != 0 {
|
||||
// For networks that support it, allow special reduction of the
|
||||
// required difficulty once too much time has elapsed without
|
||||
// mining a block.
|
||||
if b.chainParams.ReduceMinDifficulty {
|
||||
// Return minimum difficulty when more than the desired
|
||||
// amount of time has elapsed without mining a block.
|
||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||
time.Second)
|
||||
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 networks that support it, allow special reduction of the
|
||||
// required difficulty once too much time has elapsed without
|
||||
// mining a block.
|
||||
if b.chainParams.ReduceMinDifficulty {
|
||||
// Return minimum difficulty when more than the desired
|
||||
// amount of time has elapsed without mining a block.
|
||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||
time.Second)
|
||||
allowMinTime := lastNode.timestamp + reductionTime
|
||||
if newBlockTime.Unix() > allowMinTime {
|
||||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// For the main network (or any unrecognized networks), simply
|
||||
// return the previous block's difficulty requirements.
|
||||
return lastNode.bits, 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
|
||||
}
|
||||
|
||||
// Get the block node at the previous retarget (targetTimespan days
|
||||
// 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 {
|
||||
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
|
||||
// difficulty.
|
||||
actualTimespan := lastNode.timestamp - firstNode.timestamp
|
||||
adjustedTimespan := actualTimespan
|
||||
if actualTimespan < b.minRetargetTimespan {
|
||||
adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
|
||||
if adjustedTimespan < b.minRetargetTimespan {
|
||||
adjustedTimespan = b.minRetargetTimespan
|
||||
} else if actualTimespan > b.maxRetargetTimespan {
|
||||
} else if adjustedTimespan > b.maxRetargetTimespan {
|
||||
adjustedTimespan = b.maxRetargetTimespan
|
||||
}
|
||||
|
||||
|
@ -275,7 +276,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
|||
// result.
|
||||
oldTarget := CompactToBig(lastNode.bits)
|
||||
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
|
||||
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
|
||||
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
|
||||
|
||||
// Limit new value to the proof of work limit.
|
||||
|
|
|
@ -26,42 +26,42 @@ caller a high level of flexibility in how they want to react to certain events
|
|||
such as orphan blocks which need their parents requested and newly connected
|
||||
main chain blocks which might result in wallet updates.
|
||||
|
||||
Bitcoin Chain Processing Overview
|
||||
# Bitcoin Chain Processing Overview
|
||||
|
||||
Before a block is allowed into the block chain, it must go through an intensive
|
||||
series of validation rules. The following list serves as a general outline of
|
||||
those rules to provide some intuition into what is going on under the hood, but
|
||||
is by no means exhaustive:
|
||||
|
||||
- Reject duplicate blocks
|
||||
- Perform a series of sanity checks on the block and its transactions such as
|
||||
verifying proof of work, timestamps, number and character of transactions,
|
||||
transaction amounts, script complexity, and merkle root calculations
|
||||
- Compare the block against predetermined checkpoints for expected timestamps
|
||||
and difficulty based on elapsed time since the checkpoint
|
||||
- Save the most recent orphan blocks for a limited time in case their parent
|
||||
blocks become available
|
||||
- Stop processing if the block is an orphan as the rest of the processing
|
||||
depends on the block's position within the block chain
|
||||
- Perform a series of more thorough checks that depend on the block's position
|
||||
within the block chain such as verifying block difficulties adhere to
|
||||
difficulty retarget rules, timestamps are after the median of the last
|
||||
several blocks, all transactions are finalized, checkpoint blocks match, and
|
||||
block versions are in line with the previous blocks
|
||||
- Determine how the block fits into the chain and perform different actions
|
||||
accordingly in order to ensure any side chains which have higher difficulty
|
||||
than the main chain become the new main chain
|
||||
- When a block is being connected to the main chain (either through
|
||||
reorganization of a side chain to the main chain or just extending the
|
||||
main chain), perform further checks on the block's transactions such as
|
||||
verifying transaction duplicates, script complexity for the combination of
|
||||
connected scripts, coinbase maturity, double spends, and connected
|
||||
transaction values
|
||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||
coins
|
||||
- Insert the block into the block database
|
||||
- Reject duplicate blocks
|
||||
- Perform a series of sanity checks on the block and its transactions such as
|
||||
verifying proof of work, timestamps, number and character of transactions,
|
||||
transaction amounts, script complexity, and merkle root calculations
|
||||
- Compare the block against predetermined checkpoints for expected timestamps
|
||||
and difficulty based on elapsed time since the checkpoint
|
||||
- Save the most recent orphan blocks for a limited time in case their parent
|
||||
blocks become available
|
||||
- Stop processing if the block is an orphan as the rest of the processing
|
||||
depends on the block's position within the block chain
|
||||
- Perform a series of more thorough checks that depend on the block's position
|
||||
within the block chain such as verifying block difficulties adhere to
|
||||
difficulty retarget rules, timestamps are after the median of the last
|
||||
several blocks, all transactions are finalized, checkpoint blocks match, and
|
||||
block versions are in line with the previous blocks
|
||||
- Determine how the block fits into the chain and perform different actions
|
||||
accordingly in order to ensure any side chains which have higher difficulty
|
||||
than the main chain become the new main chain
|
||||
- When a block is being connected to the main chain (either through
|
||||
reorganization of a side chain to the main chain or just extending the
|
||||
main chain), perform further checks on the block's transactions such as
|
||||
verifying transaction duplicates, script complexity for the combination of
|
||||
connected scripts, coinbase maturity, double spends, and connected
|
||||
transaction values
|
||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||
coins
|
||||
- Insert the block into the block database
|
||||
|
||||
Errors
|
||||
# Errors
|
||||
|
||||
Errors returned by this package are either the raw errors provided by underlying
|
||||
calls or of type blockchain.RuleError. This allows the caller to differentiate
|
||||
|
@ -70,12 +70,12 @@ violations through type assertions. In addition, callers can programmatically
|
|||
determine the specific rule violation by examining the ErrorCode field of the
|
||||
type asserted blockchain.RuleError.
|
||||
|
||||
Bitcoin Improvement Proposals
|
||||
# Bitcoin Improvement Proposals
|
||||
|
||||
This package includes spec changes outlined by the following BIPs:
|
||||
|
||||
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
|
||||
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
|
||||
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
|
||||
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
|
||||
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
|
||||
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
|
||||
*/
|
||||
package blockchain
|
||||
|
|
|
@ -220,6 +220,10 @@ const (
|
|||
// current chain tip. This is not a block validation rule, but is required
|
||||
// for block proposals submitted via getblocktemplate RPC.
|
||||
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.
|
||||
|
@ -267,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
||||
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
||||
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
||||
ErrBadClaimTrie: "ErrBadClaimTrie",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
|
|
|
@ -10,11 +10,11 @@ import (
|
|||
"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"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// This example demonstrates how to create a new chain instance and use
|
||||
|
@ -69,7 +69,7 @@ func ExampleBlockChain_ProcessBlock() {
|
|||
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
|
||||
|
||||
// Output:
|
||||
// Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
||||
// Failed to process block: already have block 9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463
|
||||
}
|
||||
|
||||
// This example demonstrates how to convert the compact "bits" in a block header
|
||||
|
|
|
@ -12,15 +12,15 @@ import (
|
|||
"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"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/blockchain/fullblocktests"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -139,7 +139,7 @@ func TestFullBlocks(t *testing.T) {
|
|||
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("fullblocktest",
|
||||
&chaincfg.RegressionNetParams)
|
||||
fullblocktests.FbRegressionNetParams)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup chain instance: %v", err)
|
||||
return
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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)
|
||||
[![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
|
||||
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
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/blockchain/fullblocktests
|
||||
$ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -18,24 +18,24 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// Intentionally defined here rather than using constants from codebase
|
||||
// to ensure consensus changes are detected.
|
||||
maxBlockSigOps = 20000
|
||||
maxBlockSize = 1000000
|
||||
maxBlockSize = 8000000
|
||||
minCoinbaseScriptLen = 2
|
||||
maxCoinbaseScriptLen = 100
|
||||
medianTimeBlocks = 11
|
||||
maxScriptElementSize = 520
|
||||
maxScriptElementSize = 20000
|
||||
|
||||
// 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
|
||||
|
@ -342,10 +342,8 @@ func solveBlock(header *wire.BlockHeader) bool {
|
|||
return
|
||||
default:
|
||||
hdr.Nonce = i
|
||||
hash := hdr.BlockHash()
|
||||
if blockchain.HashToBig(&hash).Cmp(
|
||||
targetDifficulty) <= 0 {
|
||||
|
||||
hash := hdr.BlockPoWHash()
|
||||
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
|
||||
results <- sbResult{true, i}
|
||||
return
|
||||
}
|
||||
|
@ -466,9 +464,9 @@ func createSpendTxForTx(tx *wire.MsgTx, fee btcutil.Amount) *wire.MsgTx {
|
|||
// - A coinbase that pays the required subsidy to an OP_TRUE script
|
||||
// - When a spendable output is provided:
|
||||
// - A transaction that spends from the provided output the following outputs:
|
||||
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
|
||||
// - One that contains an OP_RETURN output with a random uint64 in order to
|
||||
// ensure the transaction has a unique hash
|
||||
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
|
||||
// - One that contains an OP_RETURN output with a random uint64 in order to
|
||||
// ensure the transaction has a unique hash
|
||||
//
|
||||
// Additionally, if one or more munge functions are specified, they will be
|
||||
// invoked with the block prior to solving it. This provides callers with the
|
||||
|
@ -811,7 +809,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
|||
|
||||
// Create a test generator instance initialized with the genesis block
|
||||
// as the tip.
|
||||
g, err := makeTestGenerator(regressionNetParams)
|
||||
g, err := makeTestGenerator(FbRegressionNetParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1444,7 +1442,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
|||
// Keep incrementing the nonce until the hash treated as
|
||||
// a uint256 is higher than the limit.
|
||||
b46.Header.Nonce++
|
||||
blockHash := b46.BlockHash()
|
||||
blockHash := b46.Header.BlockPoWHash()
|
||||
hashNum := blockchain.HashToBig(&blockHash)
|
||||
if hashNum.Cmp(g.params.PowLimit) >= 0 {
|
||||
break
|
||||
|
@ -1875,7 +1873,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
|||
//
|
||||
// Comment assumptions:
|
||||
// maxBlockSigOps = 20000
|
||||
// maxScriptElementSize = 520
|
||||
// maxScriptElementSize = 20000
|
||||
//
|
||||
// [0-19999] : OP_CHECKSIG
|
||||
// [20000] : OP_PUSHDATA4
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// newHashFromStr converts the passed big-endian hex string into a
|
||||
|
@ -54,6 +54,7 @@ var (
|
|||
Version: 1,
|
||||
PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"),
|
||||
ClaimTrie: chainhash.Hash{1}, // EmptyTrieHash
|
||||
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
|
||||
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 2,
|
||||
|
@ -83,23 +84,25 @@ var (
|
|||
LockTime: 0,
|
||||
}},
|
||||
}
|
||||
|
||||
regTestGenesisBlockHash = regTestGenesisBlock.BlockHash()
|
||||
)
|
||||
|
||||
// regressionNetParams defines the network parameters for the regression test
|
||||
// FbRegressionNetParams defines the network parameters for the regression test
|
||||
// network.
|
||||
//
|
||||
// NOTE: The test generator intentionally does not use the existing definitions
|
||||
// in the chaincfg package since the intent is to be able to generate known
|
||||
// good tests which exercise that code. Using the chaincfg parameters would
|
||||
// allow them to change out from under the tests potentially invalidating them.
|
||||
var regressionNetParams = &chaincfg.Params{
|
||||
var FbRegressionNetParams = &chaincfg.Params{
|
||||
Name: "regtest",
|
||||
Net: wire.TestNet,
|
||||
DefaultPort: "18444",
|
||||
|
||||
// Chain parameters
|
||||
GenesisBlock: ®TestGenesisBlock,
|
||||
GenesisHash: newHashFromStr("5bec7567af40504e0994db3b573c186fffcc4edefe096ff2e58d00523bd7e8a6"),
|
||||
GenesisHash: ®TestGenesisBlockHash,
|
||||
PowLimit: regressionPowLimit,
|
||||
PowLimitBits: 0x207fffff,
|
||||
CoinbaseMaturity: 100,
|
||||
|
@ -113,6 +116,7 @@ var regressionNetParams = &chaincfg.Params{
|
|||
ReduceMinDifficulty: true,
|
||||
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
|
||||
GenerateSupported: true,
|
||||
MinerConfirmationWindow: 1,
|
||||
|
||||
// Checkpoints ordered from oldest to newest.
|
||||
Checkpoints: nil,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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)
|
||||
[![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.
|
||||
|
||||
|
@ -23,7 +23,7 @@ via an RPC interface.
|
|||
## Installation
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/blockchain/indexers
|
||||
$ go get -u github.com/lbryio/lbcd/blockchain/indexers
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// addrIndexBucket provides a mock address index database bucket by implementing
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/btcsuite/btclog"
|
||||
"github.com/btcsuite/btcutil"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// blockProgressLogger provides periodic logging for other services in order
|
||||
|
@ -27,8 +27,9 @@ type blockProgressLogger struct {
|
|||
|
||||
// newBlockProgressLogger returns a new block progress logger.
|
||||
// The progress message is templated as follows:
|
||||
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
|
||||
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
|
||||
//
|
||||
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
|
||||
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
|
||||
func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {
|
||||
return &blockProgressLogger{
|
||||
lastBlockLogTime: time.Now(),
|
||||
|
|
|
@ -7,14 +7,14 @@ package indexers
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/gcs"
|
||||
"github.com/btcsuite/btcutil/gcs/builder"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
"github.com/lbryio/lbcutil/gcs"
|
||||
"github.com/lbryio/lbcutil/gcs/builder"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,11 +8,11 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,11 +8,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -183,7 +183,7 @@ func (m *medianTime) AddTimeSample(sourceID string, timeVal time.Time) {
|
|||
// Warn if none of the time samples are close.
|
||||
if !remoteHasCloseTime {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -86,7 +87,7 @@ func HashMerkleBranches(left *chainhash.Hash, right *chainhash.Hash) *chainhash.
|
|||
//
|
||||
// The above stored as a linear array is as follows:
|
||||
//
|
||||
// [h1 h2 h3 h4 h12 h34 root]
|
||||
// [h1 h2 h3 h4 h12 h34 root]
|
||||
//
|
||||
// As the above shows, the merkle root is always the last element in the array.
|
||||
//
|
||||
|
@ -227,11 +228,25 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error {
|
|||
// coinbase transaction MUST have exactly one witness element within
|
||||
// its witness data and that element must be exactly
|
||||
// CoinbaseWitnessDataLen bytes.
|
||||
//
|
||||
// Some popular pool software, for example yiimp, uses pre-BIP0141
|
||||
// coinbase struture. In this case, we don't just accept it, but also
|
||||
// turn it into post-BIP0141 format.
|
||||
if len(coinbaseTx.MsgTx().TxIn[0].Witness) == 0 {
|
||||
log.Infof("pre-BIP0141 coinbase transaction detected. Height: %d", blk.Height())
|
||||
|
||||
var witnessNonce [CoinbaseWitnessDataLen]byte
|
||||
coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
|
||||
blk.MsgBlock().Transactions[0].TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
|
||||
|
||||
// Clear cached serialized block.
|
||||
blk.SetBytes(nil)
|
||||
}
|
||||
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
|
||||
if len(coinbaseWitness) != 1 {
|
||||
str := fmt.Sprintf("the coinbase transaction has %d items in "+
|
||||
"its witness stack when only one is allowed",
|
||||
len(coinbaseWitness))
|
||||
"its witness stack when only one is allowed. Height: %d",
|
||||
len(coinbaseWitness), blk.Height())
|
||||
return ruleError(ErrInvalidWitnessCommitment, str)
|
||||
}
|
||||
witnessNonce := coinbaseWitness[0]
|
||||
|
|
|
@ -6,16 +6,14 @@ package blockchain
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// TestMerkle tests the BuildMerkleTreeStore API.
|
||||
func TestMerkle(t *testing.T) {
|
||||
block := btcutil.NewBlock(&Block100000)
|
||||
block := GetBlock100000()
|
||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||
wantMerkle := &Block100000.Header.MerkleRoot
|
||||
wantMerkle := block.MsgBlock().Header.MerkleRoot
|
||||
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
||||
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
|
||||
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
|
||||
|
|
|
@ -50,9 +50,9 @@ func (n NotificationType) String() string {
|
|||
// Notification defines notification that is sent to the caller via the callback
|
||||
// function provided during the call to New and consists of a notification type
|
||||
// as well as associated data that depends on the type as follows:
|
||||
// - NTBlockAccepted: *btcutil.Block
|
||||
// - NTBlockConnected: *btcutil.Block
|
||||
// - NTBlockDisconnected: *btcutil.Block
|
||||
// - NTBlockAccepted: *btcutil.Block
|
||||
// - NTBlockConnected: *btcutil.Block
|
||||
// - NTBlockDisconnected: *btcutil.Block
|
||||
type Notification struct {
|
||||
Type NotificationType
|
||||
Data interface{}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
|
||||
|
@ -29,6 +29,10 @@ const (
|
|||
// not be performed.
|
||||
BFNoPoWCheck
|
||||
|
||||
// BFNoDupBlockCheck signals if the block should skip existence
|
||||
// checks.
|
||||
BFNoDupBlockCheck
|
||||
|
||||
// BFNone is a convenience value to specifically indicate no flags.
|
||||
BFNone BehaviorFlags = 0
|
||||
)
|
||||
|
@ -148,24 +152,26 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
|
|||
blockHash := block.Hash()
|
||||
log.Tracef("Processing block %v", blockHash)
|
||||
|
||||
// The block must not already exist in the main chain or side chains.
|
||||
exists, err := b.blockExists(blockHash)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if exists {
|
||||
str := fmt.Sprintf("already have block %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
|
||||
// The block must not already exist in the main chain or side chains.
|
||||
exists, err := b.blockExists(blockHash)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if exists {
|
||||
str := fmt.Sprintf("already have block %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
|
||||
// The block must not already exist as an orphan.
|
||||
if _, exists := b.orphans[*blockHash]; exists {
|
||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
// The block must not already exist as an orphan.
|
||||
if _, exists := b.orphans[*blockHash]; exists {
|
||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
}
|
||||
|
||||
// Perform preliminary sanity checks on the block and its transactions.
|
||||
err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
||||
err := checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// txValidateItem holds a transaction along with which input to validate.
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
)
|
||||
|
||||
// TestCheckBlockScripts ensures that validating the all of the scripts in a
|
||||
|
|
BIN
blockchain/testdata/blk_0_to_4.dat.bz2
vendored
BIN
blockchain/testdata/blk_0_to_4.dat.bz2
vendored
Binary file not shown.
BIN
blockchain/testdata/blk_3A.dat.bz2
vendored
BIN
blockchain/testdata/blk_3A.dat.bz2
vendored
Binary file not shown.
BIN
blockchain/testdata/blk_4A.dat.bz2
vendored
BIN
blockchain/testdata/blk_4A.dat.bz2
vendored
Binary file not shown.
BIN
blockchain/testdata/blk_5A.dat.bz2
vendored
BIN
blockchain/testdata/blk_5A.dat.bz2
vendored
Binary file not shown.
180
blockchain/testdata/reorgtest.hex
vendored
180
blockchain/testdata/reorgtest.hex
vendored
|
@ -1,180 +0,0 @@
|
|||
File path: reorgTest/blk_0_to_4.dat
|
||||
|
||||
Block 0:
|
||||
f9beb4d9
|
||||
1d010000
|
||||
|
||||
01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 3ba3edfd 7a7b12b2 7ac72c3e 67768f61 7fc81bc3 888a5132 3a9fb8aa
|
||||
4b1e5e4a 29ab5f49 ffff001d 1dac2b7c
|
||||
01
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff4d04ff ff001d01 04455468 65205469 6d657320 30332f4a
|
||||
616e2f32 30303920 4368616e 63656c6c 6f72206f 6e206272 696e6b20 6f662073
|
||||
65636f6e 64206261 696c6f75 7420666f 72206261 6e6b73ff ffffff01 00f2052a
|
||||
01000000 43410467 8afdb0fe 55482719 67f1a671 30b7105c d6a828e0 3909a679
|
||||
62e0ea1f 61deb649 f6bc3f4c ef38c4f3 5504e51e c112de5c 384df7ba 0b8d578a
|
||||
4c702b6b f11d5fac 00000000
|
||||
Block 1:
|
||||
f9beb4d9
|
||||
d4000000
|
||||
|
||||
01000000 6fe28c0a b6f1b372 c1a6a246 ae63f74f 931e8365 e15a089c 68d61900
|
||||
00000000 3bbd67ad e98fbbb7 0718cd80 f9e9acf9 3b5fae91 7bb2b41d 4c3bb82c
|
||||
77725ca5 81ad5f49 ffff001d 44e69904
|
||||
01
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff04722f 2e2bffff ffff0100 f2052a01 00000043 41046868
|
||||
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
|
||||
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
|
||||
000000
|
||||
Block 2:
|
||||
f9beb4d9
|
||||
95010000
|
||||
|
||||
01000000 13ca7940 4c11c63e ca906bbd f190b751 2872b857 1b5143ae e8cb5737
|
||||
00000000 fc07c983 d7391736 0aeda657 29d0d4d3 2533eb84 76ee9d64 aa27538f
|
||||
9b4fc00a d9af5f49 ffff001d 630bea22
|
||||
02
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff04eb96 14e5ffff ffff0100 f2052a01 00000043 41046868
|
||||
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
|
||||
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
|
||||
000000
|
||||
|
||||
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
|
||||
4fdcb8ee d2000000 004a4930 46022100 3dde52c6 5e339f45 7fe1015e 70eed208
|
||||
872eb71e dd484c07 206b190e cb2ec3f8 02210011 c78dcfd0 3d43fa63 61242a33
|
||||
6291ba2a 8c1ef5bc d5472126 2468f2bf 8dee4d01 ffffffff 0200ca9a 3b000000
|
||||
001976a9 14cb2abd e8bccacc 32e893df 3a054b9e f7f227a4 ce88ac00 286bee00
|
||||
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
|
||||
00
|
||||
Block 3:
|
||||
f9beb4d9
|
||||
96020000
|
||||
|
||||
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
|
||||
00000000 4806fe80 bf85931b 882ea645 77ca5a03 22bb8af2 3f277b20 55f160cd
|
||||
972c8e8b 31b25f49 ffff001d e8f0c653
|
||||
03
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff044abd 8159ffff ffff0100 f2052a01 00000043 4104b95c
|
||||
249d84f4 17e3e395 a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c
|
||||
a5e56c90 f340988d 3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ac00
|
||||
000000
|
||||
|
||||
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
|
||||
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
|
||||
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
|
||||
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
|
||||
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
|
||||
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
|
||||
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
|
||||
00
|
||||
|
||||
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
|
||||
bad253d3 77000000 008c4930 46022100 b08b922a c4bde411 1c229f92 9fe6eb6a
|
||||
50161f98 1f4cf47e a9214d35 bf74d380 022100d2 f6640327 e677a1e1 cc474991
|
||||
b9a48ba5 bd1e0c94 d1c8df49 f7b0193b 7ea4fa01 4104b95c 249d84f4 17e3e395
|
||||
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
|
||||
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
|
||||
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
|
||||
00
|
||||
|
||||
Block 4:
|
||||
f9beb4d9
|
||||
73010000
|
||||
|
||||
01000000 5da36499 06f35e09 9be42a1d 87b6dd42 11bc1400 6c220694 0807eaae
|
||||
00000000 48eeeaed 2d9d8522 e6201173 743823fd 4b87cd8a ca8e6408 ec75ca38
|
||||
302c2ff0 89b45f49 ffff001d 00530839
|
||||
02
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff04d41d 2213ffff ffff0100 f2052a01 00000043 4104678a
|
||||
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
|
||||
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
|
||||
000000
|
||||
|
||||
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
|
||||
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
|
||||
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
|
||||
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
|
||||
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000
|
||||
|
||||
File path: reorgTest/blk_3A.dat
|
||||
Block 3A:
|
||||
f9beb4d9
|
||||
96020000
|
||||
|
||||
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
|
||||
00000000 5a15f573 1177a353 bdca7aab 20e16624 dfe90adc 70accadc 68016732
|
||||
302c20a7 31b25f49 ffff001d 6a901440
|
||||
03
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff04ad1b e7d5ffff ffff0100 f2052a01 00000043 4104ed83
|
||||
704c95d8 29046f1a c2780621 1132102c 34e9ac7f fa1b7111 0658e5b9 d1bdedc4
|
||||
16f5cefc 1db0625c d0c75de8 192d2b59 2d7e3b00 bcfb4a0e 860d880f d1fcac00
|
||||
000000
|
||||
|
||||
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
|
||||
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
|
||||
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
|
||||
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
|
||||
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
|
||||
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
|
||||
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
|
||||
00
|
||||
|
||||
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
|
||||
bad253d3 77000000 008c4930 46022100 9cc67ddd aa6f592a 6b2babd4 d6ff954f
|
||||
25a784cf 4fe4bb13 afb9f49b 08955119 022100a2 d99545b7 94080757 fcf2b563
|
||||
f2e91287 86332f46 0ec6b90f f085fb28 41a69701 4104b95c 249d84f4 17e3e395
|
||||
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
|
||||
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
|
||||
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
|
||||
00
|
||||
|
||||
File path: reorgTest/blk_4A.dat
|
||||
Block 4A:
|
||||
f9beb4d9
|
||||
d4000000
|
||||
|
||||
01000000 aae77468 2205667d 4f413a58 47cc8fe8 9795f1d5 645d5b24 1daf3c92
|
||||
00000000 361c9cde a09637a0 d0c05c3b 4e7a5d91 9edb184a 0a4c7633 d92e2ddd
|
||||
f04cb854 89b45f49 ffff001d 9e9aa1e8
|
||||
01
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff0401b8 f3eaffff ffff0100 f2052a01 00000043 4104678a
|
||||
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
|
||||
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
|
||||
000000
|
||||
|
||||
File path: reorgTest/blk_5A.dat
|
||||
Block 5A:
|
||||
f9beb4d9
|
||||
73010000
|
||||
|
||||
01000000 ebc7d0de 9c31a71b 7f41d275 2c080ba4 11e1854b d45cb2cf 8c1e4624
|
||||
00000000 a607774b 79b8eb50 b52a5a32 c1754281 ec67f626 9561df28 57d1fe6a
|
||||
ea82c696 e1b65f49 ffff001d 4a263577
|
||||
02
|
||||
|
||||
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00ffffff ff049971 0c7dffff ffff0100 f2052a01 00000043 4104678a
|
||||
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
|
||||
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
|
||||
000000
|
||||
|
||||
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
|
||||
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
|
||||
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
|
||||
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
|
||||
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000
|
||||
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// 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]
|
||||
|
||||
// added to mimic LBRYcrd:
|
||||
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
|
||||
return ThresholdActive, nil
|
||||
}
|
||||
|
||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||
cache := &b.deploymentCaches[deploymentID]
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// TestThresholdStateStringer tests the stringized output for the
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -232,24 +232,25 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
|
|||
//
|
||||
// The legacy format is as follows:
|
||||
//
|
||||
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
|
||||
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
|
||||
//
|
||||
// Field Type Size
|
||||
// version VLQ variable
|
||||
// block height VLQ variable
|
||||
// header code VLQ variable
|
||||
// unspentness bitmap []byte variable
|
||||
// compressed txouts
|
||||
// compressed amount VLQ variable
|
||||
// compressed script []byte variable
|
||||
// Field Type Size
|
||||
// version VLQ variable
|
||||
// block height VLQ variable
|
||||
// header code VLQ variable
|
||||
// unspentness bitmap []byte variable
|
||||
// compressed txouts
|
||||
// compressed amount VLQ variable
|
||||
// compressed script []byte variable
|
||||
//
|
||||
// The serialized header code format is:
|
||||
// bit 0 - containing transaction is a coinbase
|
||||
// bit 1 - output zero is unspent
|
||||
// bit 2 - output one is unspent
|
||||
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
|
||||
// are unset, it encodes N-1 since there must be at least one unspent
|
||||
// output.
|
||||
//
|
||||
// bit 0 - containing transaction is a coinbase
|
||||
// bit 1 - output zero is unspent
|
||||
// bit 2 - output one is unspent
|
||||
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
|
||||
// are unset, it encodes N-1 since there must be at least one unspent
|
||||
// output.
|
||||
//
|
||||
// The rationale for the header code scheme is as follows:
|
||||
// - Transactions which only pay to a single output and a change output are
|
||||
|
@ -269,65 +270,65 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
|
|||
// From tx in main blockchain:
|
||||
// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
|
||||
//
|
||||
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
|
||||
// <><><><------------------------------------------------------------------>
|
||||
// | | \--------\ |
|
||||
// | height | compressed txout 0
|
||||
// version header code
|
||||
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
|
||||
// <><><><------------------------------------------------------------------>
|
||||
// | | \--------\ |
|
||||
// | height | compressed txout 0
|
||||
// version header code
|
||||
//
|
||||
// - version: 1
|
||||
// - height: 1
|
||||
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
|
||||
// - unspentness: Nothing since it is zero bytes
|
||||
// - compressed txout 0:
|
||||
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
|
||||
// - 0x04: special script type pay-to-pubkey
|
||||
// - 0x96...52: x-coordinate of the pubkey
|
||||
// - version: 1
|
||||
// - height: 1
|
||||
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
|
||||
// - unspentness: Nothing since it is zero bytes
|
||||
// - compressed txout 0:
|
||||
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
|
||||
// - 0x04: special script type pay-to-pubkey
|
||||
// - 0x96...52: x-coordinate of the pubkey
|
||||
//
|
||||
// Example 2:
|
||||
// From tx in main blockchain:
|
||||
// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f
|
||||
//
|
||||
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
|
||||
// <><----><><><------------------------------------------><-------------------------------------------->
|
||||
// | | | \-------------------\ | |
|
||||
// version | \--------\ unspentness | compressed txout 2
|
||||
// height header code compressed txout 0
|
||||
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
|
||||
// <><----><><><------------------------------------------><-------------------------------------------->
|
||||
// | | | \-------------------\ | |
|
||||
// version | \--------\ unspentness | compressed txout 2
|
||||
// height header code compressed txout 0
|
||||
//
|
||||
// - version: 1
|
||||
// - height: 113931
|
||||
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
|
||||
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
|
||||
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||
// - compressed txout 0:
|
||||
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
|
||||
// - 0x00: special script type pay-to-pubkey-hash
|
||||
// - 0xe2...8a: pubkey hash
|
||||
// - compressed txout 2:
|
||||
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
|
||||
// - 0x00: special script type pay-to-pubkey-hash
|
||||
// - 0xb8...58: pubkey hash
|
||||
// - version: 1
|
||||
// - height: 113931
|
||||
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
|
||||
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
|
||||
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||
// - compressed txout 0:
|
||||
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
|
||||
// - 0x00: special script type pay-to-pubkey-hash
|
||||
// - 0xe2...8a: pubkey hash
|
||||
// - compressed txout 2:
|
||||
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
|
||||
// - 0x00: special script type pay-to-pubkey-hash
|
||||
// - 0xb8...58: pubkey hash
|
||||
//
|
||||
// Example 3:
|
||||
// From tx in main blockchain:
|
||||
// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620
|
||||
//
|
||||
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
|
||||
// <><----><><----><-------------------------------------------------->
|
||||
// | | | \-----------------\ |
|
||||
// version | \--------\ unspentness |
|
||||
// height header code compressed txout 22
|
||||
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
|
||||
// <><----><><----><-------------------------------------------------->
|
||||
// | | | \-----------------\ |
|
||||
// version | \--------\ unspentness |
|
||||
// height header code compressed txout 22
|
||||
//
|
||||
// - version: 1
|
||||
// - height: 338156
|
||||
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
|
||||
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
|
||||
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
|
||||
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||
// - compressed txout 22:
|
||||
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
|
||||
// - 0x01: special script type pay-to-script-hash
|
||||
// - 0x1d...e6: script hash
|
||||
// - version: 1
|
||||
// - height: 338156
|
||||
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
|
||||
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
|
||||
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
|
||||
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||
// - compressed txout 22:
|
||||
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
|
||||
// - 0x01: special script type pay-to-script-hash
|
||||
// - 0x1d...e6: script hash
|
||||
func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
|
||||
// Deserialize the version.
|
||||
//
|
||||
|
|
|
@ -7,11 +7,11 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// txoFlags is a bitmask defining additional information and state for a
|
||||
|
|
|
@ -11,11 +11,11 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -40,7 +40,7 @@ const (
|
|||
|
||||
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
||||
// value is halved every SubsidyHalvingInterval blocks.
|
||||
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
|
||||
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -192,17 +192,44 @@ func isBIP0030Node(node *blockNode) bool {
|
|||
// At the target block generation rate for the main network, this is
|
||||
// approximately every 4 years.
|
||||
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
|
||||
if chainParams.SubsidyReductionInterval == 0 {
|
||||
return baseSubsidy
|
||||
h := int64(height)
|
||||
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)
|
||||
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
|
||||
lv := (h - 55001) / int64(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
|
||||
// ensure it is sane. These checks are context free.
|
||||
func CheckTransactionSanity(tx *btcutil.Tx) error {
|
||||
// ensure it is sane.
|
||||
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
|
||||
// A transaction must have at least one input.
|
||||
msgTx := tx.MsgTx()
|
||||
if len(msgTx.TxIn) == 0 {
|
||||
|
@ -261,6 +288,11 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
|||
btcutil.MaxSatoshi)
|
||||
return ruleError(ErrBadTxOutValue, str)
|
||||
}
|
||||
|
||||
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
|
||||
if err != nil {
|
||||
return ruleError(ErrBadTxOutValue, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate transaction inputs.
|
||||
|
@ -302,8 +334,8 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
|||
// target difficulty as claimed.
|
||||
//
|
||||
// The flags modify the behavior of this function as follows:
|
||||
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
||||
// difficulty is not performed.
|
||||
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
||||
// difficulty is not performed.
|
||||
func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error {
|
||||
// The target difficulty must be larger than zero.
|
||||
target := CompactToBig(header.Bits)
|
||||
|
@ -324,7 +356,7 @@ func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags Behavio
|
|||
// to avoid proof of work checks is set.
|
||||
if flags&BFNoPoWCheck != BFNoPoWCheck {
|
||||
// The block hash must be less than the claimed target.
|
||||
hash := header.BlockHash()
|
||||
hash := header.BlockPoWHash()
|
||||
hashNum := HashToBig(&hash)
|
||||
if hashNum.Cmp(target) > 0 {
|
||||
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
|
||||
// sane before continuing.
|
||||
for _, tx := range transactions {
|
||||
err := CheckTransactionSanity(tx)
|
||||
err := CheckTransactionSanity(tx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -637,8 +669,8 @@ func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error {
|
|||
// which depend on its position within the block chain.
|
||||
//
|
||||
// The flags modify the behavior of this function as follows:
|
||||
// - BFFastAdd: All checks except those involving comparing the header against
|
||||
// the checkpoints are not performed.
|
||||
// - BFFastAdd: All checks except those involving comparing the header against
|
||||
// the checkpoints are not performed.
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for writes).
|
||||
func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode *blockNode, flags BehaviorFlags) error {
|
||||
|
@ -716,8 +748,8 @@ func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode
|
|||
// on its position within the block chain.
|
||||
//
|
||||
// The flags modify the behavior of this function as follows:
|
||||
// - BFFastAdd: The transaction are not checked to see if they are finalized
|
||||
// and the somewhat expensive BIP0034 validation is not performed.
|
||||
// - BFFastAdd: The transaction are not checked to see if they are finalized
|
||||
// and the somewhat expensive BIP0034 validation is not performed.
|
||||
//
|
||||
// The flags are also passed to checkBlockHeaderContext. See its documentation
|
||||
// for how the flags modify its behavior.
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
|
||||
|
@ -63,96 +64,11 @@ func TestSequenceLocksActive(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to
|
||||
// ensure it fails.
|
||||
func TestCheckConnectBlockTemplate(t *testing.T) {
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("checkconnectblocktemplate",
|
||||
&chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup chain instance: %v", err)
|
||||
return
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
// Since we're not dealing with the real block chain, set the coinbase
|
||||
// maturity to 1.
|
||||
chain.TstSetCoinbaseMaturity(1)
|
||||
|
||||
// Load up blocks such that there is a side chain.
|
||||
// (genesis block) -> 1 -> 2 -> 3 -> 4
|
||||
// \-> 3a
|
||||
testFiles := []string{
|
||||
"blk_0_to_4.dat.bz2",
|
||||
"blk_3A.dat.bz2",
|
||||
}
|
||||
|
||||
var blocks []*btcutil.Block
|
||||
for _, file := range testFiles {
|
||||
blockTmp, err := loadBlocks(file)
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading file: %v\n", err)
|
||||
}
|
||||
blocks = append(blocks, blockTmp...)
|
||||
}
|
||||
|
||||
for i := 1; i <= 3; i++ {
|
||||
isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
|
||||
"processing block %d: %v", i, err)
|
||||
}
|
||||
if !isMainChain {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
|
||||
"to main chain", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Block 3 should fail to connect since it's already inserted.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[3])
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 3")
|
||||
}
|
||||
|
||||
// Block 4 should connect successfully to tip of chain.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[4])
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
|
||||
"block 4: %v", err)
|
||||
}
|
||||
|
||||
// Block 3a should fail to connect since does not build on chain tip.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[5])
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 3a")
|
||||
}
|
||||
|
||||
// Block 4 should connect even if proof of work is invalid.
|
||||
invalidPowBlock := *blocks[4].MsgBlock()
|
||||
invalidPowBlock.Header.Nonce++
|
||||
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidPowBlock))
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
|
||||
"block 4 with bad nonce: %v", err)
|
||||
}
|
||||
|
||||
// Invalid block building on chain tip should fail to connect.
|
||||
invalidBlock := *blocks[4].MsgBlock()
|
||||
invalidBlock.Header.Bits--
|
||||
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidBlock))
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 4 with invalid difficulty bits")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
||||
// as expected.
|
||||
func TestCheckBlockSanity(t *testing.T) {
|
||||
powLimit := chaincfg.MainNetParams.PowLimit
|
||||
block := btcutil.NewBlock(&Block100000)
|
||||
block := GetBlock100000()
|
||||
timeSource := NewMedianTime()
|
||||
err := CheckBlockSanity(block, powLimit, timeSource)
|
||||
if err != nil {
|
||||
|
@ -234,254 +150,12 @@ func TestCheckSerializedHeight(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Block100000 defines block 100,000 of the block chain. It is used to
|
||||
var block100000Hex = "0000002024cbdc8644ee3983e66b003a0733891c069ca74c114c034c7b3e2e7ad7a12cd67e95e0555c0e056f6f2af538268ff9d21b420e529750d08eacb25c40f1322936637109b8a051157604c1c163cd39237687f6244b4e6d2b3a94e9d816babaecbb10c56058c811041b2b9c43000701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2003a086010410c56058081011314abf0100000d2f6e6f64655374726174756d2f000000000180354a6e0a0000001976a914b5e74e7cc9e1f480a6599895c92aab1401f870f188ac000000000100000002f1b75decc2c1c59c2178852822de412f574ad9796b65ac9092a79630d8109aaf000000006a47304402202f78ed3bf8dcadb6c17e289cd06e9c96b02c6f23aa1f446a4a7896a31cfd1e4702202862261e2eb59475ac91092c620b3cac5a831372bafc446d5ee450866040b532012103db4f3785354d84311fab7624c52784a61e3046d8f364463d327bdd96281b5b90feffffff987ee6b4bf95548d01e443683261dd0ffdcb2eb335b2f7119df0d41b60756b92010000006a47304402200c422c7560b6418d45443138bb957ec44eb293a639f4b2235a622205ca6cac370220759f15d5dc2543fd1aef80104c93427fcb025847bf895669025d1d82c62fbf6801210201864b998db5436990a0029fc3fb153c09e8c2689214b91c8ed68784995c8da0feffffff022bccfedd000000001976a914738f16132942a01d00cb9699bd058c4925aada3288ac1f4d030c000000001976a914c4292e757f5ff6a27c2f0a87d3a4aea5e46c275a88ac9f86010001000000015fbb26ad6d818186032baeef4d3f475dfe165c6da2d93411b8ec5f9f523cf1a4000000006a4730440220356999ad5a9f6f09b676f17dd4a2617a0af234722d68a50edc3768c983c0623d022056b4e5531608aeb0205fde9c44f741158da3bba1f4c3788c9fe79d36d43ea355012103509893a2a7c765d49ac9ff70126cb1af54871d70baba2c7e39ec9b4096289a9bfeffffff02389332fa080000001976a914f85e054405fbcedc2341cf8bf41ea989090587a288acf9321a41000000001976a914e85e90c048fdfbe1c2117a7132856ff4b39b470188ac9f86010001000000013508189b9bb61ac2aa536b905447b58f6c58c17cdef305240f566caa689d760a010000006a4730440220669a2b86e5abe58bae54829d3c271669540a9ad965c2fb79e8cc1fb609c0b60002202f958403d979138075cb53d8cb5ff6bb14e18d66dfdb6701c7d43a8ceeed0fa80121029935a602205a3fb72446064f3bc3a55ab9cd2e3459bf2ffdf80a48ab029d4b42feffffff02523c2f13000000001976a914c5b2ae398496f0f9ceaf81b83c28a27ddc890e3588ac211958f2000000001976a914ac65f1d16e5a2af37408b5d65406000a7ea143ca88ac9f8601000100000001bdd724322c555a21d5eb62d4aadbdc051663bcd4ec03f8d9005992f299783c21000000006a47304402205448141a2a788f73310025123bd24f5bee01dd8f48f18d7abc62d7c26465008902207ab46e6ddf6ba416decf3fbb97b6946a1428ea0a7c25a55cab47c47110d8e9ce0121029d6ff3b1235f2a08560b23dd4a08b14cc415b544801b885365736ea8ab1d3470feffffff029d104ccf000000001976a914999d5b0e3d5efcf601c711127b91841afbf5c37a88ace5c5a07f070000001976a9144aade372298eb387da9b6ac69d215a213e822f3f88ac9f86010001000000011658304d4ce796cd450228a10fdf647c6ea42295c9f5e1663df11481af1c884d010000006b483045022100a35d5d3ccde85b41559047d976ae6210b8e6ba5653c53aae1adc90048de0761002200d6bd6ebc6d73f97855f435c6fd595009ee71d23bb34870ab83ad53f67eeb22b012102d2f681ebfd1a570416d602986a47ca4254d8dedf2935b3f8c2ba55dcee8e98f4feffffff025ee913e6020000001976a91468076c9380d3c6b468ad1d6109c36770fb181e8f88acb165394f000000001976a9147ae970e81b3657cbb59df26517e372165807be0088ac9f86010001000000018f285109f78524a88ff328a4f94de2ac03224c50984b11c68adda192e8f78efa010000006b483045022100d77f2ac32dd6a3015f02f7115a13f617c57952fc5d53a33a87dc3fc00ffe1864022006455f74cff864b10424e445c530a59243f86d309dc92c5010ec5709e38471ab012102fdac7335b41edcd2846fc7e2166bb48312ee583ed6ff70fb5c27bcb2addaad86feffffff028b7a6d5c000000001976a914c65106d2e7ea4ec6aa8aa30ba4d11cfd1143123388ac5934c228000000001976a914d1c4d190b07edb972b91f33c36c6568b80358dd488ac9f860100"
|
||||
|
||||
// GetBlock100000 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,
|
||||
},
|
||||
},
|
||||
func GetBlock100000() *btcutil.Block {
|
||||
var block100000Bytes, _ = hex.DecodeString(block100000Hex)
|
||||
var results, _ = btcutil.NewBlockFromBytes(block100000Bytes)
|
||||
return results
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -195,6 +195,12 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
|
|||
expectedVersion := uint32(vbTopBits)
|
||||
for id := 0; id < len(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]
|
||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||
state, err := b.thresholdState(prevNode, checker, cache)
|
||||
|
|
|
@ -7,9 +7,9 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -20,11 +20,11 @@ const (
|
|||
// 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
|
||||
// less than, or equal to MaxBlockWeight.
|
||||
MaxBlockWeight = 4000000
|
||||
MaxBlockWeight = 8000000
|
||||
|
||||
// MaxBlockBaseSize is the maximum number of bytes within a block
|
||||
// which can be allocated to non-witness data.
|
||||
MaxBlockBaseSize = 1000000
|
||||
MaxBlockBaseSize = 8000000
|
||||
|
||||
// MaxBlockSigOpsCost is the maximum number of signature operations
|
||||
// allowed for a block. It is calculated via a weighted algorithm which
|
||||
|
|
|
@ -1,68 +1,11 @@
|
|||
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)
|
||||
[![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
|
||||
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
|
||||
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
|
||||
signficantly diverged since then. The btcsuite developers original is licensed
|
||||
under the liberal ISC license.
|
||||
|
||||
Although this package was primarily written for btcd, it has intentionally been
|
||||
designed so it can be used as a standalone package for any projects needing to
|
||||
use secp256k1 elliptic curve cryptography.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/btcec
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
|
||||
Demonstrates signing a message with a secp256k1 private key that is first
|
||||
parsed form raw bytes and serializing the generated signature.
|
||||
|
||||
* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
|
||||
Demonstrates verifying a secp256k1 signature against a public key that is
|
||||
first parsed from raw bytes. The signature is also parsed from raw bytes.
|
||||
|
||||
* [Encryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
|
||||
Demonstrates encrypting a message for a public key that is first parsed from
|
||||
raw bytes, then decrypting it using the corresponding private key.
|
||||
|
||||
* [Decryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
|
||||
Demonstrates decrypting a message using a private key that is first parsed
|
||||
from raw bytes.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
|
||||
except for btcec.go and btcec_test.go which is under the same license as Go.
|
||||
|
||||
signficantly diverged since then.
|
|
@ -527,7 +527,7 @@ type baseMultTest struct {
|
|||
x, y string
|
||||
}
|
||||
|
||||
//TODO: add more test vectors
|
||||
// TODO: add more test vectors
|
||||
var s256BaseMultTests = []baseMultTest{
|
||||
{
|
||||
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522",
|
||||
|
@ -556,7 +556,7 @@ var s256BaseMultTests = []baseMultTest{
|
|||
},
|
||||
}
|
||||
|
||||
//TODO: test different curves as well?
|
||||
// TODO: test different curves as well?
|
||||
func TestBaseMult(t *testing.T) {
|
||||
s256 := S256()
|
||||
for i, e := range s256BaseMultTests {
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// This example demonstrates signing a message with a secp256k1 private key that
|
||||
|
|
|
@ -125,27 +125,30 @@ var (
|
|||
// the arithmetic needed for elliptic curve operations.
|
||||
//
|
||||
// The following depicts the internal representation:
|
||||
// -----------------------------------------------------------------
|
||||
// | n[9] | n[8] | ... | n[0] |
|
||||
// | 32 bits available | 32 bits available | ... | 32 bits available |
|
||||
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
|
||||
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
|
||||
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
|
||||
// -----------------------------------------------------------------
|
||||
//
|
||||
// -----------------------------------------------------------------
|
||||
// | n[9] | n[8] | ... | n[0] |
|
||||
// | 32 bits available | 32 bits available | ... | 32 bits available |
|
||||
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
|
||||
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
|
||||
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
|
||||
// -----------------------------------------------------------------
|
||||
//
|
||||
// For example, consider the number 2^49 + 1. It would be represented as:
|
||||
// n[0] = 1
|
||||
// n[1] = 2^23
|
||||
// n[2..9] = 0
|
||||
//
|
||||
// n[0] = 1
|
||||
// n[1] = 2^23
|
||||
// n[2..9] = 0
|
||||
//
|
||||
// The full 256-bit value is then calculated by looping i from 9..0 and
|
||||
// doing sum(n[i] * 2^(26i)) like so:
|
||||
// n[9] * 2^(26*9) = 0 * 2^234 = 0
|
||||
// n[8] * 2^(26*8) = 0 * 2^208 = 0
|
||||
// ...
|
||||
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
|
||||
// n[0] * 2^(26*0) = 1 * 2^0 = 1
|
||||
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
|
||||
//
|
||||
// n[9] * 2^(26*9) = 0 * 2^234 = 0
|
||||
// n[8] * 2^(26*8) = 0 * 2^208 = 0
|
||||
// ...
|
||||
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
|
||||
// n[0] * 2^(26*0) = 1 * 2^0 = 1
|
||||
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
|
||||
type fieldVal struct {
|
||||
n [10]uint32
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// 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
|
||||
// tables used to accelerate operations.
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// This file is ignored during the regular build due to the following build tag.
|
||||
// This build tag is set during go generate.
|
||||
//go:build gensecp256k1
|
||||
// +build gensecp256k1
|
||||
|
||||
package btcec
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
//go:generate go run -tags gensecp256k1 genprecomps.go
|
||||
//go:rm -f gensecp256k1.go; generate go run -tags gensecp256k1 genprecomps.go
|
||||
|
||||
// loadS256BytePoints decompresses and deserializes the pre-computed byte points
|
||||
// used to accelerate scalar base multiplication for the secp256k1 curve. This
|
||||
|
|
|
@ -353,6 +353,10 @@ func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
|
|||
// step to prevent the jacobian conversion back and forth.
|
||||
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
|
||||
|
||||
if Qx.Sign() == 0 && Qy.Sign() == 0 {
|
||||
return nil, errors.New("point (Qx, Qy) equals the point at infinity")
|
||||
}
|
||||
|
||||
return &PublicKey{
|
||||
Curve: curve,
|
||||
X: Qx,
|
||||
|
|
|
@ -549,6 +549,12 @@ var recoveryTests = []struct {
|
|||
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
|
||||
err: fmt.Errorf("invalid square root"),
|
||||
},
|
||||
{
|
||||
// Point at infinity recovered
|
||||
msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
|
||||
sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
|
||||
err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"),
|
||||
},
|
||||
{
|
||||
// Low R and S values.
|
||||
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",
|
||||
|
|
|
@ -1,70 +1,8 @@
|
|||
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)
|
||||
[![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
|
||||
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
|
||||
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.
|
||||
proper functionality.
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcdExtCustomResults ensures any results that have custom marshalling
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
|
||||
|
@ -48,6 +48,15 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd {
|
|||
}
|
||||
}
|
||||
|
||||
// ClearBannedCmd defines the clearbanned JSON-RPC command.
|
||||
type ClearBannedCmd struct{}
|
||||
|
||||
// NewClearBannedCmd returns a new instance which can be used to issue an clearbanned
|
||||
// JSON-RPC command.
|
||||
func NewClearBannedCmd() *ClearBannedCmd {
|
||||
return &ClearBannedCmd{}
|
||||
}
|
||||
|
||||
// TransactionInput represents the inputs to a transaction. Specifically a
|
||||
// transaction hash and output number pair.
|
||||
type TransactionInput struct {
|
||||
|
@ -58,7 +67,7 @@ type TransactionInput struct {
|
|||
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
|
||||
type CreateRawTransactionCmd struct {
|
||||
Inputs []TransactionInput
|
||||
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
|
||||
Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"`
|
||||
LockTime *int64
|
||||
}
|
||||
|
||||
|
@ -67,7 +76,7 @@ type CreateRawTransactionCmd struct {
|
|||
//
|
||||
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
|
||||
// both gets interpreted as the empty slice.
|
||||
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
|
||||
func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{},
|
||||
lockTime *int64) *CreateRawTransactionCmd {
|
||||
// to make sure we're serializing this to the empty list and not null, we
|
||||
// explicitly initialize the list
|
||||
|
@ -76,7 +85,7 @@ func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]fl
|
|||
}
|
||||
return &CreateRawTransactionCmd{
|
||||
Inputs: inputs,
|
||||
Amounts: amounts,
|
||||
Outputs: outputs,
|
||||
LockTime: lockTime,
|
||||
}
|
||||
}
|
||||
|
@ -650,7 +659,7 @@ func NewGetRawMempoolCmd(verbose *bool) *GetRawMempoolCmd {
|
|||
// Core even though it really should be a bool.
|
||||
type GetRawTransactionCmd struct {
|
||||
Txid string
|
||||
Verbose *int `jsonrpcdefault:"0"`
|
||||
Verbose *bool `jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
// NewGetRawTransactionCmd returns a new instance which can be used to issue a
|
||||
|
@ -658,7 +667,7 @@ type GetRawTransactionCmd struct {
|
|||
//
|
||||
// The parameters which are pointers indicate they are optional. Passing nil
|
||||
// for optional parameters will use the default value.
|
||||
func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd {
|
||||
func NewGetRawTransactionCmd(txHash string, verbose *bool) *GetRawTransactionCmd {
|
||||
return &GetRawTransactionCmd{
|
||||
Txid: txHash,
|
||||
Verbose: verbose,
|
||||
|
@ -757,6 +766,15 @@ func NewInvalidateBlockCmd(blockHash string) *InvalidateBlockCmd {
|
|||
}
|
||||
}
|
||||
|
||||
// ListBannedCmd defines the listbanned JSON-RPC command.
|
||||
type ListBannedCmd struct{}
|
||||
|
||||
// NewListBannedCmd returns a new instance which can be used to issue a listbanned
|
||||
// JSON-RPC command.
|
||||
func NewListBannedCmd() *ListBannedCmd {
|
||||
return &ListBannedCmd{}
|
||||
}
|
||||
|
||||
// PingCmd defines the ping JSON-RPC command.
|
||||
type PingCmd struct{}
|
||||
|
||||
|
@ -903,6 +921,39 @@ func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTr
|
|||
}
|
||||
}
|
||||
|
||||
// SetBanSubCmd defines the type used in the setban JSON-RPC command for the
|
||||
// sub command field.
|
||||
type SetBanSubCmd string
|
||||
|
||||
const (
|
||||
// SBAdd indicates the specified host should be added as a persistent
|
||||
// peer.
|
||||
SBAdd SetBanSubCmd = "add"
|
||||
|
||||
// SBRemove indicates the specified peer should be removed.
|
||||
SBRemove SetBanSubCmd = "remove"
|
||||
)
|
||||
|
||||
// SetBanCmd defines the setban JSON-RPC command.
|
||||
type SetBanCmd struct {
|
||||
Addr string
|
||||
SubCmd SetBanSubCmd `jsonrpcusage:"\"add|remove\""`
|
||||
BanTime *int `jsonrpcdefault:"0"`
|
||||
Absolute *bool `jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
// NewSetBanCmd returns a new instance which can be used to issue an setban
|
||||
// JSON-RPC command.
|
||||
func NewSetBanCmd(addr string, subCmd SetBanSubCmd, banTime *int,
|
||||
absolute *bool) *SetBanCmd {
|
||||
return &SetBanCmd{
|
||||
Addr: addr,
|
||||
SubCmd: subCmd,
|
||||
BanTime: banTime,
|
||||
Absolute: absolute,
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerateCmd defines the setgenerate JSON-RPC command.
|
||||
type SetGenerateCmd struct {
|
||||
Generate bool
|
||||
|
@ -1080,6 +1131,9 @@ func init() {
|
|||
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
|
||||
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
|
||||
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
|
||||
MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags)
|
||||
MustRegisterCmd("setban", (*SetBanCmd)(nil), flags)
|
||||
MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags)
|
||||
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
|
||||
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
|
||||
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
|
||||
|
@ -52,13 +52,13 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
txInputs := []btcjson.TransactionInput{
|
||||
{Txid: "123", Vout: 1},
|
||||
}
|
||||
amounts := map[string]float64{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
|
||||
txOutputs := map[string]interface{}{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
|
||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||
Amounts: map[string]float64{"456": .0123},
|
||||
Outputs: map[string]interface{}{"456": .0123},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -67,13 +67,13 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
amounts := map[string]float64{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil)
|
||||
txOutputs := map[string]interface{}{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(nil, txOutputs, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`,
|
||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||
Inputs: []btcjson.TransactionInput{},
|
||||
Amounts: map[string]float64{"456": .0123},
|
||||
Outputs: map[string]interface{}{"456": .0123},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -86,16 +86,35 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
txInputs := []btcjson.TransactionInput{
|
||||
{Txid: "123", Vout: 1},
|
||||
}
|
||||
amounts := map[string]float64{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
|
||||
txOutputs := map[string]interface{}{"456": .0123}
|
||||
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333))
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
|
||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||
Amounts: map[string]float64{"456": .0123},
|
||||
Outputs: map[string]interface{}{"456": .0123},
|
||||
LockTime: btcjson.Int64(12312333333),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "createrawtransaction with data",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
|
||||
`{"data":"6a134920616d204672616374616c456e6372797074"}`)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
txInputs := []btcjson.TransactionInput{
|
||||
{Txid: "123", Vout: 1},
|
||||
}
|
||||
txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
|
||||
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
|
||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||
Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fundrawtransaction - empty opts",
|
||||
newCmd: func() (i interface{}, e error) {
|
||||
|
@ -388,7 +407,7 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
|
||||
},
|
||||
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",
|
||||
|
@ -399,7 +418,7 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
|
||||
},
|
||||
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",
|
||||
|
@ -872,21 +891,21 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
|
||||
unmarshalled: &btcjson.GetRawTransactionCmd{
|
||||
Txid: "123",
|
||||
Verbose: btcjson.Int(0),
|
||||
Verbose: btcjson.Bool(false),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "getrawtransaction optional",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("getrawtransaction", "123", 1)
|
||||
return btcjson.NewCmd("getrawtransaction", "123", true)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewGetRawTransactionCmd("123", btcjson.Int(1))
|
||||
return btcjson.NewGetRawTransactionCmd("123", btcjson.Bool(true))
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`,
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",true],"id":1}`,
|
||||
unmarshalled: &btcjson.GetRawTransactionCmd{
|
||||
Txid: "123",
|
||||
Verbose: btcjson.Int(1),
|
||||
Verbose: btcjson.Bool(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
|
||||
|
@ -25,6 +25,7 @@ type GetBlockHeaderVerboseResult struct {
|
|||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
ClaimTrie string `json:"nameclaimroot,omitempty"`
|
||||
Time int64 `json:"time"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
|
@ -34,35 +35,60 @@ type GetBlockHeaderVerboseResult struct {
|
|||
}
|
||||
|
||||
// GetBlockStatsResult models the data from the getblockstats command.
|
||||
// Pointers are used instead of values to allow for optional fields.
|
||||
type GetBlockStatsResult struct {
|
||||
AverageFee int64 `json:"avgfee"`
|
||||
AverageFeeRate int64 `json:"avgfeerate"`
|
||||
AverageTxSize int64 `json:"avgtxsize"`
|
||||
FeeratePercentiles []int64 `json:"feerate_percentiles"`
|
||||
Hash string `json:"blockhash"`
|
||||
Height int64 `json:"height"`
|
||||
Ins int64 `json:"ins"`
|
||||
MaxFee int64 `json:"maxfee"`
|
||||
MaxFeeRate int64 `json:"maxfeerate"`
|
||||
MaxTxSize int64 `json:"maxtxsize"`
|
||||
MedianFee int64 `json:"medianfee"`
|
||||
MedianTime int64 `json:"mediantime"`
|
||||
MedianTxSize int64 `json:"mediantxsize"`
|
||||
MinFee int64 `json:"minfee"`
|
||||
MinFeeRate int64 `json:"minfeerate"`
|
||||
MinTxSize int64 `json:"mintxsize"`
|
||||
Outs int64 `json:"outs"`
|
||||
SegWitTotalSize int64 `json:"swtotal_size"`
|
||||
SegWitTotalWeight int64 `json:"swtotal_weight"`
|
||||
SegWitTxs int64 `json:"swtxs"`
|
||||
Subsidy int64 `json:"subsidy"`
|
||||
Time int64 `json:"time"`
|
||||
TotalOut int64 `json:"total_out"`
|
||||
TotalSize int64 `json:"total_size"`
|
||||
TotalWeight int64 `json:"total_weight"`
|
||||
Txs int64 `json:"txs"`
|
||||
UTXOIncrease int64 `json:"utxo_increase"`
|
||||
UTXOSizeIncrease int64 `json:"utxo_size_inc"`
|
||||
AverageFee *int64 `json:"avgfee,omitempty"`
|
||||
AverageFeeRate *int64 `json:"avgfeerate,omitempty"`
|
||||
AverageTxSize *int64 `json:"avgtxsize,omitempty"`
|
||||
FeeratePercentiles *[]int64 `json:"feerate_percentiles,omitempty"`
|
||||
Hash *string `json:"blockhash,omitempty"`
|
||||
Height *int64 `json:"height,omitempty"`
|
||||
Ins *int64 `json:"ins,omitempty"`
|
||||
MaxFee *int64 `json:"maxfee,omitempty"`
|
||||
MaxFeeRate *int64 `json:"maxfeerate,omitempty"`
|
||||
MaxTxSize *int64 `json:"maxtxsize,omitempty"`
|
||||
MedianFee *int64 `json:"medianfee,omitempty"`
|
||||
MedianTime *int64 `json:"mediantime,omitempty"`
|
||||
MedianTxSize *int64 `json:"mediantxsize,omitempty"`
|
||||
MinFee *int64 `json:"minfee,omitempty"`
|
||||
MinFeeRate *int64 `json:"minfeerate,omitempty"`
|
||||
MinTxSize *int64 `json:"mintxsize,omitempty"`
|
||||
Outs *int64 `json:"outs,omitempty"`
|
||||
SegWitTotalSize *int64 `json:"swtotal_size,omitempty"`
|
||||
SegWitTotalWeight *int64 `json:"swtotal_weight,omitempty"`
|
||||
SegWitTxs *int64 `json:"swtxs,omitempty"`
|
||||
Subsidy *int64 `json:"subsidy,omitempty"`
|
||||
Time *int64 `json:"time,omitempty"`
|
||||
TotalOut *int64 `json:"total_out,omitempty"`
|
||||
TotalSize *int64 `json:"total_size,omitempty"`
|
||||
TotalWeight *int64 `json:"total_weight,omitempty"`
|
||||
TotalFee *int64 `json:"totalfee,omitempty"`
|
||||
Txs *int64 `json:"txs,omitempty"`
|
||||
UTXOIncrease *int64 `json:"utxo_increase,omitempty"`
|
||||
UTXOSizeIncrease *int64 `json:"utxo_size_inc,omitempty"`
|
||||
}
|
||||
|
||||
type GetBlockVerboseResultBase struct {
|
||||
Hash string `json:"hash"`
|
||||
Confirmations int64 `json:"confirmations"`
|
||||
StrippedSize int32 `json:"strippedsize"`
|
||||
Size int32 `json:"size"`
|
||||
Weight int32 `json:"weight"`
|
||||
Height int64 `json:"height"`
|
||||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
Time int64 `json:"time"`
|
||||
MedianTime int64 `json:"mediantime"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
Difficulty float64 `json:"difficulty"`
|
||||
ChainWork string `json:"chainwork"`
|
||||
PreviousHash string `json:"previousblockhash,omitempty"`
|
||||
NextHash string `json:"nextblockhash,omitempty"`
|
||||
|
||||
ClaimTrie string `json:"nameclaimroot,omitempty"`
|
||||
TxCount int `json:"nTx"` // For backwards compatibility only
|
||||
}
|
||||
|
||||
// GetBlockVerboseResult models the data from the getblock command when the
|
||||
|
@ -72,23 +98,8 @@ type GetBlockStatsResult struct {
|
|||
// 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.
|
||||
type GetBlockVerboseResult 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"`
|
||||
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"`
|
||||
GetBlockVerboseResultBase
|
||||
Tx []string `json:"tx"`
|
||||
}
|
||||
|
||||
// GetBlockVerboseTxResult models the data from the getblock command when the
|
||||
|
@ -98,23 +109,8 @@ type GetBlockVerboseResult struct {
|
|||
// 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.
|
||||
type GetBlockVerboseTxResult 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"`
|
||||
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"`
|
||||
GetBlockVerboseResultBase
|
||||
Tx []TxRawResult `json:"tx"`
|
||||
}
|
||||
|
||||
// GetChainTxStatsResult models the data from the getchaintxstats command.
|
||||
|
@ -296,6 +292,10 @@ type GetBlockTemplateResult struct {
|
|||
// Block proposal from BIP 0023.
|
||||
Capabilities []string `json:"capabilities,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
|
||||
|
@ -327,13 +327,27 @@ type GetMempoolEntryResult struct {
|
|||
WTxId string `json:"wtxid"`
|
||||
Fees MempoolFees `json:"fees"`
|
||||
Depends []string `json:"depends"`
|
||||
SpentBy []string `json:"spentby"`
|
||||
}
|
||||
|
||||
// GetChainTipsResult models the data returns from the getchaintips command.
|
||||
type GetChainTipsResult struct {
|
||||
Height int64 `json:"height"`
|
||||
Hash string `json:"hash"`
|
||||
BranchLen int64 `json:"branchlen"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// GetMempoolInfoResult models the data returned from the getmempoolinfo
|
||||
// command.
|
||||
type GetMempoolInfoResult struct {
|
||||
Size int64 `json:"size"`
|
||||
Bytes int64 `json:"bytes"`
|
||||
Size int64 `json:"size"` // Current tx count
|
||||
Bytes int64 `json:"bytes"` // Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted
|
||||
Usage int64 `json:"usage"` // Total memory usage for the mempool
|
||||
TotalFee float64 `json:"total_fee"` // Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction
|
||||
MemPoolMinFee float64 `json:"mempoolminfee"` // Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee
|
||||
MinRelayTxFee float64 `json:"minrelaytxfee"` // Current minimum relay fee for transactions
|
||||
UnbroadcastCount int64 `json:"unbroadcastcount"` // Current number of transactions that haven't passed initial broadcast yet
|
||||
}
|
||||
|
||||
// NetworksResult models the networks data from the getnetworkinfo command.
|
||||
|
@ -428,6 +442,9 @@ type ScriptPubKeyResult struct {
|
|||
Hex string `json:"hex,omitempty"`
|
||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||
Type string `json:"type"`
|
||||
SubType string `json:"subtype"`
|
||||
IsClaim bool `json:"isclaim"`
|
||||
IsSupport bool `json:"issupport"`
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -586,6 +603,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
|||
type PrevOut struct {
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
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
|
||||
|
@ -704,6 +723,15 @@ type InfoChainResult struct {
|
|||
Errors string `json:"errors"`
|
||||
}
|
||||
|
||||
// ListBannedResult models the data returned from the listbanned command.
|
||||
type ListBannedResult struct {
|
||||
Address string `json:"address"`
|
||||
BanCreated int64 `json:"ban_created"`
|
||||
BannedUntil int64 `json:"banned_until"`
|
||||
BanDuration int64 `json:"ban_duration"`
|
||||
TimeRemaining int64 `json:"time_remaining"`
|
||||
}
|
||||
|
||||
// TxRawResult models the data from the getrawtransaction command.
|
||||
type TxRawResult struct {
|
||||
Hex string `json:"hex"`
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"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
|
||||
|
@ -70,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
|
|||
},
|
||||
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}`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsNtfns tests all of the chain server websocket-specific
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsResults ensures any results that have custom marshalling
|
||||
|
|
97
btcjson/claimcmds.go
Normal file
97
btcjson/claimcmds.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package btcjson
|
||||
|
||||
func init() {
|
||||
// No special flags for commands in this file.
|
||||
flags := UsageFlag(0)
|
||||
|
||||
MustRegisterCmd("getchangesinblock", (*GetChangesInBlockCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsforname", (*GetClaimsForNameCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebyid", (*GetClaimsForNameByIDCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
|
||||
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)
|
||||
}
|
||||
|
||||
// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
|
||||
// optional inputs have to be at the bottom of the struct
|
||||
// optional outputs require ",omitempty"
|
||||
// traditional bitcoin fields are all lowercase
|
||||
|
||||
type GetChangesInBlockCmd struct {
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
}
|
||||
|
||||
type GetChangesInBlockResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Height int32 `json:"height"`
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameCmd struct {
|
||||
Name string `json:"name"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameByIDCmd struct {
|
||||
Name string `json:"name"`
|
||||
PartialClaimIDs []string `json:"partialclaimids"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameByBidCmd struct {
|
||||
Name string `json:"name"`
|
||||
Bids []int32 `json:"bids"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameBySeqCmd struct {
|
||||
Name string `json:"name"`
|
||||
Sequences []int32 `json:"sequences" jsonrpcusage:"[sequence,...]"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Height int32 `json:"height"`
|
||||
LastTakeoverHeight int32 `json:"lasttakeoverheight"`
|
||||
NormalizedName string `json:"normalizedname"`
|
||||
Claims []ClaimResult `json:"claims"`
|
||||
// UnclaimedSupports []SupportResult `json:"supportswithoutclaim"` how would this work with other constraints?
|
||||
}
|
||||
|
||||
type SupportResult struct {
|
||||
TXID string `json:"txid"`
|
||||
N uint32 `json:"n"`
|
||||
Height int32 `json:"height"`
|
||||
ValidAtHeight int32 `json:"validatheight"`
|
||||
Amount int64 `json:"amount"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type ClaimResult struct {
|
||||
ClaimID string `json:"claimid"`
|
||||
TXID string `json:"txid"`
|
||||
N uint32 `json:"n"`
|
||||
Bid int32 `json:"bid"`
|
||||
Sequence int32 `json:"sequence"`
|
||||
Height int32 `json:"height"`
|
||||
ValidAtHeight int32 `json:"validatheight"`
|
||||
Amount int64 `json:"amount"`
|
||||
EffectiveAmount int64 `json:"effectiveamount"`
|
||||
Supports []SupportResult `json:"supports,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type GetNormalizedCmd struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type GetNormalizedResult struct {
|
||||
NormalizedName string `json:"normalizedname"`
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected
|
||||
|
|
|
@ -134,6 +134,16 @@ func UnmarshalCmd(r *Request) (interface{}, error) {
|
|||
// Unmarshal the parameter into the struct field.
|
||||
concreteVal := rvf.Addr().Interface()
|
||||
if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil {
|
||||
// Parse Integer into Bool for compatibility with lbrycrd.
|
||||
if rvf.Kind() == reflect.Ptr &&
|
||||
rvf.Elem().Type().Kind() == reflect.Bool {
|
||||
boolInt, errBoolInt := strconv.Atoi(string(r.Params[i]))
|
||||
if errBoolInt == nil {
|
||||
rvf.Elem().SetBool(boolInt != 0)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// The most common error is the wrong type, so
|
||||
// explicitly detect that error and make it nicer.
|
||||
fieldName := strings.ToLower(rt.Field(i).Name)
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestAssignField tests the assignField function handles supported combinations
|
||||
|
@ -557,7 +557,7 @@ func TestUnmarshalCmdErrors(t *testing.T) {
|
|||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getblock",
|
||||
Params: []json.RawMessage{[]byte("1")},
|
||||
Params: []json.RawMessage{[]byte("1.0")},
|
||||
ID: nil,
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
|
@ -591,3 +591,84 @@ func TestUnmarshalCmdErrors(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmarshalCmdBoolParams tests the parsing of boolean paramers of the UnmarshalCmd function.
|
||||
func TestUnmarshalCmdBoolParams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
txid := []byte(`"ab91c149aff2b37a4a1856e9935ea623c973f47886d032ed7511ad8ca37855bb"`)
|
||||
tests := []struct {
|
||||
name string
|
||||
request btcjson.Request
|
||||
expect bool
|
||||
}{
|
||||
{
|
||||
name: "parse true",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getrawtransaction",
|
||||
Params: []json.RawMessage{txid, []byte("true")},
|
||||
ID: nil,
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "parse false",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getrawtransaction",
|
||||
Params: []json.RawMessage{txid, []byte("false")},
|
||||
ID: nil,
|
||||
},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
name: "parse integer 0 to false",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getrawtransaction",
|
||||
Params: []json.RawMessage{txid, []byte("0")},
|
||||
ID: nil,
|
||||
},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
name: "parse integer 1 to true",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getrawtransaction",
|
||||
Params: []json.RawMessage{txid, []byte("1")},
|
||||
ID: nil,
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
name: "parse integer 100 to true",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getrawtransaction",
|
||||
Params: []json.RawMessage{txid, []byte("100")},
|
||||
ID: nil,
|
||||
},
|
||||
expect: true,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
cmd, err := btcjson.UnmarshalCmd(&test.request)
|
||||
if err != nil {
|
||||
t.Errorf("Test #%d (%s) error - got %T (%v)", i, test.name,
|
||||
err, err)
|
||||
continue
|
||||
}
|
||||
cc := cmd.(*btcjson.GetRawTransactionCmd)
|
||||
verbose := *cc.Verbose
|
||||
if verbose != test.expect {
|
||||
t.Errorf("Test #%d (%s) got %t, want %v", i, test.name,
|
||||
verbose, test.expect)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
/*
|
||||
Package btcjson provides primitives for working with the bitcoin JSON-RPC API.
|
||||
|
||||
Overview
|
||||
# Overview
|
||||
|
||||
When communicating via the JSON-RPC protocol, all of the commands need to be
|
||||
marshalled to and from the the wire in the appropriate format. This package
|
||||
|
@ -14,7 +14,7 @@ provides data structures and primitives to ease this process.
|
|||
In addition, it also provides some additional features such as custom command
|
||||
registration, command categorization, and reflection-based help generation.
|
||||
|
||||
JSON-RPC Protocol Overview
|
||||
# JSON-RPC Protocol Overview
|
||||
|
||||
This information is not necessary in order to use this package, but it does
|
||||
provide some intuition into what the marshalling and unmarshalling that is
|
||||
|
@ -47,39 +47,39 @@ with it) doesn't always follow the spec and will sometimes return an error
|
|||
string in the result field with a null error for certain commands. However,
|
||||
for the most part, the error field will be set as described on failure.
|
||||
|
||||
Marshalling and Unmarshalling
|
||||
# Marshalling and Unmarshalling
|
||||
|
||||
Based upon the discussion above, it should be easy to see how the types of this
|
||||
package map into the required parts of the protocol
|
||||
|
||||
- Request Objects (type Request)
|
||||
- Commands (type <Foo>Cmd)
|
||||
- Notifications (type <Foo>Ntfn)
|
||||
- Commands (type <Foo>Cmd)
|
||||
- Notifications (type <Foo>Ntfn)
|
||||
- Response Objects (type Response)
|
||||
- Result (type <Foo>Result)
|
||||
- Result (type <Foo>Result)
|
||||
|
||||
To simplify the marshalling of the requests and responses, the MarshalCmd and
|
||||
MarshalResponse functions are provided. They return the raw bytes ready to be
|
||||
sent across the wire.
|
||||
|
||||
Unmarshalling a received Request object is a two step process:
|
||||
1) Unmarshal the raw bytes into a Request struct instance via json.Unmarshal
|
||||
2) Use UnmarshalCmd on the Result field of the unmarshalled Request to create
|
||||
a concrete command or notification instance with all struct fields set
|
||||
accordingly
|
||||
1. Unmarshal the raw bytes into a Request struct instance via json.Unmarshal
|
||||
2. Use UnmarshalCmd on the Result field of the unmarshalled Request to create
|
||||
a concrete command or notification instance with all struct fields set
|
||||
accordingly
|
||||
|
||||
This approach is used since it provides the caller with access to the additional
|
||||
fields in the request that are not part of the command such as the ID.
|
||||
|
||||
Unmarshalling a received Response object is also a two step process:
|
||||
1) Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal
|
||||
2) Depending on the ID, unmarshal the Result field of the unmarshalled
|
||||
Response to create a concrete type instance
|
||||
1. Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal
|
||||
2. Depending on the ID, unmarshal the Result field of the unmarshalled
|
||||
Response to create a concrete type instance
|
||||
|
||||
As above, this approach is used since it provides the caller with access to the
|
||||
fields in the response such as the ID and Error.
|
||||
|
||||
Command Creation
|
||||
# Command Creation
|
||||
|
||||
This package provides two approaches for creating a new command. This first,
|
||||
and preferred, method is to use one of the New<Foo>Cmd functions. This allows
|
||||
|
@ -93,7 +93,7 @@ obviously, run-time which means any mistakes won't be found until the code is
|
|||
actually executed. However, it is quite useful for user-supplied commands
|
||||
that are intentionally dynamic.
|
||||
|
||||
Custom Command Registration
|
||||
# Custom Command Registration
|
||||
|
||||
The command handling of this package is built around the concept of registered
|
||||
commands. This is true for the wide variety of commands already provided by the
|
||||
|
@ -104,7 +104,7 @@ function for this purpose.
|
|||
A list of all registered methods can be obtained with the RegisteredCmdMethods
|
||||
function.
|
||||
|
||||
Command Inspection
|
||||
# Command Inspection
|
||||
|
||||
All registered commands are registered with flags that identify information such
|
||||
as whether the command applies to a chain server, wallet server, or is a
|
||||
|
@ -112,7 +112,7 @@ notification along with the method name to use. These flags can be obtained
|
|||
with the MethodUsageFlags flags, and the method can be obtained with the
|
||||
CmdMethod function.
|
||||
|
||||
Help Generation
|
||||
# Help Generation
|
||||
|
||||
To facilitate providing consistent help to users of the RPC server, this package
|
||||
exposes the GenerateHelp and function which uses reflection on registered
|
||||
|
@ -122,7 +122,7 @@ generate the final help text.
|
|||
In addition, the MethodUsageText function is provided to generate consistent
|
||||
one-line usage for registered commands and notifications using reflection.
|
||||
|
||||
Errors
|
||||
# Errors
|
||||
|
||||
There are 2 distinct type of errors supported by this package:
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package btcjson_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestErrorCodeStringer tests the stringized output for the ErrorCode type.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue