mirror of
https://github.com/LBRYFoundation/lbcd.git
synced 2025-08-23 17:47:24 +00:00
Compare commits
423 commits
v0.20.1-be
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
64f6fcecb8 | ||
|
e293c5ab57 | ||
|
5625d54f37 | ||
|
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 | ||
|
63438c6d36 | ||
|
aaf19b26f3 | ||
|
418f9204f4 | ||
|
ee5896bad5 | ||
|
7b6c2b3423 | ||
|
0ec4bdc1b8 | ||
|
ce697fe7e8 | ||
|
7eba688b65 | ||
|
37a6e8485b | ||
|
f0f4784c1c | ||
|
7d1ab0b4d7 | ||
|
8a62cf0ef5 | ||
|
3eac153437 | ||
|
73ecb5997b | ||
|
2d7825cf70 | ||
|
540786fda6 | ||
|
36a96f6a00 | ||
|
f133593b93 | ||
|
f86ae60936 | ||
|
01c6a6fe9b | ||
|
fdb479f121 | ||
|
556620fea6 | ||
|
d08785547a | ||
|
dff2198fc5 | ||
|
2a1aa5129e | ||
|
31b66488b4 | ||
|
fa683a69dc | ||
|
5300a19d06 | ||
|
1dd693480c | ||
|
77fd96753c | ||
|
7bbd9b0284 | ||
|
c3ece697da | ||
|
e747eb9284 | ||
|
12abc84cb2 | ||
|
6bd4c64a54 | ||
|
29c9ff351c | ||
|
610bb55ae8 | ||
|
0886f1e5c1 | ||
|
e9c7a5ac64 | ||
|
9e8bb3eddb | ||
|
9fd26cf795 | ||
|
65d2b7a18c | ||
|
93cc7f36cf | ||
|
9250064837 | ||
|
f070f7f2be | ||
|
535f25593d | ||
|
5e56ca05e1 | ||
|
1d75e0a885 | ||
|
6adfc07d1e | ||
|
6519c04a6f | ||
|
584c382334 | ||
|
0bf42f4476 | ||
|
40ae93587d | ||
|
e9a51e8dcd | ||
|
1340513786 | ||
|
ac3f235eb9 | ||
|
6daaf73544 | ||
|
f4024160f3 | ||
|
e5521de652 | ||
|
297c6120bb | ||
|
c693bd8bc5 | ||
|
42782bba18 | ||
|
ff59bbc14a | ||
|
5ae1f21cd9 | ||
|
6f49f1f194 | ||
|
fff96610aa | ||
|
9ef973c282 | ||
|
2547246f84 | ||
|
eb05726dac | ||
|
bdab8dfe81 | ||
|
3b926ef77b | ||
|
95fea6420c | ||
|
ba3fe57507 | ||
|
7cbf95675a | ||
|
8facfdd04d | ||
|
61634447e7 | ||
|
23d149cbfb | ||
|
355472b0f7 | ||
|
35194e2dac | ||
|
d13e907952 | ||
|
90a5c7997c | ||
|
fffe4a909b | ||
|
d2c0123bef | ||
|
b68c50e33c | ||
|
7145eef75b | ||
|
36d4ae08e8 | ||
|
7d69fb9ba6 | ||
|
efae8e9967 | ||
|
70a0132485 | ||
|
56cc42fe07 | ||
|
4527c5671f | ||
|
2a0d6fd0e3 | ||
|
4255e1ed7b | ||
|
1db1b6f821 | ||
|
24db7d7c0c | ||
|
69773a7b41 | ||
|
3c56a6bd3a | ||
|
c7390232d3 | ||
|
d28c7167a5 | ||
|
875b51c9fb | ||
|
e2d9cf4b55 | ||
|
7b2ff5d180 | ||
|
e4f59022a3 | ||
|
73d69f09d0 | ||
|
a383a71670 | ||
|
b11bf582c5 | ||
|
714de3f3c7 | ||
|
6d521ff8cd | ||
|
e6f163e61e | ||
|
915788b8e6 | ||
|
280845a8a4 | ||
|
9f0179fd2c | ||
|
9a88e1dd33 | ||
|
742935e3a9 | ||
|
d38279ee74 | ||
|
f7399e6157 | ||
|
bc8d63bf15 | ||
|
a505b99ba3 | ||
|
b470eee477 | ||
|
b298415583 | ||
|
8512affc59 | ||
|
8b54b0b964 | ||
|
9f15a7e6af | ||
|
57d44d022e | ||
|
08b8751559 | ||
|
cfcf4fb762 | ||
|
8b1be46463 | ||
|
a8eadd2ce4 | ||
|
d9ce6b037f | ||
|
c4f39996ac | ||
|
fd0921b9b4 | ||
|
96f3808dc9 | ||
|
9e94ccbd0e | ||
|
1d0bfca5b0 | ||
|
e9f15eda7e | ||
|
a310aa6e74 | ||
|
57cb8e4b11 | ||
|
468154a052 | ||
|
160c388285 | ||
|
06e5c43499 | ||
|
e2c08cc80b | ||
|
ef4cecf42b | ||
|
46461dc84a | ||
|
318c89dfed | ||
|
0c76fbd26f | ||
|
8bbbe98be9 | ||
|
1639d6c070 | ||
|
3eb4739b75 | ||
|
eed57cdcf1 | ||
|
c01c98159b | ||
|
6799104157 |
437 changed files with 52293 additions and 14406 deletions
32
.github/workflows/basic-check.yml
vendored
Normal file
32
.github/workflows/basic-check.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
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.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: Build
|
||||||
|
run: go build ./...
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
sh ./goclean.sh
|
||||||
|
|
||||||
|
- name: Send coverage
|
||||||
|
uses: shogo82148/actions-goveralls@v1
|
||||||
|
with:
|
||||||
|
path-to-profile: profile.cov
|
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
|
21
.gitignore
vendored
21
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
# Databases
|
# Databases
|
||||||
btcd.db
|
btcd.db
|
||||||
|
lbcd.db
|
||||||
*-shm
|
*-shm
|
||||||
*-wal
|
*-wal
|
||||||
|
|
||||||
|
@ -32,3 +33,23 @@ _cgo_export.*
|
||||||
_testmain.go
|
_testmain.go
|
||||||
|
|
||||||
*.exe
|
*.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/lbryfoundation/lbcd/version.appTag={{ .Tag }}
|
||||||
|
targets:
|
||||||
|
- linux_amd64
|
||||||
|
- linux_arm64
|
||||||
|
- darwin_amd64
|
||||||
|
- darwin_arm64
|
||||||
|
- windows_amd64
|
||||||
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
|
-
|
||||||
|
main: ./cmd/lbcctl
|
||||||
|
id: "lbcctl"
|
||||||
|
binary: "lbcctl"
|
||||||
|
flags:
|
||||||
|
- -trimpath
|
||||||
|
ldflags:
|
||||||
|
- -s -w
|
||||||
|
- -buildid=
|
||||||
|
- -X github.com/lbryfoundation/lbcd/version.appTag={{ .Tag }}
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
targets:
|
||||||
|
- linux_amd64
|
||||||
|
- linux_arm64
|
||||||
|
- darwin_amd64
|
||||||
|
- darwin_arm64
|
||||||
|
- windows_amd64
|
||||||
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
snapshot:
|
||||||
|
name_template: "{{ .Version }}+{{ .Commit }}"
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- '^docs:'
|
||||||
|
- '^test:'
|
||||||
|
|
||||||
|
dockers:
|
||||||
|
- use: buildx
|
||||||
|
dockerfile: Dockerfile.goreleaser
|
||||||
|
image_templates:
|
||||||
|
- "docker.io/lbryfoundation/lbcd:{{ .Tag }}"
|
||||||
|
- "docker.io/lbryfoundation/lbcd:latest"
|
||||||
|
|
||||||
|
release:
|
||||||
|
draft: true
|
||||||
|
prerelease: auto
|
19
.travis.yml
19
.travis.yml
|
@ -1,19 +0,0 @@
|
||||||
language: go
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $GOCACHE
|
|
||||||
- $GOPATH
|
|
||||||
- $GOPATH/pkg/mod
|
|
||||||
- $GOPATH/github.com/golang
|
|
||||||
- $GOPATH/gopkg.in/alecthomas
|
|
||||||
go:
|
|
||||||
- "1.13.x"
|
|
||||||
sudo: false
|
|
||||||
install:
|
|
||||||
- export PATH=$PATH:$PWD/linux-amd64/
|
|
||||||
- GO111MODULE=on go install . ./cmd/...
|
|
||||||
- GO111MODULE=off go get -u gopkg.in/alecthomas/gometalinter.v2
|
|
||||||
- GO111MODULE=off gometalinter.v2 --install
|
|
||||||
script:
|
|
||||||
- export PATH=$PATH:$HOME/gopath/bin
|
|
||||||
- ./goclean.sh
|
|
955
CHANGES
955
CHANGES
|
@ -1,955 +0,0 @@
|
||||||
============================================================================
|
|
||||||
User visible changes for btcd
|
|
||||||
A full-node bitcoin implementation written in Go
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
Changes in 0.12.0 (Fri Nov 20 2015)
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- Add a new checkpoint at block height 382320 (#555)
|
|
||||||
- Implement BIP0065 which includes support for version 4 blocks, a new
|
|
||||||
consensus opcode (OP_CHECKLOCKTIMEVERIFY) that enforces transaction
|
|
||||||
lock times, and a double-threshold switchover mechanism (#535, #459,
|
|
||||||
#455)
|
|
||||||
- Implement BIP0111 which provides a new bloom filter service flag and
|
|
||||||
hence provides support for protocol version 70011 (#499)
|
|
||||||
- Add a new parameter --nopeerbloomfilters to allow disabling bloom
|
|
||||||
filter support (#499)
|
|
||||||
- Reject non-canonically encoded variable length integers (#507)
|
|
||||||
- Add mainnet peer discovery DNS seed (seed.bitcoin.jonasschnelli.ch)
|
|
||||||
(#496)
|
|
||||||
- Correct reconnect handling for persistent peers (#463, #464)
|
|
||||||
- Ignore requests for block headers if not fully synced (#444)
|
|
||||||
- Add CLI support for specifying the zone id on IPv6 addresses (#538)
|
|
||||||
- Fix a couple of issues where the initial block sync could stall (#518,
|
|
||||||
#229, #486)
|
|
||||||
- Fix an issue which prevented the --onion option from working as
|
|
||||||
intended (#446)
|
|
||||||
- Transaction relay (memory pool) changes:
|
|
||||||
- Require transactions to only include signatures encoded with the
|
|
||||||
canonical 'low-s' encoding (#512)
|
|
||||||
- Add a new parameter --minrelaytxfee to allow the minimum transaction
|
|
||||||
fee in BTC/kB to be overridden (#520)
|
|
||||||
- Retain memory pool transactions when they redeem another one that is
|
|
||||||
removed when a block is accepted (#539)
|
|
||||||
- Do not send reject messages for a transaction if it is valid but
|
|
||||||
causes an orphan transaction which depends on it to be determined
|
|
||||||
as invalid (#546)
|
|
||||||
- Refrain from attempting to add orphans to the memory pool multiple
|
|
||||||
times when the transaction they redeem is added (#551)
|
|
||||||
- Modify minimum transaction fee calculations to scale based on bytes
|
|
||||||
instead of full kilobyte boundaries (#521, #537)
|
|
||||||
- Implement signature cache:
|
|
||||||
- Provides a limited memory cache of validated signatures which is a
|
|
||||||
huge optimization when verifying blocks for transactions that are
|
|
||||||
already in the memory pool (#506)
|
|
||||||
- Add a new parameter '--sigcachemaxsize' which allows the size of the
|
|
||||||
new cache to be manually changed if desired (#506)
|
|
||||||
- Mining support changes:
|
|
||||||
- Notify getblocktemplate long polling clients when a block is pushed
|
|
||||||
via submitblock (#488)
|
|
||||||
- Speed up getblocktemplate by making use of the new signature cache
|
|
||||||
(#506)
|
|
||||||
- RPC changes:
|
|
||||||
- Implement getmempoolinfo command (#453)
|
|
||||||
- Implement getblockheader command (#461)
|
|
||||||
- Modify createrawtransaction command to accept a new optional parameter
|
|
||||||
'locktime' (#529)
|
|
||||||
- Modify listunspent result to include the 'spendable' field (#440)
|
|
||||||
- Modify getinfo command to include 'errors' field (#511)
|
|
||||||
- Add timestamps to blockconnected and blockdisconnected notifications
|
|
||||||
(#450)
|
|
||||||
- Several modifications to searchrawtranscations command:
|
|
||||||
- Accept a new optional parameter 'vinextra' which causes the results
|
|
||||||
to include information about the outputs referenced by a transaction's
|
|
||||||
inputs (#485, #487)
|
|
||||||
- Skip entries in the mempool too (#495)
|
|
||||||
- Accept a new optional parameter 'reverse' to return the results in
|
|
||||||
reverse order (most recent to oldest) (#497)
|
|
||||||
- Accept a new optional parameter 'filteraddrs' which causes the
|
|
||||||
results to only include inputs and outputs which involve the
|
|
||||||
provided addresses (#516)
|
|
||||||
- Change the notification order to notify clients about mined
|
|
||||||
transactions (recvtx, redeemingtx) before the blockconnected
|
|
||||||
notification (#449)
|
|
||||||
- Update verifymessage RPC to use the standard algorithm so it is
|
|
||||||
compatible with other implementations (#515)
|
|
||||||
- Improve ping statistics by pinging on an interval (#517)
|
|
||||||
- Websocket changes:
|
|
||||||
- Implement session command which returns a per-session unique id (#500,
|
|
||||||
#503)
|
|
||||||
- btcctl utility changes:
|
|
||||||
- Add getmempoolinfo command (#453)
|
|
||||||
- Add getblockheader command (#461)
|
|
||||||
- Add getwalletinfo command (#471)
|
|
||||||
- Notable developer-related package changes:
|
|
||||||
- Introduce a new peer package which acts a common base for creating and
|
|
||||||
concurrently managing bitcoin network peers (#445)
|
|
||||||
- Various cleanup of the new peer package (#528, #531, #524, #534,
|
|
||||||
#549)
|
|
||||||
- Blocks heights now consistently use int32 everywhere (#481)
|
|
||||||
- The BlockHeader type in the wire package now provides the BtcDecode
|
|
||||||
and BtcEncode methods (#467)
|
|
||||||
- Update wire package to recognize BIP0064 (getutxo) service bit (#489)
|
|
||||||
- Export LockTimeThreshold constant from txscript package (#454)
|
|
||||||
- Export MaxDataCarrierSize constant from txscript package (#466)
|
|
||||||
- Provide new IsUnspendable function from the txscript package (#478)
|
|
||||||
- Export variable length string functions from the wire package (#514)
|
|
||||||
- Export DNS Seeds for each network from the chaincfg package (#544)
|
|
||||||
- Preliminary work towards separating the memory pool into a separate
|
|
||||||
package (#525, #548)
|
|
||||||
- Misc changes:
|
|
||||||
- Various documentation updates (#442, #462, #465, #460, #470, #473,
|
|
||||||
#505, #530, #545)
|
|
||||||
- Add installation instructions for gentoo (#542)
|
|
||||||
- Ensure an error is shown if OS limits can't be set at startup (#498)
|
|
||||||
- Tighten the standardness checks for multisig scripts (#526)
|
|
||||||
- Test coverage improvement (#468, #494, #527, #543, #550)
|
|
||||||
- Several optimizations (#457, #474, #475, #476, #508, #509)
|
|
||||||
- Minor code cleanup and refactoring (#472, #479, #482, #519, #540)
|
|
||||||
- Contributors (alphabetical order):
|
|
||||||
- Ben Echols
|
|
||||||
- Bruno Clermont
|
|
||||||
- danda
|
|
||||||
- Daniel Krawisz
|
|
||||||
- Dario Nieuwenhuis
|
|
||||||
- Dave Collins
|
|
||||||
- David Hill
|
|
||||||
- Javed Khan
|
|
||||||
- Jonathan Gillham
|
|
||||||
- Joseph Becher
|
|
||||||
- Josh Rickmar
|
|
||||||
- Justus Ranvier
|
|
||||||
- Mawuli Adzoe
|
|
||||||
- Olaoluwa Osuntokun
|
|
||||||
- Rune T. Aune
|
|
||||||
|
|
||||||
Changes in 0.11.1 (Wed May 27 2015)
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- Use correct sub-command in reject message for rejected transactions
|
|
||||||
(#436, #437)
|
|
||||||
- Add a new parameter --torisolation which forces new circuits for each
|
|
||||||
connection when using tor (#430)
|
|
||||||
- Transaction relay (memory pool) changes:
|
|
||||||
- Reduce the default number max number of allowed orphan transactions
|
|
||||||
to 1000 (#419)
|
|
||||||
- Add a new parameter --maxorphantx which allows the maximum number of
|
|
||||||
orphan transactions stored in the mempool to be specified (#419)
|
|
||||||
- RPC changes:
|
|
||||||
- Modify listtransactions result to include the 'involveswatchonly' and
|
|
||||||
'vout' fields (#427)
|
|
||||||
- Update getrawtransaction result to omit the 'confirmations' field
|
|
||||||
when it is 0 (#420, #422)
|
|
||||||
- Update signrawtransaction result to include errors (#423)
|
|
||||||
- btcctl utility changes:
|
|
||||||
- Add gettxoutproof command (#428)
|
|
||||||
- Add verifytxoutproof command (#428)
|
|
||||||
- Notable developer-related package changes:
|
|
||||||
- The btcec package now provides the ability to perform ECDH
|
|
||||||
encryption and decryption (#375)
|
|
||||||
- The block and header validation in the blockchain package has been
|
|
||||||
split to help pave the way toward concurrent downloads (#386)
|
|
||||||
- Misc changes:
|
|
||||||
- Minor peer optimization (#433)
|
|
||||||
- Contributors (alphabetical order):
|
|
||||||
- Dave Collins
|
|
||||||
- David Hill
|
|
||||||
- Federico Bond
|
|
||||||
- Ishbir Singh
|
|
||||||
- Josh Rickmar
|
|
||||||
|
|
||||||
Changes in 0.11.0 (Wed May 06 2015)
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- **IMPORTANT: Update is required due to the following point**
|
|
||||||
- Correct a few corner cases in script handling which could result in
|
|
||||||
forking from the network on non-standard transactions (#425)
|
|
||||||
- Add a new checkpoint at block height 352940 (#418)
|
|
||||||
- Optimized script execution (#395, #400, #404, #409)
|
|
||||||
- Fix a case that could lead stalled syncs (#138, #296)
|
|
||||||
- Network address manager changes:
|
|
||||||
- Implement eclipse attack countermeasures as proposed in
|
|
||||||
http://cs-people.bu.edu/heilman/eclipse (#370, #373)
|
|
||||||
- Optional address indexing changes:
|
|
||||||
- Fix an issue where a reorg could cause an orderly shutdown when the
|
|
||||||
address index is active (#340, #357)
|
|
||||||
- Transaction relay (memory pool) changes:
|
|
||||||
- Increase maximum allowed space for nulldata transactions to 80 bytes
|
|
||||||
(#331)
|
|
||||||
- Implement support for the following rules specified by BIP0062:
|
|
||||||
- The S value in ECDSA signature must be at most half the curve order
|
|
||||||
(rule 5) (#349)
|
|
||||||
- Script execution must result in a single non-zero value on the stack
|
|
||||||
(rule 6) (#347)
|
|
||||||
- NOTE: All 7 rules of BIP0062 are now implemented
|
|
||||||
- Use network adjusted time in finalized transaction checks to improve
|
|
||||||
consistency across nodes (#332)
|
|
||||||
- Process orphan transactions on acceptance of new transactions (#345)
|
|
||||||
- RPC changes:
|
|
||||||
- Add support for a limited RPC user which is not allowed admin level
|
|
||||||
operations on the server (#363)
|
|
||||||
- Implement node command for more unified control over connected peers
|
|
||||||
(#79, #341)
|
|
||||||
- Implement generate command for regtest/simnet to support
|
|
||||||
deterministically mining a specified number of blocks (#362, #407)
|
|
||||||
- Update searchrawtransactions to return the matching transactions in
|
|
||||||
order (#354)
|
|
||||||
- Correct an issue with searchrawtransactions where it could return
|
|
||||||
duplicates (#346, #354)
|
|
||||||
- Increase precision of 'difficulty' field in getblock result to 8
|
|
||||||
(#414, #415)
|
|
||||||
- Omit 'nextblockhash' field from getblock result when it is empty
|
|
||||||
(#416, #417)
|
|
||||||
- Add 'id' and 'timeoffset' fields to getpeerinfo result (#335)
|
|
||||||
- Websocket changes:
|
|
||||||
- Implement new commands stopnotifyspent, stopnotifyreceived,
|
|
||||||
stopnotifyblocks, and stopnotifynewtransactions to allow clients to
|
|
||||||
cancel notification registrations (#122, #342)
|
|
||||||
- btcctl utility changes:
|
|
||||||
- A single dash can now be used as an argument to cause that argument to
|
|
||||||
be read from stdin (#348)
|
|
||||||
- Add generate command
|
|
||||||
- Notable developer-related package changes:
|
|
||||||
- The new version 2 btcjson package has now replaced the deprecated
|
|
||||||
version 1 package (#368)
|
|
||||||
- The btcec package now performs all signing using RFC6979 deterministic
|
|
||||||
signatures (#358, #360)
|
|
||||||
- The txscript package has been significantly cleaned up and had a few
|
|
||||||
API changes (#387, #388, #389, #390, #391, #392, #393, #395, #396,
|
|
||||||
#400, #403, #404, #405, #406, #408, #409, #410, #412)
|
|
||||||
- A new PkScriptLocs function has been added to the wire package MsgTx
|
|
||||||
type which provides callers that deal with scripts optimization
|
|
||||||
opportunities (#343)
|
|
||||||
- Misc changes:
|
|
||||||
- Minor wire hashing optimizations (#366, #367)
|
|
||||||
- Other minor internal optimizations
|
|
||||||
- Contributors (alphabetical order):
|
|
||||||
- Alex Akselrod
|
|
||||||
- Arne Brutschy
|
|
||||||
- Chris Jepson
|
|
||||||
- Daniel Krawisz
|
|
||||||
- Dave Collins
|
|
||||||
- David Hill
|
|
||||||
- Jimmy Song
|
|
||||||
- Jonas Nick
|
|
||||||
- Josh Rickmar
|
|
||||||
- Olaoluwa Osuntokun
|
|
||||||
- Oleg Andreev
|
|
||||||
|
|
||||||
Changes in 0.10.0 (Sun Mar 01 2015)
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- Add a new checkpoint at block height 343185
|
|
||||||
- Implement BIP066 which includes support for version 3 blocks, a new
|
|
||||||
consensus rule which prevents non-DER encoded signatures, and a
|
|
||||||
double-threshold switchover mechanism
|
|
||||||
- Rather than announcing all known addresses on getaddr requests which
|
|
||||||
can possibly result in multiple messages, randomize the results and
|
|
||||||
limit them to the max allowed by a single message (1000 addresses)
|
|
||||||
- Add more reserved IP spaces to the address manager
|
|
||||||
- Transaction relay (memory pool) changes:
|
|
||||||
- Make transactions which contain reserved opcodes nonstandard
|
|
||||||
- No longer accept or relay free and low-fee transactions that have
|
|
||||||
insufficient priority to be mined in the next block
|
|
||||||
- Implement support for the following rules specified by BIP0062:
|
|
||||||
- ECDSA signature must use strict DER encoding (rule 1)
|
|
||||||
- The signature script must only contain push operations (rule 2)
|
|
||||||
- All push operations must use the smallest possible encoding (rule 3)
|
|
||||||
- All stack values interpreted as a number must be encoding using the
|
|
||||||
shortest possible form (rule 4)
|
|
||||||
- NOTE: Rule 1 was already enforced, however the entire script now
|
|
||||||
evaluates to false rather than only the signature verification as
|
|
||||||
required by BIP0062
|
|
||||||
- Allow transactions with nulldata transaction outputs to be treated as
|
|
||||||
standard
|
|
||||||
- Mining support changes:
|
|
||||||
- Modify the getblocktemplate RPC to generate and return block templates
|
|
||||||
for version 3 blocks which are compatible with BIP0066
|
|
||||||
- Allow getblocktemplate to serve blocks when the current time is
|
|
||||||
less than the minimum allowed time for a generated block template
|
|
||||||
(https://github.com/btcsuite/btcd/issues/209)
|
|
||||||
- Crypto changes:
|
|
||||||
- Optimize scalar multiplication by the base point by using a
|
|
||||||
pre-computed table which results in approximately a 35% speedup
|
|
||||||
(https://github.com/btcsuite/btcec/issues/2)
|
|
||||||
- Optimize general scalar multiplication by using the secp256k1
|
|
||||||
endomorphism which results in approximately a 17-20% speedup
|
|
||||||
(https://github.com/btcsuite/btcec/issues/1)
|
|
||||||
- Optimize general scalar multiplication by using non-adjacent form
|
|
||||||
which results in approximately an additional 8% speedup
|
|
||||||
(https://github.com/btcsuite/btcec/issues/3)
|
|
||||||
- Implement optional address indexing:
|
|
||||||
- Add a new parameter --addrindex which will enable the creation of an
|
|
||||||
address index which can be queried to determine all transactions which
|
|
||||||
involve a given address
|
|
||||||
(https://github.com/btcsuite/btcd/issues/190)
|
|
||||||
- Add a new logging subsystem for address index related operations
|
|
||||||
- Support new searchrawtransactions RPC
|
|
||||||
(https://github.com/btcsuite/btcd/issues/185)
|
|
||||||
- RPC changes:
|
|
||||||
- Require TLS version 1.2 as the minimum version for all TLS connections
|
|
||||||
- Provide support for disabling TLS when only listening on localhost
|
|
||||||
(https://github.com/btcsuite/btcd/pull/192)
|
|
||||||
- Modify help output for all commands to provide much more consistent
|
|
||||||
and detailed information
|
|
||||||
- Correct case in getrawtransaction which would refuse to serve certain
|
|
||||||
transactions with invalid scripts
|
|
||||||
(https://github.com/btcsuite/btcd/issues/210)
|
|
||||||
- Correct error handling in the getrawtransaction RPC which could lead
|
|
||||||
to a crash in rare cases
|
|
||||||
(https://github.com/btcsuite/btcd/issues/196)
|
|
||||||
- Update getinfo RPC to include the appropriate 'timeoffset' calculated
|
|
||||||
from the median network time
|
|
||||||
- Modify listreceivedbyaddress result type to include txids field so it
|
|
||||||
is compatible
|
|
||||||
- Add 'iswatchonly' field to validateaddress result
|
|
||||||
- Add 'startingpriority' and 'currentpriority' fields to getrawmempool
|
|
||||||
(https://github.com/btcsuite/btcd/issues/178)
|
|
||||||
- Don't omit the 'confirmations' field from getrawtransaction when it is
|
|
||||||
zero
|
|
||||||
- Websocket changes:
|
|
||||||
- Modify the behavior of the rescan command to automatically register
|
|
||||||
for notifications about transactions paying to rescanned addresses
|
|
||||||
or spending outputs from the final rescan utxo set when the rescan
|
|
||||||
is through the best block in the chain
|
|
||||||
- btcctl utility changes:
|
|
||||||
- Make the list of commands available via the -l option rather than
|
|
||||||
dumping the entire list on usage errors
|
|
||||||
- Alphabetize and categorize the list of commands by chain and wallet
|
|
||||||
- Make the help option only show the help options instead of also
|
|
||||||
dumping all of the commands
|
|
||||||
- Make the usage syntax much more consistent and correct a few cases of
|
|
||||||
misnamed fields
|
|
||||||
(https://github.com/btcsuite/btcd/issues/305)
|
|
||||||
- Improve usage errors to show the specific parameter number, reason,
|
|
||||||
and error code
|
|
||||||
- Only show the usage for specific command is shown when a valid command
|
|
||||||
is provided with invalid parameters
|
|
||||||
- Add support for a SOCK5 proxy
|
|
||||||
- Modify output for integer fields (such as timestamps) to display
|
|
||||||
normally instead in scientific notation
|
|
||||||
- Add invalidateblock command
|
|
||||||
- Add reconsiderblock command
|
|
||||||
- Add createnewaccount command
|
|
||||||
- Add renameaccount command
|
|
||||||
- Add searchrawtransactions command
|
|
||||||
- Add importaddress command
|
|
||||||
- Add importpubkey command
|
|
||||||
- showblock utility changes:
|
|
||||||
- Remove utility in favor of the RPC getblock method
|
|
||||||
- Notable developer-related package changes:
|
|
||||||
- Many of the core packages have been relocated into the btcd repository
|
|
||||||
(https://github.com/btcsuite/btcd/issues/214)
|
|
||||||
- A new version of the btcjson package that has been completely
|
|
||||||
redesigned from the ground up based based upon how the project has
|
|
||||||
evolved and lessons learned while using it since it was first written
|
|
||||||
is now available in the btcjson/v2/btcjson directory
|
|
||||||
- This will ultimately replace the current version so anyone making
|
|
||||||
use of this package will need to update their code accordingly
|
|
||||||
- The btcec package now provides better facilities for working directly
|
|
||||||
with its public and private keys without having to mix elements from
|
|
||||||
the ecdsa package
|
|
||||||
- Update the script builder to ensure all rules specified by BIP0062 are
|
|
||||||
adhered to when creating scripts
|
|
||||||
- The blockchain package now provides a MedianTimeSource interface and
|
|
||||||
concrete implementation for providing time samples from remote peers
|
|
||||||
and using that data to calculate an offset against the local time
|
|
||||||
- Misc changes:
|
|
||||||
- Fix a slow memory leak due to tickers not being stopped
|
|
||||||
(https://github.com/btcsuite/btcd/issues/189)
|
|
||||||
- Fix an issue where a mix of orphans and SPV clients could trigger a
|
|
||||||
condition where peers would no longer be served
|
|
||||||
(https://github.com/btcsuite/btcd/issues/231)
|
|
||||||
- The RPC username and password can now contain symbols which previously
|
|
||||||
conflicted with special symbols used in URLs
|
|
||||||
- Improve handling of obtaining random nonces to prevent cases where it
|
|
||||||
could error when not enough entropy was available
|
|
||||||
- Improve handling of home directory creation errors such as in the case
|
|
||||||
of unmounted symlinks (https://github.com/btcsuite/btcd/issues/193)
|
|
||||||
- Improve the error reporting for rejected transactions to include the
|
|
||||||
inputs which are missing and/or being double spent
|
|
||||||
- Update sample config file with new options and correct a comment
|
|
||||||
regarding the fact the RPC server only listens on localhost by default
|
|
||||||
(https://github.com/btcsuite/btcd/issues/218)
|
|
||||||
- Update the continuous integration builds to run several tools which
|
|
||||||
help keep code quality high
|
|
||||||
- Significant amount of internal code cleanup and improvements
|
|
||||||
- Other minor internal optimizations
|
|
||||||
- Code Contributors (alphabetical order):
|
|
||||||
- Beldur
|
|
||||||
- Ben Holden-Crowther
|
|
||||||
- Dave Collins
|
|
||||||
- David Evans
|
|
||||||
- David Hill
|
|
||||||
- Guilherme Salgado
|
|
||||||
- Javed Khan
|
|
||||||
- Jimmy Song
|
|
||||||
- John C. Vernaleo
|
|
||||||
- Jonathan Gillham
|
|
||||||
- Josh Rickmar
|
|
||||||
- Michael Ford
|
|
||||||
- Michail Kargakis
|
|
||||||
- kac
|
|
||||||
- Olaoluwa Osuntokun
|
|
||||||
|
|
||||||
Changes in 0.9.0 (Sat Sep 20 2014)
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- Add a new checkpoint at block height 319400
|
|
||||||
- Add support for BIP0037 bloom filters
|
|
||||||
(https://github.com/conformal/btcd/issues/132)
|
|
||||||
- Implement BIP0061 reject handling and hence support for protocol
|
|
||||||
version 70002 (https://github.com/conformal/btcd/issues/133)
|
|
||||||
- Add testnet DNS seeds for peer discovery (testnet-seed.alexykot.me
|
|
||||||
and testnet-seed.bitcoin.schildbach.de)
|
|
||||||
- Add mainnet DNS seed for peer discovery (seeds.bitcoin.open-nodes.org)
|
|
||||||
- Make multisig transactions with non-null dummy data nonstandard
|
|
||||||
(https://github.com/conformal/btcd/issues/131)
|
|
||||||
- Make transactions with an excessive number of signature operations
|
|
||||||
nonstandard
|
|
||||||
- Perform initial DNS lookups concurrently which allows connections
|
|
||||||
more quickly
|
|
||||||
- Improve the address manager to significantly reduce memory usage and
|
|
||||||
add tests
|
|
||||||
- Remove orphan transactions when they appear in a mined block
|
|
||||||
(https://github.com/conformal/btcd/issues/166)
|
|
||||||
- Apply incremental back off on connection retries for persistent peers
|
|
||||||
that give invalid replies to mirror the logic used for failed
|
|
||||||
connections (https://github.com/conformal/btcd/issues/103)
|
|
||||||
- Correct rate-limiting of free and low-fee transactions
|
|
||||||
- Mining support changes:
|
|
||||||
- Implement getblocktemplate RPC with the following support:
|
|
||||||
(https://github.com/conformal/btcd/issues/124)
|
|
||||||
- BIP0022 Non-Optional Sections
|
|
||||||
- BIP0022 Long Polling
|
|
||||||
- BIP0023 Basic Pool Extensions
|
|
||||||
- BIP0023 Mutation coinbase/append
|
|
||||||
- BIP0023 Mutations time, time/increment, and time/decrement
|
|
||||||
- BIP0023 Mutation transactions/add
|
|
||||||
- BIP0023 Mutations prevblock, coinbase, and generation
|
|
||||||
- BIP0023 Block Proposals
|
|
||||||
- Implement built-in concurrent CPU miner
|
|
||||||
(https://github.com/conformal/btcd/issues/137)
|
|
||||||
NOTE: CPU mining on mainnet is pointless. This has been provided
|
|
||||||
for testing purposes such as for the new simulation test network
|
|
||||||
- Add --generate flag to enable CPU mining
|
|
||||||
- Deprecate the --getworkkey flag in favor of --miningaddr which
|
|
||||||
specifies which addresses generated blocks will choose from to pay
|
|
||||||
the subsidy to
|
|
||||||
- RPC changes:
|
|
||||||
- Implement gettxout command
|
|
||||||
(https://github.com/conformal/btcd/issues/141)
|
|
||||||
- Implement validateaddress command
|
|
||||||
- Implement verifymessage command
|
|
||||||
- Mark getunconfirmedbalance RPC as wallet-only
|
|
||||||
- Mark getwalletinfo RPC as wallet-only
|
|
||||||
- Update getgenerate, setgenerate, gethashespersec, and getmininginfo
|
|
||||||
to return the appropriate information about new CPU mining status
|
|
||||||
- Modify getpeerinfo pingtime and pingwait field types to float64 so
|
|
||||||
they are compatible
|
|
||||||
- Improve disconnect handling for normal HTTP clients
|
|
||||||
- Make error code returns for invalid hex more consistent
|
|
||||||
- Websocket changes:
|
|
||||||
- Switch to a new more efficient websocket package
|
|
||||||
(https://github.com/conformal/btcd/issues/134)
|
|
||||||
- Add rescanfinished notification
|
|
||||||
- Modify the rescanprogress notification to include block hash as well
|
|
||||||
as height (https://github.com/conformal/btcd/issues/151)
|
|
||||||
- btcctl utility changes:
|
|
||||||
- Accept --simnet flag which automatically selects the appropriate port
|
|
||||||
and TLS certificates needed to communicate with btcd and btcwallet on
|
|
||||||
the simulation test network
|
|
||||||
- Fix createrawtransaction command to send amounts denominated in BTC
|
|
||||||
- Add estimatefee command
|
|
||||||
- Add estimatepriority command
|
|
||||||
- Add getmininginfo command
|
|
||||||
- Add getnetworkinfo command
|
|
||||||
- Add gettxout command
|
|
||||||
- Add lockunspent command
|
|
||||||
- Add signrawtransaction command
|
|
||||||
- addblock utility changes:
|
|
||||||
- Accept --simnet flag which automatically selects the appropriate port
|
|
||||||
and TLS certificates needed to communicate with btcd and btcwallet on
|
|
||||||
the simulation test network
|
|
||||||
- Notable developer-related package changes:
|
|
||||||
- Provide a new bloom package in btcutil which allows creating and
|
|
||||||
working with BIP0037 bloom filters
|
|
||||||
- Provide a new hdkeychain package in btcutil which allows working with
|
|
||||||
BIP0032 hierarchical deterministic key chains
|
|
||||||
- Introduce a new btcnet package which houses network parameters
|
|
||||||
- Provide new simnet network (--simnet) which is useful for private
|
|
||||||
simulation testing
|
|
||||||
- Enforce low S values in serialized signatures as detailed in BIP0062
|
|
||||||
- Return errors from all methods on the btcdb.Db interface
|
|
||||||
(https://github.com/conformal/btcdb/issues/5)
|
|
||||||
- Allow behavior flags to alter btcchain.ProcessBlock
|
|
||||||
(https://github.com/conformal/btcchain/issues/5)
|
|
||||||
- Provide a new SerializeSize API for blocks
|
|
||||||
(https://github.com/conformal/btcwire/issues/19)
|
|
||||||
- Several of the core packages now work with Google App Engine
|
|
||||||
- Misc changes:
|
|
||||||
- Correct an issue where the database could corrupt under certain
|
|
||||||
circumstances which would require a new chain download
|
|
||||||
- Slightly optimize deserialization
|
|
||||||
- Use the correct IP block for he.net
|
|
||||||
- Fix an issue where it was possible the block manager could hang on
|
|
||||||
shutdown
|
|
||||||
- Update sample config file so the comments are on a separate line
|
|
||||||
rather than the end of a line so they are not interpreted as settings
|
|
||||||
(https://github.com/conformal/btcd/issues/135)
|
|
||||||
- Correct an issue where getdata requests were not being properly
|
|
||||||
throttled which could lead to larger than necessary memory usage
|
|
||||||
- Always show help when given the help flag even when the config file
|
|
||||||
contains invalid entries
|
|
||||||
- General code cleanup and minor optimizations
|
|
||||||
|
|
||||||
Changes in 0.8.0-beta (Sun May 25 2014)
|
|
||||||
- Btcd is now Beta (https://github.com/conformal/btcd/issues/130)
|
|
||||||
- Add a new checkpoint at block height 300255
|
|
||||||
- Protocol and network related changes:
|
|
||||||
- Lower the minimum transaction relay fee to 1000 satoshi to match
|
|
||||||
recent reference client changes
|
|
||||||
(https://github.com/conformal/btcd/issues/100)
|
|
||||||
- Raise the maximum signature script size to support standard 15-of-15
|
|
||||||
multi-signature pay-to-sript-hash transactions with compressed pubkeys
|
|
||||||
to remain compatible with the reference client
|
|
||||||
(https://github.com/conformal/btcd/issues/128)
|
|
||||||
- Reduce max bytes allowed for a standard nulldata transaction to 40 for
|
|
||||||
compatibility with the reference client
|
|
||||||
- Introduce a new btcnet package which houses all of the network params
|
|
||||||
for each network (mainnet, testnet3, regtest) to ultimately enable
|
|
||||||
easier addition and tweaking of networks without needing to change
|
|
||||||
several packages
|
|
||||||
- Fix several script discrepancies found by reference client test data
|
|
||||||
- Add new DNS seed for peer discovery (seed.bitnodes.io)
|
|
||||||
- Reduce the max known inventory cache from 20000 items to 1000 items
|
|
||||||
- Fix an issue where unknown inventory types could lead to a hung peer
|
|
||||||
- Implement inventory rebroadcast handler for sendrawtransaction
|
|
||||||
(https://github.com/conformal/btcd/issues/99)
|
|
||||||
- Update user agent to fully support BIP0014
|
|
||||||
(https://github.com/conformal/btcwire/issues/10)
|
|
||||||
- Implement initial mining support:
|
|
||||||
- Add a new logging subsystem for mining related operations
|
|
||||||
- Implement infrastructure for creating block templates
|
|
||||||
- Provide options to control block template creation settings
|
|
||||||
- Support the getwork RPC
|
|
||||||
- Allow address identifiers to apply to more than one network since both
|
|
||||||
testnet3 and the regression test network unfortunately use the same
|
|
||||||
identifier
|
|
||||||
- RPC changes:
|
|
||||||
- Set the content type for HTTP POST RPC connections to application/json
|
|
||||||
(https://github.com/conformal/btcd/issues/121)
|
|
||||||
- Modified the RPC server startup so it only requires at least one valid
|
|
||||||
listen interface
|
|
||||||
- Correct an error path where it was possible certain errors would not
|
|
||||||
be returned
|
|
||||||
- Implement getwork command
|
|
||||||
(https://github.com/conformal/btcd/issues/125)
|
|
||||||
- Update sendrawtransaction command to reject orphans
|
|
||||||
- Update sendrawtransaction command to include the reason a transaction
|
|
||||||
was rejected
|
|
||||||
- Update getinfo command to populate connection count field
|
|
||||||
- Update getinfo command to include relay fee field
|
|
||||||
(https://github.com/conformal/btcd/issues/107)
|
|
||||||
- Allow transactions submitted with sendrawtransaction to bypass the
|
|
||||||
rate limiter
|
|
||||||
- Allow the getcurrentnet and getbestblock extensions to be accessed via
|
|
||||||
HTTP POST in addition to Websockets
|
|
||||||
(https://github.com/conformal/btcd/issues/127)
|
|
||||||
- Websocket changes:
|
|
||||||
- Rework notifications to ensure they are delivered in the order they
|
|
||||||
occur
|
|
||||||
- Rename notifynewtxs command to notifyreceived (funds received)
|
|
||||||
- Rename notifyallnewtxs command to notifynewtransactions
|
|
||||||
- Rename alltx notification to txaccepted
|
|
||||||
- Rename allverbosetx notification to txacceptedverbose
|
|
||||||
(https://github.com/conformal/btcd/issues/98)
|
|
||||||
- Add rescan progress notification
|
|
||||||
- Add recvtx notification
|
|
||||||
- Add redeemingtx notification
|
|
||||||
- Modify notifyspent command to accept an array of outpoints
|
|
||||||
(https://github.com/conformal/btcd/issues/123)
|
|
||||||
- Significantly optimize the rescan command to yield up to a 60x speed
|
|
||||||
increase
|
|
||||||
- btcctl utility changes:
|
|
||||||
- Add createencryptedwallet command
|
|
||||||
- Add getblockchaininfo command
|
|
||||||
- Add importwallet command
|
|
||||||
- Add addmultisigaddress command
|
|
||||||
- Add setgenerate command
|
|
||||||
- Accept --testnet and --wallet flags which automatically select
|
|
||||||
the appropriate port and TLS certificates needed to communicate
|
|
||||||
with btcd and btcwallet (https://github.com/conformal/btcd/issues/112)
|
|
||||||
- Allow path expansion from config file entries
|
|
||||||
(https://github.com/conformal/btcd/issues/113)
|
|
||||||
- Minor refactor simplify handling of options
|
|
||||||
- addblock utility changes:
|
|
||||||
- Improve logging by making it consistent with the logging provided by
|
|
||||||
btcd (https://github.com/conformal/btcd/issues/90)
|
|
||||||
- Improve several package APIs for developers:
|
|
||||||
- Add new amount type for consistently handling monetary values
|
|
||||||
- Add new coin selector API
|
|
||||||
- Add new WIF (Wallet Import Format) API
|
|
||||||
- Add new crypto types for private keys and signatures
|
|
||||||
- Add new API to sign transactions including script merging and hash
|
|
||||||
types
|
|
||||||
- Expose function to extract all pushed data from a script
|
|
||||||
(https://github.com/conformal/btcscript/issues/8)
|
|
||||||
- Misc changes:
|
|
||||||
- Optimize address manager shuffling to do 67% less work on average
|
|
||||||
- Resolve a couple of benign data races found by the race detector
|
|
||||||
(https://github.com/conformal/btcd/issues/101)
|
|
||||||
- Add IP address to all peer related errors to clarify which peer is the
|
|
||||||
cause (https://github.com/conformal/btcd/issues/102)
|
|
||||||
- Fix a UPNP case issue that prevented the --upnp option from working
|
|
||||||
with some UPNP servers
|
|
||||||
- Update documentation in the sample config file regarding debug levels
|
|
||||||
- Adjust some logging levels to improve debug messages
|
|
||||||
- Improve the throughput of query messages to the block manager
|
|
||||||
- Several minor optimizations to reduce GC churn and enhance speed
|
|
||||||
- Other minor refactoring
|
|
||||||
- General code cleanup
|
|
||||||
|
|
||||||
Changes in 0.7.0 (Thu Feb 20 2014)
|
|
||||||
- Fix an issue when parsing scripts which contain a multi-signature script
|
|
||||||
which require zero signatures such as testnet block
|
|
||||||
000000001881dccfeda317393c261f76d09e399e15e27d280e5368420f442632
|
|
||||||
(https://github.com/conformal/btcscript/issues/7)
|
|
||||||
- Add check to ensure all transactions accepted to mempool only contain
|
|
||||||
canonical data pushes (https://github.com/conformal/btcscript/issues/6)
|
|
||||||
- Fix an issue causing excessive memory consumption
|
|
||||||
- Significantly rework and improve the websocket notification system:
|
|
||||||
- Each client is now independent so slow clients no longer limit the
|
|
||||||
speed of other connected clients
|
|
||||||
- Potentially long-running operations such as rescans are now run in
|
|
||||||
their own handler and rate-limited to one operation at a time without
|
|
||||||
preventing simultaneous requests from the same client for the faster
|
|
||||||
requests or notifications
|
|
||||||
- A couple of scenarios which could cause shutdown to hang have been
|
|
||||||
resolved
|
|
||||||
- Update notifynewtx notifications to support all address types instead
|
|
||||||
of only pay-to-pubkey-hash
|
|
||||||
- Provide a --rpcmaxwebsockets option to allow limiting the number of
|
|
||||||
concurrent websocket clients
|
|
||||||
- Add a new websocket command notifyallnewtxs to request notifications
|
|
||||||
(https://github.com/conformal/btcd/issues/86) (thanks @flammit)
|
|
||||||
- Improve btcctl utility in the following ways:
|
|
||||||
- Add getnetworkhashps command
|
|
||||||
- Add gettransaction command (wallet-specific)
|
|
||||||
- Add signmessage command (wallet-specific)
|
|
||||||
- Update getwork command to accept
|
|
||||||
- Continue cleanup and work on implementing the RPC API:
|
|
||||||
- Implement getnettotals command
|
|
||||||
(https://github.com/conformal/btcd/issues/84)
|
|
||||||
- Implement networkhashps command
|
|
||||||
(https://github.com/conformal/btcd/issues/87)
|
|
||||||
- Update getpeerinfo to always include syncnode field even when false
|
|
||||||
- Remove help addenda for getpeerinfo now that it supports all fields
|
|
||||||
- Close standard RPC connections on auth failure
|
|
||||||
- Provide a --rpcmaxclients option to allow limiting the number of
|
|
||||||
concurrent RPC clients (https://github.com/conformal/btcd/issues/68)
|
|
||||||
- Include IP address in RPC auth failure log messages
|
|
||||||
- Resolve a rather harmless data races found by the race detector
|
|
||||||
(https://github.com/conformal/btcd/issues/94)
|
|
||||||
- Increase block priority size and max standard transaction size to 50k
|
|
||||||
and 100k, respectively (https://github.com/conformal/btcd/issues/71)
|
|
||||||
- Add rate limiting of free transactions to the memory pool to prevent
|
|
||||||
penny flooding (https://github.com/conformal/btcd/issues/40)
|
|
||||||
- Provide a --logdir option (https://github.com/conformal/btcd/issues/95)
|
|
||||||
- Change the default log file path to include the network
|
|
||||||
- Add a new ScriptBuilder interface to btcscript to support creation of
|
|
||||||
custom scripts (https://github.com/conformal/btcscript/issues/5)
|
|
||||||
- General code cleanup
|
|
||||||
|
|
||||||
Changes in 0.6.0 (Tue Feb 04 2014)
|
|
||||||
- Fix an issue when parsing scripts which contain invalid signatures that
|
|
||||||
caused a chain fork on block
|
|
||||||
0000000000000001e4241fd0b3469a713f41c5682605451c05d3033288fb2244
|
|
||||||
- Correct an issue which could lead to an error in removeBlockNode
|
|
||||||
(https://github.com/conformal/btcchain/issues/4)
|
|
||||||
- Improve addblock utility as follows:
|
|
||||||
- Check imported blocks against all chain rules and checkpoints
|
|
||||||
- Skip blocks which are already known so you can stop and restart the
|
|
||||||
import or start the import after you have already downloaded a portion
|
|
||||||
of the chain
|
|
||||||
- Correct an issue where the utility did not shutdown cleanly after
|
|
||||||
processing all blocks
|
|
||||||
- Add error on attempt to import orphan blocks
|
|
||||||
- Improve error handling and reporting
|
|
||||||
- Display statistics after input file has been fully processed
|
|
||||||
- Rework, optimize, and improve headers-first mode:
|
|
||||||
- Resuming the chain sync from any point before the final checkpoint
|
|
||||||
will now use headers-first mode
|
|
||||||
(https://github.com/conformal/btcd/issues/69)
|
|
||||||
- Verify all checkpoints as opposed to only the final one
|
|
||||||
- Reduce and bound memory usage
|
|
||||||
- Rollback to the last known good point when a header does not match a
|
|
||||||
checkpoint
|
|
||||||
- Log information about what is happening with headers
|
|
||||||
- Improve btcctl utility in the following ways:
|
|
||||||
- Add getaddednodeinfo command
|
|
||||||
- Add getnettotals command
|
|
||||||
- Add getblocktemplate command (wallet-specific)
|
|
||||||
- Add getwork command (wallet-specific)
|
|
||||||
- Add getnewaddress command (wallet-specific)
|
|
||||||
- Add walletpassphrasechange command (wallet-specific)
|
|
||||||
- Add walletlock command (wallet-specific)
|
|
||||||
- Add sendfrom command (wallet-specific)
|
|
||||||
- Add sendmany command (wallet-specific)
|
|
||||||
- Add settxfee command (wallet-specific)
|
|
||||||
- Add listsinceblock command (wallet-specific)
|
|
||||||
- Add listaccounts command (wallet-specific)
|
|
||||||
- Add keypoolrefill command (wallet-specific)
|
|
||||||
- Add getreceivedbyaccount command (wallet-specific)
|
|
||||||
- Add getrawchangeaddress command (wallet-specific)
|
|
||||||
- Add gettxoutsetinfo command (wallet-specific)
|
|
||||||
- Add listaddressgroupings command (wallet-specific)
|
|
||||||
- Add listlockunspent command (wallet-specific)
|
|
||||||
- Add listlock command (wallet-specific)
|
|
||||||
- Add listreceivedbyaccount command (wallet-specific)
|
|
||||||
- Add validateaddress command (wallet-specific)
|
|
||||||
- Add verifymessage command (wallet-specific)
|
|
||||||
- Add sendtoaddress command (wallet-specific)
|
|
||||||
- Continue cleanup and work on implementing the RPC API:
|
|
||||||
- Implement submitblock command
|
|
||||||
(https://github.com/conformal/btcd/issues/61)
|
|
||||||
- Implement help command
|
|
||||||
- Implement ping command
|
|
||||||
- Implement getaddednodeinfo command
|
|
||||||
(https://github.com/conformal/btcd/issues/78)
|
|
||||||
- Implement getinfo command
|
|
||||||
- Update getpeerinfo to support bytesrecv and bytessent
|
|
||||||
(https://github.com/conformal/btcd/issues/83)
|
|
||||||
- Improve and correct several RPC server and websocket areas:
|
|
||||||
- Change the connection endpoint for websockets from /wallet to /ws
|
|
||||||
(https://github.com/conformal/btcd/issues/80)
|
|
||||||
- Implement an alternative authentication for websockets so clients
|
|
||||||
such as javascript from browsers that don't support setting HTTP
|
|
||||||
headers can authenticate (https://github.com/conformal/btcd/issues/77)
|
|
||||||
- Add an authentication deadline for RPC connections
|
|
||||||
(https://github.com/conformal/btcd/issues/68)
|
|
||||||
- Use standard authentication failure responses for RPC connections
|
|
||||||
- Make automatically generated certificate more standard so it works
|
|
||||||
from client such as node.js and Firefox
|
|
||||||
- Correct some minor issues which could prevent the RPC server from
|
|
||||||
shutting down in an orderly fashion
|
|
||||||
- Make all websocket notifications require registration
|
|
||||||
- Change the data sent over websockets to text since it is JSON-RPC
|
|
||||||
- Allow connections that do not have an Origin header set
|
|
||||||
- Expose and track the number of bytes read and written per peer
|
|
||||||
(https://github.com/conformal/btcwire/issues/6)
|
|
||||||
- Correct an issue with sendrawtransaction when invoked via websockets
|
|
||||||
which prevented a minedtx notification from being added
|
|
||||||
- Rescan operations issued from remote wallets are no stopped when
|
|
||||||
the wallet disconnects mid-operation
|
|
||||||
(https://github.com/conformal/btcd/issues/66)
|
|
||||||
- Several optimizations related to fetching block information from the
|
|
||||||
database
|
|
||||||
- General code cleanup
|
|
||||||
|
|
||||||
Changes in 0.5.0 (Mon Jan 13 2014)
|
|
||||||
- Optimize initial block download by introducing a new mode which
|
|
||||||
downloads the block headers first (up to the final checkpoint)
|
|
||||||
- Improve peer handling to remove the potential for slow peers to cause
|
|
||||||
sluggishness amongst all peers
|
|
||||||
(https://github.com/conformal/btcd/issues/63)
|
|
||||||
- Fix an issue where the initial block sync could stall when the sync peer
|
|
||||||
disconnects (https://github.com/conformal/btcd/issues/62)
|
|
||||||
- Correct an issue where --externalip was doing a DNS lookup on the full
|
|
||||||
host:port instead of just the host portion
|
|
||||||
(https://github.com/conformal/btcd/issues/38)
|
|
||||||
- Fix an issue which could lead to a panic on chain switches
|
|
||||||
(https://github.com/conformal/btcd/issues/70)
|
|
||||||
- Improve btcctl utility in the following ways:
|
|
||||||
- Show getdifficulty output as floating point to 6 digits of precision
|
|
||||||
- Show all JSON object replies formatted as standard JSON
|
|
||||||
- Allow btcctl getblock to accept optional params
|
|
||||||
- Add getaccount command (wallet-specific)
|
|
||||||
- Add getaccountaddress command (wallet-specific)
|
|
||||||
- Add sendrawtransaction command
|
|
||||||
- Continue cleanup and work on implementing RPC API calls
|
|
||||||
- Update getrawmempool to support new optional verbose flag
|
|
||||||
- Update getrawtransaction to match the reference client
|
|
||||||
- Update getblock to support new optional verbose flag
|
|
||||||
- Update raw transactions to fully match the reference client including
|
|
||||||
support for all transaction types and address types
|
|
||||||
- Correct getrawmempool fee field to return BTC instead of Satoshi
|
|
||||||
- Correct getpeerinfo service flag to return 8 digit string so it
|
|
||||||
matches the reference client
|
|
||||||
- Correct verifychain to return a boolean
|
|
||||||
- Implement decoderawtransaction command
|
|
||||||
- Implement createrawtransaction command
|
|
||||||
- Implement decodescript command
|
|
||||||
- Implement gethashespersec command
|
|
||||||
- Allow RPC handler overrides when invoked via a websocket versus
|
|
||||||
legacy connection
|
|
||||||
- Add new DNS seed for peer discovery
|
|
||||||
- Display user agent on new valid peer log message
|
|
||||||
(https://github.com/conformal/btcd/issues/64)
|
|
||||||
- Notify wallet when new transactions that pay to registered addresses
|
|
||||||
show up in the mempool before being mined into a block
|
|
||||||
- Support a tor-specific proxy in addition to a normal proxy
|
|
||||||
(https://github.com/conformal/btcd/issues/47)
|
|
||||||
- Remove deprecated sqlite3 imports from utilities
|
|
||||||
- Remove leftover profile write from addblock utility
|
|
||||||
- Quite a bit of code cleanup and refactoring to improve maintainability
|
|
||||||
|
|
||||||
Changes in 0.4.0 (Thu Dec 12 2013)
|
|
||||||
- Allow listen interfaces to be specified via --listen instead of only the
|
|
||||||
port (https://github.com/conformal/btcd/issues/33)
|
|
||||||
- Allow listen interfaces for the RPC server to be specified via
|
|
||||||
--rpclisten instead of only the port
|
|
||||||
(https://github.com/conformal/btcd/issues/34)
|
|
||||||
- Only disable listening when --connect or --proxy are used when no
|
|
||||||
--listen interface are specified
|
|
||||||
(https://github.com/conformal/btcd/issues/10)
|
|
||||||
- Add several new standard transaction checks to transaction memory pool:
|
|
||||||
- Support nulldata scripts as standard
|
|
||||||
- Only allow a max of one nulldata output per transaction
|
|
||||||
- Enforce a maximum of 3 public keys in multi-signature transactions
|
|
||||||
- The number of signatures in multi-signature transactions must not
|
|
||||||
exceed the number of public keys
|
|
||||||
- The number of inputs to a signature script must match the expected
|
|
||||||
number of inputs for the script type
|
|
||||||
- The number of inputs pushed onto the stack by a redeeming signature
|
|
||||||
script must match the number of inputs consumed by the referenced
|
|
||||||
public key script
|
|
||||||
- When a block is connected, remove any transactions from the memory pool
|
|
||||||
which are now double spends as a result of the newly connected
|
|
||||||
transactions
|
|
||||||
- Don't relay transactions resurrected during a chain switch since
|
|
||||||
other peers will also be switching chains and therefore already know
|
|
||||||
about them
|
|
||||||
- Cleanup a few cases where rejected transactions showed as an error
|
|
||||||
rather than as a rejected transaction
|
|
||||||
- Ignore the default configuration file when --regtest (regression test
|
|
||||||
mode) is specified
|
|
||||||
- Implement TLS support for RPC including automatic certificate generation
|
|
||||||
- Support HTTP authentication headers for web sockets
|
|
||||||
- Update address manager to recognize and properly work with Tor
|
|
||||||
addresses (https://github.com/conformal/btcd/issues/36) and
|
|
||||||
(https://github.com/conformal/btcd/issues/37)
|
|
||||||
- Improve btcctl utility in the following ways:
|
|
||||||
- Add the ability to specify a configuration file
|
|
||||||
- Add a default entry for the RPC cert to point to the location
|
|
||||||
it will likely be in the btcd home directory
|
|
||||||
- Implement --version flag
|
|
||||||
- Provide a --notls option to support non-TLS configurations
|
|
||||||
- Fix a couple of minor races found by the Go race detector
|
|
||||||
- Improve logging
|
|
||||||
- Allow logging level to be specified on a per subsystem basis
|
|
||||||
(https://github.com/conformal/btcd/issues/48)
|
|
||||||
- Allow logging levels to be dynamically changed via RPC
|
|
||||||
(https://github.com/conformal/btcd/issues/15)
|
|
||||||
- Implement a rolling log file with a max of 10MB per file and a
|
|
||||||
rotation size of 3 which results in a max logging size of 30 MB
|
|
||||||
- Correct a minor issue with the rescanning websocket call
|
|
||||||
(https://github.com/conformal/btcd/issues/54)
|
|
||||||
- Fix a race with pushing address messages that could lead to a panic
|
|
||||||
(https://github.com/conformal/btcd/issues/58)
|
|
||||||
- Improve which external IP address is reported to peers based on which
|
|
||||||
interface they are connected through
|
|
||||||
(https://github.com/conformal/btcd/issues/35)
|
|
||||||
- Add --externalip option to allow an external IP address to be specified
|
|
||||||
for cases such as tor hidden services or advanced network configurations
|
|
||||||
(https://github.com/conformal/btcd/issues/38)
|
|
||||||
- Add --upnp option to support automatic port mapping via UPnP
|
|
||||||
(https://github.com/conformal/btcd/issues/51)
|
|
||||||
- Update Ctrl+C interrupt handler to properly sync address manager and
|
|
||||||
remove the UPnP port mapping (if needed)
|
|
||||||
- Continue cleanup and work on implementing RPC API calls
|
|
||||||
- Add importprivkey (import private key) command to btcctl
|
|
||||||
- Update getrawtransaction to provide addresses properly, support
|
|
||||||
new verbose param, and match the reference implementation with the
|
|
||||||
exception of MULTISIG (thanks @flammit)
|
|
||||||
- Update getblock with new verbose flag (thanks @flammit)
|
|
||||||
- Add listtransactions command to btcctl
|
|
||||||
- Add getbalance command to btcctl
|
|
||||||
- Add basic support for btcd to run as a native Windows service
|
|
||||||
(https://github.com/conformal/btcd/issues/42)
|
|
||||||
- Package addblock utility with Windows MSIs
|
|
||||||
- Add support for TravisCI (continuous build integration)
|
|
||||||
- Cleanup some documentation and usage
|
|
||||||
- Several other minor bug fixes and general code cleanup
|
|
||||||
|
|
||||||
Changes in 0.3.3 (Wed Nov 13 2013)
|
|
||||||
- Significantly improve initial block chain download speed
|
|
||||||
(https://github.com/conformal/btcd/issues/20)
|
|
||||||
- Add a new checkpoint at block height 267300
|
|
||||||
- Optimize most recently used inventory handling
|
|
||||||
(https://github.com/conformal/btcd/issues/21)
|
|
||||||
- Optimize duplicate transaction input check
|
|
||||||
(https://github.com/conformal/btcchain/issues/2)
|
|
||||||
- Optimize transaction hashing
|
|
||||||
(https://github.com/conformal/btcd/issues/25)
|
|
||||||
- Rework and optimize wallet listener notifications
|
|
||||||
(https://github.com/conformal/btcd/issues/22)
|
|
||||||
- Optimize serialization and deserialization
|
|
||||||
(https://github.com/conformal/btcd/issues/27)
|
|
||||||
- Add support for minimum transaction fee to memory pool acceptance
|
|
||||||
(https://github.com/conformal/btcd/issues/29)
|
|
||||||
- Improve leveldb database performance by removing explicit GC call
|
|
||||||
- Fix an issue where Ctrl+C was not always finishing orderly database
|
|
||||||
shutdown
|
|
||||||
- Fix an issue in the script handling for OP_CHECKSIG
|
|
||||||
- Impose max limits on all variable length protocol entries to prevent
|
|
||||||
abuse from malicious peers
|
|
||||||
- Enforce DER signatures for transactions allowed into the memory pool
|
|
||||||
- Separate the debug profile http server from the RPC server
|
|
||||||
- Rework of the RPC code to improve performance and make the code cleaner
|
|
||||||
- The getrawtransaction RPC call now properly checks the memory pool
|
|
||||||
before consulting the db (https://github.com/conformal/btcd/issues/26)
|
|
||||||
- Add support for the following RPC calls: getpeerinfo, getconnectedcount,
|
|
||||||
addnode, verifychain
|
|
||||||
(https://github.com/conformal/btcd/issues/13)
|
|
||||||
(https://github.com/conformal/btcd/issues/17)
|
|
||||||
- Implement rescan websocket extension to allow wallet rescans
|
|
||||||
- Use correct paths for application data storage for all supported
|
|
||||||
operating systems (https://github.com/conformal/btcd/issues/30)
|
|
||||||
- Add a default redirect to the http profiling page when accessing the
|
|
||||||
http profile server
|
|
||||||
- Add a new --cpuprofile option which can be used to generate CPU
|
|
||||||
profiling data on platforms that support it
|
|
||||||
- Several other minor performance optimizations
|
|
||||||
- Other minor bug fixes and general code cleanup
|
|
||||||
|
|
||||||
Changes in 0.3.2 (Tue Oct 22 2013)
|
|
||||||
- Fix an issue that could cause the download of the block chain to stall
|
|
||||||
(https://github.com/conformal/btcd/issues/12)
|
|
||||||
- Remove deprecated sqlite as an available database backend
|
|
||||||
- Close sqlite compile issue as sqlite has now been removed
|
|
||||||
(https://github.com/conformal/btcd/issues/11)
|
|
||||||
- Change default RPC ports to 8334 (mainnet) and 18334 (testnet)
|
|
||||||
- Continue cleanup and work on implementing RPC API calls
|
|
||||||
- Add support for the following RPC calls: getrawmempool,
|
|
||||||
getbestblockhash, decoderawtransaction, getdifficulty,
|
|
||||||
getconnectioncount, getpeerinfo, and addnode
|
|
||||||
- Improve the btcctl utility that is used to issue JSON-RPC commands
|
|
||||||
- Fix an issue preventing btcd from cleanly shutting down with the RPC
|
|
||||||
stop command
|
|
||||||
- Add a number of database interface tests to ensure backends implement
|
|
||||||
the expected interface
|
|
||||||
- Expose some additional information from btcscript to be used for
|
|
||||||
identifying "standard"" transactions
|
|
||||||
- Add support for plan9 - thanks @mischief
|
|
||||||
(https://github.com/conformal/btcd/pull/19)
|
|
||||||
- Other minor bug fixes and general code cleanup
|
|
||||||
|
|
||||||
Changes in 0.3.1-alpha (Tue Oct 15 2013)
|
|
||||||
- Change default database to leveldb
|
|
||||||
NOTE: This does mean you will have to redownload the block chain. Since we
|
|
||||||
are still in alpha, we didn't feel writing a converter was worth the time as
|
|
||||||
it would take away from more important issues at this stage
|
|
||||||
- Add a warning if there are multiple block chain databases of different types
|
|
||||||
- Fix issue with unexpected EOF in leveldb -- https://github.com/conformal/btcd/issues/18
|
|
||||||
- Fix issue preventing block 21066 on testnet -- https://github.com/conformal/btcchain/issues/1
|
|
||||||
- Fix issue preventing block 96464 on testnet -- https://github.com/conformal/btcscript/issues/1
|
|
||||||
- Optimize transaction lookups
|
|
||||||
- Correct a few cases of list removal that could result in improper cleanup
|
|
||||||
of no longer needed orphans
|
|
||||||
- Add functionality to increase ulimits on non-Windows platforms
|
|
||||||
- Add support for mempool command which allows remote peers to query the
|
|
||||||
transaction memory pool via the bitcoin protocol
|
|
||||||
- Clean up logging a bit
|
|
||||||
- Add a flag to disable checkpoints for developers
|
|
||||||
- Add a lot of useful debug logging such as message summaries
|
|
||||||
- Other minor bug fixes and general code cleanup
|
|
||||||
|
|
||||||
Initial Release 0.3.0-alpha (Sat Oct 05 2013):
|
|
||||||
- Initial release
|
|
40
Dockerfile
Normal file
40
Dockerfile
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# 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 lbcd amd64 container:
|
||||||
|
#
|
||||||
|
# docker build . -t yourregistry/lbcd
|
||||||
|
#
|
||||||
|
# You can use the following command to buid an arm64v8 container:
|
||||||
|
#
|
||||||
|
# docker build . -t yourregistry/lbcd --build-arg ARCH=arm64v8
|
||||||
|
#
|
||||||
|
# For more information how to use this docker image visit:
|
||||||
|
# https://github.com/lbryio/lbcd/tree/master/docs
|
||||||
|
#
|
||||||
|
# 9246 Mainnet LBRY peer-to-peer port
|
||||||
|
# 9245 Mainet RPC port
|
||||||
|
|
||||||
|
ARG ARCH=amd64
|
||||||
|
|
||||||
|
FROM golang:1.19 AS build-container
|
||||||
|
|
||||||
|
ARG ARCH
|
||||||
|
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set -ex \
|
||||||
|
&& if [ "${ARCH}" = "amd64" ]; then export GOARCH=amd64; fi \
|
||||||
|
&& if [ "${ARCH}" = "arm32v7" ]; then export GOARCH=arm; fi \
|
||||||
|
&& if [ "${ARCH}" = "arm64v8" ]; then export GOARCH=arm64; fi \
|
||||||
|
&& echo "Compiling for $GOARCH" \
|
||||||
|
&& go install -v . ./cmd/...
|
||||||
|
|
||||||
|
FROM $ARCH/debian:bullseye-20220418-slim
|
||||||
|
|
||||||
|
COPY --from=build-container /go/bin /bin
|
||||||
|
|
||||||
|
VOLUME ["/root/.lbcd"]
|
||||||
|
|
||||||
|
EXPOSE 9245 9246
|
||||||
|
|
||||||
|
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
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2021 The LBRY developers
|
||||||
Copyright (c) 2013-2017 The btcsuite developers
|
Copyright (c) 2013-2017 The btcsuite developers
|
||||||
Copyright (c) 2015-2016 The Decred developers
|
Copyright (c) 2015-2016 The Decred developers
|
||||||
|
|
||||||
|
|
369
README.md
369
README.md
|
@ -1,130 +1,335 @@
|
||||||
btcd
|
# lbcd
|
||||||
====
|
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcd)
|
[](https://github.com/lbryio/lbcd/actions)
|
||||||
[](http://copyfree.org)
|
[](https://coveralls.io/github/lbryio/lbcd?branch=master)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd)
|
[](http://copyfree.org)
|
||||||
|
<!--[](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
|
Software stack developed by LBRY teams has been all migrated to **lbcd**.
|
||||||
is extremely stable and has been in production use since October 2013.
|
|
||||||
|
|
||||||
It properly downloads, validates, and serves the block chain using the exact
|
We're working with exchanges and pool oerators to migrate from **lbrycrd** to **lbcd**.
|
||||||
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.
|
|
||||||
|
|
||||||
It also properly relays newly mined blocks, maintains a transaction pool, and
|
If you're integrating with **lbcd+lbcwallet**, please check the Wiki for current [supported RPCs](wiki/RPC-availability).
|
||||||
relays individual transactions that have not yet made it into a block. It
|
|
||||||
ensures all individual transactions admitted to the pool follow the rules
|
|
||||||
required by the block chain and also includes more strict checks which filter
|
|
||||||
transactions based on miner requirements ("standard" transactions).
|
|
||||||
|
|
||||||
One key difference between btcd and Bitcoin Core is that btcd does *NOT* include
|
Note: **lbcd** does *NOT* include wallet functionality. That functionality is provided by the
|
||||||
wallet functionality and this was a very intentional design decision. See the
|
[lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk).
|
||||||
blog entry [here](https://blog.conformal.com/btcd-not-your-moms-bitcoin-daemon)
|
|
||||||
for more details. This means you can't actually make or receive payments
|
|
||||||
directly with btcd. That functionality is provided by the
|
|
||||||
[btcwallet](https://github.com/btcsuite/btcwallet) and
|
|
||||||
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
|
|
||||||
which are both under active development.
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
[Go](http://golang.org) 1.12 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
|
## Installation
|
||||||
|
|
||||||
#### Windows - MSI Available
|
Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases)
|
||||||
|
|
||||||
https://github.com/btcsuite/btcd/releases
|
For compilation, [Go](http://golang.org) 1.19 or newer is required.
|
||||||
|
Install Go according to its [installation instructions](http://golang.org/doc/install).
|
||||||
|
|
||||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
``` sh
|
||||||
|
# lbcd (full node)
|
||||||
|
$ go install github.com/lbryio/lbcd@latest
|
||||||
|
|
||||||
- Install Go according to the installation instructions here:
|
# lbcctl (rpc client utility)
|
||||||
http://golang.org/doc/install
|
$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest
|
||||||
|
|
||||||
- Ensure Go was installed properly and is a supported version:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go version
|
|
||||||
$ go env GOROOT GOPATH
|
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is
|
## Usage
|
||||||
recommended that `GOPATH` is set to a directory in your home directory such as
|
|
||||||
`~/goprojects` to avoid write permission issues. It is also recommended to add
|
|
||||||
`$GOPATH/bin` to your `PATH` at this point.
|
|
||||||
|
|
||||||
- Run the following commands to obtain btcd, all dependencies, and install it:
|
Default application folder `${LBCDDIR}`:
|
||||||
|
|
||||||
```bash
|
- Linux: `~/.lbcd/`
|
||||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
- MacOS: `/Users/<username>/Library/Application Support/Lbcd/`
|
||||||
$ GO111MODULE=on go install -v . ./cmd/...
|
|
||||||
|
### Start the **lbcd**
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
./lbcd
|
||||||
```
|
```
|
||||||
|
|
||||||
- btcd (and utilities) will now be installed in ```$GOPATH/bin```. If you did
|
**lbcd** loads config file at `"${LBCDDIR}/lbcd.conf"`.
|
||||||
not already add the bin directory to your system path during Go installation,
|
|
||||||
we recommend you do so now.
|
|
||||||
|
|
||||||
## 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).
|
||||||
|
|
||||||
#### Windows
|
### RPC server
|
||||||
|
|
||||||
Install a newer MSI
|
RPC credentials (`rpcuser` and `rpcpass`) is required to enable RPC server. It can be specify in the `"${LBCDDIR}/lbcd.conf"`, using command line options:
|
||||||
|
|
||||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
``` sh
|
||||||
|
./lbcd --rpcuser=rpcuser --rpcpass=rpcpass
|
||||||
|
|
||||||
- Run the following commands to update btcd, all dependencies, and install it:
|
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
|
||||||
```bash
|
|
||||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
|
||||||
$ git pull
|
|
||||||
$ GO111MODULE=on go install -v . ./cmd/...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting Started
|
### Working with TLS (Default)
|
||||||
|
|
||||||
btcd has several configuration options available to tweak how it runs, but all
|
By default, **lbcd** runs RPC server with TLS enabled, and generates the `rpc.cert` and `rpc.key` under `${LBCDDIR}`, if not exist already.
|
||||||
of the basic operations described in the intro section work with zero
|
|
||||||
configuration.
|
|
||||||
|
|
||||||
#### Windows (Installed from MSI)
|
To interact with the RPC server, a client has to either specify the `rpc.cert`, or disable the certification verification for TLS.
|
||||||
|
|
||||||
Launch btcd from your Start menu.
|
Interact with **lbcd** RPC using `lbcctl`
|
||||||
|
|
||||||
#### Linux/BSD/POSIX/Source
|
``` sh
|
||||||
|
$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount
|
||||||
|
|
||||||
```bash
|
# or disable the certificate verification
|
||||||
$ ./btcd
|
$ ./lbcctl --skipverify getblockcount
|
||||||
|
|
||||||
|
1200062
|
||||||
```
|
```
|
||||||
|
|
||||||
## IRC
|
Interact with **lbcd** RPC using `curl`
|
||||||
|
|
||||||
- irc.freenode.net
|
``` sh
|
||||||
- channel #btcd
|
$ curl --user rpcuser:rpcpass \
|
||||||
- [webchat](https://webchat.freenode.net/?channels=btcd)
|
--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)
|
``` json
|
||||||
is used for this project.
|
{"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
|
Please see our [documentation on the current build/verification
|
||||||
process](https://github.com/btcsuite/btcd/tree/master/release) for all our
|
process](https://github.com/lbryio/lbcd/tree/master/release) for all our
|
||||||
releases for information on how to verify the integrity of published releases
|
releases for information on how to verify the integrity of published releases
|
||||||
using our reproducible build system.
|
using our reproducible build system.
|
||||||
|
-->
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
btcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
lbcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||||
|
|
|
@ -23,14 +23,14 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddrManager provides a concurrency safe address manager for caching potential
|
// AddrManager provides a concurrency safe address manager for caching potential
|
||||||
// peers on the bitcoin network.
|
// peers on the bitcoin network.
|
||||||
type AddrManager struct {
|
type AddrManager struct {
|
||||||
mtx sync.Mutex
|
mtx sync.RWMutex
|
||||||
peersFile string
|
peersFile string
|
||||||
lookupFunc func(string) ([]net.IP, error)
|
lookupFunc func(string) ([]net.IP, error)
|
||||||
rand *rand.Rand
|
rand *rand.Rand
|
||||||
|
@ -45,7 +45,7 @@ type AddrManager struct {
|
||||||
nTried int
|
nTried int
|
||||||
nNew int
|
nNew int
|
||||||
lamtx sync.Mutex
|
lamtx sync.Mutex
|
||||||
localAddresses map[string]*localAddress
|
localAddresses map[string]*LocalAddress
|
||||||
version int
|
version int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,9 +69,9 @@ type serializedAddrManager struct {
|
||||||
TriedBuckets [triedBucketCount][]string
|
TriedBuckets [triedBucketCount][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type localAddress struct {
|
type LocalAddress struct {
|
||||||
na *wire.NetAddress
|
NA *wire.NetAddress
|
||||||
score AddressPriority
|
Score AddressPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddressPriority type is used to describe the hierarchy of local address
|
// AddressPriority type is used to describe the hierarchy of local address
|
||||||
|
@ -176,9 +176,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
|
||||||
// TODO: only update addresses periodically.
|
// TODO: only update addresses periodically.
|
||||||
// Update the last seen time and services.
|
// Update the last seen time and services.
|
||||||
// note that to prevent causing excess garbage on getaddr
|
// note that to prevent causing excess garbage on getaddr
|
||||||
// messages the netaddresses in addrmaanger are *immutable*,
|
// messages the netaddresses in addrmanager are *immutable*,
|
||||||
// if we need to change them then we replace the pointer with a
|
// if we need to change them then we replace the pointer with a
|
||||||
// new copy so that we don't have to copy every na for getaddr.
|
// new copy so that we don't have to copy every NA for getaddr.
|
||||||
if netAddr.Timestamp.After(ka.na.Timestamp) ||
|
if netAddr.Timestamp.After(ka.na.Timestamp) ||
|
||||||
(ka.na.Services&netAddr.Services) !=
|
(ka.na.Services&netAddr.Services) !=
|
||||||
netAddr.Services {
|
netAddr.Services {
|
||||||
|
@ -186,7 +186,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
|
||||||
naCopy := *ka.na
|
naCopy := *ka.na
|
||||||
naCopy.Timestamp = netAddr.Timestamp
|
naCopy.Timestamp = netAddr.Timestamp
|
||||||
naCopy.AddService(netAddr.Services)
|
naCopy.AddService(netAddr.Services)
|
||||||
|
ka.mtx.Lock()
|
||||||
ka.na = &naCopy
|
ka.na = &naCopy
|
||||||
|
ka.mtx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If already in tried, we have nothing to do here.
|
// If already in tried, we have nothing to do here.
|
||||||
|
@ -645,8 +647,8 @@ func (a *AddrManager) numAddresses() int {
|
||||||
|
|
||||||
// NumAddresses returns the number of addresses known to the address manager.
|
// NumAddresses returns the number of addresses known to the address manager.
|
||||||
func (a *AddrManager) NumAddresses() int {
|
func (a *AddrManager) NumAddresses() int {
|
||||||
a.mtx.Lock()
|
a.mtx.RLock()
|
||||||
defer a.mtx.Unlock()
|
defer a.mtx.RUnlock()
|
||||||
|
|
||||||
return a.numAddresses()
|
return a.numAddresses()
|
||||||
}
|
}
|
||||||
|
@ -654,8 +656,8 @@ func (a *AddrManager) NumAddresses() int {
|
||||||
// NeedMoreAddresses returns whether or not the address manager needs more
|
// NeedMoreAddresses returns whether or not the address manager needs more
|
||||||
// addresses.
|
// addresses.
|
||||||
func (a *AddrManager) NeedMoreAddresses() bool {
|
func (a *AddrManager) NeedMoreAddresses() bool {
|
||||||
a.mtx.Lock()
|
a.mtx.RLock()
|
||||||
defer a.mtx.Unlock()
|
defer a.mtx.RUnlock()
|
||||||
|
|
||||||
return a.numAddresses() < needAddressThreshold
|
return a.numAddresses() < needAddressThreshold
|
||||||
}
|
}
|
||||||
|
@ -685,8 +687,8 @@ func (a *AddrManager) AddressCache() []*wire.NetAddress {
|
||||||
// getAddresses returns all of the addresses currently found within the
|
// getAddresses returns all of the addresses currently found within the
|
||||||
// manager's address cache.
|
// manager's address cache.
|
||||||
func (a *AddrManager) getAddresses() []*wire.NetAddress {
|
func (a *AddrManager) getAddresses() []*wire.NetAddress {
|
||||||
a.mtx.Lock()
|
a.mtx.RLock()
|
||||||
defer a.mtx.Unlock()
|
defer a.mtx.RUnlock()
|
||||||
|
|
||||||
addrIndexLen := len(a.addrIndex)
|
addrIndexLen := len(a.addrIndex)
|
||||||
if addrIndexLen == 0 {
|
if addrIndexLen == 0 {
|
||||||
|
@ -753,7 +755,7 @@ func (a *AddrManager) HostToNetAddress(host string, port uint16, services wire.S
|
||||||
// the relevant .onion address.
|
// the relevant .onion address.
|
||||||
func ipString(na *wire.NetAddress) string {
|
func ipString(na *wire.NetAddress) string {
|
||||||
if IsOnionCatTor(na) {
|
if IsOnionCatTor(na) {
|
||||||
// We know now that na.IP is long enough.
|
// We know now that NA.IP is long enough.
|
||||||
base32 := base32.StdEncoding.EncodeToString(na.IP[6:])
|
base32 := base32.StdEncoding.EncodeToString(na.IP[6:])
|
||||||
return strings.ToLower(base32) + ".onion"
|
return strings.ToLower(base32) + ".onion"
|
||||||
}
|
}
|
||||||
|
@ -857,8 +859,11 @@ func (a *AddrManager) Attempt(addr *wire.NetAddress) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// set last tried time to now
|
// set last tried time to now
|
||||||
|
now := time.Now()
|
||||||
|
ka.mtx.Lock()
|
||||||
ka.attempts++
|
ka.attempts++
|
||||||
ka.lastattempt = time.Now()
|
ka.lastattempt = now
|
||||||
|
ka.mtx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connected Marks the given address as currently connected and working at the
|
// Connected Marks the given address as currently connected and working at the
|
||||||
|
@ -877,10 +882,12 @@ func (a *AddrManager) Connected(addr *wire.NetAddress) {
|
||||||
// so.
|
// so.
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if now.After(ka.na.Timestamp.Add(time.Minute * 20)) {
|
if now.After(ka.na.Timestamp.Add(time.Minute * 20)) {
|
||||||
// ka.na is immutable, so replace it.
|
// ka.NA is immutable, so replace it.
|
||||||
naCopy := *ka.na
|
naCopy := *ka.na
|
||||||
naCopy.Timestamp = time.Now()
|
naCopy.Timestamp = time.Now()
|
||||||
|
ka.mtx.Lock()
|
||||||
ka.na = &naCopy
|
ka.na = &naCopy
|
||||||
|
ka.mtx.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,11 +906,13 @@ func (a *AddrManager) Good(addr *wire.NetAddress) {
|
||||||
// ka.Timestamp is not updated here to avoid leaking information
|
// ka.Timestamp is not updated here to avoid leaking information
|
||||||
// about currently connected peers.
|
// about currently connected peers.
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
ka.mtx.Lock()
|
||||||
ka.lastsuccess = now
|
ka.lastsuccess = now
|
||||||
ka.lastattempt = now
|
ka.lastattempt = now
|
||||||
ka.attempts = 0
|
ka.attempts = 0
|
||||||
|
ka.mtx.Unlock() // tried and refs synchronized via a.mtx
|
||||||
|
|
||||||
// move to tried set, optionally evicting other addresses if neeed.
|
// move to tried set, optionally evicting other addresses if need.
|
||||||
if ka.tried {
|
if ka.tried {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -985,14 +994,16 @@ func (a *AddrManager) SetServices(addr *wire.NetAddress, services wire.ServiceFl
|
||||||
|
|
||||||
// Update the services if needed.
|
// Update the services if needed.
|
||||||
if ka.na.Services != services {
|
if ka.na.Services != services {
|
||||||
// ka.na is immutable, so replace it.
|
// ka.NA is immutable, so replace it.
|
||||||
naCopy := *ka.na
|
naCopy := *ka.na
|
||||||
naCopy.Services = services
|
naCopy.Services = services
|
||||||
|
ka.mtx.Lock()
|
||||||
ka.na = &naCopy
|
ka.na = &naCopy
|
||||||
|
ka.mtx.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLocalAddress adds na to the list of known local addresses to advertise
|
// AddLocalAddress adds NA to the list of known local addresses to advertise
|
||||||
// with the given priority.
|
// with the given priority.
|
||||||
func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error {
|
func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error {
|
||||||
if !IsRoutable(na) {
|
if !IsRoutable(na) {
|
||||||
|
@ -1004,13 +1015,13 @@ func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPrior
|
||||||
|
|
||||||
key := NetAddressKey(na)
|
key := NetAddressKey(na)
|
||||||
la, ok := a.localAddresses[key]
|
la, ok := a.localAddresses[key]
|
||||||
if !ok || la.score < priority {
|
if !ok || la.Score < priority {
|
||||||
if ok {
|
if ok {
|
||||||
la.score = priority + 1
|
la.Score = priority + 1
|
||||||
} else {
|
} else {
|
||||||
a.localAddresses[key] = &localAddress{
|
a.localAddresses[key] = &LocalAddress{
|
||||||
na: na,
|
NA: na,
|
||||||
score: priority,
|
Score: priority,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1106,12 +1117,12 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
|
||||||
var bestscore AddressPriority
|
var bestscore AddressPriority
|
||||||
var bestAddress *wire.NetAddress
|
var bestAddress *wire.NetAddress
|
||||||
for _, la := range a.localAddresses {
|
for _, la := range a.localAddresses {
|
||||||
reach := getReachabilityFrom(la.na, remoteAddr)
|
reach := getReachabilityFrom(la.NA, remoteAddr)
|
||||||
if reach > bestreach ||
|
if reach > bestreach ||
|
||||||
(reach == bestreach && la.score > bestscore) {
|
(reach == bestreach && la.Score > bestscore) {
|
||||||
bestreach = reach
|
bestreach = reach
|
||||||
bestscore = la.score
|
bestscore = la.Score
|
||||||
bestAddress = la.na
|
bestAddress = la.NA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bestAddress != nil {
|
if bestAddress != nil {
|
||||||
|
@ -1135,6 +1146,15 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
|
||||||
return bestAddress
|
return bestAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocalAddresses returns the list of local addresses for our node.
|
||||||
|
func (a *AddrManager) LocalAddresses() []*LocalAddress {
|
||||||
|
var addrs []*LocalAddress
|
||||||
|
for _, addr := range a.localAddresses {
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
}
|
||||||
|
return addrs
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new bitcoin address manager.
|
// New returns a new bitcoin address manager.
|
||||||
// Use Start to begin processing asynchronous address updates.
|
// Use Start to begin processing asynchronous address updates.
|
||||||
func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
|
func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
|
||||||
|
@ -1143,7 +1163,7 @@ func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager
|
||||||
lookupFunc: lookupFunc,
|
lookupFunc: lookupFunc,
|
||||||
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
localAddresses: make(map[string]*localAddress),
|
localAddresses: make(map[string]*LocalAddress),
|
||||||
version: serialisationVersion,
|
version: serialisationVersion,
|
||||||
}
|
}
|
||||||
am.reset()
|
am.reset()
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
|
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/addrmgr"
|
"github.com/lbryio/lbcd/addrmgr"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// naTest is used to describe a test to be performed against the NetAddressKey
|
// naTest is used to describe a test to be performed against the NetAddressKey
|
||||||
|
@ -34,61 +34,61 @@ var someIP = "173.194.115.66"
|
||||||
func addNaTests() {
|
func addNaTests() {
|
||||||
// IPv4
|
// IPv4
|
||||||
// Localhost
|
// Localhost
|
||||||
addNaTest("127.0.0.1", 8333, "127.0.0.1:8333")
|
addNaTest("127.0.0.1", 9244, "127.0.0.1:9244")
|
||||||
addNaTest("127.0.0.1", 8334, "127.0.0.1:8334")
|
addNaTest("127.0.0.1", 9245, "127.0.0.1:9245")
|
||||||
|
|
||||||
// Class A
|
// Class A
|
||||||
addNaTest("1.0.0.1", 8333, "1.0.0.1:8333")
|
addNaTest("1.0.0.1", 9244, "1.0.0.1:9244")
|
||||||
addNaTest("2.2.2.2", 8334, "2.2.2.2:8334")
|
addNaTest("2.2.2.2", 9245, "2.2.2.2:9245")
|
||||||
addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
|
addNaTest("27.253.252.251", 9246, "27.253.252.251:9246")
|
||||||
addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
|
addNaTest("123.3.2.1", 9247, "123.3.2.1:9247")
|
||||||
|
|
||||||
// Private Class A
|
// Private Class A
|
||||||
addNaTest("10.0.0.1", 8333, "10.0.0.1:8333")
|
addNaTest("10.0.0.1", 9244, "10.0.0.1:9244")
|
||||||
addNaTest("10.1.1.1", 8334, "10.1.1.1:8334")
|
addNaTest("10.1.1.1", 9245, "10.1.1.1:9245")
|
||||||
addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
|
addNaTest("10.2.2.2", 9246, "10.2.2.2:9246")
|
||||||
addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
|
addNaTest("10.10.10.10", 9247, "10.10.10.10:9247")
|
||||||
|
|
||||||
// Class B
|
// Class B
|
||||||
addNaTest("128.0.0.1", 8333, "128.0.0.1:8333")
|
addNaTest("128.0.0.1", 9244, "128.0.0.1:9244")
|
||||||
addNaTest("129.1.1.1", 8334, "129.1.1.1:8334")
|
addNaTest("129.1.1.1", 9245, "129.1.1.1:9245")
|
||||||
addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
|
addNaTest("180.2.2.2", 9246, "180.2.2.2:9246")
|
||||||
addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
|
addNaTest("191.10.10.10", 9247, "191.10.10.10:9247")
|
||||||
|
|
||||||
// Private Class B
|
// Private Class B
|
||||||
addNaTest("172.16.0.1", 8333, "172.16.0.1:8333")
|
addNaTest("172.16.0.1", 9244, "172.16.0.1:9244")
|
||||||
addNaTest("172.16.1.1", 8334, "172.16.1.1:8334")
|
addNaTest("172.16.1.1", 9245, "172.16.1.1:9245")
|
||||||
addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
|
addNaTest("172.16.2.2", 9246, "172.16.2.2:9246")
|
||||||
addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
|
addNaTest("172.16.172.172", 9247, "172.16.172.172:9247")
|
||||||
|
|
||||||
// Class C
|
// Class C
|
||||||
addNaTest("193.0.0.1", 8333, "193.0.0.1:8333")
|
addNaTest("193.0.0.1", 9244, "193.0.0.1:9244")
|
||||||
addNaTest("200.1.1.1", 8334, "200.1.1.1:8334")
|
addNaTest("200.1.1.1", 9245, "200.1.1.1:9245")
|
||||||
addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
|
addNaTest("205.2.2.2", 9246, "205.2.2.2:9246")
|
||||||
addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
|
addNaTest("223.10.10.10", 9247, "223.10.10.10:9247")
|
||||||
|
|
||||||
// Private Class C
|
// Private Class C
|
||||||
addNaTest("192.168.0.1", 8333, "192.168.0.1:8333")
|
addNaTest("192.168.0.1", 9244, "192.168.0.1:9244")
|
||||||
addNaTest("192.168.1.1", 8334, "192.168.1.1:8334")
|
addNaTest("192.168.1.1", 9245, "192.168.1.1:9245")
|
||||||
addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
|
addNaTest("192.168.2.2", 9246, "192.168.2.2:9246")
|
||||||
addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
|
addNaTest("192.168.192.192", 9247, "192.168.192.192:9247")
|
||||||
|
|
||||||
// IPv6
|
// IPv6
|
||||||
// Localhost
|
// Localhost
|
||||||
addNaTest("::1", 8333, "[::1]:8333")
|
addNaTest("::1", 9244, "[::1]:9244")
|
||||||
addNaTest("fe80::1", 8334, "[fe80::1]:8334")
|
addNaTest("fe80::1", 9245, "[fe80::1]:9245")
|
||||||
|
|
||||||
// Link-local
|
// Link-local
|
||||||
addNaTest("fe80::1:1", 8333, "[fe80::1:1]:8333")
|
addNaTest("fe80::1:1", 9244, "[fe80::1:1]:9244")
|
||||||
addNaTest("fe91::2:2", 8334, "[fe91::2:2]:8334")
|
addNaTest("fe91::2:2", 9245, "[fe91::2:2]:9245")
|
||||||
addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
|
addNaTest("fea2::3:3", 9246, "[fea2::3:3]:9246")
|
||||||
addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
|
addNaTest("feb3::4:4", 9247, "[feb3::4:4]:9247")
|
||||||
|
|
||||||
// Site-local
|
// Site-local
|
||||||
addNaTest("fec0::1:1", 8333, "[fec0::1:1]:8333")
|
addNaTest("fec0::1:1", 9244, "[fec0::1:1]:9244")
|
||||||
addNaTest("fed1::2:2", 8334, "[fed1::2:2]:8334")
|
addNaTest("fed1::2:2", 9245, "[fed1::2:2]:9245")
|
||||||
addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
|
addNaTest("fee2::3:3", 9246, "[fee2::3:3]:9246")
|
||||||
addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
|
addNaTest("fef3::4:4", 9247, "[fef3::4:4]:9247")
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNaTest(ip string, port uint16, want string) {
|
func addNaTest(ip string, port uint16, want string) {
|
||||||
|
@ -119,7 +119,7 @@ func TestAddAddressByIP(t *testing.T) {
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
someIP + ":8333",
|
someIP + ":9244",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ func TestAddAddressByIP(t *testing.T) {
|
||||||
addrErr,
|
addrErr,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
someIP[:12] + ":8333",
|
someIP[:12] + ":9244",
|
||||||
fmtErr,
|
fmtErr,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -212,7 +212,7 @@ func TestAttempt(t *testing.T) {
|
||||||
n := addrmgr.New("testattempt", lookupFunc)
|
n := addrmgr.New("testattempt", lookupFunc)
|
||||||
|
|
||||||
// Add a new address and get it
|
// Add a new address and get it
|
||||||
err := n.AddAddressByIP(someIP + ":8333")
|
err := n.AddAddressByIP(someIP + ":9244")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
t.Fatalf("Adding address failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ func TestConnected(t *testing.T) {
|
||||||
n := addrmgr.New("testconnected", lookupFunc)
|
n := addrmgr.New("testconnected", lookupFunc)
|
||||||
|
|
||||||
// Add a new address and get it
|
// Add a new address and get it
|
||||||
err := n.AddAddressByIP(someIP + ":8333")
|
err := n.AddAddressByIP(someIP + ":9244")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
t.Fatalf("Adding address failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -261,14 +261,14 @@ func TestNeedMoreAddresses(t *testing.T) {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < addrsToAdd; i++ {
|
for i := 0; i < addrsToAdd; i++ {
|
||||||
s := fmt.Sprintf("%d.%d.173.147: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)
|
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
|
||||||
|
|
||||||
n.AddAddresses(addrs, srcAddr)
|
n.AddAddresses(addrs, srcAddr)
|
||||||
numAddrs := n.NumAddresses()
|
numAddrs := n.NumAddresses()
|
||||||
|
@ -289,14 +289,14 @@ func TestGood(t *testing.T) {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < addrsToAdd; i++ {
|
for i := 0; i < addrsToAdd; i++ {
|
||||||
s := fmt.Sprintf("%d.173.147.%d: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)
|
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
|
||||||
|
|
||||||
n.AddAddresses(addrs, srcAddr)
|
n.AddAddresses(addrs, srcAddr)
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
|
@ -323,7 +323,7 @@ func TestGetAddress(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new address and get it
|
// Add a new address and get it
|
||||||
err := n.AddAddressByIP(someIP + ":8333")
|
err := n.AddAddressByIP(someIP + ":9244")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
t.Fatalf("Adding address failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
/*
|
/*
|
||||||
Package addrmgr implements concurrency safe Bitcoin address manager.
|
Package addrmgr implements concurrency safe Bitcoin address manager.
|
||||||
|
|
||||||
Address Manager Overview
|
# Address Manager Overview
|
||||||
|
|
||||||
In order maintain the peer-to-peer Bitcoin network, there needs to be a source
|
In order maintain the peer-to-peer Bitcoin network, there needs to be a source
|
||||||
of addresses to connect to as nodes come and go. The Bitcoin protocol provides
|
of addresses to connect to as nodes come and go. The Bitcoin protocol provides
|
||||||
|
|
|
@ -7,7 +7,7 @@ package addrmgr
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TstKnownAddressIsBad(ka *KnownAddress) bool {
|
func TstKnownAddressIsBad(ka *KnownAddress) bool {
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
package addrmgr
|
package addrmgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KnownAddress tracks information about a known network address that is used
|
// KnownAddress tracks information about a known network address that is used
|
||||||
// to determine how viable an address is.
|
// to determine how viable an address is.
|
||||||
type KnownAddress struct {
|
type KnownAddress struct {
|
||||||
|
mtx sync.RWMutex // na and lastattempt
|
||||||
na *wire.NetAddress
|
na *wire.NetAddress
|
||||||
srcAddr *wire.NetAddress
|
srcAddr *wire.NetAddress
|
||||||
attempts int
|
attempts int
|
||||||
|
@ -25,19 +27,28 @@ type KnownAddress struct {
|
||||||
// NetAddress returns the underlying wire.NetAddress associated with the
|
// NetAddress returns the underlying wire.NetAddress associated with the
|
||||||
// known address.
|
// known address.
|
||||||
func (ka *KnownAddress) NetAddress() *wire.NetAddress {
|
func (ka *KnownAddress) NetAddress() *wire.NetAddress {
|
||||||
|
ka.mtx.RLock()
|
||||||
|
defer ka.mtx.RUnlock()
|
||||||
return ka.na
|
return ka.na
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastAttempt returns the last time the known address was attempted.
|
// LastAttempt returns the last time the known address was attempted.
|
||||||
func (ka *KnownAddress) LastAttempt() time.Time {
|
func (ka *KnownAddress) LastAttempt() time.Time {
|
||||||
|
ka.mtx.RLock()
|
||||||
|
defer ka.mtx.RUnlock()
|
||||||
return ka.lastattempt
|
return ka.lastattempt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Services returns the services supported by the peer with the known address.
|
// Services returns the services supported by the peer with the known address.
|
||||||
func (ka *KnownAddress) Services() wire.ServiceFlag {
|
func (ka *KnownAddress) Services() wire.ServiceFlag {
|
||||||
|
ka.mtx.RLock()
|
||||||
|
defer ka.mtx.RUnlock()
|
||||||
return ka.na.Services
|
return ka.na.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The unexported methods, chance and isBad, are used from within AddrManager
|
||||||
|
// where KnownAddress field access is synchronized via it's own Mutex.
|
||||||
|
|
||||||
// chance returns the selection probability for a known address. The priority
|
// chance returns the selection probability for a known address. The priority
|
||||||
// depends upon how recently the address has been seen, how recently it was last
|
// depends upon how recently the address has been seen, how recently it was last
|
||||||
// attempted and how often attempts to connect to it have failed.
|
// attempted and how often attempts to connect to it have failed.
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/addrmgr"
|
"github.com/lbryio/lbcd/addrmgr"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChance(t *testing.T) {
|
func TestChance(t *testing.T) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/addrmgr"
|
"github.com/lbryio/lbcd/addrmgr"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestIPTypes ensures the various functions which determine the type of an IP
|
// TestIPTypes ensures the various functions which determine the type of an IP
|
||||||
|
@ -39,7 +39,7 @@ func TestIPTypes(t *testing.T) {
|
||||||
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
|
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
|
||||||
local, valid, routable bool) ipTest {
|
local, valid, routable bool) ipTest {
|
||||||
nip := net.ParseIP(ip)
|
nip := net.ParseIP(ip)
|
||||||
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
|
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
|
||||||
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
|
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
|
||||||
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
|
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
|
||||||
return test
|
return test
|
||||||
|
@ -192,7 +192,7 @@ func TestGroupKey(t *testing.T) {
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
nip := net.ParseIP(test.ip)
|
nip := net.ParseIP(test.ip)
|
||||||
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
|
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
|
||||||
if key := addrmgr.GroupKey(&na); key != test.expected {
|
if key := addrmgr.GroupKey(&na); key != test.expected {
|
||||||
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
|
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
|
||||||
"- got '%s', want '%s'", i, test.name,
|
"- got '%s', want '%s'", i, test.name,
|
||||||
|
|
|
@ -1,30 +1,9 @@
|
||||||
blockchain
|
blockchain
|
||||||
==========
|
==========
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcd)
|
|
||||||
[](http://copyfree.org)
|
[](http://copyfree.org)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd/blockchain)
|
|
||||||
|
|
||||||
Package blockchain implements bitcoin block handling and chain selection rules.
|
### Bitcoin Chain Processing Overview
|
||||||
The test coverage is currently only around 60%, but will be increasing over
|
|
||||||
time. See `test_coverage.txt` for the gocov coverage report. Alternatively, if
|
|
||||||
you are running a POSIX OS, you can run the `cov_report.sh` script for a
|
|
||||||
real-time report. Package blockchain is licensed under the liberal ISC license.
|
|
||||||
|
|
||||||
There is an associated blog post about the release of this package
|
|
||||||
[here](https://blog.conformal.com/btcchain-the-bitcoin-chain-package-from-bctd/).
|
|
||||||
|
|
||||||
This package has intentionally been designed so it can be used as a standalone
|
|
||||||
package for any projects needing to handle processing of blocks into the bitcoin
|
|
||||||
block chain.
|
|
||||||
|
|
||||||
## Installation and Updating
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go get -u github.com/btcsuite/btcd/blockchain
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bitcoin Chain Processing Overview
|
|
||||||
|
|
||||||
Before a block is allowed into the block chain, it must go through an intensive
|
Before a block is allowed into the block chain, it must go through an intensive
|
||||||
series of validation rules. The following list serves as a general outline of
|
series of validation rules. The following list serves as a general outline of
|
||||||
|
@ -57,47 +36,4 @@ is by no means exhaustive:
|
||||||
transaction values
|
transaction values
|
||||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||||
coins
|
coins
|
||||||
- Insert the block into the block database
|
- Insert the block into the block database
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
* [ProcessBlock Example](http://godoc.org/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](http://godoc.org/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](http://godoc.org/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.
|
|
|
@ -7,8 +7,8 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// maybeAcceptBlock potentially accepts a block into the block chain and, if
|
// maybeAcceptBlock potentially accepts a block into the block chain and, if
|
||||||
|
@ -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
|
// Notify the caller that the new block was accepted into the block
|
||||||
// chain. The caller would typically want to react by relaying the
|
// chain. The caller would typically want to react by relaying the
|
||||||
// inventory to other peers.
|
// inventory to other peers.
|
||||||
|
b.notificationSendLock.Lock()
|
||||||
|
defer b.notificationSendLock.Unlock()
|
||||||
b.chainLock.Unlock()
|
b.chainLock.Unlock()
|
||||||
|
defer b.chainLock.Lock()
|
||||||
b.sendNotification(NTBlockAccepted, block)
|
b.sendNotification(NTBlockAccepted, block)
|
||||||
b.chainLock.Lock()
|
|
||||||
|
|
||||||
return isMainChain, nil
|
return isMainChain, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,12 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
|
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
|
||||||
// function.
|
// function.
|
||||||
func BenchmarkIsCoinBase(b *testing.B) {
|
func BenchmarkIsCoinBase(b *testing.B) {
|
||||||
tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
|
tx, _ := GetBlock100000().Tx(1)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
IsCoinBase(tx)
|
IsCoinBase(tx)
|
||||||
|
@ -23,9 +21,9 @@ func BenchmarkIsCoinBase(b *testing.B) {
|
||||||
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
|
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
|
||||||
// function.
|
// function.
|
||||||
func BenchmarkIsCoinBaseTx(b *testing.B) {
|
func BenchmarkIsCoinBaseTx(b *testing.B) {
|
||||||
tx := Block100000.Transactions[1]
|
tx, _ := GetBlock100000().Tx(1)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
IsCoinBaseTx(tx)
|
IsCoinBaseTx(tx.MsgTx())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blockStatus is a bit field representing the validation state of the block.
|
// blockStatus is a bit field representing the validation state of the block.
|
||||||
|
@ -93,6 +93,7 @@ type blockNode struct {
|
||||||
nonce uint32
|
nonce uint32
|
||||||
timestamp int64
|
timestamp int64
|
||||||
merkleRoot chainhash.Hash
|
merkleRoot chainhash.Hash
|
||||||
|
claimTrie chainhash.Hash
|
||||||
|
|
||||||
// status is a bitfield representing the validation state of the block. The
|
// status is a bitfield representing the validation state of the block. The
|
||||||
// status field, unlike the other fields, may be written to and so should
|
// status field, unlike the other fields, may be written to and so should
|
||||||
|
@ -114,6 +115,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
|
||||||
nonce: blockHeader.Nonce,
|
nonce: blockHeader.Nonce,
|
||||||
timestamp: blockHeader.Timestamp.Unix(),
|
timestamp: blockHeader.Timestamp.Unix(),
|
||||||
merkleRoot: blockHeader.MerkleRoot,
|
merkleRoot: blockHeader.MerkleRoot,
|
||||||
|
claimTrie: blockHeader.ClaimTrie,
|
||||||
}
|
}
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
node.parent = parent
|
node.parent = parent
|
||||||
|
@ -144,6 +146,7 @@ func (node *blockNode) Header() wire.BlockHeader {
|
||||||
Version: node.version,
|
Version: node.version,
|
||||||
PrevBlock: *prevHash,
|
PrevBlock: *prevHash,
|
||||||
MerkleRoot: node.merkleRoot,
|
MerkleRoot: node.merkleRoot,
|
||||||
|
ClaimTrie: node.claimTrie,
|
||||||
Timestamp: time.Unix(node.timestamp, 0),
|
Timestamp: time.Unix(node.timestamp, 0),
|
||||||
Bits: node.bits,
|
Bits: node.bits,
|
||||||
Nonce: node.nonce,
|
Nonce: node.nonce,
|
||||||
|
|
|
@ -8,15 +8,18 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbcd/claimtrie"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -34,8 +37,9 @@ const (
|
||||||
// from the block being located.
|
// from the block being located.
|
||||||
//
|
//
|
||||||
// For example, assume a block chain with a side chain as depicted below:
|
// For example, assume a block chain with a side chain as depicted below:
|
||||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
//
|
||||||
// \-> 16a -> 17a
|
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||||
|
// \-> 16a -> 17a
|
||||||
//
|
//
|
||||||
// The block locator for block 17a would be the hashes of blocks:
|
// 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]
|
// [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.
|
// fields in this struct below this point.
|
||||||
chainLock sync.RWMutex
|
chainLock sync.RWMutex
|
||||||
|
|
||||||
|
// notificationSendLock helps us only process one block at a time.
|
||||||
|
// It's definitely a hack. DCRD has much better structure in this regard.
|
||||||
|
// Without this you will get an error if you invalidate a block and then generate more right after.
|
||||||
|
// Taken from https://github.com/gcash/bchd/pull/308
|
||||||
|
notificationSendLock sync.Mutex
|
||||||
|
|
||||||
// These fields are related to the memory block index. They both have
|
// These fields are related to the memory block index. They both have
|
||||||
// their own locks, however they are often also protected by the chain
|
// their own locks, however they are often also protected by the chain
|
||||||
// lock to help prevent logic races when blocks are being processed.
|
// lock to help prevent logic races when blocks are being processed.
|
||||||
|
@ -174,16 +184,14 @@ type BlockChain struct {
|
||||||
//
|
//
|
||||||
// unknownRulesWarned refers to warnings due to unknown rules being
|
// unknownRulesWarned refers to warnings due to unknown rules being
|
||||||
// activated.
|
// activated.
|
||||||
//
|
unknownRulesWarned bool
|
||||||
// unknownVersionsWarned refers to warnings due to unknown versions
|
|
||||||
// being mined.
|
|
||||||
unknownRulesWarned bool
|
|
||||||
unknownVersionsWarned bool
|
|
||||||
|
|
||||||
// The notifications field stores a slice of callbacks to be executed on
|
// The notifications field stores a slice of callbacks to be executed on
|
||||||
// certain blockchain events.
|
// certain blockchain events.
|
||||||
notificationsLock sync.RWMutex
|
notificationsLock sync.RWMutex
|
||||||
notifications []NotificationCallback
|
notifications []NotificationCallback
|
||||||
|
|
||||||
|
claimTrie *claimtrie.ClaimTrie
|
||||||
}
|
}
|
||||||
|
|
||||||
// HaveBlock returns whether or not the chain instance has the block represented
|
// HaveBlock returns whether or not the chain instance has the block represented
|
||||||
|
@ -199,6 +207,15 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
|
||||||
return exists || b.IsKnownOrphan(hash), nil
|
return exists || b.IsKnownOrphan(hash), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWarnings returns a bool for whether unknownRules
|
||||||
|
// has been warned.
|
||||||
|
func (b *BlockChain) GetWarnings() bool {
|
||||||
|
b.chainLock.RLock()
|
||||||
|
defer b.chainLock.RUnlock()
|
||||||
|
|
||||||
|
return b.unknownRulesWarned
|
||||||
|
}
|
||||||
|
|
||||||
// IsKnownOrphan returns whether the passed hash is currently a known orphan.
|
// IsKnownOrphan returns whether the passed hash is currently a known orphan.
|
||||||
// Keep in mind that only a limited number of orphans are held onto for a
|
// Keep in mind that only a limited number of orphans are held onto for a
|
||||||
// limited amount of time, so this function must not be used as an absolute
|
// limited amount of time, so this function must not be used as an absolute
|
||||||
|
@ -472,7 +489,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView
|
||||||
// LockTimeToSequence converts the passed relative locktime to a sequence
|
// LockTimeToSequence converts the passed relative locktime to a sequence
|
||||||
// number in accordance to BIP-68.
|
// number in accordance to BIP-68.
|
||||||
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
|
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
|
||||||
// * (Compatibility)
|
// - (Compatibility)
|
||||||
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
|
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
|
||||||
// If we're expressing the relative lock time in blocks, then the
|
// If we're expressing the relative lock time in blocks, then the
|
||||||
// corresponding sequence number is simply the desired input age.
|
// corresponding sequence number is simply the desired input age.
|
||||||
|
@ -574,19 +591,21 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
||||||
"spent transaction out information")
|
"spent transaction out information")
|
||||||
}
|
}
|
||||||
|
|
||||||
// No warnings about unknown rules or versions until the chain is
|
// No warnings about unknown rules until the chain is current.
|
||||||
// current.
|
current := b.isCurrent()
|
||||||
if b.isCurrent() {
|
if current {
|
||||||
// Warn if any unknown new rules are either about to activate or
|
// Warn if any unknown new rules are either about to activate or
|
||||||
// have already been activated.
|
// have already been activated.
|
||||||
if err := b.warnUnknownRuleActivations(node); err != nil {
|
if err := b.warnUnknownRuleActivations(node); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Warn if a high enough percentage of the last blocks have
|
// Handle LBRY Claim Scripts
|
||||||
// unexpected versions.
|
if b.claimTrie != nil {
|
||||||
if err := b.warnUnknownVersions(node); err != nil {
|
shouldFlush := current && b.chainParams.Net != wire.TestNet
|
||||||
return err
|
if err := b.ParseClaimScripts(block, node, view, shouldFlush); err != nil {
|
||||||
|
return ruleError(ErrBadClaimTrie, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,9 +691,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
||||||
// Notify the caller that the block was connected to the main chain.
|
// Notify the caller that the block was connected to the main chain.
|
||||||
// The caller would typically want to react with actions such as
|
// The caller would typically want to react with actions such as
|
||||||
// updating wallets.
|
// updating wallets.
|
||||||
|
b.notificationSendLock.Lock()
|
||||||
|
defer b.notificationSendLock.Unlock()
|
||||||
b.chainLock.Unlock()
|
b.chainLock.Unlock()
|
||||||
|
defer b.chainLock.Lock()
|
||||||
b.sendNotification(NTBlockConnected, block)
|
b.sendNotification(NTBlockConnected, block)
|
||||||
b.chainLock.Lock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -772,6 +793,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.claimTrie != nil {
|
||||||
|
if err = b.claimTrie.ResetHeight(node.parent.height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prune fully spent entries and mark all entries in the view unmodified
|
// Prune fully spent entries and mark all entries in the view unmodified
|
||||||
// now that the modifications have been committed to the database.
|
// now that the modifications have been committed to the database.
|
||||||
view.commit()
|
view.commit()
|
||||||
|
@ -791,9 +818,11 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
||||||
// Notify the caller that the block was disconnected from the main
|
// Notify the caller that the block was disconnected from the main
|
||||||
// chain. The caller would typically want to react with actions such as
|
// chain. The caller would typically want to react with actions such as
|
||||||
// updating wallets.
|
// updating wallets.
|
||||||
|
b.notificationSendLock.Lock()
|
||||||
|
defer b.notificationSendLock.Unlock()
|
||||||
b.chainLock.Unlock()
|
b.chainLock.Unlock()
|
||||||
|
defer b.chainLock.Lock()
|
||||||
b.sendNotification(NTBlockDisconnected, block)
|
b.sendNotification(NTBlockDisconnected, block)
|
||||||
b.chainLock.Lock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -977,6 +1006,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
|
||||||
err = b.checkConnectBlock(n, block, view, nil)
|
err = b.checkConnectBlock(n, block, view, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(RuleError); ok {
|
if _, ok := err.(RuleError); ok {
|
||||||
|
b.index.UnsetStatusFlags(n, statusValid)
|
||||||
b.index.SetStatusFlags(n, statusValidateFailed)
|
b.index.SetStatusFlags(n, statusValidateFailed)
|
||||||
for de := e.Next(); de != nil; de = de.Next() {
|
for de := e.Next(); de != nil; de = de.Next() {
|
||||||
dn := de.Value.(*blockNode)
|
dn := de.Value.(*blockNode)
|
||||||
|
@ -1078,8 +1108,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
|
||||||
// a reorganization to become the main chain).
|
// a reorganization to become the main chain).
|
||||||
//
|
//
|
||||||
// The flags modify the behavior of this function as follows:
|
// The flags modify the behavior of this function as follows:
|
||||||
// - BFFastAdd: Avoids several expensive transaction validation operations.
|
// - BFFastAdd: Avoids several expensive transaction validation operations.
|
||||||
// This is useful when using checkpoints.
|
// This is useful when using checkpoints.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the chain state lock held (for writes).
|
// 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) {
|
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) {
|
||||||
|
@ -1114,6 +1144,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
||||||
if err == nil {
|
if err == nil {
|
||||||
b.index.SetStatusFlags(node, statusValid)
|
b.index.SetStatusFlags(node, statusValid)
|
||||||
} else if _, ok := err.(RuleError); ok {
|
} else if _, ok := err.(RuleError); ok {
|
||||||
|
b.index.UnsetStatusFlags(node, statusValid)
|
||||||
b.index.SetStatusFlags(node, statusValidateFailed)
|
b.index.SetStatusFlags(node, statusValidateFailed)
|
||||||
} else {
|
} else {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -1148,6 +1179,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
||||||
// that status of the block as invalid and flush the
|
// that status of the block as invalid and flush the
|
||||||
// index state to disk before returning with the error.
|
// index state to disk before returning with the error.
|
||||||
if _, ok := err.(RuleError); ok {
|
if _, ok := err.(RuleError); ok {
|
||||||
|
b.index.UnsetStatusFlags(node, statusValid)
|
||||||
b.index.SetStatusFlags(
|
b.index.SetStatusFlags(
|
||||||
node, statusValidateFailed,
|
node, statusValidateFailed,
|
||||||
)
|
)
|
||||||
|
@ -1218,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
|
// 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
|
// factors are used to guess, but the key factors that allow the chain to
|
||||||
// believe it is current are:
|
// believe it is current are:
|
||||||
// - Latest block height is after the latest checkpoint (if enabled)
|
// - Latest block height is after the latest checkpoint (if enabled)
|
||||||
// - Latest block has a timestamp newer than 24 hours ago
|
// - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
|
||||||
//
|
//
|
||||||
// This function MUST be called with the chain state lock held (for reads).
|
// This function MUST be called with the chain state lock held (for reads).
|
||||||
func (b *BlockChain) isCurrent() bool {
|
func (b *BlockChain) isCurrent() bool {
|
||||||
|
@ -1230,20 +1262,20 @@ func (b *BlockChain) isCurrent() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not current if the latest best block has a timestamp before 24 hours
|
// Not current if the latest best block has a timestamp before 7 hours
|
||||||
// ago.
|
// ago.
|
||||||
//
|
//
|
||||||
// The chain appears to be current if none of the checks reported
|
// The chain appears to be current if none of the checks reported
|
||||||
// otherwise.
|
// otherwise.
|
||||||
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
|
hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
|
||||||
return b.bestChain.Tip().timestamp >= minus24Hours
|
return b.bestChain.Tip().timestamp >= hours
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCurrent returns whether or not the chain believes it is current. Several
|
// IsCurrent returns whether or not the chain believes it is current. Several
|
||||||
// factors are used to guess, but the key factors that allow the chain to
|
// factors are used to guess, but the key factors that allow the chain to
|
||||||
// believe it is current are:
|
// believe it is current are:
|
||||||
// - Latest block height is after the latest checkpoint (if enabled)
|
// - Latest block height is after the latest checkpoint (if enabled)
|
||||||
// - Latest block has a timestamp newer than 24 hours ago
|
// - Latest block has a timestamp newer than 24 hours ago
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (b *BlockChain) IsCurrent() bool {
|
func (b *BlockChain) IsCurrent() bool {
|
||||||
|
@ -1343,6 +1375,57 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro
|
||||||
return &node.hash, nil
|
return &node.hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockAttributes desribes a Block in relation to others on the main chain.
|
||||||
|
type BlockAttributes struct {
|
||||||
|
Height int32
|
||||||
|
Confirmations int32
|
||||||
|
MedianTime time.Time
|
||||||
|
ChainWork *big.Int
|
||||||
|
PrevHash *chainhash.Hash
|
||||||
|
NextHash *chainhash.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockAttributesByHash returns BlockAttributes for the block with the given hash
|
||||||
|
// relative to other blocks in the main chain. A BestState snapshot describing
|
||||||
|
// the main chain is also returned for convenience.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) (
|
||||||
|
attrs *BlockAttributes, best *BestState, err error) {
|
||||||
|
best = b.BestSnapshot()
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil {
|
||||||
|
str := fmt.Sprintf("block %s not found", hash)
|
||||||
|
return nil, best, errNotInMainChain(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs = &BlockAttributes{
|
||||||
|
Height: node.height,
|
||||||
|
Confirmations: 1 + best.Height - node.height,
|
||||||
|
MedianTime: node.CalcPastMedianTime(),
|
||||||
|
ChainWork: node.workSum,
|
||||||
|
}
|
||||||
|
if !b.bestChain.Contains(node) {
|
||||||
|
attrs.Confirmations = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate prev block hash if there is one.
|
||||||
|
if node.height > 0 {
|
||||||
|
attrs.PrevHash = prevHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate next block hash if there is one.
|
||||||
|
if node.height < best.Height {
|
||||||
|
nextHash, err := b.BlockHashByHeight(node.height + 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, best, err
|
||||||
|
}
|
||||||
|
attrs.NextHash = nextHash
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, best, nil
|
||||||
|
}
|
||||||
|
|
||||||
// HeightRange returns a range of block hashes for the given start and end
|
// HeightRange returns a range of block hashes for the given start and end
|
||||||
// heights. It is inclusive of the start height and exclusive of the end
|
// heights. It is inclusive of the start height and exclusive of the end
|
||||||
// height. The end height will be limited to the current main chain height.
|
// height. The end height will be limited to the current main chain height.
|
||||||
|
@ -1478,11 +1561,11 @@ func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int,
|
||||||
//
|
//
|
||||||
// In addition, there are two special cases:
|
// In addition, there are two special cases:
|
||||||
//
|
//
|
||||||
// - When no locators are provided, the stop hash is treated as a request for
|
// - 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
|
// that block, so it will either return the node associated with the stop hash
|
||||||
// if it is known, or nil if it is unknown
|
// if it is known, or nil if it is unknown
|
||||||
// - When locators are provided, but none of them are known, nodes starting
|
// - When locators are provided, but none of them are known, nodes starting
|
||||||
// after the genesis block will be returned
|
// after the genesis block will be returned
|
||||||
//
|
//
|
||||||
// This is primarily a helper function for the locateBlocks and locateHeaders
|
// This is primarily a helper function for the locateBlocks and locateHeaders
|
||||||
// functions.
|
// functions.
|
||||||
|
@ -1566,11 +1649,11 @@ func (b *BlockChain) locateBlocks(locator BlockLocator, hashStop *chainhash.Hash
|
||||||
//
|
//
|
||||||
// In addition, there are two special cases:
|
// In addition, there are two special cases:
|
||||||
//
|
//
|
||||||
// - When no locators are provided, the stop hash is treated as a request for
|
// - 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,
|
// that block, so it will either return the stop hash itself if it is known,
|
||||||
// or nil if it is unknown
|
// or nil if it is unknown
|
||||||
// - When locators are provided, but none of them are known, hashes starting
|
// - When locators are provided, but none of them are known, hashes starting
|
||||||
// after the genesis block will be returned
|
// after the genesis block will be returned
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash {
|
func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash {
|
||||||
|
@ -1611,11 +1694,11 @@ func (b *BlockChain) locateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
||||||
//
|
//
|
||||||
// In addition, there are two special cases:
|
// In addition, there are two special cases:
|
||||||
//
|
//
|
||||||
// - When no locators are provided, the stop hash is treated as a request for
|
// - 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
|
// that header, so it will either return the header for the stop hash itself
|
||||||
// if it is known, or nil if it is unknown
|
// if it is known, or nil if it is unknown
|
||||||
// - When locators are provided, but none of them are known, headers starting
|
// - When locators are provided, but none of them are known, headers starting
|
||||||
// after the genesis block will be returned
|
// after the genesis block will be returned
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader {
|
func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader {
|
||||||
|
@ -1625,6 +1708,121 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvalidateBlock takes a block hash and invalidates it.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
|
||||||
|
b.chainLock.Lock()
|
||||||
|
defer b.chainLock.Unlock()
|
||||||
|
return b.invalidateBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidateBlock takes a block hash and invalidates it.
|
||||||
|
func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil {
|
||||||
|
err := fmt.Errorf("block %s is not known", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to invalidate if its already invalid.
|
||||||
|
if node.status.KnownInvalid() {
|
||||||
|
err := fmt.Errorf("block %s is already invalid", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.parent == nil {
|
||||||
|
err := fmt.Errorf("block %s has no parent", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.index.SetStatusFlags(node, statusValidateFailed)
|
||||||
|
b.index.UnsetStatusFlags(node, statusValid)
|
||||||
|
|
||||||
|
detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
|
||||||
|
|
||||||
|
err := b.reorganizeChain(detachNodes, attachNodes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
|
||||||
|
n := e.Value.(*blockNode)
|
||||||
|
|
||||||
|
b.index.SetStatusFlags(n, statusInvalidAncestor)
|
||||||
|
b.index.UnsetStatusFlags(n, statusValid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||||
|
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReconsiderBlock takes a block hash and allows it to be revalidated.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) ReconsiderBlock(hash *chainhash.Hash) error {
|
||||||
|
return b.reconsiderBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconsiderBlock takes a block hash and allows it to be revalidated.
|
||||||
|
func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil {
|
||||||
|
err := fmt.Errorf("block %s is not known", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to reconsider, it is already valid.
|
||||||
|
if node.status.KnownValid() && !node.status.KnownInvalid() { // second clause works around old bug
|
||||||
|
err := fmt.Errorf("block %s is already valid", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a reference to the first node in the chain of invalid
|
||||||
|
// blocks so we can reprocess after status flags are updated.
|
||||||
|
firstNode := node
|
||||||
|
|
||||||
|
// Find previous node to the point where the blocks are valid again.
|
||||||
|
for n := node; n.status.KnownInvalid(); n = n.parent {
|
||||||
|
b.index.UnsetStatusFlags(n, statusInvalidAncestor)
|
||||||
|
b.index.UnsetStatusFlags(n, statusValidateFailed)
|
||||||
|
|
||||||
|
firstNode = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we need an rlock on chainstate for this section?
|
||||||
|
var blk *btcutil.Block
|
||||||
|
err := b.db.View(func(dbTx database.Tx) error {
|
||||||
|
var err error
|
||||||
|
blk, err = dbFetchBlockByNode(dbTx, firstNode)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process it all again. This will take care of the
|
||||||
|
// orphans as well.
|
||||||
|
_, _, err = b.ProcessBlock(blk, BFNoDupBlockCheck)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||||
|
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaimTrie returns the claimTrie associated wit hthe chain.
|
||||||
|
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
||||||
|
return b.claimTrie
|
||||||
|
}
|
||||||
|
|
||||||
// IndexManager provides a generic interface that the is called when blocks are
|
// IndexManager provides a generic interface that the is called when blocks are
|
||||||
// connected and disconnected to and from the tip of the main chain for the
|
// connected and disconnected to and from the tip of the main chain for the
|
||||||
// purpose of supporting optional indexes.
|
// purpose of supporting optional indexes.
|
||||||
|
@ -1711,6 +1909,8 @@ type Config struct {
|
||||||
// This field can be nil if the caller is not interested in using a
|
// This field can be nil if the caller is not interested in using a
|
||||||
// signature cache.
|
// signature cache.
|
||||||
HashCache *txscript.HashCache
|
HashCache *txscript.HashCache
|
||||||
|
|
||||||
|
ClaimTrie *claimtrie.ClaimTrie
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a BlockChain instance using the provided configuration details.
|
// New returns a BlockChain instance using the provided configuration details.
|
||||||
|
@ -1747,7 +1947,6 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
params := config.ChainParams
|
params := config.ChainParams
|
||||||
targetTimespan := int64(params.TargetTimespan / time.Second)
|
targetTimespan := int64(params.TargetTimespan / time.Second)
|
||||||
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
|
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
|
||||||
adjustmentFactor := params.RetargetAdjustmentFactor
|
|
||||||
b := BlockChain{
|
b := BlockChain{
|
||||||
checkpoints: config.Checkpoints,
|
checkpoints: config.Checkpoints,
|
||||||
checkpointsByHeight: checkpointsByHeight,
|
checkpointsByHeight: checkpointsByHeight,
|
||||||
|
@ -1756,8 +1955,8 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
timeSource: config.TimeSource,
|
timeSource: config.TimeSource,
|
||||||
sigCache: config.SigCache,
|
sigCache: config.SigCache,
|
||||||
indexManager: config.IndexManager,
|
indexManager: config.IndexManager,
|
||||||
minRetargetTimespan: targetTimespan / adjustmentFactor,
|
minRetargetTimespan: targetTimespan - (targetTimespan / 8),
|
||||||
maxRetargetTimespan: targetTimespan * adjustmentFactor,
|
maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
|
||||||
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
||||||
index: newBlockIndex(config.DB, params),
|
index: newBlockIndex(config.DB, params),
|
||||||
hashCache: config.HashCache,
|
hashCache: config.HashCache,
|
||||||
|
@ -1766,6 +1965,7 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
||||||
warningCaches: newThresholdCaches(vbNumBits),
|
warningCaches: newThresholdCaches(vbNumBits),
|
||||||
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
|
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
|
||||||
|
claimTrie: config.ClaimTrie,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the chain state from the passed database. When the db
|
// Initialize the chain state from the passed database. When the db
|
||||||
|
@ -1775,6 +1975,20 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to insert the output in genesis block in to the
|
||||||
|
// transaction database.
|
||||||
|
fn := func(dbTx database.Tx) error {
|
||||||
|
genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock)
|
||||||
|
view := NewUtxoViewpoint()
|
||||||
|
if err := view.connectTransactions(genesisBlock, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return dbPutUtxoView(dbTx, view)
|
||||||
|
}
|
||||||
|
if err := b.db.Update(fn); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Perform any upgrades to the various chain-specific buckets as needed.
|
// Perform any upgrades to the various chain-specific buckets as needed.
|
||||||
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
|
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1794,6 +2008,14 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.claimTrie != nil {
|
||||||
|
err := rebuildMissingClaimTrieData(&b, config.Interrupt)
|
||||||
|
if err != nil {
|
||||||
|
b.claimTrie.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bestNode := b.bestChain.Tip()
|
bestNode := b.bestChain.Tip()
|
||||||
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
|
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
|
||||||
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
|
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
|
||||||
|
@ -1801,3 +2023,63 @@ func New(config *Config) (*BlockChain, error) {
|
||||||
|
|
||||||
return &b, nil
|
return &b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rebuildMissingClaimTrieData(b *BlockChain, done <-chan struct{}) error {
|
||||||
|
target := b.bestChain.Height()
|
||||||
|
if b.claimTrie.Height() == target {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if b.claimTrie.Height() > target {
|
||||||
|
return b.claimTrie.ResetHeight(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
lastReport := time.Now()
|
||||||
|
// TODO: move this view inside the loop (or recreate it every 5 sec.)
|
||||||
|
// as accumulating all inputs has potential to use a huge amount of RAM
|
||||||
|
// but we need to get the spent inputs working for that to be possible
|
||||||
|
view := NewUtxoViewpoint()
|
||||||
|
for h := int32(0); h < target; h++ {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return fmt.Errorf("rebuild unfinished at height %d", b.claimTrie.Height())
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
n := b.bestChain.NodeByHeight(h + 1)
|
||||||
|
|
||||||
|
var block *btcutil.Block
|
||||||
|
err := b.db.View(func(dbTx database.Tx) error {
|
||||||
|
var err error
|
||||||
|
block, err = dbFetchBlockByNode(dbTx, n)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = view.fetchInputUtxos(b.db, block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = view.connectTransactions(block, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if h >= b.claimTrie.Height() {
|
||||||
|
err = b.ParseClaimScripts(block, n, view, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if time.Since(lastReport) > time.Second*5 {
|
||||||
|
lastReport = time.Now()
|
||||||
|
log.Infof("Rebuilding claim trie data to %d. At: %d", target, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Infof("Completed rebuilding claim trie data to %d. Took %s ",
|
||||||
|
b.claimTrie.Height(), time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -9,108 +9,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
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
|
// TestCalcSequenceLock tests the LockTimeToSequence function, and the
|
||||||
// CalcSequenceLock method of a Chain instance. The tests exercise several
|
// CalcSequenceLock method of a Chain instance. The tests exercise several
|
||||||
// combinations of inputs to the CalcSequenceLock function in order to ensure
|
// combinations of inputs to the CalcSequenceLock function in order to ensure
|
||||||
|
|
|
@ -12,10 +12,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -120,7 +120,7 @@ func dbFetchVersion(dbTx database.Tx, key []byte) uint32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return byteOrder.Uint32(serialized[:])
|
return byteOrder.Uint32(serialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbPutVersion uses an existing database transaction to update the provided
|
// dbPutVersion uses an existing database transaction to update the provided
|
||||||
|
@ -943,7 +943,7 @@ func serializeBestChainState(state bestChainState) []byte {
|
||||||
byteOrder.PutUint32(serializedData[offset:], workSumBytesLen)
|
byteOrder.PutUint32(serializedData[offset:], workSumBytesLen)
|
||||||
offset += 4
|
offset += 4
|
||||||
copy(serializedData[offset:], workSumBytes)
|
copy(serializedData[offset:], workSumBytes)
|
||||||
return serializedData[:]
|
return serializedData
|
||||||
}
|
}
|
||||||
|
|
||||||
// deserializeBestChainState deserializes the passed serialized best chain
|
// deserializeBestChainState deserializes the passed serialized best chain
|
||||||
|
@ -1149,18 +1149,9 @@ func (b *BlockChain) initChainState() error {
|
||||||
|
|
||||||
blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName)
|
blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName)
|
||||||
|
|
||||||
// Determine how many blocks will be loaded into the index so we can
|
|
||||||
// allocate the right amount.
|
|
||||||
var blockCount int32
|
|
||||||
cursor := blockIndexBucket.Cursor()
|
|
||||||
for ok := cursor.First(); ok; ok = cursor.Next() {
|
|
||||||
blockCount++
|
|
||||||
}
|
|
||||||
blockNodes := make([]blockNode, blockCount)
|
|
||||||
|
|
||||||
var i int32
|
var i int32
|
||||||
var lastNode *blockNode
|
var lastNode *blockNode
|
||||||
cursor = blockIndexBucket.Cursor()
|
cursor := blockIndexBucket.Cursor()
|
||||||
for ok := cursor.First(); ok; ok = cursor.Next() {
|
for ok := cursor.First(); ok; ok = cursor.Next() {
|
||||||
header, status, err := deserializeBlockRow(cursor.Value())
|
header, status, err := deserializeBlockRow(cursor.Value())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1193,7 +1184,7 @@ func (b *BlockChain) initChainState() error {
|
||||||
|
|
||||||
// Initialize the block node for the block, connect it,
|
// Initialize the block node for the block, connect it,
|
||||||
// and add it to the block index.
|
// and add it to the block index.
|
||||||
node := &blockNodes[i]
|
node := new(blockNode)
|
||||||
initBlockNode(node, header, parent)
|
initBlockNode(node, header, parent)
|
||||||
node.status = status
|
node.status = status
|
||||||
b.index.addNode(node)
|
b.index.addNode(node)
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work
|
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work
|
||||||
|
|
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 comparing chains.
|
||||||
//
|
//
|
||||||
// For example, assume a block chain with a side chain as depicted below:
|
// For example, assume a block chain with a side chain as depicted below:
|
||||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
//
|
||||||
// \-> 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:
|
// The chain view for the branch ending in 6a consists of:
|
||||||
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
|
//
|
||||||
|
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
|
||||||
type chainView struct {
|
type chainView struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
nodes []*blockNode
|
nodes []*blockNode
|
||||||
|
@ -258,12 +260,14 @@ func (c *chainView) next(node *blockNode) *blockNode {
|
||||||
// view.
|
// view.
|
||||||
//
|
//
|
||||||
// For example, assume a block chain with a side chain as depicted below:
|
// For example, assume a block chain with a side chain as depicted below:
|
||||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
//
|
||||||
// \-> 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
|
// Further, assume the view is for the longer chain depicted above. That is to
|
||||||
// say it consists of:
|
// say it consists of:
|
||||||
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
//
|
||||||
|
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
|
||||||
//
|
//
|
||||||
// Invoking this function with block node 5 would return block node 6 while
|
// Invoking this function with block node 5 would return block node 6 while
|
||||||
// invoking it with block node 5a would return nil since that node is not part
|
// 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.
|
// the chain view. It will return nil if there is no common block.
|
||||||
//
|
//
|
||||||
// For example, assume a block chain with a side chain as depicted below:
|
// For example, assume a block chain with a side chain as depicted below:
|
||||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
|
//
|
||||||
// \-> 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
|
// Further, assume the view is for the longer chain depicted above. That is to
|
||||||
// say it consists of:
|
// say it consists of:
|
||||||
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
|
//
|
||||||
|
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
|
||||||
//
|
//
|
||||||
// Invoking this function with block node 7a would return block node 5 while
|
// Invoking this function with block node 7a would return block node 5 while
|
||||||
// invoking it with block node 7 would return itself since it is already part of
|
// invoking it with block node 7 would return itself since it is already part of
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testNoncePrng provides a deterministic prng for the nonce in generated fake
|
// testNoncePrng provides a deterministic prng for the nonce in generated fake
|
||||||
|
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckpointConfirmations is the number of blocks before the end of the current
|
// CheckpointConfirmations is the number of blocks before the end of the current
|
||||||
|
@ -172,7 +172,8 @@ func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
|
||||||
func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
||||||
// Check all of the output public key scripts for non-standard scripts.
|
// Check all of the output public key scripts for non-standard scripts.
|
||||||
for _, txOut := range tx.MsgTx().TxOut {
|
for _, txOut := range tx.MsgTx().TxOut {
|
||||||
scriptClass := txscript.GetScriptClass(txOut.PkScript)
|
stripped := txscript.StripClaimScriptPrefix(txOut.PkScript)
|
||||||
|
scriptClass := txscript.GetScriptClass(stripped)
|
||||||
if scriptClass == txscript.NonStandardTy {
|
if scriptClass == txscript.NonStandardTy {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -184,14 +185,14 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
||||||
// checkpoint candidate.
|
// checkpoint candidate.
|
||||||
//
|
//
|
||||||
// The factors used to determine a good checkpoint are:
|
// The factors used to determine a good checkpoint are:
|
||||||
// - The block must be in the main chain
|
// - The block must be in the main chain
|
||||||
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
|
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
|
||||||
// current end of the main chain
|
// current end of the main chain
|
||||||
// - The timestamps for the blocks before and after the checkpoint must have
|
// - The timestamps for the blocks before and after the checkpoint must have
|
||||||
// timestamps which are also before and after the checkpoint, respectively
|
// timestamps which are also before and after the checkpoint, respectively
|
||||||
// (due to the median time allowance this is not always the case)
|
// (due to the median time allowance this is not always the case)
|
||||||
// - The block must not contain any strange transaction such as those with
|
// - The block must not contain any strange transaction such as those with
|
||||||
// nonstandard scripts
|
// nonstandard scripts
|
||||||
//
|
//
|
||||||
// The intent is that candidates are reviewed by a developer to make the final
|
// 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.
|
// 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
|
package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -14,13 +15,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -63,13 +64,13 @@ func isSupportedDbType(dbType string) bool {
|
||||||
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
||||||
filename = filepath.Join("testdata/", filename)
|
filename = filepath.Join("testdata/", filename)
|
||||||
|
|
||||||
var network = wire.MainNet
|
var network = 0xd9b4bef9 // bitcoin's network ID
|
||||||
var dr io.Reader
|
var dr io.Reader
|
||||||
var fi io.ReadCloser
|
var fi io.ReadCloser
|
||||||
|
|
||||||
fi, err = os.Open(filename)
|
fi, err = os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return blocks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(filename, ".bz2") {
|
if strings.HasSuffix(filename, ".bz2") {
|
||||||
|
@ -95,7 +96,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if rintbuf != uint32(network) {
|
if rintbuf != uint32(network) {
|
||||||
break
|
continue
|
||||||
}
|
}
|
||||||
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
|
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
|
||||||
blocklen := rintbuf
|
blocklen := rintbuf
|
||||||
|
@ -105,14 +106,20 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
||||||
// read block
|
// read block
|
||||||
dr.Read(rbytes)
|
dr.Read(rbytes)
|
||||||
|
|
||||||
|
// inject claimtrie:
|
||||||
|
tail := make([]byte, len(rbytes)-68)
|
||||||
|
copy(tail, rbytes[68:])
|
||||||
|
rbytes = append(rbytes[:68], bytes.Repeat([]byte{23}, chainhash.HashSize)...)
|
||||||
|
rbytes = append(rbytes, tail...)
|
||||||
|
|
||||||
block, err = btcutil.NewBlockFromBytes(rbytes)
|
block, err = btcutil.NewBlockFromBytes(rbytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return blocks, err
|
||||||
}
|
}
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return blocks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// chainSetup is used to create a new db and chain instance with the genesis
|
// chainSetup is used to create a new db and chain instance with the genesis
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
package blockchain
|
package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lbryio/lbcd/btcec"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -42,18 +42,21 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
|
||||||
// Like IEEE754 floating point, there are three basic components: the sign,
|
// Like IEEE754 floating point, there are three basic components: the sign,
|
||||||
// the exponent, and the mantissa. They are broken out as follows:
|
// the exponent, and the mantissa. They are broken out as follows:
|
||||||
//
|
//
|
||||||
// * the most significant 8 bits represent the unsigned base 256 exponent
|
// - the most significant 8 bits represent the unsigned base 256 exponent
|
||||||
// * bit 23 (the 24th bit) represents the sign bit
|
|
||||||
// * the least significant 23 bits represent the mantissa
|
|
||||||
//
|
//
|
||||||
// -------------------------------------------------
|
// - bit 23 (the 24th bit) represents the sign bit
|
||||||
// | Exponent | Sign | Mantissa |
|
//
|
||||||
// -------------------------------------------------
|
// - the least significant 23 bits represent the mantissa
|
||||||
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
//
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
// | Exponent | Sign | Mantissa |
|
||||||
|
// -------------------------------------------------
|
||||||
|
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
|
||||||
|
// -------------------------------------------------
|
||||||
//
|
//
|
||||||
// The formula to calculate N is:
|
// The formula to calculate N is:
|
||||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
//
|
||||||
|
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||||
//
|
//
|
||||||
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers
|
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers
|
||||||
// which represent difficulty targets, thus there really is not a need for a
|
// 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 {
|
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
|
||||||
// Convert types used in the calculations below.
|
// Convert types used in the calculations below.
|
||||||
durationVal := int64(duration / time.Second)
|
durationVal := int64(duration / time.Second)
|
||||||
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
|
|
||||||
|
|
||||||
// The test network rules allow minimum difficulty blocks after more
|
// The test network rules allow minimum difficulty blocks after more
|
||||||
// than twice the desired amount of time needed to generate a block has
|
// than twice the desired amount of time needed to generate a block has
|
||||||
|
@ -178,7 +180,8 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
|
||||||
// multiplied by the max adjustment factor.
|
// multiplied by the max adjustment factor.
|
||||||
newTarget := CompactToBig(bits)
|
newTarget := CompactToBig(bits)
|
||||||
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
|
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
|
||||||
newTarget.Mul(newTarget, adjustmentFactor)
|
adj := new(big.Int).Div(newTarget, big.NewInt(2))
|
||||||
|
newTarget.Add(newTarget, adj)
|
||||||
durationVal -= b.maxRetargetTimespan
|
durationVal -= b.maxRetargetTimespan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,47 +227,45 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
||||||
return b.chainParams.PowLimitBits, nil
|
return b.chainParams.PowLimitBits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the previous block's difficulty requirements if this block
|
// For networks that support it, allow special reduction of the
|
||||||
// is not at a difficulty retarget interval.
|
// required difficulty once too much time has elapsed without
|
||||||
if (lastNode.height+1)%b.blocksPerRetarget != 0 {
|
// mining a block.
|
||||||
// For networks that support it, allow special reduction of the
|
if b.chainParams.ReduceMinDifficulty {
|
||||||
// required difficulty once too much time has elapsed without
|
// Return minimum difficulty when more than the desired
|
||||||
// mining a block.
|
// amount of time has elapsed without mining a block.
|
||||||
if b.chainParams.ReduceMinDifficulty {
|
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||||
// Return minimum difficulty when more than the desired
|
time.Second)
|
||||||
// amount of time has elapsed without mining a block.
|
allowMinTime := lastNode.timestamp + reductionTime
|
||||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
if newBlockTime.Unix() > allowMinTime {
|
||||||
time.Second)
|
return b.chainParams.PowLimitBits, nil
|
||||||
allowMinTime := lastNode.timestamp + reductionTime
|
|
||||||
if newBlockTime.Unix() > allowMinTime {
|
|
||||||
return b.chainParams.PowLimitBits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The block was mined within the desired timeframe, so
|
|
||||||
// return the difficulty for the last block which did
|
|
||||||
// not have the special minimum difficulty rule applied.
|
|
||||||
return b.findPrevTestNetDifficulty(lastNode), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the main network (or any unrecognized networks), simply
|
// The block was mined within the desired timeframe, so
|
||||||
// return the previous block's difficulty requirements.
|
// return the difficulty for the last block which did
|
||||||
return lastNode.bits, nil
|
// not have the special minimum difficulty rule applied.
|
||||||
|
return b.findPrevTestNetDifficulty(lastNode), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the block node at the previous retarget (targetTimespan days
|
// Get the block node at the previous retarget (targetTimespan days
|
||||||
// worth of blocks).
|
// worth of blocks).
|
||||||
firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1)
|
blocksBack := b.blocksPerRetarget
|
||||||
|
if blocksBack > lastNode.height {
|
||||||
|
blocksBack = lastNode.height
|
||||||
|
}
|
||||||
|
firstNode := lastNode.RelativeAncestor(blocksBack)
|
||||||
if firstNode == nil {
|
if firstNode == nil {
|
||||||
return 0, AssertError("unable to obtain previous retarget block")
|
return 0, AssertError("unable to obtain previous retarget block")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
|
||||||
|
|
||||||
// Limit the amount of adjustment that can occur to the previous
|
// Limit the amount of adjustment that can occur to the previous
|
||||||
// difficulty.
|
// difficulty.
|
||||||
actualTimespan := lastNode.timestamp - firstNode.timestamp
|
actualTimespan := lastNode.timestamp - firstNode.timestamp
|
||||||
adjustedTimespan := actualTimespan
|
adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
|
||||||
if actualTimespan < b.minRetargetTimespan {
|
if adjustedTimespan < b.minRetargetTimespan {
|
||||||
adjustedTimespan = b.minRetargetTimespan
|
adjustedTimespan = b.minRetargetTimespan
|
||||||
} else if actualTimespan > b.maxRetargetTimespan {
|
} else if adjustedTimespan > b.maxRetargetTimespan {
|
||||||
adjustedTimespan = b.maxRetargetTimespan
|
adjustedTimespan = b.maxRetargetTimespan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +276,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
||||||
// result.
|
// result.
|
||||||
oldTarget := CompactToBig(lastNode.bits)
|
oldTarget := CompactToBig(lastNode.bits)
|
||||||
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
|
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
|
||||||
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
|
|
||||||
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
|
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
|
||||||
|
|
||||||
// Limit new value to the proof of work limit.
|
// Limit new value to the proof of work limit.
|
||||||
|
|
|
@ -63,7 +63,7 @@ func TestCalcWork(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for x, test := range tests {
|
for x, test := range tests {
|
||||||
bits := uint32(test.in)
|
bits := test.in
|
||||||
|
|
||||||
r := CalcWork(bits)
|
r := CalcWork(bits)
|
||||||
if r.Int64() != test.out {
|
if r.Int64() != test.out {
|
||||||
|
|
|
@ -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
|
such as orphan blocks which need their parents requested and newly connected
|
||||||
main chain blocks which might result in wallet updates.
|
main chain blocks which might result in wallet updates.
|
||||||
|
|
||||||
Bitcoin Chain Processing Overview
|
# Bitcoin Chain Processing Overview
|
||||||
|
|
||||||
Before a block is allowed into the block chain, it must go through an intensive
|
Before a block is allowed into the block chain, it must go through an intensive
|
||||||
series of validation rules. The following list serves as a general outline of
|
series of validation rules. The following list serves as a general outline of
|
||||||
those rules to provide some intuition into what is going on under the hood, but
|
those rules to provide some intuition into what is going on under the hood, but
|
||||||
is by no means exhaustive:
|
is by no means exhaustive:
|
||||||
|
|
||||||
- Reject duplicate blocks
|
- Reject duplicate blocks
|
||||||
- Perform a series of sanity checks on the block and its transactions such as
|
- Perform a series of sanity checks on the block and its transactions such as
|
||||||
verifying proof of work, timestamps, number and character of transactions,
|
verifying proof of work, timestamps, number and character of transactions,
|
||||||
transaction amounts, script complexity, and merkle root calculations
|
transaction amounts, script complexity, and merkle root calculations
|
||||||
- Compare the block against predetermined checkpoints for expected timestamps
|
- Compare the block against predetermined checkpoints for expected timestamps
|
||||||
and difficulty based on elapsed time since the checkpoint
|
and difficulty based on elapsed time since the checkpoint
|
||||||
- Save the most recent orphan blocks for a limited time in case their parent
|
- Save the most recent orphan blocks for a limited time in case their parent
|
||||||
blocks become available
|
blocks become available
|
||||||
- Stop processing if the block is an orphan as the rest of the processing
|
- Stop processing if the block is an orphan as the rest of the processing
|
||||||
depends on the block's position within the block chain
|
depends on the block's position within the block chain
|
||||||
- Perform a series of more thorough checks that depend on the block's position
|
- 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
|
within the block chain such as verifying block difficulties adhere to
|
||||||
difficulty retarget rules, timestamps are after the median of the last
|
difficulty retarget rules, timestamps are after the median of the last
|
||||||
several blocks, all transactions are finalized, checkpoint blocks match, and
|
several blocks, all transactions are finalized, checkpoint blocks match, and
|
||||||
block versions are in line with the previous blocks
|
block versions are in line with the previous blocks
|
||||||
- Determine how the block fits into the chain and perform different actions
|
- Determine how the block fits into the chain and perform different actions
|
||||||
accordingly in order to ensure any side chains which have higher difficulty
|
accordingly in order to ensure any side chains which have higher difficulty
|
||||||
than the main chain become the new main chain
|
than the main chain become the new main chain
|
||||||
- When a block is being connected to the main chain (either through
|
- 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
|
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
|
main chain), perform further checks on the block's transactions such as
|
||||||
verifying transaction duplicates, script complexity for the combination of
|
verifying transaction duplicates, script complexity for the combination of
|
||||||
connected scripts, coinbase maturity, double spends, and connected
|
connected scripts, coinbase maturity, double spends, and connected
|
||||||
transaction values
|
transaction values
|
||||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||||
coins
|
coins
|
||||||
- Insert the block into the block database
|
- Insert the block into the block database
|
||||||
|
|
||||||
Errors
|
# Errors
|
||||||
|
|
||||||
Errors returned by this package are either the raw errors provided by underlying
|
Errors returned by this package are either the raw errors provided by underlying
|
||||||
calls or of type blockchain.RuleError. This allows the caller to differentiate
|
calls or of type blockchain.RuleError. This allows the caller to differentiate
|
||||||
|
@ -70,12 +70,12 @@ violations through type assertions. In addition, callers can programmatically
|
||||||
determine the specific rule violation by examining the ErrorCode field of the
|
determine the specific rule violation by examining the ErrorCode field of the
|
||||||
type asserted blockchain.RuleError.
|
type asserted blockchain.RuleError.
|
||||||
|
|
||||||
Bitcoin Improvement Proposals
|
# Bitcoin Improvement Proposals
|
||||||
|
|
||||||
This package includes spec changes outlined by the following BIPs:
|
This package includes spec changes outlined by the following BIPs:
|
||||||
|
|
||||||
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
|
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
|
||||||
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
|
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
|
||||||
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
|
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
|
||||||
*/
|
*/
|
||||||
package blockchain
|
package blockchain
|
||||||
|
|
|
@ -220,6 +220,10 @@ const (
|
||||||
// current chain tip. This is not a block validation rule, but is required
|
// current chain tip. This is not a block validation rule, but is required
|
||||||
// for block proposals submitted via getblocktemplate RPC.
|
// for block proposals submitted via getblocktemplate RPC.
|
||||||
ErrPrevBlockNotBest
|
ErrPrevBlockNotBest
|
||||||
|
|
||||||
|
// ErrBadClaimTrie indicates the calculated ClaimTrie root does not match
|
||||||
|
// the expected value.
|
||||||
|
ErrBadClaimTrie
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||||
|
@ -267,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
||||||
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
||||||
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
||||||
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
||||||
|
ErrBadClaimTrie: "ErrBadClaimTrie",
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the ErrorCode as a human-readable name.
|
// String returns the ErrorCode as a human-readable name.
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example demonstrates how to create a new chain instance and use
|
// This example demonstrates how to create a new chain instance and use
|
||||||
|
@ -69,7 +69,7 @@ func ExampleBlockChain_ProcessBlock() {
|
||||||
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
|
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
// Failed to process block: already have block 9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463
|
||||||
}
|
}
|
||||||
|
|
||||||
// This example demonstrates how to convert the compact "bits" in a block header
|
// This example demonstrates how to convert the compact "bits" in a block header
|
||||||
|
|
|
@ -12,15 +12,15 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/blockchain/fullblocktests"
|
"github.com/lbryio/lbcd/blockchain/fullblocktests"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -139,7 +139,7 @@ func TestFullBlocks(t *testing.T) {
|
||||||
|
|
||||||
// Create a new database and chain instance to run tests against.
|
// Create a new database and chain instance to run tests against.
|
||||||
chain, teardownFunc, err := chainSetup("fullblocktest",
|
chain, teardownFunc, err := chainSetup("fullblocktest",
|
||||||
&chaincfg.RegressionNetParams)
|
fullblocktests.FbRegressionNetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to setup chain instance: %v", err)
|
t.Errorf("Failed to setup chain instance: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
fullblocktests
|
fullblocktests
|
||||||
==============
|
==============
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcd)
|
[](https://github.com/lbryio/lbcd/actions)
|
||||||
[](http://copyfree.org)
|
[](http://copyfree.org)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd/blockchain/fullblocktests)
|
[](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/fullblocktests)
|
||||||
|
|
||||||
Package fullblocktests provides a set of full block tests to be used for testing
|
Package fullblocktests provides a set of full block tests to be used for testing
|
||||||
the consensus validation rules. The tests are intended to be flexible enough to
|
the consensus validation rules. The tests are intended to be flexible enough to
|
||||||
|
@ -20,7 +20,7 @@ of blocks that exercise the consensus validation rules.
|
||||||
## Installation and Updating
|
## Installation and Updating
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ go get -u github.com/btcsuite/btcd/blockchain/fullblocktests
|
$ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
@ -18,24 +18,24 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lbryio/lbcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Intentionally defined here rather than using constants from codebase
|
// Intentionally defined here rather than using constants from codebase
|
||||||
// to ensure consensus changes are detected.
|
// to ensure consensus changes are detected.
|
||||||
maxBlockSigOps = 20000
|
maxBlockSigOps = 20000
|
||||||
maxBlockSize = 1000000
|
maxBlockSize = 8000000
|
||||||
minCoinbaseScriptLen = 2
|
minCoinbaseScriptLen = 2
|
||||||
maxCoinbaseScriptLen = 100
|
maxCoinbaseScriptLen = 100
|
||||||
medianTimeBlocks = 11
|
medianTimeBlocks = 11
|
||||||
maxScriptElementSize = 520
|
maxScriptElementSize = 20000
|
||||||
|
|
||||||
// numLargeReorgBlocks is the number of blocks to use in the large block
|
// numLargeReorgBlocks is the number of blocks to use in the large block
|
||||||
// reorg test (when enabled). This is the equivalent of 1 week's worth
|
// reorg test (when enabled). This is the equivalent of 1 week's worth
|
||||||
|
@ -342,10 +342,8 @@ func solveBlock(header *wire.BlockHeader) bool {
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
hdr.Nonce = i
|
hdr.Nonce = i
|
||||||
hash := hdr.BlockHash()
|
hash := hdr.BlockPoWHash()
|
||||||
if blockchain.HashToBig(&hash).Cmp(
|
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
|
||||||
targetDifficulty) <= 0 {
|
|
||||||
|
|
||||||
results <- sbResult{true, i}
|
results <- sbResult{true, i}
|
||||||
return
|
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
|
// - A coinbase that pays the required subsidy to an OP_TRUE script
|
||||||
// - When a spendable output is provided:
|
// - When a spendable output is provided:
|
||||||
// - A transaction that spends from the provided output the following outputs:
|
// - 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 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
|
// - One that contains an OP_RETURN output with a random uint64 in order to
|
||||||
// ensure the transaction has a unique hash
|
// ensure the transaction has a unique hash
|
||||||
//
|
//
|
||||||
// Additionally, if one or more munge functions are specified, they will be
|
// 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
|
// 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
|
// Create a test generator instance initialized with the genesis block
|
||||||
// as the tip.
|
// as the tip.
|
||||||
g, err := makeTestGenerator(regressionNetParams)
|
g, err := makeTestGenerator(FbRegressionNetParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1444,7 +1442,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
// Keep incrementing the nonce until the hash treated as
|
// Keep incrementing the nonce until the hash treated as
|
||||||
// a uint256 is higher than the limit.
|
// a uint256 is higher than the limit.
|
||||||
b46.Header.Nonce++
|
b46.Header.Nonce++
|
||||||
blockHash := b46.BlockHash()
|
blockHash := b46.Header.BlockPoWHash()
|
||||||
hashNum := blockchain.HashToBig(&blockHash)
|
hashNum := blockchain.HashToBig(&blockHash)
|
||||||
if hashNum.Cmp(g.params.PowLimit) >= 0 {
|
if hashNum.Cmp(g.params.PowLimit) >= 0 {
|
||||||
break
|
break
|
||||||
|
@ -1875,7 +1873,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
//
|
//
|
||||||
// Comment assumptions:
|
// Comment assumptions:
|
||||||
// maxBlockSigOps = 20000
|
// maxBlockSigOps = 20000
|
||||||
// maxScriptElementSize = 520
|
// maxScriptElementSize = 20000
|
||||||
//
|
//
|
||||||
// [0-19999] : OP_CHECKSIG
|
// [0-19999] : OP_CHECKSIG
|
||||||
// [20000] : OP_PUSHDATA4
|
// [20000] : OP_PUSHDATA4
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newHashFromStr converts the passed big-endian hex string into a
|
// newHashFromStr converts the passed big-endian hex string into a
|
||||||
|
@ -54,6 +54,7 @@ var (
|
||||||
Version: 1,
|
Version: 1,
|
||||||
PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"),
|
PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||||
MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"),
|
MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"),
|
||||||
|
ClaimTrie: chainhash.Hash{1}, // EmptyTrieHash
|
||||||
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
|
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
|
||||||
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
|
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
|
||||||
Nonce: 2,
|
Nonce: 2,
|
||||||
|
@ -83,23 +84,25 @@ var (
|
||||||
LockTime: 0,
|
LockTime: 0,
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regTestGenesisBlockHash = regTestGenesisBlock.BlockHash()
|
||||||
)
|
)
|
||||||
|
|
||||||
// regressionNetParams defines the network parameters for the regression test
|
// FbRegressionNetParams defines the network parameters for the regression test
|
||||||
// network.
|
// network.
|
||||||
//
|
//
|
||||||
// NOTE: The test generator intentionally does not use the existing definitions
|
// NOTE: The test generator intentionally does not use the existing definitions
|
||||||
// in the chaincfg package since the intent is to be able to generate known
|
// in the chaincfg package since the intent is to be able to generate known
|
||||||
// good tests which exercise that code. Using the chaincfg parameters would
|
// good tests which exercise that code. Using the chaincfg parameters would
|
||||||
// allow them to change out from under the tests potentially invalidating them.
|
// allow them to change out from under the tests potentially invalidating them.
|
||||||
var regressionNetParams = &chaincfg.Params{
|
var FbRegressionNetParams = &chaincfg.Params{
|
||||||
Name: "regtest",
|
Name: "regtest",
|
||||||
Net: wire.TestNet,
|
Net: wire.TestNet,
|
||||||
DefaultPort: "18444",
|
DefaultPort: "18444",
|
||||||
|
|
||||||
// Chain parameters
|
// Chain parameters
|
||||||
GenesisBlock: ®TestGenesisBlock,
|
GenesisBlock: ®TestGenesisBlock,
|
||||||
GenesisHash: newHashFromStr("5bec7567af40504e0994db3b573c186fffcc4edefe096ff2e58d00523bd7e8a6"),
|
GenesisHash: ®TestGenesisBlockHash,
|
||||||
PowLimit: regressionPowLimit,
|
PowLimit: regressionPowLimit,
|
||||||
PowLimitBits: 0x207fffff,
|
PowLimitBits: 0x207fffff,
|
||||||
CoinbaseMaturity: 100,
|
CoinbaseMaturity: 100,
|
||||||
|
@ -113,6 +116,7 @@ var regressionNetParams = &chaincfg.Params{
|
||||||
ReduceMinDifficulty: true,
|
ReduceMinDifficulty: true,
|
||||||
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
|
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
|
||||||
GenerateSupported: true,
|
GenerateSupported: true,
|
||||||
|
MinerConfirmationWindow: 1,
|
||||||
|
|
||||||
// Checkpoints ordered from oldest to newest.
|
// Checkpoints ordered from oldest to newest.
|
||||||
Checkpoints: nil,
|
Checkpoints: nil,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
indexers
|
indexers
|
||||||
========
|
========
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcd)
|
[](https://github.com/lbryio/lbcd/actions)
|
||||||
[](http://copyfree.org)
|
[](http://copyfree.org)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd/blockchain/indexers)
|
[](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers)
|
||||||
|
|
||||||
Package indexers implements optional block chain indexes.
|
Package indexers implements optional block chain indexes.
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ via an RPC interface.
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ go get -u github.com/btcsuite/btcd/blockchain/indexers
|
$ go get -u github.com/lbryio/lbcd/blockchain/indexers
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
@ -9,13 +9,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -155,7 +155,9 @@ func serializeAddrIndexEntry(blockID uint32, txLoc wire.TxLoc) []byte {
|
||||||
// provided region struct according to the format described in detail above and
|
// provided region struct according to the format described in detail above and
|
||||||
// uses the passed block hash fetching function in order to conver the block ID
|
// uses the passed block hash fetching function in order to conver the block ID
|
||||||
// to the associated block hash.
|
// to the associated block hash.
|
||||||
func deserializeAddrIndexEntry(serialized []byte, region *database.BlockRegion, fetchBlockHash fetchBlockHashFunc) error {
|
func deserializeAddrIndexEntry(serialized []byte, region *database.BlockRegion,
|
||||||
|
fetchBlockHash fetchBlockHashFunc) error {
|
||||||
|
|
||||||
// Ensure there are enough bytes to decode.
|
// Ensure there are enough bytes to decode.
|
||||||
if len(serialized) < txEntrySize {
|
if len(serialized) < txEntrySize {
|
||||||
return errDeserialize("unexpected end of data")
|
return errDeserialize("unexpected end of data")
|
||||||
|
@ -182,7 +184,9 @@ func keyForLevel(addrKey [addrKeySize]byte, level uint8) [levelKeySize]byte {
|
||||||
|
|
||||||
// dbPutAddrIndexEntry updates the address index to include the provided entry
|
// dbPutAddrIndexEntry updates the address index to include the provided entry
|
||||||
// according to the level-based scheme described in detail above.
|
// according to the level-based scheme described in detail above.
|
||||||
func dbPutAddrIndexEntry(bucket internalBucket, addrKey [addrKeySize]byte, blockID uint32, txLoc wire.TxLoc) error {
|
func dbPutAddrIndexEntry(bucket internalBucket, addrKey [addrKeySize]byte,
|
||||||
|
blockID uint32, txLoc wire.TxLoc) error {
|
||||||
|
|
||||||
// Start with level 0 and its initial max number of entries.
|
// Start with level 0 and its initial max number of entries.
|
||||||
curLevel := uint8(0)
|
curLevel := uint8(0)
|
||||||
maxLevelBytes := level0MaxEntries * txEntrySize
|
maxLevelBytes := level0MaxEntries * txEntrySize
|
||||||
|
@ -253,7 +257,10 @@ func dbPutAddrIndexEntry(bucket internalBucket, addrKey [addrKeySize]byte, block
|
||||||
// the given address key and the number of entries skipped since it could have
|
// the given address key and the number of entries skipped since it could have
|
||||||
// been less in the case where there are less total entries than the requested
|
// been less in the case where there are less total entries than the requested
|
||||||
// number of entries to skip.
|
// number of entries to skip.
|
||||||
func dbFetchAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte, numToSkip, numRequested uint32, reverse bool, fetchBlockHash fetchBlockHashFunc) ([]database.BlockRegion, uint32, error) {
|
func dbFetchAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte,
|
||||||
|
numToSkip, numRequested uint32, reverse bool,
|
||||||
|
fetchBlockHash fetchBlockHashFunc) ([]database.BlockRegion, uint32, error) {
|
||||||
|
|
||||||
// When the reverse flag is not set, all levels need to be fetched
|
// When the reverse flag is not set, all levels need to be fetched
|
||||||
// because numToSkip and numRequested are counted from the oldest
|
// because numToSkip and numRequested are counted from the oldest
|
||||||
// transactions (highest level) and thus the total count is needed.
|
// transactions (highest level) and thus the total count is needed.
|
||||||
|
@ -356,7 +363,9 @@ func maxEntriesForLevel(level uint8) int {
|
||||||
// dbRemoveAddrIndexEntries removes the specified number of entries from from
|
// dbRemoveAddrIndexEntries removes the specified number of entries from from
|
||||||
// the address index for the provided key. An assertion error will be returned
|
// the address index for the provided key. An assertion error will be returned
|
||||||
// if the count exceeds the total number of entries in the index.
|
// if the count exceeds the total number of entries in the index.
|
||||||
func dbRemoveAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte, count int) error {
|
func dbRemoveAddrIndexEntries(bucket internalBucket, addrKey [addrKeySize]byte,
|
||||||
|
count int) error {
|
||||||
|
|
||||||
// Nothing to do if no entries are being deleted.
|
// Nothing to do if no entries are being deleted.
|
||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -796,7 +805,9 @@ func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
|
||||||
// that involve a given address.
|
// that involve a given address.
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (idx *AddrIndex) TxRegionsForAddress(dbTx database.Tx, addr btcutil.Address, numToSkip, numRequested uint32, reverse bool) ([]database.BlockRegion, uint32, error) {
|
func (idx *AddrIndex) TxRegionsForAddress(dbTx database.Tx, addr btcutil.Address,
|
||||||
|
numToSkip, numRequested uint32, reverse bool) ([]database.BlockRegion, uint32, error) {
|
||||||
|
|
||||||
addrKey, err := addrToKey(addr)
|
addrKey, err := addrToKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// addrIndexBucket provides a mock address index database bucket by implementing
|
// addrIndexBucket provides a mock address index database bucket by implementing
|
||||||
|
@ -68,7 +68,7 @@ func (b *addrIndexBucket) printLevels(addrKey [addrKeySize]byte) string {
|
||||||
if !bytes.Equal(k[:levelOffset], addrKey[:]) {
|
if !bytes.Equal(k[:levelOffset], addrKey[:]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
level := uint8(k[levelOffset])
|
level := k[levelOffset]
|
||||||
if level > highestLevel {
|
if level > highestLevel {
|
||||||
highestLevel = level
|
highestLevel = level
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func (b *addrIndexBucket) sanityCheck(addrKey [addrKeySize]byte, expectedTotal i
|
||||||
if !bytes.Equal(k[:levelOffset], addrKey[:]) {
|
if !bytes.Equal(k[:levelOffset], addrKey[:]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
level := uint8(k[levelOffset])
|
level := k[levelOffset]
|
||||||
if level > highestLevel {
|
if level > highestLevel {
|
||||||
highestLevel = level
|
highestLevel = level
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btclog"
|
"github.com/btcsuite/btclog"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blockProgressLogger provides periodic logging for other services in order
|
// blockProgressLogger provides periodic logging for other services in order
|
||||||
|
@ -27,8 +27,9 @@ type blockProgressLogger struct {
|
||||||
|
|
||||||
// newBlockProgressLogger returns a new block progress logger.
|
// newBlockProgressLogger returns a new block progress logger.
|
||||||
// The progress message is templated as follows:
|
// The progress message is templated as follows:
|
||||||
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
|
//
|
||||||
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
|
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
|
||||||
|
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
|
||||||
func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {
|
func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {
|
||||||
return &blockProgressLogger{
|
return &blockProgressLogger{
|
||||||
lastBlockLogTime: time.Now(),
|
lastBlockLogTime: time.Now(),
|
||||||
|
|
|
@ -7,14 +7,14 @@ package indexers
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
"github.com/btcsuite/btcutil/gcs"
|
"github.com/lbryio/lbcutil/gcs"
|
||||||
"github.com/btcsuite/btcutil/gcs/builder"
|
"github.com/lbryio/lbcutil/gcs/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/blockchain"
|
"github.com/lbryio/lbcd/blockchain"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -183,7 +183,7 @@ func (m *medianTime) AddTimeSample(sourceID string, timeVal time.Time) {
|
||||||
// Warn if none of the time samples are close.
|
// Warn if none of the time samples are close.
|
||||||
if !remoteHasCloseTime {
|
if !remoteHasCloseTime {
|
||||||
log.Warnf("Please check your date and time " +
|
log.Warnf("Please check your date and time " +
|
||||||
"are correct! btcd will not work " +
|
"are correct! lbcd will not work " +
|
||||||
"properly with an invalid time")
|
"properly with an invalid time")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/lbryio/lbcd/wire"
|
||||||
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -86,7 +87,7 @@ func HashMerkleBranches(left *chainhash.Hash, right *chainhash.Hash) *chainhash.
|
||||||
//
|
//
|
||||||
// The above stored as a linear array is as follows:
|
// 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.
|
// 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
|
// coinbase transaction MUST have exactly one witness element within
|
||||||
// its witness data and that element must be exactly
|
// its witness data and that element must be exactly
|
||||||
// CoinbaseWitnessDataLen bytes.
|
// CoinbaseWitnessDataLen bytes.
|
||||||
|
//
|
||||||
|
// Some popular pool software, for example yiimp, uses pre-BIP0141
|
||||||
|
// coinbase struture. In this case, we don't just accept it, but also
|
||||||
|
// turn it into post-BIP0141 format.
|
||||||
|
if len(coinbaseTx.MsgTx().TxIn[0].Witness) == 0 {
|
||||||
|
log.Infof("pre-BIP0141 coinbase transaction detected. Height: %d", blk.Height())
|
||||||
|
|
||||||
|
var witnessNonce [CoinbaseWitnessDataLen]byte
|
||||||
|
coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
|
||||||
|
blk.MsgBlock().Transactions[0].TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
|
||||||
|
|
||||||
|
// Clear cached serialized block.
|
||||||
|
blk.SetBytes(nil)
|
||||||
|
}
|
||||||
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
|
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
|
||||||
if len(coinbaseWitness) != 1 {
|
if len(coinbaseWitness) != 1 {
|
||||||
str := fmt.Sprintf("the coinbase transaction has %d items in "+
|
str := fmt.Sprintf("the coinbase transaction has %d items in "+
|
||||||
"its witness stack when only one is allowed",
|
"its witness stack when only one is allowed. Height: %d",
|
||||||
len(coinbaseWitness))
|
len(coinbaseWitness), blk.Height())
|
||||||
return ruleError(ErrInvalidWitnessCommitment, str)
|
return ruleError(ErrInvalidWitnessCommitment, str)
|
||||||
}
|
}
|
||||||
witnessNonce := coinbaseWitness[0]
|
witnessNonce := coinbaseWitness[0]
|
||||||
|
|
|
@ -6,16 +6,14 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestMerkle tests the BuildMerkleTreeStore API.
|
// TestMerkle tests the BuildMerkleTreeStore API.
|
||||||
func TestMerkle(t *testing.T) {
|
func TestMerkle(t *testing.T) {
|
||||||
block := btcutil.NewBlock(&Block100000)
|
block := GetBlock100000()
|
||||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
||||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||||
wantMerkle := &Block100000.Header.MerkleRoot
|
wantMerkle := block.MsgBlock().Header.MerkleRoot
|
||||||
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
||||||
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
|
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
|
||||||
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
|
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
|
||||||
|
|
|
@ -50,9 +50,9 @@ func (n NotificationType) String() string {
|
||||||
// Notification defines notification that is sent to the caller via the callback
|
// 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
|
// 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:
|
// as well as associated data that depends on the type as follows:
|
||||||
// - NTBlockAccepted: *btcutil.Block
|
// - NTBlockAccepted: *btcutil.Block
|
||||||
// - NTBlockConnected: *btcutil.Block
|
// - NTBlockConnected: *btcutil.Block
|
||||||
// - NTBlockDisconnected: *btcutil.Block
|
// - NTBlockDisconnected: *btcutil.Block
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
Type NotificationType
|
Type NotificationType
|
||||||
Data interface{}
|
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"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
|
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
|
||||||
|
@ -29,6 +29,10 @@ const (
|
||||||
// not be performed.
|
// not be performed.
|
||||||
BFNoPoWCheck
|
BFNoPoWCheck
|
||||||
|
|
||||||
|
// BFNoDupBlockCheck signals if the block should skip existence
|
||||||
|
// checks.
|
||||||
|
BFNoDupBlockCheck
|
||||||
|
|
||||||
// BFNone is a convenience value to specifically indicate no flags.
|
// BFNone is a convenience value to specifically indicate no flags.
|
||||||
BFNone BehaviorFlags = 0
|
BFNone BehaviorFlags = 0
|
||||||
)
|
)
|
||||||
|
@ -148,24 +152,26 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
|
||||||
blockHash := block.Hash()
|
blockHash := block.Hash()
|
||||||
log.Tracef("Processing block %v", blockHash)
|
log.Tracef("Processing block %v", blockHash)
|
||||||
|
|
||||||
// The block must not already exist in the main chain or side chains.
|
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
|
||||||
exists, err := b.blockExists(blockHash)
|
// The block must not already exist in the main chain or side chains.
|
||||||
if err != nil {
|
exists, err := b.blockExists(blockHash)
|
||||||
return false, false, err
|
if err != nil {
|
||||||
}
|
return false, false, err
|
||||||
if exists {
|
}
|
||||||
str := fmt.Sprintf("already have block %v", blockHash)
|
if exists {
|
||||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
str := fmt.Sprintf("already have block %v", blockHash)
|
||||||
}
|
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||||
|
}
|
||||||
|
|
||||||
// The block must not already exist as an orphan.
|
// The block must not already exist as an orphan.
|
||||||
if _, exists := b.orphans[*blockHash]; exists {
|
if _, exists := b.orphans[*blockHash]; exists {
|
||||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform preliminary sanity checks on the block and its transactions.
|
// Perform preliminary sanity checks on the block and its transactions.
|
||||||
err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
err := checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// txValidateItem holds a transaction along with which input to validate.
|
// txValidateItem holds a transaction along with which input to validate.
|
||||||
|
|
|
@ -6,17 +6,14 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestCheckBlockScripts ensures that validating the all of the scripts in a
|
// TestCheckBlockScripts ensures that validating the all of the scripts in a
|
||||||
// known-good block doesn't return an error.
|
// known-good block doesn't return an error.
|
||||||
func TestCheckBlockScripts(t *testing.T) {
|
func TestCheckBlockScripts(t *testing.T) {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
||||||
|
|
||||||
testBlockNum := 277647
|
testBlockNum := 277647
|
||||||
blockDataFile := fmt.Sprintf("%d.dat.bz2", testBlockNum)
|
blockDataFile := fmt.Sprintf("%d.dat.bz2", testBlockNum)
|
||||||
blocks, err := loadBlocks(blockDataFile)
|
blocks, err := loadBlocks(blockDataFile)
|
||||||
|
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ThresholdState define the various threshold states used when voting on
|
// ThresholdState define the various threshold states used when voting on
|
||||||
|
@ -302,6 +302,12 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment := &b.chainParams.Deployments[deploymentID]
|
deployment := &b.chainParams.Deployments[deploymentID]
|
||||||
|
|
||||||
|
// added to mimic LBRYcrd:
|
||||||
|
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
|
||||||
|
return ThresholdActive, nil
|
||||||
|
}
|
||||||
|
|
||||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||||
cache := &b.deploymentCaches[deploymentID]
|
cache := &b.deploymentCaches[deploymentID]
|
||||||
|
|
||||||
|
@ -310,7 +316,7 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
|
||||||
|
|
||||||
// initThresholdCaches initializes the threshold state caches for each warning
|
// initThresholdCaches initializes the threshold state caches for each warning
|
||||||
// bit and defined deployment and provides warnings if the chain is current per
|
// bit and defined deployment and provides warnings if the chain is current per
|
||||||
// the warnUnknownVersions and warnUnknownRuleActivations functions.
|
// the warnUnknownRuleActivations function.
|
||||||
func (b *BlockChain) initThresholdCaches() error {
|
func (b *BlockChain) initThresholdCaches() error {
|
||||||
// Initialize the warning and deployment caches by calculating the
|
// Initialize the warning and deployment caches by calculating the
|
||||||
// threshold state for each of them. This will ensure the caches are
|
// threshold state for each of them. This will ensure the caches are
|
||||||
|
@ -335,15 +341,9 @@ func (b *BlockChain) initThresholdCaches() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No warnings about unknown rules or versions until the chain is
|
// No warnings about unknown rules until the chain is current.
|
||||||
// current.
|
|
||||||
if b.isCurrent() {
|
if b.isCurrent() {
|
||||||
// Warn if a high enough percentage of the last blocks have
|
|
||||||
// unexpected versions.
|
|
||||||
bestNode := b.bestChain.Tip()
|
bestNode := b.bestChain.Tip()
|
||||||
if err := b.warnUnknownVersions(bestNode); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn if any unknown new rules are either about to activate or
|
// Warn if any unknown new rules are either about to activate or
|
||||||
// have already been activated.
|
// have already been activated.
|
||||||
|
|
|
@ -7,7 +7,7 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestThresholdStateStringer tests the stringized output for the
|
// TestThresholdStateStringer tests the stringized output for the
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -232,24 +232,25 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
|
||||||
//
|
//
|
||||||
// The legacy format is as follows:
|
// 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
|
// Field Type Size
|
||||||
// version VLQ variable
|
// version VLQ variable
|
||||||
// block height VLQ variable
|
// block height VLQ variable
|
||||||
// header code VLQ variable
|
// header code VLQ variable
|
||||||
// unspentness bitmap []byte variable
|
// unspentness bitmap []byte variable
|
||||||
// compressed txouts
|
// compressed txouts
|
||||||
// compressed amount VLQ variable
|
// compressed amount VLQ variable
|
||||||
// compressed script []byte variable
|
// compressed script []byte variable
|
||||||
//
|
//
|
||||||
// The serialized header code format is:
|
// The serialized header code format is:
|
||||||
// bit 0 - containing transaction is a coinbase
|
//
|
||||||
// bit 1 - output zero is unspent
|
// bit 0 - containing transaction is a coinbase
|
||||||
// bit 2 - output one is unspent
|
// bit 1 - output zero is unspent
|
||||||
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
|
// bit 2 - output one is unspent
|
||||||
// are unset, it encodes N-1 since there must be at least one unspent
|
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
|
||||||
// output.
|
// 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:
|
// The rationale for the header code scheme is as follows:
|
||||||
// - Transactions which only pay to a single output and a change output are
|
// - 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:
|
// From tx in main blockchain:
|
||||||
// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
|
// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
|
||||||
//
|
//
|
||||||
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
|
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
|
||||||
// <><><><------------------------------------------------------------------>
|
// <><><><------------------------------------------------------------------>
|
||||||
// | | \--------\ |
|
// | | \--------\ |
|
||||||
// | height | compressed txout 0
|
// | height | compressed txout 0
|
||||||
// version header code
|
// version header code
|
||||||
//
|
//
|
||||||
// - version: 1
|
// - version: 1
|
||||||
// - height: 1
|
// - height: 1
|
||||||
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
|
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
|
||||||
// - unspentness: Nothing since it is zero bytes
|
// - unspentness: Nothing since it is zero bytes
|
||||||
// - compressed txout 0:
|
// - compressed txout 0:
|
||||||
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
|
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
|
||||||
// - 0x04: special script type pay-to-pubkey
|
// - 0x04: special script type pay-to-pubkey
|
||||||
// - 0x96...52: x-coordinate of the pubkey
|
// - 0x96...52: x-coordinate of the pubkey
|
||||||
//
|
//
|
||||||
// Example 2:
|
// Example 2:
|
||||||
// From tx in main blockchain:
|
// From tx in main blockchain:
|
||||||
// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f
|
// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f
|
||||||
//
|
//
|
||||||
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
|
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
|
||||||
// <><----><><><------------------------------------------><-------------------------------------------->
|
// <><----><><><------------------------------------------><-------------------------------------------->
|
||||||
// | | | \-------------------\ | |
|
// | | | \-------------------\ | |
|
||||||
// version | \--------\ unspentness | compressed txout 2
|
// version | \--------\ unspentness | compressed txout 2
|
||||||
// height header code compressed txout 0
|
// height header code compressed txout 0
|
||||||
//
|
//
|
||||||
// - version: 1
|
// - version: 1
|
||||||
// - height: 113931
|
// - height: 113931
|
||||||
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
|
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
|
||||||
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
|
// - 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
|
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||||
// - compressed txout 0:
|
// - compressed txout 0:
|
||||||
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
|
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
|
||||||
// - 0x00: special script type pay-to-pubkey-hash
|
// - 0x00: special script type pay-to-pubkey-hash
|
||||||
// - 0xe2...8a: pubkey hash
|
// - 0xe2...8a: pubkey hash
|
||||||
// - compressed txout 2:
|
// - compressed txout 2:
|
||||||
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
|
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
|
||||||
// - 0x00: special script type pay-to-pubkey-hash
|
// - 0x00: special script type pay-to-pubkey-hash
|
||||||
// - 0xb8...58: pubkey hash
|
// - 0xb8...58: pubkey hash
|
||||||
//
|
//
|
||||||
// Example 3:
|
// Example 3:
|
||||||
// From tx in main blockchain:
|
// From tx in main blockchain:
|
||||||
// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620
|
// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620
|
||||||
//
|
//
|
||||||
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
|
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
|
||||||
// <><----><><----><-------------------------------------------------->
|
// <><----><><----><-------------------------------------------------->
|
||||||
// | | | \-----------------\ |
|
// | | | \-----------------\ |
|
||||||
// version | \--------\ unspentness |
|
// version | \--------\ unspentness |
|
||||||
// height header code compressed txout 22
|
// height header code compressed txout 22
|
||||||
//
|
//
|
||||||
// - version: 1
|
// - version: 1
|
||||||
// - height: 338156
|
// - height: 338156
|
||||||
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
|
// - 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.
|
// 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)
|
// - 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
|
// NOTE: It's +2 since the first two outputs are encoded in the header code
|
||||||
// - compressed txout 22:
|
// - compressed txout 22:
|
||||||
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
|
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
|
||||||
// - 0x01: special script type pay-to-script-hash
|
// - 0x01: special script type pay-to-script-hash
|
||||||
// - 0x1d...e6: script hash
|
// - 0x1d...e6: script hash
|
||||||
func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
|
func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
|
||||||
// Deserialize the version.
|
// Deserialize the version.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,11 +7,11 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/database"
|
"github.com/lbryio/lbcd/database"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// txoFlags is a bitmask defining additional information and state for a
|
// txoFlags is a bitmask defining additional information and state for a
|
||||||
|
@ -111,6 +111,22 @@ func (entry *UtxoEntry) Clone() *UtxoEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewUtxoEntry returns a new UtxoEntry built from the arguments.
|
||||||
|
func NewUtxoEntry(
|
||||||
|
txOut *wire.TxOut, blockHeight int32, isCoinbase bool) *UtxoEntry {
|
||||||
|
var cbFlag txoFlags
|
||||||
|
if isCoinbase {
|
||||||
|
cbFlag |= tfCoinBase
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UtxoEntry{
|
||||||
|
amount: txOut.Value,
|
||||||
|
pkScript: txOut.PkScript,
|
||||||
|
blockHeight: blockHeight,
|
||||||
|
packedFlags: cbFlag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UtxoViewpoint represents a view into the set of unspent transaction outputs
|
// UtxoViewpoint represents a view into the set of unspent transaction outputs
|
||||||
// from a specific point of view in the chain. For example, it could be for
|
// from a specific point of view in the chain. For example, it could be for
|
||||||
// the end of the main chain, some point in the history of the main chain, or
|
// the end of the main chain, some point in the history of the main chain, or
|
||||||
|
|
|
@ -11,11 +11,11 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -40,7 +40,7 @@ const (
|
||||||
|
|
||||||
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
||||||
// value is halved every SubsidyHalvingInterval blocks.
|
// value is halved every SubsidyHalvingInterval blocks.
|
||||||
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
|
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -192,17 +192,44 @@ func isBIP0030Node(node *blockNode) bool {
|
||||||
// At the target block generation rate for the main network, this is
|
// At the target block generation rate for the main network, this is
|
||||||
// approximately every 4 years.
|
// approximately every 4 years.
|
||||||
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
|
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
|
||||||
if chainParams.SubsidyReductionInterval == 0 {
|
h := int64(height)
|
||||||
return baseSubsidy
|
if h == 0 {
|
||||||
|
return btcutil.SatoshiPerBitcoin * 4e8
|
||||||
|
}
|
||||||
|
if h <= 5100 {
|
||||||
|
return btcutil.SatoshiPerBitcoin
|
||||||
|
}
|
||||||
|
if h <= 55000 {
|
||||||
|
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
|
lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval)
|
||||||
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
|
reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2
|
||||||
|
for !withinLevelBounds(reduction, lv) {
|
||||||
|
if ((reduction*reduction + reduction) >> 1) > lv {
|
||||||
|
reduction--
|
||||||
|
} else {
|
||||||
|
reduction++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subsidyReduction := btcutil.SatoshiPerBitcoin * reduction
|
||||||
|
if subsidyReduction >= baseSubsidy {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return baseSubsidy - subsidyReduction
|
||||||
|
}
|
||||||
|
|
||||||
|
func withinLevelBounds(reduction int64, lv int64) bool {
|
||||||
|
if ((reduction*reduction + reduction) >> 1) > lv {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
reduction++
|
||||||
|
return ((reduction*reduction + reduction) >> 1) > lv
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
||||||
// ensure it is sane. These checks are context free.
|
// ensure it is sane.
|
||||||
func CheckTransactionSanity(tx *btcutil.Tx) error {
|
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
|
||||||
// A transaction must have at least one input.
|
// A transaction must have at least one input.
|
||||||
msgTx := tx.MsgTx()
|
msgTx := tx.MsgTx()
|
||||||
if len(msgTx.TxIn) == 0 {
|
if len(msgTx.TxIn) == 0 {
|
||||||
|
@ -261,6 +288,11 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
||||||
btcutil.MaxSatoshi)
|
btcutil.MaxSatoshi)
|
||||||
return ruleError(ErrBadTxOutValue, str)
|
return ruleError(ErrBadTxOutValue, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
|
||||||
|
if err != nil {
|
||||||
|
return ruleError(ErrBadTxOutValue, err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate transaction inputs.
|
// Check for duplicate transaction inputs.
|
||||||
|
@ -302,8 +334,8 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
||||||
// target difficulty as claimed.
|
// target difficulty as claimed.
|
||||||
//
|
//
|
||||||
// The flags modify the behavior of this function as follows:
|
// The flags modify the behavior of this function as follows:
|
||||||
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
|
||||||
// difficulty is not performed.
|
// difficulty is not performed.
|
||||||
func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error {
|
func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error {
|
||||||
// The target difficulty must be larger than zero.
|
// The target difficulty must be larger than zero.
|
||||||
target := CompactToBig(header.Bits)
|
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.
|
// to avoid proof of work checks is set.
|
||||||
if flags&BFNoPoWCheck != BFNoPoWCheck {
|
if flags&BFNoPoWCheck != BFNoPoWCheck {
|
||||||
// The block hash must be less than the claimed target.
|
// The block hash must be less than the claimed target.
|
||||||
hash := header.BlockHash()
|
hash := header.BlockPoWHash()
|
||||||
hashNum := HashToBig(&hash)
|
hashNum := HashToBig(&hash)
|
||||||
if hashNum.Cmp(target) > 0 {
|
if hashNum.Cmp(target) > 0 {
|
||||||
str := fmt.Sprintf("block hash of %064x is higher than "+
|
str := fmt.Sprintf("block hash of %064x is higher than "+
|
||||||
|
@ -515,7 +547,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
|
||||||
// Do some preliminary checks on each transaction to ensure they are
|
// Do some preliminary checks on each transaction to ensure they are
|
||||||
// sane before continuing.
|
// sane before continuing.
|
||||||
for _, tx := range transactions {
|
for _, tx := range transactions {
|
||||||
err := CheckTransactionSanity(tx)
|
err := CheckTransactionSanity(tx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -637,8 +669,8 @@ func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error {
|
||||||
// which depend on its position within the block chain.
|
// which depend on its position within the block chain.
|
||||||
//
|
//
|
||||||
// The flags modify the behavior of this function as follows:
|
// The flags modify the behavior of this function as follows:
|
||||||
// - BFFastAdd: All checks except those involving comparing the header against
|
// - BFFastAdd: All checks except those involving comparing the header against
|
||||||
// the checkpoints are not performed.
|
// the checkpoints are not performed.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the chain state lock held (for writes).
|
// 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 {
|
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.
|
// on its position within the block chain.
|
||||||
//
|
//
|
||||||
// The flags modify the behavior of this function as follows:
|
// The flags modify the behavior of this function as follows:
|
||||||
// - BFFastAdd: The transaction are not checked to see if they are finalized
|
// - BFFastAdd: The transaction are not checked to see if they are finalized
|
||||||
// and the somewhat expensive BIP0034 validation is not performed.
|
// and the somewhat expensive BIP0034 validation is not performed.
|
||||||
//
|
//
|
||||||
// The flags are also passed to checkBlockHeaderContext. See its documentation
|
// The flags are also passed to checkBlockHeaderContext. See its documentation
|
||||||
// for how the flags modify its behavior.
|
// for how the flags modify its behavior.
|
||||||
|
@ -877,7 +909,6 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
txHash := tx.Hash()
|
|
||||||
var totalSatoshiIn int64
|
var totalSatoshiIn int64
|
||||||
for txInIndex, txIn := range tx.MsgTx().TxIn {
|
for txInIndex, txIn := range tx.MsgTx().TxIn {
|
||||||
// Ensure the referenced input transaction is available.
|
// Ensure the referenced input transaction is available.
|
||||||
|
@ -954,7 +985,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
|
||||||
if totalSatoshiIn < totalSatoshiOut {
|
if totalSatoshiIn < totalSatoshiOut {
|
||||||
str := fmt.Sprintf("total value of all transaction inputs for "+
|
str := fmt.Sprintf("total value of all transaction inputs for "+
|
||||||
"transaction %v is %v which is less than the amount "+
|
"transaction %v is %v which is less than the amount "+
|
||||||
"spent of %v", txHash, totalSatoshiIn, totalSatoshiOut)
|
"spent of %v", tx.Hash(), totalSatoshiIn, totalSatoshiOut)
|
||||||
return 0, ruleError(ErrSpendTooHigh, str)
|
return 0, ruleError(ErrSpendTooHigh, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,15 +5,16 @@
|
||||||
package blockchain
|
package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
|
// 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
|
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
||||||
// as expected.
|
// as expected.
|
||||||
func TestCheckBlockSanity(t *testing.T) {
|
func TestCheckBlockSanity(t *testing.T) {
|
||||||
powLimit := chaincfg.MainNetParams.PowLimit
|
powLimit := chaincfg.MainNetParams.PowLimit
|
||||||
block := btcutil.NewBlock(&Block100000)
|
block := GetBlock100000()
|
||||||
timeSource := NewMedianTime()
|
timeSource := NewMedianTime()
|
||||||
err := CheckBlockSanity(block, powLimit, timeSource)
|
err := CheckBlockSanity(block, powLimit, timeSource)
|
||||||
if err != nil {
|
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.
|
// test Block operations.
|
||||||
var Block100000 = wire.MsgBlock{
|
func GetBlock100000() *btcutil.Block {
|
||||||
Header: wire.BlockHeader{
|
var block100000Bytes, _ = hex.DecodeString(block100000Hex)
|
||||||
Version: 1,
|
var results, _ = btcutil.NewBlockFromBytes(block100000Bytes)
|
||||||
PrevBlock: chainhash.Hash([32]byte{ // Make go vet happy.
|
return results
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/lbryio/lbcd/chaincfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -26,15 +26,6 @@ const (
|
||||||
// vbNumBits is the total number of bits available for use with the
|
// vbNumBits is the total number of bits available for use with the
|
||||||
// version bits scheme.
|
// version bits scheme.
|
||||||
vbNumBits = 29
|
vbNumBits = 29
|
||||||
|
|
||||||
// unknownVerNumToCheck is the number of previous blocks to consider
|
|
||||||
// when checking for a threshold of unknown block versions for the
|
|
||||||
// purposes of warning the user.
|
|
||||||
unknownVerNumToCheck = 100
|
|
||||||
|
|
||||||
// unknownVerWarnNum is the threshold of previous blocks that have an
|
|
||||||
// unknown version to use for the purposes of warning the user.
|
|
||||||
unknownVerWarnNum = unknownVerNumToCheck / 2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// bitConditionChecker provides a thresholdConditionChecker which can be used to
|
// bitConditionChecker provides a thresholdConditionChecker which can be used to
|
||||||
|
@ -204,6 +195,12 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
|
||||||
expectedVersion := uint32(vbTopBits)
|
expectedVersion := uint32(vbTopBits)
|
||||||
for id := 0; id < len(b.chainParams.Deployments); id++ {
|
for id := 0; id < len(b.chainParams.Deployments); id++ {
|
||||||
deployment := &b.chainParams.Deployments[id]
|
deployment := &b.chainParams.Deployments[id]
|
||||||
|
|
||||||
|
// added to mimic LBRYcrd:
|
||||||
|
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
cache := &b.deploymentCaches[id]
|
cache := &b.deploymentCaches[id]
|
||||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||||
state, err := b.thresholdState(prevNode, checker, cache)
|
state, err := b.thresholdState(prevNode, checker, cache)
|
||||||
|
@ -264,38 +261,3 @@ func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnUnknownVersions logs a warning if a high enough percentage of the last
|
|
||||||
// blocks have unexpected versions.
|
|
||||||
//
|
|
||||||
// This function MUST be called with the chain state lock held (for writes)
|
|
||||||
func (b *BlockChain) warnUnknownVersions(node *blockNode) error {
|
|
||||||
// Nothing to do if already warned.
|
|
||||||
if b.unknownVersionsWarned {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn if enough previous blocks have unexpected versions.
|
|
||||||
numUpgraded := uint32(0)
|
|
||||||
for i := uint32(0); i < unknownVerNumToCheck && node != nil; i++ {
|
|
||||||
expectedVersion, err := b.calcNextBlockVersion(node.parent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if expectedVersion > vbLegacyBlockVersion &&
|
|
||||||
(node.version & ^expectedVersion) != 0 {
|
|
||||||
|
|
||||||
numUpgraded++
|
|
||||||
}
|
|
||||||
|
|
||||||
node = node.parent
|
|
||||||
}
|
|
||||||
if numUpgraded > unknownVerWarnNum {
|
|
||||||
log.Warn("Unknown block versions are being mined, so new " +
|
|
||||||
"rules might be in effect. Are you running the " +
|
|
||||||
"latest version of the software?")
|
|
||||||
b.unknownVersionsWarned = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ package blockchain
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/lbryio/lbcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -20,11 +20,11 @@ const (
|
||||||
// weight of a "base" byte is 4, while the weight of a witness byte is
|
// weight of a "base" byte is 4, while the weight of a witness byte is
|
||||||
// 1. As a result, for a block to be valid, the BlockWeight MUST be
|
// 1. As a result, for a block to be valid, the BlockWeight MUST be
|
||||||
// less than, or equal to MaxBlockWeight.
|
// less than, or equal to MaxBlockWeight.
|
||||||
MaxBlockWeight = 4000000
|
MaxBlockWeight = 8000000
|
||||||
|
|
||||||
// MaxBlockBaseSize is the maximum number of bytes within a block
|
// MaxBlockBaseSize is the maximum number of bytes within a block
|
||||||
// which can be allocated to non-witness data.
|
// which can be allocated to non-witness data.
|
||||||
MaxBlockBaseSize = 1000000
|
MaxBlockBaseSize = 8000000
|
||||||
|
|
||||||
// MaxBlockSigOpsCost is the maximum number of signature operations
|
// MaxBlockSigOpsCost is the maximum number of signature operations
|
||||||
// allowed for a block. It is calculated via a weighted algorithm which
|
// allowed for a block. It is calculated via a weighted algorithm which
|
||||||
|
|
|
@ -1,68 +1,11 @@
|
||||||
btcec
|
btcec
|
||||||
=====
|
=====
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcec)
|
|
||||||
[](http://copyfree.org)
|
[](http://copyfree.org)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd/btcec)
|
|
||||||
|
|
||||||
Package btcec implements elliptic curve cryptography needed for working with
|
btcec implements elliptic curve cryptography needed for working with
|
||||||
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
|
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
|
||||||
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
|
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
|
||||||
is provided to ensure proper functionality. Package btcec was originally based
|
is provided to ensure proper functionality. Package btcec was originally based
|
||||||
on work from ThePiachu which is licensed under the same terms as Go, but it has
|
on work from ThePiachu which is licensed under the same terms as Go, but it has
|
||||||
signficantly diverged since then. The btcsuite developers original is licensed
|
signficantly diverged since then.
|
||||||
under the liberal ISC license.
|
|
||||||
|
|
||||||
Although this package was primarily written for btcd, it has intentionally been
|
|
||||||
designed so it can be used as a standalone package for any projects needing to
|
|
||||||
use secp256k1 elliptic curve cryptography.
|
|
||||||
|
|
||||||
## Installation and Updating
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go get -u github.com/btcsuite/btcd/btcec
|
|
||||||
```
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
* [Sign Message](http://godoc.org/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](http://godoc.org/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](http://godoc.org/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](http://godoc.org/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.
|
|
||||||
|
|
|
@ -930,6 +930,8 @@ func initS256() {
|
||||||
secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
|
secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
|
||||||
secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
|
secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
|
||||||
secp256k1.BitSize = 256
|
secp256k1.BitSize = 256
|
||||||
|
// Curve name taken from https://safecurves.cr.yp.to/.
|
||||||
|
secp256k1.Name = "secp256k1"
|
||||||
secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
|
secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
|
||||||
big.NewInt(1)), big.NewInt(4))
|
big.NewInt(1)), big.NewInt(4))
|
||||||
secp256k1.H = 1
|
secp256k1.H = 1
|
||||||
|
|
|
@ -527,7 +527,7 @@ type baseMultTest struct {
|
||||||
x, y string
|
x, y string
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: add more test vectors
|
// TODO: add more test vectors
|
||||||
var s256BaseMultTests = []baseMultTest{
|
var s256BaseMultTests = []baseMultTest{
|
||||||
{
|
{
|
||||||
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522",
|
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522",
|
||||||
|
@ -556,7 +556,7 @@ var s256BaseMultTests = []baseMultTest{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: test different curves as well?
|
// TODO: test different curves as well?
|
||||||
func TestBaseMult(t *testing.T) {
|
func TestBaseMult(t *testing.T) {
|
||||||
s256 := S256()
|
s256 := S256()
|
||||||
for i, e := range s256BaseMultTests {
|
for i, e := range s256BaseMultTests {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lbryio/lbcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example demonstrates signing a message with a secp256k1 private key that
|
// This example demonstrates signing a message with a secp256k1 private key that
|
||||||
|
|
|
@ -125,27 +125,30 @@ var (
|
||||||
// the arithmetic needed for elliptic curve operations.
|
// the arithmetic needed for elliptic curve operations.
|
||||||
//
|
//
|
||||||
// The following depicts the internal representation:
|
// The following depicts the internal representation:
|
||||||
// -----------------------------------------------------------------
|
//
|
||||||
// | n[9] | n[8] | ... | n[0] |
|
// -----------------------------------------------------------------
|
||||||
// | 32 bits available | 32 bits available | ... | 32 bits available |
|
// | n[9] | n[8] | ... | n[0] |
|
||||||
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
|
// | 32 bits available | 32 bits available | ... | 32 bits available |
|
||||||
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
|
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
|
||||||
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
|
// | 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:
|
// For example, consider the number 2^49 + 1. It would be represented as:
|
||||||
// n[0] = 1
|
//
|
||||||
// n[1] = 2^23
|
// n[0] = 1
|
||||||
// n[2..9] = 0
|
// n[1] = 2^23
|
||||||
|
// n[2..9] = 0
|
||||||
//
|
//
|
||||||
// The full 256-bit value is then calculated by looping i from 9..0 and
|
// The full 256-bit value is then calculated by looping i from 9..0 and
|
||||||
// doing sum(n[i] * 2^(26i)) like so:
|
// doing sum(n[i] * 2^(26i)) like so:
|
||||||
// n[9] * 2^(26*9) = 0 * 2^234 = 0
|
//
|
||||||
// n[8] * 2^(26*8) = 0 * 2^208 = 0
|
// 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
|
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
|
||||||
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
|
// n[0] * 2^(26*0) = 1 * 2^0 = 1
|
||||||
|
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
|
||||||
type fieldVal struct {
|
type fieldVal struct {
|
||||||
n [10]uint32
|
n [10]uint32
|
||||||
}
|
}
|
||||||
|
@ -226,20 +229,24 @@ func (f *fieldVal) SetBytes(b *[32]byte) *fieldVal {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetByteSlice packs the passed big-endian value into the internal field value
|
// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned
|
||||||
// representation. Only the first 32-bytes are used. As a result, it is up to
|
// integer (meaning it is truncated to the first 32 bytes), packs it into the
|
||||||
// the caller to ensure numbers of the appropriate size are used or the value
|
// internal field value representation, and returns the updated field value.
|
||||||
// will be truncated.
|
//
|
||||||
|
// Note that since passing a slice with more than 32 bytes is truncated, it is
|
||||||
|
// possible that the truncated value is less than the field prime. It is up to
|
||||||
|
// the caller to decide whether it needs to provide numbers of the appropriate
|
||||||
|
// size or if it is acceptable to use this function with the described
|
||||||
|
// truncation behavior.
|
||||||
//
|
//
|
||||||
// The field value is returned to support chaining. This enables syntax like:
|
// The field value is returned to support chaining. This enables syntax like:
|
||||||
// f := new(fieldVal).SetByteSlice(byteSlice)
|
// f := new(fieldVal).SetByteSlice(byteSlice)
|
||||||
func (f *fieldVal) SetByteSlice(b []byte) *fieldVal {
|
func (f *fieldVal) SetByteSlice(b []byte) *fieldVal {
|
||||||
var b32 [32]byte
|
var b32 [32]byte
|
||||||
for i := 0; i < len(b); i++ {
|
if len(b) > 32 {
|
||||||
if i < 32 {
|
b = b[:32]
|
||||||
b32[i+(32-len(b))] = b[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
copy(b32[32-len(b):], b)
|
||||||
return f.SetBytes(&b32)
|
return f.SetBytes(&b32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ package btcec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -965,3 +966,156 @@ func testSqrt(t *testing.T, test sqrtTest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFieldSetBytes ensures that setting a field value to a 256-bit big-endian
|
||||||
|
// unsigned integer via both the slice and array methods works as expected for
|
||||||
|
// edge cases. Random cases are tested via the various other tests.
|
||||||
|
func TestFieldSetBytes(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string // test description
|
||||||
|
in string // hex encoded test value
|
||||||
|
expected [10]uint32 // expected raw ints
|
||||||
|
}{{
|
||||||
|
name: "zero",
|
||||||
|
in: "00",
|
||||||
|
expected: [10]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
}, {
|
||||||
|
name: "field prime",
|
||||||
|
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime - 1",
|
||||||
|
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime + 1 (overflow in word zero)",
|
||||||
|
in: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc30, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime first 32 bits",
|
||||||
|
in: "fffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x00000003f, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime word zero",
|
||||||
|
in: "03fffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime first 64 bits",
|
||||||
|
in: "fffffffefffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffbf, 0x00000fff, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime word zero and one",
|
||||||
|
in: "0ffffefffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffbf, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime first 96 bits",
|
||||||
|
in: "fffffffffffffffefffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x0003ffff, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "field prime word zero, one, and two",
|
||||||
|
in: "3ffffffffffefffffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "overflow in word one (prime + 1<<26)",
|
||||||
|
in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff03fffc2f",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03fffc2f, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "(field prime - 1) * 2 NOT mod P, truncated >32 bytes",
|
||||||
|
in: "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffff85c",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x01fffff8, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x00007fff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "2^256 - 1",
|
||||||
|
in: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||||
|
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "alternating bits",
|
||||||
|
in: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5,
|
||||||
|
0x01696969, 0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x00296969,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "alternating bits 2",
|
||||||
|
in: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
|
||||||
|
expected: [10]uint32{
|
||||||
|
0x025a5a5a, 0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a,
|
||||||
|
0x02969696, 0x01a5a5a5, 0x01696969, 0x025a5a5a, 0x00169696,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
inBytes := hexToBytes(test.in)
|
||||||
|
|
||||||
|
// Ensure setting the bytes via the slice method works as expected.
|
||||||
|
var f fieldVal
|
||||||
|
f.SetByteSlice(inBytes)
|
||||||
|
if !reflect.DeepEqual(f.n, test.expected) {
|
||||||
|
t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name, f.n,
|
||||||
|
test.expected)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure setting the bytes via the array method works as expected.
|
||||||
|
var f2 fieldVal
|
||||||
|
var b32 [32]byte
|
||||||
|
truncatedInBytes := inBytes
|
||||||
|
if len(truncatedInBytes) > 32 {
|
||||||
|
truncatedInBytes = truncatedInBytes[:32]
|
||||||
|
}
|
||||||
|
copy(b32[32-len(truncatedInBytes):], truncatedInBytes)
|
||||||
|
f2.SetBytes(&b32)
|
||||||
|
if !reflect.DeepEqual(f2.n, test.expected) {
|
||||||
|
t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name,
|
||||||
|
f2.n, test.expected)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hexToBytes converts the passed hex string into bytes and will panic if there
|
||||||
|
// is an error. This is only provided for the hard-coded constants so errors in
|
||||||
|
// the source code can be detected. It will only (and must only) be called with
|
||||||
|
// hard-coded values.
|
||||||
|
func hexToBytes(s string) []byte {
|
||||||
|
b, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid hex in source file: " + s)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// This file is ignored during the regular build due to the following build tag.
|
// This file is ignored during the regular build due to the following build tag.
|
||||||
// It is called by go generate and used to automatically generate pre-computed
|
// It is called by go generate and used to automatically generate pre-computed
|
||||||
// tables used to accelerate operations.
|
// tables used to accelerate operations.
|
||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lbryio/lbcd/btcec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
// This file is ignored during the regular build due to the following build tag.
|
// This file is ignored during the regular build due to the following build tag.
|
||||||
// This build tag is set during go generate.
|
// This build tag is set during go generate.
|
||||||
|
//go:build gensecp256k1
|
||||||
// +build gensecp256k1
|
// +build gensecp256k1
|
||||||
|
|
||||||
package btcec
|
package btcec
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"strings"
|
"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
|
// loadS256BytePoints decompresses and deserializes the pre-computed byte points
|
||||||
// used to accelerate scalar base multiplication for the secp256k1 curve. This
|
// used to accelerate scalar base multiplication for the secp256k1 curve. This
|
||||||
|
|
|
@ -232,11 +232,11 @@ func TestPubKeys(t *testing.T) {
|
||||||
var pkStr []byte
|
var pkStr []byte
|
||||||
switch test.format {
|
switch test.format {
|
||||||
case pubkeyUncompressed:
|
case pubkeyUncompressed:
|
||||||
pkStr = (*PublicKey)(pk).SerializeUncompressed()
|
pkStr = pk.SerializeUncompressed()
|
||||||
case pubkeyCompressed:
|
case pubkeyCompressed:
|
||||||
pkStr = (*PublicKey)(pk).SerializeCompressed()
|
pkStr = pk.SerializeCompressed()
|
||||||
case pubkeyHybrid:
|
case pubkeyHybrid:
|
||||||
pkStr = (*PublicKey)(pk).SerializeHybrid()
|
pkStr = pk.SerializeHybrid()
|
||||||
}
|
}
|
||||||
if !bytes.Equal(test.key, pkStr) {
|
if !bytes.Equal(test.key, pkStr) {
|
||||||
t.Errorf("%s pubkey: serialized keys do not match.",
|
t.Errorf("%s pubkey: serialized keys do not match.",
|
||||||
|
|
|
@ -284,6 +284,25 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
|
||||||
// format and thus we match bitcoind's behaviour here.
|
// format and thus we match bitcoind's behaviour here.
|
||||||
func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
|
func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
|
||||||
iter int, doChecks bool) (*PublicKey, error) {
|
iter int, doChecks bool) (*PublicKey, error) {
|
||||||
|
// Parse and validate the R and S signature components.
|
||||||
|
//
|
||||||
|
// Fail if r and s are not in [1, N-1].
|
||||||
|
if sig.R.Cmp(curve.Params().N) != -1 {
|
||||||
|
return nil, errors.New("signature R is >= curve order")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.R.Sign() == 0 {
|
||||||
|
return nil, errors.New("signature R is 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.S.Cmp(curve.Params().N) != -1 {
|
||||||
|
return nil, errors.New("signature S is >= curve order")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.S.Sign() == 0 {
|
||||||
|
return nil, errors.New("signature S is 0")
|
||||||
|
}
|
||||||
|
|
||||||
// 1.1 x = (n * i) + r
|
// 1.1 x = (n * i) + r
|
||||||
Rx := new(big.Int).Mul(curve.Params().N,
|
Rx := new(big.Int).Mul(curve.Params().N,
|
||||||
new(big.Int).SetInt64(int64(iter/2)))
|
new(big.Int).SetInt64(int64(iter/2)))
|
||||||
|
@ -334,6 +353,10 @@ func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
|
||||||
// step to prevent the jacobian conversion back and forth.
|
// step to prevent the jacobian conversion back and forth.
|
||||||
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
|
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
|
||||||
|
|
||||||
|
if Qx.Sign() == 0 && Qy.Sign() == 0 {
|
||||||
|
return nil, errors.New("point (Qx, Qy) equals the point at infinity")
|
||||||
|
}
|
||||||
|
|
||||||
return &PublicKey{
|
return &PublicKey{
|
||||||
Curve: curve,
|
Curve: curve,
|
||||||
X: Qx,
|
X: Qx,
|
||||||
|
@ -393,7 +416,7 @@ func SignCompact(curve *KoblitzCurve, key *PrivateKey,
|
||||||
|
|
||||||
// RecoverCompact verifies the compact signature "signature" of "hash" for the
|
// RecoverCompact verifies the compact signature "signature" of "hash" for the
|
||||||
// Koblitz curve in "curve". If the signature matches then the recovered public
|
// Koblitz curve in "curve". If the signature matches then the recovered public
|
||||||
// key will be returned as well as a boolen if the original key was compressed
|
// key will be returned as well as a boolean if the original key was compressed
|
||||||
// or not, else an error will be returned.
|
// or not, else an error will be returned.
|
||||||
func RecoverCompact(curve *KoblitzCurve, signature,
|
func RecoverCompact(curve *KoblitzCurve, signature,
|
||||||
hash []byte) (*PublicKey, bool, error) {
|
hash []byte) (*PublicKey, bool, error) {
|
||||||
|
|
|
@ -464,8 +464,7 @@ func TestSignatureSerialize(t *testing.T) {
|
||||||
|
|
||||||
func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve,
|
func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve,
|
||||||
data []byte, isCompressed bool) {
|
data []byte, isCompressed bool) {
|
||||||
tmp, _ := NewPrivateKey(curve)
|
priv, _ := NewPrivateKey(curve)
|
||||||
priv := (*PrivateKey)(tmp)
|
|
||||||
|
|
||||||
hashed := []byte("testing")
|
hashed := []byte("testing")
|
||||||
sig, err := SignCompact(curve, priv, hashed, isCompressed)
|
sig, err := SignCompact(curve, priv, hashed, isCompressed)
|
||||||
|
@ -550,12 +549,52 @@ var recoveryTests = []struct {
|
||||||
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
|
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
|
||||||
err: fmt.Errorf("invalid square root"),
|
err: fmt.Errorf("invalid square root"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Point at infinity recovered
|
||||||
|
msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
|
||||||
|
sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
|
||||||
|
err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Low R and S values.
|
// Low R and S values.
|
||||||
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",
|
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",
|
||||||
sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004",
|
sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004",
|
||||||
pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3",
|
pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Zero R value
|
||||||
|
//
|
||||||
|
// Test case contributed by Ethereum Swarm: GH-1651
|
||||||
|
msg: "3060d2c77c1e192d62ad712fb400e04e6f779914a6876328ff3b213fa85d2012",
|
||||||
|
sig: "65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037a3",
|
||||||
|
err: fmt.Errorf("signature R is 0"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Zero R value
|
||||||
|
//
|
||||||
|
// Test case contributed by Ethereum Swarm: GH-1651
|
||||||
|
msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054",
|
||||||
|
sig: "060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c",
|
||||||
|
err: fmt.Errorf("signature R is 0"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// R = N (curve order of secp256k1)
|
||||||
|
msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054",
|
||||||
|
sig: "65fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414100000000000000000000000000000000000000000000000000000000000037a3",
|
||||||
|
err: fmt.Errorf("signature R is >= curve order"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Zero S value
|
||||||
|
msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008",
|
||||||
|
sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549980000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
err: fmt.Errorf("signature S is 0"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// S = N (curve order of secp256k1)
|
||||||
|
msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008",
|
||||||
|
sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e54998fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
|
||||||
|
err: fmt.Errorf("signature S is >= curve order"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecoverCompact(t *testing.T) {
|
func TestRecoverCompact(t *testing.T) {
|
||||||
|
|
|
@ -1,70 +1,8 @@
|
||||||
btcjson
|
btcjson
|
||||||
=======
|
=======
|
||||||
|
|
||||||
[](https://travis-ci.org/btcsuite/btcd)
|
|
||||||
[](http://copyfree.org)
|
[](http://copyfree.org)
|
||||||
[](http://godoc.org/github.com/btcsuite/btcd/btcjson)
|
|
||||||
|
|
||||||
Package btcjson implements concrete types for marshalling to and from the
|
Package btcjson implements concrete types for marshalling to and from the
|
||||||
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
|
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
|
||||||
proper functionality.
|
proper functionality.
|
||||||
|
|
||||||
Although this package was primarily written for the btcsuite, it has
|
|
||||||
intentionally been designed so it can be used as a standalone package for any
|
|
||||||
projects needing to marshal to and from bitcoin JSON-RPC requests and responses.
|
|
||||||
|
|
||||||
Note that although it's possible to use this package directly to implement an
|
|
||||||
RPC client, it is not recommended since it is only intended as an infrastructure
|
|
||||||
package. Instead, RPC clients should use the
|
|
||||||
[btcrpcclient](https://github.com/btcsuite/btcrpcclient) package which provides
|
|
||||||
a full blown RPC client with many features such as automatic connection
|
|
||||||
management, websocket support, automatic notification re-registration on
|
|
||||||
reconnect, and conversion from the raw underlying RPC types (strings, floats,
|
|
||||||
ints, etc) to higher-level types with many nice and useful properties.
|
|
||||||
|
|
||||||
## Installation and Updating
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go get -u github.com/btcsuite/btcd/btcjson
|
|
||||||
```
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
* [Marshal Command](http://godoc.org/github.com/btcsuite/btcd/btcjson#example-MarshalCmd)
|
|
||||||
Demonstrates how to create and marshal a command into a JSON-RPC request.
|
|
||||||
|
|
||||||
* [Unmarshal Command](http://godoc.org/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](http://godoc.org/github.com/btcsuite/btcd/btcjson#example-MarshalResponse)
|
|
||||||
Demonstrates how to marshal a JSON-RPC response.
|
|
||||||
|
|
||||||
* [Unmarshal Response](http://godoc.org/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.
|
|
|
@ -59,6 +59,23 @@ func NewDebugLevelCmd(levelSpec string) *DebugLevelCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateToAddressCmd defines the generatetoaddress JSON-RPC command.
|
||||||
|
type GenerateToAddressCmd struct {
|
||||||
|
NumBlocks int64
|
||||||
|
Address string
|
||||||
|
MaxTries *int64 `jsonrpcdefault:"1000000"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGenerateToAddressCmd returns a new instance which can be used to issue a
|
||||||
|
// generatetoaddress JSON-RPC command.
|
||||||
|
func NewGenerateToAddressCmd(numBlocks int64, address string, maxTries *int64) *GenerateToAddressCmd {
|
||||||
|
return &GenerateToAddressCmd{
|
||||||
|
NumBlocks: numBlocks,
|
||||||
|
Address: address,
|
||||||
|
MaxTries: maxTries,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateCmd defines the generate JSON-RPC command.
|
// GenerateCmd defines the generate JSON-RPC command.
|
||||||
type GenerateCmd struct {
|
type GenerateCmd struct {
|
||||||
NumBlocks uint32
|
NumBlocks uint32
|
||||||
|
@ -131,6 +148,7 @@ func init() {
|
||||||
MustRegisterCmd("debuglevel", (*DebugLevelCmd)(nil), flags)
|
MustRegisterCmd("debuglevel", (*DebugLevelCmd)(nil), flags)
|
||||||
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
|
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
|
||||||
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
|
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("generatetoaddress", (*GenerateToAddressCmd)(nil), flags)
|
||||||
MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags)
|
MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags)
|
||||||
MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags)
|
MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags)
|
||||||
MustRegisterCmd("getheaders", (*GetHeadersCmd)(nil), flags)
|
MustRegisterCmd("getheaders", (*GetHeadersCmd)(nil), flags)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal
|
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal
|
||||||
|
@ -114,6 +114,24 @@ func TestBtcdExtCmds(t *testing.T) {
|
||||||
NumBlocks: 1,
|
NumBlocks: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "generatetoaddress",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("generatetoaddress", 1, "1Address")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGenerateToAddressCmd(1, "1Address", nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"generatetoaddress","params":[1,"1Address"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GenerateToAddressCmd{
|
||||||
|
NumBlocks: 1,
|
||||||
|
Address: "1Address",
|
||||||
|
MaxTries: func() *int64 {
|
||||||
|
var i int64 = 1000000
|
||||||
|
return &i
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getbestblock",
|
name: "getbestblock",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -193,7 +211,7 @@ func TestBtcdExtCmds(t *testing.T) {
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// Marshal the command as created by the new static command
|
// Marshal the command as created by the new static command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
|
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
@ -217,7 +235,7 @@ func TestBtcdExtCmds(t *testing.T) {
|
||||||
|
|
||||||
// Marshal the command as created by the generic new command
|
// Marshal the command as created by the generic new command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err = btcjson.MarshalCmd(testID, cmd)
|
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBtcdExtCustomResults ensures any results that have custom marshalling
|
// TestBtcdExtCustomResults ensures any results that have custom marshalling
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and
|
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and
|
||||||
|
@ -145,7 +145,7 @@ func TestBtcWalletExtCmds(t *testing.T) {
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// Marshal the command as created by the new static command
|
// Marshal the command as created by the new static command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
|
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
@ -169,7 +169,7 @@ func TestBtcWalletExtCmds(t *testing.T) {
|
||||||
|
|
||||||
// Marshal the command as created by the generic new command
|
// Marshal the command as created by the generic new command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err = btcjson.MarshalCmd(testID, cmd)
|
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
package btcjson
|
package btcjson
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"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
|
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
|
||||||
|
@ -46,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
|
// TransactionInput represents the inputs to a transaction. Specifically a
|
||||||
// transaction hash and output number pair.
|
// transaction hash and output number pair.
|
||||||
type TransactionInput struct {
|
type TransactionInput struct {
|
||||||
|
@ -56,20 +67,25 @@ type TransactionInput struct {
|
||||||
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
|
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
|
||||||
type CreateRawTransactionCmd struct {
|
type CreateRawTransactionCmd struct {
|
||||||
Inputs []TransactionInput
|
Inputs []TransactionInput
|
||||||
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
|
Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"`
|
||||||
LockTime *int64
|
LockTime *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCreateRawTransactionCmd returns a new instance which can be used to issue
|
// NewCreateRawTransactionCmd returns a new instance which can be used to issue
|
||||||
// a createrawtransaction JSON-RPC command.
|
// a createrawtransaction JSON-RPC command.
|
||||||
//
|
//
|
||||||
// Amounts are in BTC.
|
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
|
||||||
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
|
// both gets interpreted as the empty slice.
|
||||||
|
func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{},
|
||||||
lockTime *int64) *CreateRawTransactionCmd {
|
lockTime *int64) *CreateRawTransactionCmd {
|
||||||
|
// to make sure we're serializing this to the empty list and not null, we
|
||||||
|
// explicitly initialize the list
|
||||||
|
if inputs == nil {
|
||||||
|
inputs = []TransactionInput{}
|
||||||
|
}
|
||||||
return &CreateRawTransactionCmd{
|
return &CreateRawTransactionCmd{
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
Amounts: amounts,
|
Outputs: outputs,
|
||||||
LockTime: lockTime,
|
LockTime: lockTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +116,65 @@ func NewDecodeScriptCmd(hexScript string) *DecodeScriptCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeriveAddressesCmd defines the deriveaddresses JSON-RPC command.
|
||||||
|
type DeriveAddressesCmd struct {
|
||||||
|
Descriptor string
|
||||||
|
Range *DescriptorRange
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeriveAddressesCmd returns a new instance which can be used to issue a
|
||||||
|
// deriveaddresses JSON-RPC command.
|
||||||
|
func NewDeriveAddressesCmd(descriptor string, descriptorRange *DescriptorRange) *DeriveAddressesCmd {
|
||||||
|
return &DeriveAddressesCmd{
|
||||||
|
Descriptor: descriptor,
|
||||||
|
Range: descriptorRange,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeType defines the different output types to use for the change address
|
||||||
|
// of a transaction built by the node.
|
||||||
|
type ChangeType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ChangeTypeLegacy indicates a P2PKH change address type.
|
||||||
|
ChangeTypeLegacy ChangeType = "legacy"
|
||||||
|
// ChangeTypeP2SHSegWit indicates a P2WPKH-in-P2SH change address type.
|
||||||
|
ChangeTypeP2SHSegWit ChangeType = "p2sh-segwit"
|
||||||
|
// ChangeTypeBech32 indicates a P2WPKH change address type.
|
||||||
|
ChangeTypeBech32 ChangeType = "bech32"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FundRawTransactionOpts are the different options that can be passed to rawtransaction
|
||||||
|
type FundRawTransactionOpts struct {
|
||||||
|
ChangeAddress *string `json:"changeAddress,omitempty"`
|
||||||
|
ChangePosition *int `json:"changePosition,omitempty"`
|
||||||
|
ChangeType *ChangeType `json:"change_type,omitempty"`
|
||||||
|
IncludeWatching *bool `json:"includeWatching,omitempty"`
|
||||||
|
LockUnspents *bool `json:"lockUnspents,omitempty"`
|
||||||
|
FeeRate *float64 `json:"feeRate,omitempty"` // BTC/kB
|
||||||
|
SubtractFeeFromOutputs []int `json:"subtractFeeFromOutputs,omitempty"`
|
||||||
|
Replaceable *bool `json:"replaceable,omitempty"`
|
||||||
|
ConfTarget *int `json:"conf_target,omitempty"`
|
||||||
|
EstimateMode *EstimateSmartFeeMode `json:"estimate_mode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FundRawTransactionCmd defines the fundrawtransaction JSON-RPC command
|
||||||
|
type FundRawTransactionCmd struct {
|
||||||
|
HexTx string
|
||||||
|
Options FundRawTransactionOpts
|
||||||
|
IsWitness *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFundRawTransactionCmd returns a new instance which can be used to issue
|
||||||
|
// a fundrawtransaction JSON-RPC command
|
||||||
|
func NewFundRawTransactionCmd(serializedTx []byte, opts FundRawTransactionOpts, isWitness *bool) *FundRawTransactionCmd {
|
||||||
|
return &FundRawTransactionCmd{
|
||||||
|
HexTx: hex.EncodeToString(serializedTx),
|
||||||
|
Options: opts,
|
||||||
|
IsWitness: isWitness,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetAddedNodeInfoCmd defines the getaddednodeinfo JSON-RPC command.
|
// GetAddedNodeInfoCmd defines the getaddednodeinfo JSON-RPC command.
|
||||||
type GetAddedNodeInfoCmd struct {
|
type GetAddedNodeInfoCmd struct {
|
||||||
DNS bool
|
DNS bool
|
||||||
|
@ -130,8 +205,7 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
|
||||||
// GetBlockCmd defines the getblock JSON-RPC command.
|
// GetBlockCmd defines the getblock JSON-RPC command.
|
||||||
type GetBlockCmd struct {
|
type GetBlockCmd struct {
|
||||||
Hash string
|
Hash string
|
||||||
Verbose *bool `jsonrpcdefault:"true"`
|
Verbosity *int `jsonrpcdefault:"1"`
|
||||||
VerboseTx *bool `jsonrpcdefault:"false"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGetBlockCmd returns a new instance which can be used to issue a getblock
|
// NewGetBlockCmd returns a new instance which can be used to issue a getblock
|
||||||
|
@ -139,11 +213,10 @@ type GetBlockCmd struct {
|
||||||
//
|
//
|
||||||
// The parameters which are pointers indicate they are optional. Passing nil
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
// for optional parameters will use the default value.
|
// for optional parameters will use the default value.
|
||||||
func NewGetBlockCmd(hash string, verbose, verboseTx *bool) *GetBlockCmd {
|
func NewGetBlockCmd(hash string, verbosity *int) *GetBlockCmd {
|
||||||
return &GetBlockCmd{
|
return &GetBlockCmd{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
Verbose: verbose,
|
Verbosity: verbosity,
|
||||||
VerboseTx: verboseTx,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +238,33 @@ func NewGetBlockCountCmd() *GetBlockCountCmd {
|
||||||
return &GetBlockCountCmd{}
|
return &GetBlockCountCmd{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterTypeName defines the type used in the getblockfilter JSON-RPC command for the
|
||||||
|
// filter type field.
|
||||||
|
type FilterTypeName string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FilterTypeBasic is the basic filter type defined in BIP0158.
|
||||||
|
FilterTypeBasic FilterTypeName = "basic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetBlockFilterCmd defines the getblockfilter JSON-RPC command.
|
||||||
|
type GetBlockFilterCmd struct {
|
||||||
|
BlockHash string // The hash of the block
|
||||||
|
FilterType *FilterTypeName // The type name of the filter, default=basic
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetBlockFilterCmd returns a new instance which can be used to issue a
|
||||||
|
// getblockfilter JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
|
// for optional parameters will use the default value.
|
||||||
|
func NewGetBlockFilterCmd(blockHash string, filterType *FilterTypeName) *GetBlockFilterCmd {
|
||||||
|
return &GetBlockFilterCmd{
|
||||||
|
BlockHash: blockHash,
|
||||||
|
FilterType: filterType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockHashCmd defines the getblockhash JSON-RPC command.
|
// GetBlockHashCmd defines the getblockhash JSON-RPC command.
|
||||||
type GetBlockHashCmd struct {
|
type GetBlockHashCmd struct {
|
||||||
Index int64
|
Index int64
|
||||||
|
@ -193,6 +293,50 @@ func NewGetBlockHeaderCmd(hash string, verbose *bool) *GetBlockHeaderCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashOrHeight defines a type that can be used as hash_or_height value in JSON-RPC commands.
|
||||||
|
type HashOrHeight struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface
|
||||||
|
func (h HashOrHeight) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(h.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface
|
||||||
|
func (h *HashOrHeight) UnmarshalJSON(data []byte) error {
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case float64:
|
||||||
|
h.Value = int(v)
|
||||||
|
case string:
|
||||||
|
h.Value = v
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid hash_or_height value: %v", unmarshalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockStatsCmd defines the getblockstats JSON-RPC command.
|
||||||
|
type GetBlockStatsCmd struct {
|
||||||
|
HashOrHeight HashOrHeight
|
||||||
|
Stats *[]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetBlockStatsCmd returns a new instance which can be used to issue a
|
||||||
|
// getblockstats JSON-RPC command. Either height or hash must be specified.
|
||||||
|
func NewGetBlockStatsCmd(hashOrHeight HashOrHeight, stats *[]string) *GetBlockStatsCmd {
|
||||||
|
return &GetBlockStatsCmd{
|
||||||
|
HashOrHeight: hashOrHeight,
|
||||||
|
Stats: stats,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TemplateRequest is a request object as defined in BIP22
|
// TemplateRequest is a request object as defined in BIP22
|
||||||
// (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an
|
// (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an
|
||||||
// pointer argument to GetBlockTemplateCmd.
|
// pointer argument to GetBlockTemplateCmd.
|
||||||
|
@ -216,6 +360,10 @@ type TemplateRequest struct {
|
||||||
// "proposal".
|
// "proposal".
|
||||||
Data string `json:"data,omitempty"`
|
Data string `json:"data,omitempty"`
|
||||||
WorkID string `json:"workid,omitempty"`
|
WorkID string `json:"workid,omitempty"`
|
||||||
|
|
||||||
|
// list of supported softfork deployments, by name
|
||||||
|
// Ref: https://en.bitcoin.it/wiki/BIP_0009#getblocktemplate_changes.
|
||||||
|
Rules []string `json:"rules,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertTemplateRequestField potentially converts the provided value as
|
// convertTemplateRequestField potentially converts the provided value as
|
||||||
|
@ -321,6 +469,24 @@ func NewGetChainTipsCmd() *GetChainTipsCmd {
|
||||||
return &GetChainTipsCmd{}
|
return &GetChainTipsCmd{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChainTxStatsCmd defines the getchaintxstats JSON-RPC command.
|
||||||
|
type GetChainTxStatsCmd struct {
|
||||||
|
NBlocks *int32
|
||||||
|
BlockHash *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetChainTxStatsCmd returns a new instance which can be used to issue a
|
||||||
|
// getchaintxstats JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
|
// for optional parameters will use the default value.
|
||||||
|
func NewGetChainTxStatsCmd(nBlocks *int32, blockHash *string) *GetChainTxStatsCmd {
|
||||||
|
return &GetChainTxStatsCmd{
|
||||||
|
NBlocks: nBlocks,
|
||||||
|
BlockHash: blockHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetConnectionCountCmd defines the getconnectioncount JSON-RPC command.
|
// GetConnectionCountCmd defines the getconnectioncount JSON-RPC command.
|
||||||
type GetConnectionCountCmd struct{}
|
type GetConnectionCountCmd struct{}
|
||||||
|
|
||||||
|
@ -330,6 +496,19 @@ func NewGetConnectionCountCmd() *GetConnectionCountCmd {
|
||||||
return &GetConnectionCountCmd{}
|
return &GetConnectionCountCmd{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDescriptorInfoCmd defines the getdescriptorinfo JSON-RPC command.
|
||||||
|
type GetDescriptorInfoCmd struct {
|
||||||
|
Descriptor string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetDescriptorInfoCmd returns a new instance which can be used to issue a
|
||||||
|
// getdescriptorinfo JSON-RPC command.
|
||||||
|
func NewGetDescriptorInfoCmd(descriptor string) *GetDescriptorInfoCmd {
|
||||||
|
return &GetDescriptorInfoCmd{
|
||||||
|
Descriptor: descriptor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetDifficultyCmd defines the getdifficulty JSON-RPC command.
|
// GetDifficultyCmd defines the getdifficulty JSON-RPC command.
|
||||||
type GetDifficultyCmd struct{}
|
type GetDifficultyCmd struct{}
|
||||||
|
|
||||||
|
@ -433,6 +612,22 @@ func NewGetNetworkHashPSCmd(numBlocks, height *int) *GetNetworkHashPSCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeAddressesCmd defines the getnodeaddresses JSON-RPC command.
|
||||||
|
type GetNodeAddressesCmd struct {
|
||||||
|
Count *int32 `jsonrpcdefault:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetNodeAddressesCmd returns a new instance which can be used to issue a
|
||||||
|
// getnodeaddresses JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
|
// for optional parameters will use the default value.
|
||||||
|
func NewGetNodeAddressesCmd(count *int32) *GetNodeAddressesCmd {
|
||||||
|
return &GetNodeAddressesCmd{
|
||||||
|
Count: count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetPeerInfoCmd defines the getpeerinfo JSON-RPC command.
|
// GetPeerInfoCmd defines the getpeerinfo JSON-RPC command.
|
||||||
type GetPeerInfoCmd struct{}
|
type GetPeerInfoCmd struct{}
|
||||||
|
|
||||||
|
@ -464,7 +659,7 @@ func NewGetRawMempoolCmd(verbose *bool) *GetRawMempoolCmd {
|
||||||
// Core even though it really should be a bool.
|
// Core even though it really should be a bool.
|
||||||
type GetRawTransactionCmd struct {
|
type GetRawTransactionCmd struct {
|
||||||
Txid string
|
Txid string
|
||||||
Verbose *int `jsonrpcdefault:"0"`
|
Verbose *bool `jsonrpcdefault:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGetRawTransactionCmd returns a new instance which can be used to issue a
|
// NewGetRawTransactionCmd returns a new instance which can be used to issue a
|
||||||
|
@ -472,7 +667,7 @@ type GetRawTransactionCmd struct {
|
||||||
//
|
//
|
||||||
// The parameters which are pointers indicate they are optional. Passing nil
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
// for optional parameters will use the default value.
|
// for optional parameters will use the default value.
|
||||||
func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd {
|
func NewGetRawTransactionCmd(txHash string, verbose *bool) *GetRawTransactionCmd {
|
||||||
return &GetRawTransactionCmd{
|
return &GetRawTransactionCmd{
|
||||||
Txid: txHash,
|
Txid: txHash,
|
||||||
Verbose: verbose,
|
Verbose: verbose,
|
||||||
|
@ -571,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.
|
// PingCmd defines the ping JSON-RPC command.
|
||||||
type PingCmd struct{}
|
type PingCmd struct{}
|
||||||
|
|
||||||
|
@ -634,11 +838,60 @@ func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllowHighFeesOrMaxFeeRate defines a type that can either be the legacy
|
||||||
|
// allowhighfees boolean field or the new maxfeerate int field.
|
||||||
|
type AllowHighFeesOrMaxFeeRate struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of this struct, used for printing
|
||||||
|
// the marshaled default value in the help text.
|
||||||
|
func (a AllowHighFeesOrMaxFeeRate) String() string {
|
||||||
|
b, _ := a.MarshalJSON()
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface
|
||||||
|
func (a AllowHighFeesOrMaxFeeRate) MarshalJSON() ([]byte, error) {
|
||||||
|
// The default value is false which only works with the legacy versions.
|
||||||
|
if a.Value == nil ||
|
||||||
|
(reflect.ValueOf(a.Value).Kind() == reflect.Ptr &&
|
||||||
|
reflect.ValueOf(a.Value).IsNil()) {
|
||||||
|
|
||||||
|
return json.Marshal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(a.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface
|
||||||
|
func (a *AllowHighFeesOrMaxFeeRate) UnmarshalJSON(data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case bool:
|
||||||
|
a.Value = Bool(v)
|
||||||
|
case float64:
|
||||||
|
a.Value = Int32(int32(v))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid allowhighfees or maxfeerate value: "+
|
||||||
|
"%v", unmarshalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendRawTransactionCmd defines the sendrawtransaction JSON-RPC command.
|
// SendRawTransactionCmd defines the sendrawtransaction JSON-RPC command.
|
||||||
type SendRawTransactionCmd struct {
|
type SendRawTransactionCmd struct {
|
||||||
HexTx string
|
HexTx string
|
||||||
AllowHighFees *bool `jsonrpcdefault:"false"`
|
FeeSetting *AllowHighFeesOrMaxFeeRate `jsonrpcdefault:"false"`
|
||||||
MaxFeeRate *int32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
||||||
|
@ -648,8 +901,10 @@ type SendRawTransactionCmd struct {
|
||||||
// for optional parameters will use the default value.
|
// for optional parameters will use the default value.
|
||||||
func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransactionCmd {
|
func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransactionCmd {
|
||||||
return &SendRawTransactionCmd{
|
return &SendRawTransactionCmd{
|
||||||
HexTx: hexTx,
|
HexTx: hexTx,
|
||||||
AllowHighFees: allowHighFees,
|
FeeSetting: &AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: allowHighFees,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,8 +914,43 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac
|
||||||
// A 0 maxFeeRate indicates that a maximum fee rate won't be enforced.
|
// A 0 maxFeeRate indicates that a maximum fee rate won't be enforced.
|
||||||
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
|
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
|
||||||
return &SendRawTransactionCmd{
|
return &SendRawTransactionCmd{
|
||||||
HexTx: hexTx,
|
HexTx: hexTx,
|
||||||
MaxFeeRate: &maxFeeRate,
|
FeeSetting: &AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: &maxFeeRate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,6 +972,24 @@ func NewSetGenerateCmd(generate bool, genProcLimit *int) *SetGenerateCmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignMessageWithPrivKeyCmd defines the signmessagewithprivkey JSON-RPC command.
|
||||||
|
type SignMessageWithPrivKeyCmd struct {
|
||||||
|
PrivKey string // base 58 Wallet Import format private key
|
||||||
|
Message string // Message to sign
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSignMessageWithPrivKey returns a new instance which can be used to issue a
|
||||||
|
// signmessagewithprivkey JSON-RPC command.
|
||||||
|
//
|
||||||
|
// The first parameter is a private key in base 58 Wallet Import format.
|
||||||
|
// The second parameter is the message to sign.
|
||||||
|
func NewSignMessageWithPrivKey(privKey, message string) *SignMessageWithPrivKeyCmd {
|
||||||
|
return &SignMessageWithPrivKeyCmd{
|
||||||
|
PrivKey: privKey,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StopCmd defines the stop JSON-RPC command.
|
// StopCmd defines the stop JSON-RPC command.
|
||||||
type StopCmd struct{}
|
type StopCmd struct{}
|
||||||
|
|
||||||
|
@ -793,18 +1101,24 @@ func init() {
|
||||||
MustRegisterCmd("createrawtransaction", (*CreateRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("createrawtransaction", (*CreateRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("decoderawtransaction", (*DecodeRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("decoderawtransaction", (*DecodeRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("decodescript", (*DecodeScriptCmd)(nil), flags)
|
MustRegisterCmd("decodescript", (*DecodeScriptCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("deriveaddresses", (*DeriveAddressesCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("fundrawtransaction", (*FundRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("getaddednodeinfo", (*GetAddedNodeInfoCmd)(nil), flags)
|
MustRegisterCmd("getaddednodeinfo", (*GetAddedNodeInfoCmd)(nil), flags)
|
||||||
MustRegisterCmd("getbestblockhash", (*GetBestBlockHashCmd)(nil), flags)
|
MustRegisterCmd("getbestblockhash", (*GetBestBlockHashCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblock", (*GetBlockCmd)(nil), flags)
|
MustRegisterCmd("getblock", (*GetBlockCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblockchaininfo", (*GetBlockChainInfoCmd)(nil), flags)
|
MustRegisterCmd("getblockchaininfo", (*GetBlockChainInfoCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags)
|
MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getblockfilter", (*GetBlockFilterCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags)
|
MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags)
|
MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getblockstats", (*GetBlockStatsCmd)(nil), flags)
|
||||||
MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags)
|
MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags)
|
||||||
MustRegisterCmd("getcfilter", (*GetCFilterCmd)(nil), flags)
|
MustRegisterCmd("getcfilter", (*GetCFilterCmd)(nil), flags)
|
||||||
MustRegisterCmd("getcfilterheader", (*GetCFilterHeaderCmd)(nil), flags)
|
MustRegisterCmd("getcfilterheader", (*GetCFilterHeaderCmd)(nil), flags)
|
||||||
MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags)
|
MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getchaintxstats", (*GetChainTxStatsCmd)(nil), flags)
|
||||||
MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags)
|
MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getdescriptorinfo", (*GetDescriptorInfoCmd)(nil), flags)
|
||||||
MustRegisterCmd("getdifficulty", (*GetDifficultyCmd)(nil), flags)
|
MustRegisterCmd("getdifficulty", (*GetDifficultyCmd)(nil), flags)
|
||||||
MustRegisterCmd("getgenerate", (*GetGenerateCmd)(nil), flags)
|
MustRegisterCmd("getgenerate", (*GetGenerateCmd)(nil), flags)
|
||||||
MustRegisterCmd("gethashespersec", (*GetHashesPerSecCmd)(nil), flags)
|
MustRegisterCmd("gethashespersec", (*GetHashesPerSecCmd)(nil), flags)
|
||||||
|
@ -815,7 +1129,11 @@ func init() {
|
||||||
MustRegisterCmd("getnetworkinfo", (*GetNetworkInfoCmd)(nil), flags)
|
MustRegisterCmd("getnetworkinfo", (*GetNetworkInfoCmd)(nil), flags)
|
||||||
MustRegisterCmd("getnettotals", (*GetNetTotalsCmd)(nil), flags)
|
MustRegisterCmd("getnettotals", (*GetNetTotalsCmd)(nil), flags)
|
||||||
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
|
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
|
||||||
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
|
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("setban", (*SetBanCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags)
|
||||||
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
|
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
|
||||||
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)
|
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)
|
||||||
|
@ -830,6 +1148,7 @@ func init() {
|
||||||
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
|
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
|
||||||
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
|
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
|
||||||
|
MustRegisterCmd("signmessagewithprivkey", (*SignMessageWithPrivKeyCmd)(nil), flags)
|
||||||
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
|
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
|
||||||
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
|
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
|
||||||
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)
|
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)
|
||||||
|
|
|
@ -6,13 +6,14 @@ package btcjson_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/lbryio/lbcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
|
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
|
||||||
|
@ -51,13 +52,28 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
txInputs := []btcjson.TransactionInput{
|
txInputs := []btcjson.TransactionInput{
|
||||||
{Txid: "123", Vout: 1},
|
{Txid: "123", Vout: 1},
|
||||||
}
|
}
|
||||||
amounts := map[string]float64{"456": .0123}
|
txOutputs := map[string]interface{}{"456": .0123}
|
||||||
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
|
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
|
||||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||||
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||||
Amounts: map[string]float64{"456": .0123},
|
Outputs: map[string]interface{}{"456": .0123},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "createrawtransaction - no inputs",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
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{},
|
||||||
|
Outputs: map[string]interface{}{"456": .0123},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -70,17 +86,137 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
txInputs := []btcjson.TransactionInput{
|
txInputs := []btcjson.TransactionInput{
|
||||||
{Txid: "123", Vout: 1},
|
{Txid: "123", Vout: 1},
|
||||||
}
|
}
|
||||||
amounts := map[string]float64{"456": .0123}
|
txOutputs := map[string]interface{}{"456": .0123}
|
||||||
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
|
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}`,
|
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
|
||||||
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||||
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||||
Amounts: map[string]float64{"456": .0123},
|
Outputs: map[string]interface{}{"456": .0123},
|
||||||
LockTime: btcjson.Int64(12312333333),
|
LockTime: btcjson.Int64(12312333333),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "createrawtransaction with data",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
|
||||||
|
`{"data":"6a134920616d204672616374616c456e6372797074"}`)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
txInputs := []btcjson.TransactionInput{
|
||||||
|
{Txid: "123", Vout: 1},
|
||||||
|
}
|
||||||
|
txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
|
||||||
|
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.CreateRawTransactionCmd{
|
||||||
|
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
|
||||||
|
Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fundrawtransaction - empty opts",
|
||||||
|
newCmd: func() (i interface{}, e error) {
|
||||||
|
return btcjson.NewCmd("fundrawtransaction", "deadbeef", "{}")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
deadbeef, err := hex.DecodeString("deadbeef")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{}, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{}],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.FundRawTransactionCmd{
|
||||||
|
HexTx: "deadbeef",
|
||||||
|
Options: btcjson.FundRawTransactionOpts{},
|
||||||
|
IsWitness: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fundrawtransaction - full opts",
|
||||||
|
newCmd: func() (i interface{}, e error) {
|
||||||
|
return btcjson.NewCmd("fundrawtransaction", "deadbeef", `{"changeAddress":"bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655","changePosition":1,"change_type":"legacy","includeWatching":true,"lockUnspents":true,"feeRate":0.7,"subtractFeeFromOutputs":[0],"replaceable":true,"conf_target":8,"estimate_mode":"ECONOMICAL"}`)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
deadbeef, err := hex.DecodeString("deadbeef")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
changeAddress := "bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655"
|
||||||
|
change := 1
|
||||||
|
changeType := btcjson.ChangeTypeLegacy
|
||||||
|
watching := true
|
||||||
|
lockUnspents := true
|
||||||
|
feeRate := 0.7
|
||||||
|
replaceable := true
|
||||||
|
confTarget := 8
|
||||||
|
|
||||||
|
return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{
|
||||||
|
ChangeAddress: &changeAddress,
|
||||||
|
ChangePosition: &change,
|
||||||
|
ChangeType: &changeType,
|
||||||
|
IncludeWatching: &watching,
|
||||||
|
LockUnspents: &lockUnspents,
|
||||||
|
FeeRate: &feeRate,
|
||||||
|
SubtractFeeFromOutputs: []int{0},
|
||||||
|
Replaceable: &replaceable,
|
||||||
|
ConfTarget: &confTarget,
|
||||||
|
EstimateMode: &btcjson.EstimateModeEconomical,
|
||||||
|
}, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{"changeAddress":"bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655","changePosition":1,"change_type":"legacy","includeWatching":true,"lockUnspents":true,"feeRate":0.7,"subtractFeeFromOutputs":[0],"replaceable":true,"conf_target":8,"estimate_mode":"ECONOMICAL"}],"id":1}`,
|
||||||
|
unmarshalled: func() interface{} {
|
||||||
|
changeAddress := "bcrt1qeeuctq9wutlcl5zatge7rjgx0k45228cxez655"
|
||||||
|
change := 1
|
||||||
|
changeType := btcjson.ChangeTypeLegacy
|
||||||
|
watching := true
|
||||||
|
lockUnspents := true
|
||||||
|
feeRate := 0.7
|
||||||
|
replaceable := true
|
||||||
|
confTarget := 8
|
||||||
|
return &btcjson.FundRawTransactionCmd{
|
||||||
|
HexTx: "deadbeef",
|
||||||
|
Options: btcjson.FundRawTransactionOpts{
|
||||||
|
ChangeAddress: &changeAddress,
|
||||||
|
ChangePosition: &change,
|
||||||
|
ChangeType: &changeType,
|
||||||
|
IncludeWatching: &watching,
|
||||||
|
LockUnspents: &lockUnspents,
|
||||||
|
FeeRate: &feeRate,
|
||||||
|
SubtractFeeFromOutputs: []int{0},
|
||||||
|
Replaceable: &replaceable,
|
||||||
|
ConfTarget: &confTarget,
|
||||||
|
EstimateMode: &btcjson.EstimateModeEconomical,
|
||||||
|
},
|
||||||
|
IsWitness: nil,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fundrawtransaction - iswitness",
|
||||||
|
newCmd: func() (i interface{}, e error) {
|
||||||
|
return btcjson.NewCmd("fundrawtransaction", "deadbeef", "{}", true)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
deadbeef, err := hex.DecodeString("deadbeef")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
t := true
|
||||||
|
return btcjson.NewFundRawTransactionCmd(deadbeef, btcjson.FundRawTransactionOpts{}, &t)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"fundrawtransaction","params":["deadbeef",{},true],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.FundRawTransactionCmd{
|
||||||
|
HexTx: "deadbeef",
|
||||||
|
Options: btcjson.FundRawTransactionOpts{},
|
||||||
|
IsWitness: func() *bool {
|
||||||
|
t := true
|
||||||
|
return &t
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "decoderawtransaction",
|
name: "decoderawtransaction",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -103,6 +239,51 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
|
||||||
unmarshalled: &btcjson.DecodeScriptCmd{HexScript: "00"},
|
unmarshalled: &btcjson.DecodeScriptCmd{HexScript: "00"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "deriveaddresses no range",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("deriveaddresses", "00")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewDeriveAddressesCmd("00", nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.DeriveAddressesCmd{Descriptor: "00"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deriveaddresses int range",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"deriveaddresses", "00", btcjson.DescriptorRange{Value: 2})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewDeriveAddressesCmd(
|
||||||
|
"00", &btcjson.DescriptorRange{Value: 2})
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",2],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.DeriveAddressesCmd{
|
||||||
|
Descriptor: "00",
|
||||||
|
Range: &btcjson.DescriptorRange{Value: 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deriveaddresses slice range",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd(
|
||||||
|
"deriveaddresses", "00",
|
||||||
|
btcjson.DescriptorRange{Value: []int{0, 2}},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewDeriveAddressesCmd(
|
||||||
|
"00", &btcjson.DescriptorRange{Value: []int{0, 2}})
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"deriveaddresses","params":["00",[0,2]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.DeriveAddressesCmd{
|
||||||
|
Descriptor: "00",
|
||||||
|
Range: &btcjson.DescriptorRange{Value: []int{0, 2}},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getaddednodeinfo",
|
name: "getaddednodeinfo",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -141,51 +322,58 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getblock",
|
name: "getblock",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblock", "123", btcjson.Int(0))
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockCmd("123", btcjson.Int(0))
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockCmd{
|
||||||
|
Hash: "123",
|
||||||
|
Verbosity: btcjson.Int(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getblock default verbosity",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("getblock", "123")
|
return btcjson.NewCmd("getblock", "123")
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewGetBlockCmd("123", nil, nil)
|
return btcjson.NewGetBlockCmd("123", nil)
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetBlockCmd{
|
unmarshalled: &btcjson.GetBlockCmd{
|
||||||
Hash: "123",
|
Hash: "123",
|
||||||
Verbose: btcjson.Bool(true),
|
Verbosity: btcjson.Int(1),
|
||||||
VerboseTx: btcjson.Bool(false),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getblock required optional1",
|
name: "getblock required optional1",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
// Intentionally use a source param that is
|
return btcjson.NewCmd("getblock", "123", btcjson.Int(1))
|
||||||
// more pointers than the destination to
|
|
||||||
// exercise that path.
|
|
||||||
verbosePtr := btcjson.Bool(true)
|
|
||||||
return btcjson.NewCmd("getblock", "123", &verbosePtr)
|
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil)
|
return btcjson.NewGetBlockCmd("123", btcjson.Int(1))
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetBlockCmd{
|
unmarshalled: &btcjson.GetBlockCmd{
|
||||||
Hash: "123",
|
Hash: "123",
|
||||||
Verbose: btcjson.Bool(true),
|
Verbosity: btcjson.Int(1),
|
||||||
VerboseTx: btcjson.Bool(false),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getblock required optional2",
|
name: "getblock required optional2",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("getblock", "123", true, true)
|
return btcjson.NewCmd("getblock", "123", btcjson.Int(2))
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true))
|
return btcjson.NewGetBlockCmd("123", btcjson.Int(2))
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true,true],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",2],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetBlockCmd{
|
unmarshalled: &btcjson.GetBlockCmd{
|
||||||
Hash: "123",
|
Hash: "123",
|
||||||
Verbose: btcjson.Bool(true),
|
Verbosity: btcjson.Int(2),
|
||||||
VerboseTx: btcjson.Bool(true),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -210,6 +398,28 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetBlockCountCmd{},
|
unmarshalled: &btcjson.GetBlockCountCmd{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getblockfilter",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockfilter", "0000afaf")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getblockfilter optional filtertype",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockfilter", "0000afaf", "basic")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getblockhash",
|
name: "getblockhash",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -235,6 +445,60 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
Verbose: btcjson.Bool(true),
|
Verbose: btcjson.Bool(true),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getblockstats height",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockStatsCmd{
|
||||||
|
HashOrHeight: btcjson.HashOrHeight{Value: 123},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getblockstats hash",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockStatsCmd{
|
||||||
|
HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getblockstats height optional stats",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: 123}, []string{"avgfee", "maxfee"})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: 123}, &[]string{"avgfee", "maxfee"})
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":[123,["avgfee","maxfee"]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockStatsCmd{
|
||||||
|
HashOrHeight: btcjson.HashOrHeight{Value: 123},
|
||||||
|
Stats: &[]string{"avgfee", "maxfee"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getblockstats hash optional stats",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getblockstats", btcjson.HashOrHeight{Value: "deadbeef"}, []string{"avgfee", "maxfee"})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetBlockStatsCmd(btcjson.HashOrHeight{Value: "deadbeef"}, &[]string{"avgfee", "maxfee"})
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getblockstats","params":["deadbeef",["avgfee","maxfee"]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetBlockStatsCmd{
|
||||||
|
HashOrHeight: btcjson.HashOrHeight{Value: "deadbeef"},
|
||||||
|
Stats: &[]string{"avgfee", "maxfee"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getblocktemplate",
|
name: "getblocktemplate",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -361,6 +625,44 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetChainTipsCmd{},
|
unmarshalled: &btcjson.GetChainTipsCmd{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getchaintxstats",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getchaintxstats")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetChainTxStatsCmd(nil, nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getchaintxstats","params":[],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetChainTxStatsCmd{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getchaintxstats optional nblocks",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getchaintxstats", btcjson.Int32(1000))
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetChainTxStatsCmd(btcjson.Int32(1000), nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getchaintxstats","params":[1000],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetChainTxStatsCmd{
|
||||||
|
NBlocks: btcjson.Int32(1000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getchaintxstats optional nblocks and blockhash",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getchaintxstats", btcjson.Int32(1000), btcjson.String("0000afaf"))
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetChainTxStatsCmd(btcjson.Int32(1000), btcjson.String("0000afaf"))
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getchaintxstats","params":[1000,"0000afaf"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetChainTxStatsCmd{
|
||||||
|
NBlocks: btcjson.Int32(1000),
|
||||||
|
BlockHash: btcjson.String("0000afaf"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getconnectioncount",
|
name: "getconnectioncount",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -515,6 +817,32 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
Height: btcjson.Int(123),
|
Height: btcjson.Int(123),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getnodeaddresses",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getnodeaddresses")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetNodeAddressesCmd(nil)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetNodeAddressesCmd{
|
||||||
|
Count: btcjson.Int32(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "getnodeaddresses optional",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getnodeaddresses", 10)
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetNodeAddressesCmd(btcjson.Int32(10))
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[10],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetNodeAddressesCmd{
|
||||||
|
Count: btcjson.Int32(10),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getpeerinfo",
|
name: "getpeerinfo",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -563,21 +891,21 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetRawTransactionCmd{
|
unmarshalled: &btcjson.GetRawTransactionCmd{
|
||||||
Txid: "123",
|
Txid: "123",
|
||||||
Verbose: btcjson.Int(0),
|
Verbose: btcjson.Bool(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getrawtransaction optional",
|
name: "getrawtransaction optional",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("getrawtransaction", "123", 1)
|
return btcjson.NewCmd("getrawtransaction", "123", true)
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
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{
|
unmarshalled: &btcjson.GetRawTransactionCmd{
|
||||||
Txid: "123",
|
Txid: "123",
|
||||||
Verbose: btcjson.Int(1),
|
Verbose: btcjson.Bool(true),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -892,32 +1220,72 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
FilterAddrs: &[]string{"1Address"},
|
FilterAddrs: &[]string{"1Address"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "searchrawtransactions",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, "null", true, []string{"1Address"})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewSearchRawTransactionsCmd("1Address",
|
||||||
|
btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), nil, btcjson.Bool(true), &[]string{"1Address"})
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,null,true,["1Address"]],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||||
|
Address: "1Address",
|
||||||
|
Verbose: btcjson.Int(0),
|
||||||
|
Skip: btcjson.Int(5),
|
||||||
|
Count: btcjson.Int(10),
|
||||||
|
VinExtra: nil,
|
||||||
|
Reverse: btcjson.Bool(true),
|
||||||
|
FilterAddrs: &[]string{"1Address"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "sendrawtransaction",
|
name: "sendrawtransaction",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("sendrawtransaction", "1122")
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{})
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewSendRawTransactionCmd("1122", nil)
|
return btcjson.NewSendRawTransactionCmd("1122", nil)
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122"],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
||||||
unmarshalled: &btcjson.SendRawTransactionCmd{
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
HexTx: "1122",
|
HexTx: "1122",
|
||||||
AllowHighFees: btcjson.Bool(false),
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Bool(false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sendrawtransaction optional",
|
name: "sendrawtransaction optional",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("sendrawtransaction", "1122", false)
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Bool(false)})
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
|
return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
||||||
unmarshalled: &btcjson.SendRawTransactionCmd{
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
HexTx: "1122",
|
HexTx: "1122",
|
||||||
AllowHighFees: btcjson.Bool(false),
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sendrawtransaction optional, bitcoind >= 0.19.0",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Int32(1234)})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewBitcoindSendRawTransactionCmd("1122", 1234)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",1234],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
|
HexTx: "1122",
|
||||||
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Int32(1234),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -948,6 +1316,20 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
GenProcLimit: btcjson.Int(6),
|
GenProcLimit: btcjson.Int(6),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "signmessagewithprivkey",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("signmessagewithprivkey", "5Hue", "Hey")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewSignMessageWithPrivKey("5Hue", "Hey")
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"signmessagewithprivkey","params":["5Hue","Hey"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.SignMessageWithPrivKeyCmd{
|
||||||
|
PrivKey: "5Hue",
|
||||||
|
Message: "Hey",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "stop",
|
name: "stop",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
|
@ -1086,13 +1468,24 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
Proof: "test",
|
Proof: "test",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getdescriptorinfo",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("getdescriptorinfo", "123")
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewGetDescriptorInfoCmd("123")
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"getdescriptorinfo","params":["123"],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.GetDescriptorInfoCmd{Descriptor: "123"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Running %d tests", len(tests))
|
t.Logf("Running %d tests", len(tests))
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// Marshal the command as created by the new static command
|
// Marshal the command as created by the new static command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
|
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
@ -1117,7 +1510,7 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
|
|
||||||
// Marshal the command as created by the generic new command
|
// Marshal the command as created by the generic new command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err = btcjson.MarshalCmd(testID, cmd)
|
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
|
|
@ -4,7 +4,16 @@
|
||||||
|
|
||||||
package btcjson
|
package btcjson
|
||||||
|
|
||||||
import "encoding/json"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbcd/wire"
|
||||||
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
|
)
|
||||||
|
|
||||||
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
|
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
|
||||||
// the verbose flag is set. When the verbose flag is not set, getblockheader
|
// the verbose flag is set. When the verbose flag is not set, getblockheader
|
||||||
|
@ -16,6 +25,7 @@ type GetBlockHeaderVerboseResult struct {
|
||||||
Version int32 `json:"version"`
|
Version int32 `json:"version"`
|
||||||
VersionHex string `json:"versionHex"`
|
VersionHex string `json:"versionHex"`
|
||||||
MerkleRoot string `json:"merkleroot"`
|
MerkleRoot string `json:"merkleroot"`
|
||||||
|
ClaimTrie string `json:"nameclaimroot,omitempty"`
|
||||||
Time int64 `json:"time"`
|
Time int64 `json:"time"`
|
||||||
Nonce uint64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
Bits string `json:"bits"`
|
Bits string `json:"bits"`
|
||||||
|
@ -24,27 +34,95 @@ type GetBlockHeaderVerboseResult struct {
|
||||||
NextHash string `json:"nextblockhash,omitempty"`
|
NextHash string `json:"nextblockhash,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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,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
|
// GetBlockVerboseResult models the data from the getblock command when the
|
||||||
// verbose flag is set. When the verbose flag is not set, getblock returns a
|
// verbose flag is set to 1. When the verbose flag is set to 0, getblock returns a
|
||||||
// hex-encoded string.
|
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
|
||||||
|
// whose tx field is an array of transaction hashes. When the verbose flag is set to 2,
|
||||||
|
// 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 {
|
type GetBlockVerboseResult struct {
|
||||||
Hash string `json:"hash"`
|
GetBlockVerboseResultBase
|
||||||
Confirmations int64 `json:"confirmations"`
|
Tx []string `json:"tx"`
|
||||||
StrippedSize int32 `json:"strippedsize"`
|
}
|
||||||
Size int32 `json:"size"`
|
|
||||||
Weight int32 `json:"weight"`
|
// GetBlockVerboseTxResult models the data from the getblock command when the
|
||||||
Height int64 `json:"height"`
|
// verbose flag is set to 2. When the verbose flag is set to 0, getblock returns a
|
||||||
Version int32 `json:"version"`
|
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
|
||||||
VersionHex string `json:"versionHex"`
|
// whose tx field is an array of transaction hashes. When the verbose flag is set to 2,
|
||||||
MerkleRoot string `json:"merkleroot"`
|
// getblock returns an object whose tx field is an array of raw transactions.
|
||||||
Tx []string `json:"tx,omitempty"`
|
// Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
|
||||||
RawTx []TxRawResult `json:"rawtx,omitempty"`
|
type GetBlockVerboseTxResult struct {
|
||||||
Time int64 `json:"time"`
|
GetBlockVerboseResultBase
|
||||||
Nonce uint32 `json:"nonce"`
|
Tx []TxRawResult `json:"tx"`
|
||||||
Bits string `json:"bits"`
|
}
|
||||||
Difficulty float64 `json:"difficulty"`
|
|
||||||
PreviousHash string `json:"previousblockhash"`
|
// GetChainTxStatsResult models the data from the getchaintxstats command.
|
||||||
NextHash string `json:"nextblockhash,omitempty"`
|
type GetChainTxStatsResult struct {
|
||||||
|
Time int64 `json:"time"`
|
||||||
|
TxCount int64 `json:"txcount"`
|
||||||
|
WindowFinalBlockHash string `json:"window_final_block_hash"`
|
||||||
|
WindowFinalBlockHeight int32 `json:"window_final_block_height"`
|
||||||
|
WindowBlockCount int32 `json:"window_block_count"`
|
||||||
|
WindowTxCount int32 `json:"window_tx_count"`
|
||||||
|
WindowInterval int32 `json:"window_interval"`
|
||||||
|
TxRate float64 `json:"txrate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMultiSigResult models the data returned from the createmultisig
|
// CreateMultiSigResult models the data returned from the createmultisig
|
||||||
|
@ -140,18 +218,28 @@ type GetBlockChainInfoResult struct {
|
||||||
Difficulty float64 `json:"difficulty"`
|
Difficulty float64 `json:"difficulty"`
|
||||||
MedianTime int64 `json:"mediantime"`
|
MedianTime int64 `json:"mediantime"`
|
||||||
VerificationProgress float64 `json:"verificationprogress,omitempty"`
|
VerificationProgress float64 `json:"verificationprogress,omitempty"`
|
||||||
|
InitialBlockDownload bool `json:"initialblockdownload,omitempty"`
|
||||||
Pruned bool `json:"pruned"`
|
Pruned bool `json:"pruned"`
|
||||||
PruneHeight int32 `json:"pruneheight,omitempty"`
|
PruneHeight int32 `json:"pruneheight,omitempty"`
|
||||||
ChainWork string `json:"chainwork,omitempty"`
|
ChainWork string `json:"chainwork,omitempty"`
|
||||||
|
SizeOnDisk int64 `json:"size_on_disk,omitempty"`
|
||||||
*SoftForks
|
*SoftForks
|
||||||
*UnifiedSoftForks
|
*UnifiedSoftForks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlockFilterResult models the data returned from the getblockfilter
|
||||||
|
// command.
|
||||||
|
type GetBlockFilterResult struct {
|
||||||
|
Filter string `json:"filter"` // the hex-encoded filter data
|
||||||
|
Header string `json:"header"` // the hex-encoded filter header
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockTemplateResultTx models the transactions field of the
|
// GetBlockTemplateResultTx models the transactions field of the
|
||||||
// getblocktemplate command.
|
// getblocktemplate command.
|
||||||
type GetBlockTemplateResultTx struct {
|
type GetBlockTemplateResultTx struct {
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
|
TxID string `json:"txid"`
|
||||||
Depends []int64 `json:"depends"`
|
Depends []int64 `json:"depends"`
|
||||||
Fee int64 `json:"fee"`
|
Fee int64 `json:"fee"`
|
||||||
SigOps int64 `json:"sigops"`
|
SigOps int64 `json:"sigops"`
|
||||||
|
@ -204,32 +292,62 @@ type GetBlockTemplateResult struct {
|
||||||
// Block proposal from BIP 0023.
|
// Block proposal from BIP 0023.
|
||||||
Capabilities []string `json:"capabilities,omitempty"`
|
Capabilities []string `json:"capabilities,omitempty"`
|
||||||
RejectReasion string `json:"reject-reason,omitempty"`
|
RejectReasion string `json:"reject-reason,omitempty"`
|
||||||
|
|
||||||
|
ClaimTrieHash string `json:"claimtrie"`
|
||||||
|
|
||||||
|
Rules []string `json:"rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMempoolEntryResult models the data returned from the getmempoolentry's
|
||||||
|
// fee field
|
||||||
|
|
||||||
|
type MempoolFees struct {
|
||||||
|
Base float64 `json:"base"`
|
||||||
|
Modified float64 `json:"modified"`
|
||||||
|
Ancestor float64 `json:"ancestor"`
|
||||||
|
Descendant float64 `json:"descendant"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolEntryResult models the data returned from the getmempoolentry
|
// GetMempoolEntryResult models the data returned from the getmempoolentry
|
||||||
// command.
|
// command.
|
||||||
type GetMempoolEntryResult struct {
|
type GetMempoolEntryResult struct {
|
||||||
Size int32 `json:"size"`
|
VSize int32 `json:"vsize"`
|
||||||
Fee float64 `json:"fee"`
|
Size int32 `json:"size"`
|
||||||
ModifiedFee float64 `json:"modifiedfee"`
|
Weight int64 `json:"weight"`
|
||||||
Time int64 `json:"time"`
|
Fee float64 `json:"fee"`
|
||||||
Height int64 `json:"height"`
|
ModifiedFee float64 `json:"modifiedfee"`
|
||||||
StartingPriority float64 `json:"startingpriority"`
|
Time int64 `json:"time"`
|
||||||
CurrentPriority float64 `json:"currentpriority"`
|
Height int64 `json:"height"`
|
||||||
DescendantCount int64 `json:"descendantcount"`
|
DescendantCount int64 `json:"descendantcount"`
|
||||||
DescendantSize int64 `json:"descendantsize"`
|
DescendantSize int64 `json:"descendantsize"`
|
||||||
DescendantFees float64 `json:"descendantfees"`
|
DescendantFees float64 `json:"descendantfees"`
|
||||||
AncestorCount int64 `json:"ancestorcount"`
|
AncestorCount int64 `json:"ancestorcount"`
|
||||||
AncestorSize int64 `json:"ancestorsize"`
|
AncestorSize int64 `json:"ancestorsize"`
|
||||||
AncestorFees float64 `json:"ancestorfees"`
|
AncestorFees float64 `json:"ancestorfees"`
|
||||||
Depends []string `json:"depends"`
|
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
|
// GetMempoolInfoResult models the data returned from the getmempoolinfo
|
||||||
// command.
|
// command.
|
||||||
type GetMempoolInfoResult struct {
|
type GetMempoolInfoResult struct {
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"` // Current tx count
|
||||||
Bytes int64 `json:"bytes"`
|
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.
|
// NetworksResult models the networks data from the getnetworkinfo command.
|
||||||
|
@ -267,6 +385,16 @@ type GetNetworkInfoResult struct {
|
||||||
Warnings string `json:"warnings"`
|
Warnings string `json:"warnings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeAddressesResult models the data returned from the getnodeaddresses
|
||||||
|
// command.
|
||||||
|
type GetNodeAddressesResult struct {
|
||||||
|
// Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen
|
||||||
|
Time int64 `json:"time"`
|
||||||
|
Services uint64 `json:"services"` // The services offered
|
||||||
|
Address string `json:"address"` // The address of the node
|
||||||
|
Port uint16 `json:"port"` // The port of the node
|
||||||
|
}
|
||||||
|
|
||||||
// GetPeerInfoResult models the data returned from the getpeerinfo command.
|
// GetPeerInfoResult models the data returned from the getpeerinfo command.
|
||||||
type GetPeerInfoResult struct {
|
type GetPeerInfoResult struct {
|
||||||
ID int32 `json:"id"`
|
ID int32 `json:"id"`
|
||||||
|
@ -314,6 +442,9 @@ type ScriptPubKeyResult struct {
|
||||||
Hex string `json:"hex,omitempty"`
|
Hex string `json:"hex,omitempty"`
|
||||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
SubType string `json:"subtype"`
|
||||||
|
IsClaim bool `json:"isclaim"`
|
||||||
|
IsSupport bool `json:"issupport"`
|
||||||
Addresses []string `json:"addresses,omitempty"`
|
Addresses []string `json:"addresses,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +457,64 @@ type GetTxOutResult struct {
|
||||||
Coinbase bool `json:"coinbase"`
|
Coinbase bool `json:"coinbase"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTxOutSetInfoResult models the data from the gettxoutsetinfo command.
|
||||||
|
type GetTxOutSetInfoResult struct {
|
||||||
|
Height int64 `json:"height"`
|
||||||
|
BestBlock chainhash.Hash `json:"bestblock"`
|
||||||
|
Transactions int64 `json:"transactions"`
|
||||||
|
TxOuts int64 `json:"txouts"`
|
||||||
|
BogoSize int64 `json:"bogosize"`
|
||||||
|
HashSerialized chainhash.Hash `json:"hash_serialized_2"`
|
||||||
|
DiskSize int64 `json:"disk_size"`
|
||||||
|
TotalAmount btcutil.Amount `json:"total_amount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals the result of the gettxoutsetinfo JSON-RPC call
|
||||||
|
func (g *GetTxOutSetInfoResult) UnmarshalJSON(data []byte) error {
|
||||||
|
// Step 1: Create type aliases of the original struct.
|
||||||
|
type Alias GetTxOutSetInfoResult
|
||||||
|
|
||||||
|
// Step 2: Create an anonymous struct with raw replacements for the special
|
||||||
|
// fields.
|
||||||
|
aux := &struct {
|
||||||
|
BestBlock string `json:"bestblock"`
|
||||||
|
HashSerialized string `json:"hash_serialized_2"`
|
||||||
|
TotalAmount float64 `json:"total_amount"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(g),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Unmarshal the data into the anonymous struct.
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Convert the raw fields to the desired types
|
||||||
|
blockHash, err := chainhash.NewHashFromStr(aux.BestBlock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.BestBlock = *blockHash
|
||||||
|
|
||||||
|
serializedHash, err := chainhash.NewHashFromStr(aux.HashSerialized)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.HashSerialized = *serializedHash
|
||||||
|
|
||||||
|
amount, err := btcutil.NewAmount(aux.TotalAmount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.TotalAmount = amount
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetNetTotalsResult models the data returned from the getnettotals command.
|
// GetNetTotalsResult models the data returned from the getnettotals command.
|
||||||
type GetNetTotalsResult struct {
|
type GetNetTotalsResult struct {
|
||||||
TotalBytesRecv uint64 `json:"totalbytesrecv"`
|
TotalBytesRecv uint64 `json:"totalbytesrecv"`
|
||||||
|
@ -414,6 +603,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
||||||
type PrevOut struct {
|
type PrevOut struct {
|
||||||
Addresses []string `json:"addresses,omitempty"`
|
Addresses []string `json:"addresses,omitempty"`
|
||||||
Value float64 `json:"value"`
|
Value float64 `json:"value"`
|
||||||
|
IsClaim bool `json:"isclaim"`
|
||||||
|
IsSupport bool `json:"issupport"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
||||||
|
@ -504,8 +695,8 @@ type GetMiningInfoResult struct {
|
||||||
Errors string `json:"errors"`
|
Errors string `json:"errors"`
|
||||||
Generate bool `json:"generate"`
|
Generate bool `json:"generate"`
|
||||||
GenProcLimit int32 `json:"genproclimit"`
|
GenProcLimit int32 `json:"genproclimit"`
|
||||||
HashesPerSec int64 `json:"hashespersec"`
|
HashesPerSec float64 `json:"hashespersec"`
|
||||||
NetworkHashPS int64 `json:"networkhashps"`
|
NetworkHashPS float64 `json:"networkhashps"`
|
||||||
PooledTx uint64 `json:"pooledtx"`
|
PooledTx uint64 `json:"pooledtx"`
|
||||||
TestNet bool `json:"testnet"`
|
TestNet bool `json:"testnet"`
|
||||||
}
|
}
|
||||||
|
@ -532,6 +723,15 @@ type InfoChainResult struct {
|
||||||
Errors string `json:"errors"`
|
Errors string `json:"errors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListBannedResult models the data returned from the listbanned command.
|
||||||
|
type ListBannedResult struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
BanCreated int64 `json:"ban_created"`
|
||||||
|
BannedUntil int64 `json:"banned_until"`
|
||||||
|
BanDuration int64 `json:"ban_duration"`
|
||||||
|
TimeRemaining int64 `json:"time_remaining"`
|
||||||
|
}
|
||||||
|
|
||||||
// TxRawResult models the data from the getrawtransaction command.
|
// TxRawResult models the data from the getrawtransaction command.
|
||||||
type TxRawResult struct {
|
type TxRawResult struct {
|
||||||
Hex string `json:"hex"`
|
Hex string `json:"hex"`
|
||||||
|
@ -540,7 +740,7 @@ type TxRawResult struct {
|
||||||
Size int32 `json:"size,omitempty"`
|
Size int32 `json:"size,omitempty"`
|
||||||
Vsize int32 `json:"vsize,omitempty"`
|
Vsize int32 `json:"vsize,omitempty"`
|
||||||
Weight int32 `json:"weight,omitempty"`
|
Weight int32 `json:"weight,omitempty"`
|
||||||
Version int32 `json:"version"`
|
Version uint32 `json:"version"`
|
||||||
LockTime uint32 `json:"locktime"`
|
LockTime uint32 `json:"locktime"`
|
||||||
Vin []Vin `json:"vin"`
|
Vin []Vin `json:"vin"`
|
||||||
Vout []Vout `json:"vout"`
|
Vout []Vout `json:"vout"`
|
||||||
|
@ -580,7 +780,93 @@ type TxRawDecodeResult struct {
|
||||||
|
|
||||||
// ValidateAddressChainResult models the data returned by the chain server
|
// ValidateAddressChainResult models the data returned by the chain server
|
||||||
// validateaddress command.
|
// validateaddress command.
|
||||||
|
//
|
||||||
|
// Compared to the Bitcoin Core version, this struct lacks the scriptPubKey
|
||||||
|
// field since it requires wallet access, which is outside the scope of btcd.
|
||||||
|
// Ref: https://bitcoincore.org/en/doc/0.20.0/rpc/util/validateaddress/
|
||||||
type ValidateAddressChainResult struct {
|
type ValidateAddressChainResult struct {
|
||||||
IsValid bool `json:"isvalid"`
|
IsValid bool `json:"isvalid"`
|
||||||
Address string `json:"address,omitempty"`
|
Address string `json:"address,omitempty"`
|
||||||
|
IsScript *bool `json:"isscript,omitempty"`
|
||||||
|
IsWitness *bool `json:"iswitness,omitempty"`
|
||||||
|
WitnessVersion *int32 `json:"witness_version,omitempty"`
|
||||||
|
WitnessProgram *string `json:"witness_program,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateSmartFeeResult models the data returned buy the chain server
|
||||||
|
// estimatesmartfee command
|
||||||
|
type EstimateSmartFeeResult struct {
|
||||||
|
FeeRate *float64 `json:"feerate,omitempty"`
|
||||||
|
Errors []string `json:"errors,omitempty"`
|
||||||
|
Blocks int64 `json:"blocks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ json.Unmarshaler = &FundRawTransactionResult{}
|
||||||
|
|
||||||
|
type rawFundRawTransactionResult struct {
|
||||||
|
Transaction string `json:"hex"`
|
||||||
|
Fee float64 `json:"fee"`
|
||||||
|
ChangePosition int `json:"changepos"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FundRawTransactionResult is the result of the fundrawtransaction JSON-RPC call
|
||||||
|
type FundRawTransactionResult struct {
|
||||||
|
Transaction *wire.MsgTx
|
||||||
|
Fee btcutil.Amount
|
||||||
|
ChangePosition int // the position of the added change output, or -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals the result of the fundrawtransaction JSON-RPC call
|
||||||
|
func (f *FundRawTransactionResult) UnmarshalJSON(data []byte) error {
|
||||||
|
var rawRes rawFundRawTransactionResult
|
||||||
|
if err := json.Unmarshal(data, &rawRes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
txBytes, err := hex.DecodeString(rawRes.Transaction)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgTx wire.MsgTx
|
||||||
|
witnessErr := msgTx.Deserialize(bytes.NewReader(txBytes))
|
||||||
|
if witnessErr != nil {
|
||||||
|
legacyErr := msgTx.DeserializeNoWitness(bytes.NewReader(txBytes))
|
||||||
|
if legacyErr != nil {
|
||||||
|
return legacyErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fee, err := btcutil.NewAmount(rawRes.Fee)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Transaction = &msgTx
|
||||||
|
f.Fee = fee
|
||||||
|
f.ChangePosition = rawRes.ChangePosition
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDescriptorInfoResult models the data from the getdescriptorinfo command.
|
||||||
|
type GetDescriptorInfoResult struct {
|
||||||
|
Descriptor string `json:"descriptor"` // descriptor in canonical form, without private keys
|
||||||
|
Checksum string `json:"checksum"` // checksum for the input descriptor
|
||||||
|
IsRange bool `json:"isrange"` // whether the descriptor is ranged
|
||||||
|
IsSolvable bool `json:"issolvable"` // whether the descriptor is solvable
|
||||||
|
HasPrivateKeys bool `json:"hasprivatekeys"` // whether the descriptor has at least one private key
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveAddressesResult models the data from the deriveaddresses command.
|
||||||
|
type DeriveAddressesResult []string
|
||||||
|
|
||||||
|
// LoadWalletResult models the data from the loadwallet command
|
||||||
|
type LoadWalletResult struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Warning string `json:"warning"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpWalletResult models the data from the dumpwallet command
|
||||||
|
type DumpWalletResult struct {
|
||||||
|
Filename string `json:"filename"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,13 @@ package btcjson_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
|
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||||
|
btcutil "github.com/lbryio/lbcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestChainSvrCustomResults ensures any results that have custom marshalling
|
// TestChainSvrCustomResults ensures any results that have custom marshalling
|
||||||
|
@ -66,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
|
||||||
},
|
},
|
||||||
Sequence: 4294967295,
|
Sequence: 4294967295,
|
||||||
},
|
},
|
||||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
|
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,3 +90,112 @@ func TestChainSvrCustomResults(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetTxOutSetInfoResult ensures that custom unmarshalling of
|
||||||
|
// GetTxOutSetInfoResult works as intended.
|
||||||
|
func TestGetTxOutSetInfoResult(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
result string
|
||||||
|
want btcjson.GetTxOutSetInfoResult
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "GetTxOutSetInfoResult - not scanning",
|
||||||
|
result: `{"height":123,"bestblock":"000000000000005f94116250e2407310463c0a7cf950f1af9ebe935b1c0687ab","transactions":1,"txouts":1,"bogosize":1,"hash_serialized_2":"9a0a561203ff052182993bc5d0cb2c620880bfafdbd80331f65fd9546c3e5c3e","disk_size":1,"total_amount":0.2}`,
|
||||||
|
want: btcjson.GetTxOutSetInfoResult{
|
||||||
|
Height: 123,
|
||||||
|
BestBlock: func() chainhash.Hash {
|
||||||
|
h, err := chainhash.NewHashFromStr("000000000000005f94116250e2407310463c0a7cf950f1af9ebe935b1c0687ab")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *h
|
||||||
|
}(),
|
||||||
|
Transactions: 1,
|
||||||
|
TxOuts: 1,
|
||||||
|
BogoSize: 1,
|
||||||
|
HashSerialized: func() chainhash.Hash {
|
||||||
|
h, err := chainhash.NewHashFromStr("9a0a561203ff052182993bc5d0cb2c620880bfafdbd80331f65fd9546c3e5c3e")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *h
|
||||||
|
}(),
|
||||||
|
DiskSize: 1,
|
||||||
|
TotalAmount: func() btcutil.Amount {
|
||||||
|
a, err := btcutil.NewAmount(0.2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Running %d tests", len(tests))
|
||||||
|
for i, test := range tests {
|
||||||
|
var out btcjson.GetTxOutSetInfoResult
|
||||||
|
err := json.Unmarshal([]byte(test.result), &out)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test #%d (%s) unexpected error: %v", i,
|
||||||
|
test.name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(out, test.want) {
|
||||||
|
t.Errorf("Test #%d (%s) unexpected unmarshalled data - "+
|
||||||
|
"got %v, want %v", i, test.name, spew.Sdump(out),
|
||||||
|
spew.Sdump(test.want))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestChainSvrMiningInfoResults ensures GetMiningInfoResults are unmarshalled correctly
|
||||||
|
func TestChainSvrMiningInfoResults(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
result string
|
||||||
|
expected btcjson.GetMiningInfoResult
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "mining info with integer networkhashps",
|
||||||
|
result: `{"networkhashps": 89790618491361}`,
|
||||||
|
expected: btcjson.GetMiningInfoResult{
|
||||||
|
NetworkHashPS: 89790618491361,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mining info with scientific notation networkhashps",
|
||||||
|
result: `{"networkhashps": 8.9790618491361e+13}`,
|
||||||
|
expected: btcjson.GetMiningInfoResult{
|
||||||
|
NetworkHashPS: 89790618491361,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Running %d tests", len(tests))
|
||||||
|
for i, test := range tests {
|
||||||
|
var miningInfoResult btcjson.GetMiningInfoResult
|
||||||
|
err := json.Unmarshal([]byte(test.result), &miningInfoResult)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test #%d (%s) unexpected error: %v", i,
|
||||||
|
test.name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if miningInfoResult != test.expected {
|
||||||
|
t.Errorf("Test #%d (%s) unexpected marhsalled data - "+
|
||||||
|
"got %+v, want %+v", i, test.name, miningInfoResult,
|
||||||
|
test.expected)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ func NewStopNotifyNewTransactionsCmd() *StopNotifyNewTransactionsCmd {
|
||||||
|
|
||||||
// NotifyReceivedCmd defines the notifyreceived JSON-RPC command.
|
// NotifyReceivedCmd defines the notifyreceived JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
// Deprecated: Use LoadTxFilterCmd instead.
|
||||||
type NotifyReceivedCmd struct {
|
type NotifyReceivedCmd struct {
|
||||||
Addresses []string
|
Addresses []string
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ type NotifyReceivedCmd struct {
|
||||||
// NewNotifyReceivedCmd returns a new instance which can be used to issue a
|
// NewNotifyReceivedCmd returns a new instance which can be used to issue a
|
||||||
// notifyreceived JSON-RPC command.
|
// notifyreceived JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
// Deprecated: Use NewLoadTxFilterCmd instead.
|
||||||
func NewNotifyReceivedCmd(addresses []string) *NotifyReceivedCmd {
|
func NewNotifyReceivedCmd(addresses []string) *NotifyReceivedCmd {
|
||||||
return &NotifyReceivedCmd{
|
return &NotifyReceivedCmd{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
|
@ -128,7 +128,7 @@ func NewLoadTxFilterCmd(reload bool, addresses []string, outPoints []OutPoint) *
|
||||||
|
|
||||||
// NotifySpentCmd defines the notifyspent JSON-RPC command.
|
// NotifySpentCmd defines the notifyspent JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
// Deprecated: Use LoadTxFilterCmd instead.
|
||||||
type NotifySpentCmd struct {
|
type NotifySpentCmd struct {
|
||||||
OutPoints []OutPoint
|
OutPoints []OutPoint
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ type NotifySpentCmd struct {
|
||||||
// NewNotifySpentCmd returns a new instance which can be used to issue a
|
// NewNotifySpentCmd returns a new instance which can be used to issue a
|
||||||
// notifyspent JSON-RPC command.
|
// notifyspent JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
// Deprecated: Use NewLoadTxFilterCmd instead.
|
||||||
func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
|
func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
|
||||||
return &NotifySpentCmd{
|
return &NotifySpentCmd{
|
||||||
OutPoints: outPoints,
|
OutPoints: outPoints,
|
||||||
|
@ -145,7 +145,7 @@ func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
|
||||||
|
|
||||||
// StopNotifyReceivedCmd defines the stopnotifyreceived JSON-RPC command.
|
// StopNotifyReceivedCmd defines the stopnotifyreceived JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
// Deprecated: Use LoadTxFilterCmd instead.
|
||||||
type StopNotifyReceivedCmd struct {
|
type StopNotifyReceivedCmd struct {
|
||||||
Addresses []string
|
Addresses []string
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ type StopNotifyReceivedCmd struct {
|
||||||
// NewStopNotifyReceivedCmd returns a new instance which can be used to issue a
|
// NewStopNotifyReceivedCmd returns a new instance which can be used to issue a
|
||||||
// stopnotifyreceived JSON-RPC command.
|
// stopnotifyreceived JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
// Deprecated: Use NewLoadTxFilterCmd instead.
|
||||||
func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
|
func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
|
||||||
return &StopNotifyReceivedCmd{
|
return &StopNotifyReceivedCmd{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
|
@ -162,7 +162,7 @@ func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
|
||||||
|
|
||||||
// StopNotifySpentCmd defines the stopnotifyspent JSON-RPC command.
|
// StopNotifySpentCmd defines the stopnotifyspent JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
|
// Deprecated: Use LoadTxFilterCmd instead.
|
||||||
type StopNotifySpentCmd struct {
|
type StopNotifySpentCmd struct {
|
||||||
OutPoints []OutPoint
|
OutPoints []OutPoint
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ type StopNotifySpentCmd struct {
|
||||||
// NewStopNotifySpentCmd returns a new instance which can be used to issue a
|
// NewStopNotifySpentCmd returns a new instance which can be used to issue a
|
||||||
// stopnotifyspent JSON-RPC command.
|
// stopnotifyspent JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
|
// Deprecated: Use NewLoadTxFilterCmd instead.
|
||||||
func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
|
func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
|
||||||
return &StopNotifySpentCmd{
|
return &StopNotifySpentCmd{
|
||||||
OutPoints: outPoints,
|
OutPoints: outPoints,
|
||||||
|
@ -179,7 +179,7 @@ func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
|
||||||
|
|
||||||
// RescanCmd defines the rescan JSON-RPC command.
|
// RescanCmd defines the rescan JSON-RPC command.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use RescanBlocksCmd instead.
|
// Deprecated: Use RescanBlocksCmd instead.
|
||||||
type RescanCmd struct {
|
type RescanCmd struct {
|
||||||
BeginBlock string
|
BeginBlock string
|
||||||
Addresses []string
|
Addresses []string
|
||||||
|
@ -193,7 +193,7 @@ type RescanCmd struct {
|
||||||
// The parameters which are pointers indicate they are optional. Passing nil
|
// The parameters which are pointers indicate they are optional. Passing nil
|
||||||
// for optional parameters will use the default value.
|
// for optional parameters will use the default value.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewRescanBlocksCmd instead.
|
// Deprecated: Use NewRescanBlocksCmd instead.
|
||||||
func NewRescanCmd(beginBlock string, addresses []string, outPoints []OutPoint, endBlock *string) *RescanCmd {
|
func NewRescanCmd(beginBlock string, addresses []string, outPoints []OutPoint, endBlock *string) *RescanCmd {
|
||||||
return &RescanCmd{
|
return &RescanCmd{
|
||||||
BeginBlock: beginBlock,
|
BeginBlock: beginBlock,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcjson"
|
"github.com/lbryio/lbcd/btcjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands
|
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands
|
||||||
|
@ -233,7 +233,7 @@ func TestChainSvrWsCmds(t *testing.T) {
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// Marshal the command as created by the new static command
|
// Marshal the command as created by the new static command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
|
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
@ -257,7 +257,7 @@ func TestChainSvrWsCmds(t *testing.T) {
|
||||||
|
|
||||||
// Marshal the command as created by the generic new command
|
// Marshal the command as created by the generic new command
|
||||||
// creation function.
|
// creation function.
|
||||||
marshalled, err = btcjson.MarshalCmd(testID, cmd)
|
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
|
||||||
test.name, err)
|
test.name, err)
|
||||||
|
|
|
@ -12,14 +12,14 @@ const (
|
||||||
// BlockConnectedNtfnMethod is the legacy, deprecated method used for
|
// BlockConnectedNtfnMethod is the legacy, deprecated method used for
|
||||||
// notifications from the chain server that a block has been connected.
|
// notifications from the chain server that a block has been connected.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use FilteredBlockConnectedNtfnMethod instead.
|
// Deprecated: Use FilteredBlockConnectedNtfnMethod instead.
|
||||||
BlockConnectedNtfnMethod = "blockconnected"
|
BlockConnectedNtfnMethod = "blockconnected"
|
||||||
|
|
||||||
// BlockDisconnectedNtfnMethod is the legacy, deprecated method used for
|
// BlockDisconnectedNtfnMethod is the legacy, deprecated method used for
|
||||||
// notifications from the chain server that a block has been
|
// notifications from the chain server that a block has been
|
||||||
// disconnected.
|
// disconnected.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use FilteredBlockDisconnectedNtfnMethod instead.
|
// Deprecated: Use FilteredBlockDisconnectedNtfnMethod instead.
|
||||||
BlockDisconnectedNtfnMethod = "blockdisconnected"
|
BlockDisconnectedNtfnMethod = "blockdisconnected"
|
||||||
|
|
||||||
// FilteredBlockConnectedNtfnMethod is the new method used for
|
// FilteredBlockConnectedNtfnMethod is the new method used for
|
||||||
|
@ -35,7 +35,7 @@ const (
|
||||||
// notifications from the chain server that a transaction which pays to
|
// notifications from the chain server that a transaction which pays to
|
||||||
// a registered address has been processed.
|
// a registered address has been processed.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfnMethod and
|
// Deprecated: Use RelevantTxAcceptedNtfnMethod and
|
||||||
// FilteredBlockConnectedNtfnMethod instead.
|
// FilteredBlockConnectedNtfnMethod instead.
|
||||||
RecvTxNtfnMethod = "recvtx"
|
RecvTxNtfnMethod = "recvtx"
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const (
|
||||||
// notifications from the chain server that a transaction which spends a
|
// notifications from the chain server that a transaction which spends a
|
||||||
// registered outpoint has been processed.
|
// registered outpoint has been processed.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfnMethod and
|
// Deprecated: Use RelevantTxAcceptedNtfnMethod and
|
||||||
// FilteredBlockConnectedNtfnMethod instead.
|
// FilteredBlockConnectedNtfnMethod instead.
|
||||||
RedeemingTxNtfnMethod = "redeemingtx"
|
RedeemingTxNtfnMethod = "redeemingtx"
|
||||||
|
|
||||||
|
@ -51,14 +51,14 @@ const (
|
||||||
// notifications from the chain server that a legacy, deprecated rescan
|
// notifications from the chain server that a legacy, deprecated rescan
|
||||||
// operation has finished.
|
// operation has finished.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
RescanFinishedNtfnMethod = "rescanfinished"
|
RescanFinishedNtfnMethod = "rescanfinished"
|
||||||
|
|
||||||
// RescanProgressNtfnMethod is the legacy, deprecated method used for
|
// RescanProgressNtfnMethod is the legacy, deprecated method used for
|
||||||
// notifications from the chain server that a legacy, deprecated rescan
|
// notifications from the chain server that a legacy, deprecated rescan
|
||||||
// operation this is underway has made progress.
|
// operation this is underway has made progress.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
RescanProgressNtfnMethod = "rescanprogress"
|
RescanProgressNtfnMethod = "rescanprogress"
|
||||||
|
|
||||||
// TxAcceptedNtfnMethod is the method used for notifications from the
|
// TxAcceptedNtfnMethod is the method used for notifications from the
|
||||||
|
@ -79,7 +79,7 @@ const (
|
||||||
|
|
||||||
// BlockConnectedNtfn defines the blockconnected JSON-RPC notification.
|
// BlockConnectedNtfn defines the blockconnected JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use FilteredBlockConnectedNtfn instead.
|
// Deprecated: Use FilteredBlockConnectedNtfn instead.
|
||||||
type BlockConnectedNtfn struct {
|
type BlockConnectedNtfn struct {
|
||||||
Hash string
|
Hash string
|
||||||
Height int32
|
Height int32
|
||||||
|
@ -89,7 +89,7 @@ type BlockConnectedNtfn struct {
|
||||||
// NewBlockConnectedNtfn returns a new instance which can be used to issue a
|
// NewBlockConnectedNtfn returns a new instance which can be used to issue a
|
||||||
// blockconnected JSON-RPC notification.
|
// blockconnected JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewFilteredBlockConnectedNtfn instead.
|
// Deprecated: Use NewFilteredBlockConnectedNtfn instead.
|
||||||
func NewBlockConnectedNtfn(hash string, height int32, time int64) *BlockConnectedNtfn {
|
func NewBlockConnectedNtfn(hash string, height int32, time int64) *BlockConnectedNtfn {
|
||||||
return &BlockConnectedNtfn{
|
return &BlockConnectedNtfn{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
|
@ -100,7 +100,7 @@ func NewBlockConnectedNtfn(hash string, height int32, time int64) *BlockConnecte
|
||||||
|
|
||||||
// BlockDisconnectedNtfn defines the blockdisconnected JSON-RPC notification.
|
// BlockDisconnectedNtfn defines the blockdisconnected JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use FilteredBlockDisconnectedNtfn instead.
|
// Deprecated: Use FilteredBlockDisconnectedNtfn instead.
|
||||||
type BlockDisconnectedNtfn struct {
|
type BlockDisconnectedNtfn struct {
|
||||||
Hash string
|
Hash string
|
||||||
Height int32
|
Height int32
|
||||||
|
@ -110,7 +110,7 @@ type BlockDisconnectedNtfn struct {
|
||||||
// NewBlockDisconnectedNtfn returns a new instance which can be used to issue a
|
// NewBlockDisconnectedNtfn returns a new instance which can be used to issue a
|
||||||
// blockdisconnected JSON-RPC notification.
|
// blockdisconnected JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewFilteredBlockDisconnectedNtfn instead.
|
// Deprecated: Use NewFilteredBlockDisconnectedNtfn instead.
|
||||||
func NewBlockDisconnectedNtfn(hash string, height int32, time int64) *BlockDisconnectedNtfn {
|
func NewBlockDisconnectedNtfn(hash string, height int32, time int64) *BlockDisconnectedNtfn {
|
||||||
return &BlockDisconnectedNtfn{
|
return &BlockDisconnectedNtfn{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
|
@ -163,7 +163,7 @@ type BlockDetails struct {
|
||||||
|
|
||||||
// RecvTxNtfn defines the recvtx JSON-RPC notification.
|
// RecvTxNtfn defines the recvtx JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfn and FilteredBlockConnectedNtfn
|
// Deprecated: Use RelevantTxAcceptedNtfn and FilteredBlockConnectedNtfn
|
||||||
// instead.
|
// instead.
|
||||||
type RecvTxNtfn struct {
|
type RecvTxNtfn struct {
|
||||||
HexTx string
|
HexTx string
|
||||||
|
@ -173,7 +173,7 @@ type RecvTxNtfn struct {
|
||||||
// NewRecvTxNtfn returns a new instance which can be used to issue a recvtx
|
// NewRecvTxNtfn returns a new instance which can be used to issue a recvtx
|
||||||
// JSON-RPC notification.
|
// JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewRelevantTxAcceptedNtfn and
|
// Deprecated: Use NewRelevantTxAcceptedNtfn and
|
||||||
// NewFilteredBlockConnectedNtfn instead.
|
// NewFilteredBlockConnectedNtfn instead.
|
||||||
func NewRecvTxNtfn(hexTx string, block *BlockDetails) *RecvTxNtfn {
|
func NewRecvTxNtfn(hexTx string, block *BlockDetails) *RecvTxNtfn {
|
||||||
return &RecvTxNtfn{
|
return &RecvTxNtfn{
|
||||||
|
@ -184,7 +184,7 @@ func NewRecvTxNtfn(hexTx string, block *BlockDetails) *RecvTxNtfn {
|
||||||
|
|
||||||
// RedeemingTxNtfn defines the redeemingtx JSON-RPC notification.
|
// RedeemingTxNtfn defines the redeemingtx JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use RelevantTxAcceptedNtfn and FilteredBlockConnectedNtfn
|
// Deprecated: Use RelevantTxAcceptedNtfn and FilteredBlockConnectedNtfn
|
||||||
// instead.
|
// instead.
|
||||||
type RedeemingTxNtfn struct {
|
type RedeemingTxNtfn struct {
|
||||||
HexTx string
|
HexTx string
|
||||||
|
@ -194,7 +194,7 @@ type RedeemingTxNtfn struct {
|
||||||
// NewRedeemingTxNtfn returns a new instance which can be used to issue a
|
// NewRedeemingTxNtfn returns a new instance which can be used to issue a
|
||||||
// redeemingtx JSON-RPC notification.
|
// redeemingtx JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Use NewRelevantTxAcceptedNtfn and
|
// Deprecated: Use NewRelevantTxAcceptedNtfn and
|
||||||
// NewFilteredBlockConnectedNtfn instead.
|
// NewFilteredBlockConnectedNtfn instead.
|
||||||
func NewRedeemingTxNtfn(hexTx string, block *BlockDetails) *RedeemingTxNtfn {
|
func NewRedeemingTxNtfn(hexTx string, block *BlockDetails) *RedeemingTxNtfn {
|
||||||
return &RedeemingTxNtfn{
|
return &RedeemingTxNtfn{
|
||||||
|
@ -205,7 +205,7 @@ func NewRedeemingTxNtfn(hexTx string, block *BlockDetails) *RedeemingTxNtfn {
|
||||||
|
|
||||||
// RescanFinishedNtfn defines the rescanfinished JSON-RPC notification.
|
// RescanFinishedNtfn defines the rescanfinished JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
type RescanFinishedNtfn struct {
|
type RescanFinishedNtfn struct {
|
||||||
Hash string
|
Hash string
|
||||||
Height int32
|
Height int32
|
||||||
|
@ -215,7 +215,7 @@ type RescanFinishedNtfn struct {
|
||||||
// NewRescanFinishedNtfn returns a new instance which can be used to issue a
|
// NewRescanFinishedNtfn returns a new instance which can be used to issue a
|
||||||
// rescanfinished JSON-RPC notification.
|
// rescanfinished JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
func NewRescanFinishedNtfn(hash string, height int32, time int64) *RescanFinishedNtfn {
|
func NewRescanFinishedNtfn(hash string, height int32, time int64) *RescanFinishedNtfn {
|
||||||
return &RescanFinishedNtfn{
|
return &RescanFinishedNtfn{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
|
@ -226,7 +226,7 @@ func NewRescanFinishedNtfn(hash string, height int32, time int64) *RescanFinishe
|
||||||
|
|
||||||
// RescanProgressNtfn defines the rescanprogress JSON-RPC notification.
|
// RescanProgressNtfn defines the rescanprogress JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
type RescanProgressNtfn struct {
|
type RescanProgressNtfn struct {
|
||||||
Hash string
|
Hash string
|
||||||
Height int32
|
Height int32
|
||||||
|
@ -236,7 +236,7 @@ type RescanProgressNtfn struct {
|
||||||
// NewRescanProgressNtfn returns a new instance which can be used to issue a
|
// NewRescanProgressNtfn returns a new instance which can be used to issue a
|
||||||
// rescanprogress JSON-RPC notification.
|
// rescanprogress JSON-RPC notification.
|
||||||
//
|
//
|
||||||
// NOTE: Deprecated. Not used with rescanblocks command.
|
// Deprecated: Not used with rescanblocks command.
|
||||||
func NewRescanProgressNtfn(hash string, height int32, time int64) *RescanProgressNtfn {
|
func NewRescanProgressNtfn(hash string, height int32, time int64) *RescanProgressNtfn {
|
||||||
return &RescanProgressNtfn{
|
return &RescanProgressNtfn{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue