Compare commits

..

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

437 changed files with 14392 additions and 52279 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

21
.gitignore vendored
View file

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

View file

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

View file

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

19
.travis.yml Normal file
View file

@ -0,0 +1,19 @@
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 Normal file
View file

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

View file

@ -1,40 +0,0 @@
# 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"]

View file

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

View file

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

369
README.md
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,30 @@
blockchain
==========
[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/blockchain)
### Bitcoin Chain Processing Overview
Package blockchain implements bitcoin block handling and chain selection rules.
The test coverage is currently only around 60%, but will be increasing over
time. See `test_coverage.txt` for the gocov coverage report. Alternatively, if
you are running a POSIX OS, you can run the `cov_report.sh` script for a
real-time report. Package blockchain is licensed under the liberal ISC license.
There is an associated blog post about the release of this package
[here](https://blog.conformal.com/btcchain-the-bitcoin-chain-package-from-bctd/).
This package has intentionally been designed so it can be used as a standalone
package for any projects needing to handle processing of blocks into the bitcoin
block chain.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/blockchain
```
## Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of
@ -36,4 +57,47 @@ is by no means exhaustive:
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
- 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.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,10 +12,10 @@ import (
"sync"
"time"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
@ -120,7 +120,7 @@ func dbFetchVersion(dbTx database.Tx, key []byte) uint32 {
return 0
}
return byteOrder.Uint32(serialized)
return byteOrder.Uint32(serialized[:])
}
// dbPutVersion uses an existing database transaction to update the provided
@ -943,7 +943,7 @@ func serializeBestChainState(state bestChainState) []byte {
byteOrder.PutUint32(serializedData[offset:], workSumBytesLen)
offset += 4
copy(serializedData[offset:], workSumBytes)
return serializedData
return serializedData[:]
}
// deserializeBestChainState deserializes the passed serialized best chain
@ -1149,9 +1149,18 @@ func (b *BlockChain) initChainState() error {
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 lastNode *blockNode
cursor := blockIndexBucket.Cursor()
cursor = blockIndexBucket.Cursor()
for ok := cursor.First(); ok; ok = cursor.Next() {
header, status, err := deserializeBlockRow(cursor.Value())
if err != nil {
@ -1184,7 +1193,7 @@ func (b *BlockChain) initChainState() error {
// Initialize the block node for the block, connect it,
// and add it to the block index.
node := new(blockNode)
node := &blockNodes[i]
initBlockNode(node, header, parent)
node.status = status
b.index.addNode(node)

View file

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

View file

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

View file

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

View file

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

View file

@ -8,10 +8,10 @@ import (
"fmt"
"time"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil"
)
// CheckpointConfirmations is the number of blocks before the end of the current
@ -172,8 +172,7 @@ func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
func isNonstandardTransaction(tx *btcutil.Tx) bool {
// Check all of the output public key scripts for non-standard scripts.
for _, txOut := range tx.MsgTx().TxOut {
stripped := txscript.StripClaimScriptPrefix(txOut.PkScript)
scriptClass := txscript.GetScriptClass(stripped)
scriptClass := txscript.GetScriptClass(txOut.PkScript)
if scriptClass == txscript.NonStandardTy {
return true
}
@ -185,14 +184,14 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool {
// checkpoint candidate.
//
// The factors used to determine a good checkpoint are:
// - The block must be in the main chain
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
// current end of the main chain
// - The timestamps for the blocks before and after the checkpoint must have
// timestamps which are also before and after the checkpoint, respectively
// (due to the median time allowance this is not always the case)
// - The block must not contain any strange transaction such as those with
// nonstandard scripts
// - The block must be in the main chain
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
// current end of the main chain
// - The timestamps for the blocks before and after the checkpoint must have
// timestamps which are also before and after the checkpoint, respectively
// (due to the median time allowance this is not always the case)
// - The block must not contain any strange transaction such as those with
// nonstandard scripts
//
// The intent is that candidates are reviewed by a developer to make the final
// decision and then manually added to the list of checkpoints for a network.

View file

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

View file

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

View file

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

View file

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

View file

@ -63,7 +63,7 @@ func TestCalcWork(t *testing.T) {
}
for x, test := range tests {
bits := test.in
bits := uint32(test.in)
r := CalcWork(bits)
if r.Int64() != test.out {

View file

@ -26,42 +26,42 @@ caller a high level of flexibility in how they want to react to certain events
such as orphan blocks which need their parents requested and newly connected
main chain blocks which might result in wallet updates.
# Bitcoin Chain Processing Overview
Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of
those rules to provide some intuition into what is going on under the hood, but
is by no means exhaustive:
- Reject duplicate blocks
- Perform a series of sanity checks on the block and its transactions such as
verifying proof of work, timestamps, number and character of transactions,
transaction amounts, script complexity, and merkle root calculations
- Compare the block against predetermined checkpoints for expected timestamps
and difficulty based on elapsed time since the checkpoint
- Save the most recent orphan blocks for a limited time in case their parent
blocks become available
- Stop processing if the block is an orphan as the rest of the processing
depends on the block's position within the block chain
- Perform a series of more thorough checks that depend on the block's position
within the block chain such as verifying block difficulties adhere to
difficulty retarget rules, timestamps are after the median of the last
several blocks, all transactions are finalized, checkpoint blocks match, and
block versions are in line with the previous blocks
- Determine how the block fits into the chain and perform different actions
accordingly in order to ensure any side chains which have higher difficulty
than the main chain become the new main chain
- When a block is being connected to the main chain (either through
reorganization of a side chain to the main chain or just extending the
main chain), perform further checks on the block's transactions such as
verifying transaction duplicates, script complexity for the combination of
connected scripts, coinbase maturity, double spends, and connected
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
- Reject duplicate blocks
- Perform a series of sanity checks on the block and its transactions such as
verifying proof of work, timestamps, number and character of transactions,
transaction amounts, script complexity, and merkle root calculations
- Compare the block against predetermined checkpoints for expected timestamps
and difficulty based on elapsed time since the checkpoint
- Save the most recent orphan blocks for a limited time in case their parent
blocks become available
- Stop processing if the block is an orphan as the rest of the processing
depends on the block's position within the block chain
- Perform a series of more thorough checks that depend on the block's position
within the block chain such as verifying block difficulties adhere to
difficulty retarget rules, timestamps are after the median of the last
several blocks, all transactions are finalized, checkpoint blocks match, and
block versions are in line with the previous blocks
- Determine how the block fits into the chain and perform different actions
accordingly in order to ensure any side chains which have higher difficulty
than the main chain become the new main chain
- When a block is being connected to the main chain (either through
reorganization of a side chain to the main chain or just extending the
main chain), perform further checks on the block's transactions such as
verifying transaction duplicates, script complexity for the combination of
connected scripts, coinbase maturity, double spends, and connected
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
# Errors
Errors
Errors returned by this package are either the raw errors provided by underlying
calls or of type blockchain.RuleError. This allows the caller to differentiate
@ -70,12 +70,12 @@ violations through type assertions. In addition, callers can programmatically
determine the specific rule violation by examining the ErrorCode field of the
type asserted blockchain.RuleError.
# Bitcoin Improvement Proposals
Bitcoin Improvement Proposals
This package includes spec changes outlined by the following BIPs:
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
*/
package blockchain

View file

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

View file

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

View file

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

View file

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

View file

@ -18,24 +18,24 @@ import (
"runtime"
"time"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
// Intentionally defined here rather than using constants from codebase
// to ensure consensus changes are detected.
maxBlockSigOps = 20000
maxBlockSize = 8000000
maxBlockSize = 1000000
minCoinbaseScriptLen = 2
maxCoinbaseScriptLen = 100
medianTimeBlocks = 11
maxScriptElementSize = 20000
maxScriptElementSize = 520
// numLargeReorgBlocks is the number of blocks to use in the large block
// reorg test (when enabled). This is the equivalent of 1 week's worth
@ -342,8 +342,10 @@ func solveBlock(header *wire.BlockHeader) bool {
return
default:
hdr.Nonce = i
hash := hdr.BlockPoWHash()
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
hash := hdr.BlockHash()
if blockchain.HashToBig(&hash).Cmp(
targetDifficulty) <= 0 {
results <- sbResult{true, i}
return
}
@ -464,9 +466,9 @@ func createSpendTxForTx(tx *wire.MsgTx, fee btcutil.Amount) *wire.MsgTx {
// - A coinbase that pays the required subsidy to an OP_TRUE script
// - When a spendable output is provided:
// - A transaction that spends from the provided output the following outputs:
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
// - One that contains an OP_RETURN output with a random uint64 in order to
// ensure the transaction has a unique hash
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
// - One that contains an OP_RETURN output with a random uint64 in order to
// ensure the transaction has a unique hash
//
// Additionally, if one or more munge functions are specified, they will be
// invoked with the block prior to solving it. This provides callers with the
@ -809,7 +811,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Create a test generator instance initialized with the genesis block
// as the tip.
g, err := makeTestGenerator(FbRegressionNetParams)
g, err := makeTestGenerator(regressionNetParams)
if err != nil {
return nil, err
}
@ -1442,7 +1444,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Keep incrementing the nonce until the hash treated as
// a uint256 is higher than the limit.
b46.Header.Nonce++
blockHash := b46.Header.BlockPoWHash()
blockHash := b46.BlockHash()
hashNum := blockchain.HashToBig(&blockHash)
if hashNum.Cmp(g.params.PowLimit) >= 0 {
break
@ -1873,7 +1875,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
//
// Comment assumptions:
// maxBlockSigOps = 20000
// maxScriptElementSize = 20000
// maxScriptElementSize = 520
//
// [0-19999] : OP_CHECKSIG
// [20000] : OP_PUSHDATA4

View file

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

View file

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

View file

@ -9,13 +9,13 @@ import (
"fmt"
"sync"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
@ -155,9 +155,7 @@ func serializeAddrIndexEntry(blockID uint32, txLoc wire.TxLoc) []byte {
// 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
// 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.
if len(serialized) < txEntrySize {
return errDeserialize("unexpected end of data")
@ -184,9 +182,7 @@ func keyForLevel(addrKey [addrKeySize]byte, level uint8) [levelKeySize]byte {
// dbPutAddrIndexEntry updates the address index to include the provided entry
// 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.
curLevel := uint8(0)
maxLevelBytes := level0MaxEntries * txEntrySize
@ -257,10 +253,7 @@ func dbPutAddrIndexEntry(bucket internalBucket, addrKey [addrKeySize]byte,
// 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
// 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
// because numToSkip and numRequested are counted from the oldest
// transactions (highest level) and thus the total count is needed.
@ -363,9 +356,7 @@ func maxEntriesForLevel(level uint8) int {
// dbRemoveAddrIndexEntries removes the specified number of entries from from
// 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.
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.
if count <= 0 {
return nil
@ -805,9 +796,7 @@ func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
// that involve a given address.
//
// 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)
if err != nil {
return nil, 0, err

View file

@ -9,7 +9,7 @@ import (
"fmt"
"testing"
"github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcd/wire"
)
// 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[:]) {
continue
}
level := k[levelOffset]
level := uint8(k[levelOffset])
if level > highestLevel {
highestLevel = level
}
@ -105,7 +105,7 @@ func (b *addrIndexBucket) sanityCheck(addrKey [addrKeySize]byte, expectedTotal i
if !bytes.Equal(k[:levelOffset], addrKey[:]) {
continue
}
level := k[levelOffset]
level := uint8(k[levelOffset])
if level > highestLevel {
highestLevel = level
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -50,9 +50,9 @@ func (n NotificationType) String() string {
// Notification defines notification that is sent to the caller via the callback
// function provided during the call to New and consists of a notification type
// as well as associated data that depends on the type as follows:
// - NTBlockAccepted: *btcutil.Block
// - NTBlockConnected: *btcutil.Block
// - NTBlockDisconnected: *btcutil.Block
// - NTBlockAccepted: *btcutil.Block
// - NTBlockConnected: *btcutil.Block
// - NTBlockDisconnected: *btcutil.Block
type Notification struct {
Type NotificationType
Data interface{}

View file

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

View file

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

View file

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

View file

@ -6,14 +6,17 @@ package blockchain
import (
"fmt"
"runtime"
"testing"
"github.com/lbryio/lbcd/txscript"
"github.com/btcsuite/btcd/txscript"
)
// TestCheckBlockScripts ensures that validating the all of the scripts in a
// known-good block doesn't return an error.
func TestCheckBlockScripts(t *testing.T) {
runtime.GOMAXPROCS(runtime.NumCPU())
testBlockNum := 277647
blockDataFile := fmt.Sprintf("%d.dat.bz2", testBlockNum)
blocks, err := loadBlocks(blockDataFile)

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

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

View file

@ -7,7 +7,7 @@ package blockchain
import (
"fmt"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
// ThresholdState define the various threshold states used when voting on
@ -302,12 +302,6 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
}
deployment := &b.chainParams.Deployments[deploymentID]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
return ThresholdActive, nil
}
checker := deploymentChecker{deployment: deployment, chain: b}
cache := &b.deploymentCaches[deploymentID]
@ -316,7 +310,7 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
// initThresholdCaches initializes the threshold state caches for each warning
// bit and defined deployment and provides warnings if the chain is current per
// the warnUnknownRuleActivations function.
// the warnUnknownVersions and warnUnknownRuleActivations functions.
func (b *BlockChain) initThresholdCaches() error {
// Initialize the warning and deployment caches by calculating the
// threshold state for each of them. This will ensure the caches are
@ -341,9 +335,15 @@ func (b *BlockChain) initThresholdCaches() error {
}
}
// No warnings about unknown rules until the chain is current.
// No warnings about unknown rules or versions until the chain is
// current.
if b.isCurrent() {
// Warn if a high enough percentage of the last blocks have
// unexpected versions.
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
// have already been activated.

View file

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

View file

@ -11,9 +11,9 @@ import (
"fmt"
"time"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
)
const (
@ -232,25 +232,24 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
//
// The legacy format is as follows:
//
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
//
// Field Type Size
// version VLQ variable
// block height VLQ variable
// header code VLQ variable
// unspentness bitmap []byte variable
// compressed txouts
// compressed amount VLQ variable
// compressed script []byte variable
// Field Type Size
// version VLQ variable
// block height VLQ variable
// header code VLQ variable
// unspentness bitmap []byte variable
// compressed txouts
// compressed amount VLQ variable
// compressed script []byte variable
//
// The serialized header code format is:
//
// bit 0 - containing transaction is a coinbase
// bit 1 - output zero is unspent
// bit 2 - output one is unspent
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
// are unset, it encodes N-1 since there must be at least one unspent
// output.
// bit 0 - containing transaction is a coinbase
// bit 1 - output zero is unspent
// bit 2 - output one is unspent
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
// are unset, it encodes N-1 since there must be at least one unspent
// output.
//
// The rationale for the header code scheme is as follows:
// - Transactions which only pay to a single output and a change output are
@ -270,65 +269,65 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
// From tx in main blockchain:
// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
//
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
// <><><><------------------------------------------------------------------>
// | | \--------\ |
// | height | compressed txout 0
// version header code
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
// <><><><------------------------------------------------------------------>
// | | \--------\ |
// | height | compressed txout 0
// version header code
//
// - version: 1
// - height: 1
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
// - unspentness: Nothing since it is zero bytes
// - compressed txout 0:
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
// - 0x04: special script type pay-to-pubkey
// - 0x96...52: x-coordinate of the pubkey
// - version: 1
// - height: 1
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
// - unspentness: Nothing since it is zero bytes
// - compressed txout 0:
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
// - 0x04: special script type pay-to-pubkey
// - 0x96...52: x-coordinate of the pubkey
//
// Example 2:
// From tx in main blockchain:
// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f
//
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
// <><----><><><------------------------------------------><-------------------------------------------->
// | | | \-------------------\ | |
// version | \--------\ unspentness | compressed txout 2
// height header code compressed txout 0
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
// <><----><><><------------------------------------------><-------------------------------------------->
// | | | \-------------------\ | |
// version | \--------\ unspentness | compressed txout 2
// height header code compressed txout 0
//
// - version: 1
// - height: 113931
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 0:
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xe2...8a: pubkey hash
// - compressed txout 2:
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xb8...58: pubkey hash
// - version: 1
// - height: 113931
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 0:
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xe2...8a: pubkey hash
// - compressed txout 2:
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xb8...58: pubkey hash
//
// Example 3:
// From tx in main blockchain:
// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620
//
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
// <><----><><----><-------------------------------------------------->
// | | | \-----------------\ |
// version | \--------\ unspentness |
// height header code compressed txout 22
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
// <><----><><----><-------------------------------------------------->
// | | | \-----------------\ |
// version | \--------\ unspentness |
// height header code compressed txout 22
//
// - version: 1
// - height: 338156
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 22:
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
// - 0x01: special script type pay-to-script-hash
// - 0x1d...e6: script hash
// - version: 1
// - height: 338156
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 22:
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
// - 0x01: special script type pay-to-script-hash
// - 0x1d...e6: script hash
func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
// Deserialize the version.
//

View file

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

View file

@ -11,11 +11,11 @@ import (
"math/big"
"time"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
@ -40,7 +40,7 @@ const (
// baseSubsidy is the starting subsidy amount for mined blocks. This
// value is halved every SubsidyHalvingInterval blocks.
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
)
var (
@ -192,44 +192,17 @@ func isBIP0030Node(node *blockNode) bool {
// At the target block generation rate for the main network, this is
// approximately every 4 years.
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
h := int64(height)
if h == 0 {
return btcutil.SatoshiPerBitcoin * 4e8
}
if h <= 5100 {
return btcutil.SatoshiPerBitcoin
}
if h <= 55000 {
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
if chainParams.SubsidyReductionInterval == 0 {
return baseSubsidy
}
lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval)
reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2
for !withinLevelBounds(reduction, lv) {
if ((reduction*reduction + reduction) >> 1) > lv {
reduction--
} else {
reduction++
}
}
subsidyReduction := btcutil.SatoshiPerBitcoin * reduction
if subsidyReduction >= baseSubsidy {
return 0
}
return baseSubsidy - subsidyReduction
}
func withinLevelBounds(reduction int64, lv int64) bool {
if ((reduction*reduction + reduction) >> 1) > lv {
return false
}
reduction++
return ((reduction*reduction + reduction) >> 1) > lv
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
}
// CheckTransactionSanity performs some preliminary checks on a transaction to
// ensure it is sane.
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
// ensure it is sane. These checks are context free.
func CheckTransactionSanity(tx *btcutil.Tx) error {
// A transaction must have at least one input.
msgTx := tx.MsgTx()
if len(msgTx.TxIn) == 0 {
@ -288,11 +261,6 @@ func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
btcutil.MaxSatoshi)
return ruleError(ErrBadTxOutValue, str)
}
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
if err != nil {
return ruleError(ErrBadTxOutValue, err.Error())
}
}
// Check for duplicate transaction inputs.
@ -334,8 +302,8 @@ func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
// target difficulty as claimed.
//
// The flags modify the behavior of this function as follows:
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error {
// The target difficulty must be larger than zero.
target := CompactToBig(header.Bits)
@ -356,7 +324,7 @@ func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags Behavio
// to avoid proof of work checks is set.
if flags&BFNoPoWCheck != BFNoPoWCheck {
// The block hash must be less than the claimed target.
hash := header.BlockPoWHash()
hash := header.BlockHash()
hashNum := HashToBig(&hash)
if hashNum.Cmp(target) > 0 {
str := fmt.Sprintf("block hash of %064x is higher than "+
@ -547,7 +515,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
// Do some preliminary checks on each transaction to ensure they are
// sane before continuing.
for _, tx := range transactions {
err := CheckTransactionSanity(tx, false)
err := CheckTransactionSanity(tx)
if err != nil {
return err
}
@ -669,8 +637,8 @@ func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error {
// which depend on its position within the block chain.
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: All checks except those involving comparing the header against
// the checkpoints are not performed.
// - BFFastAdd: All checks except those involving comparing the header against
// the checkpoints are not performed.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode *blockNode, flags BehaviorFlags) error {
@ -748,8 +716,8 @@ func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode
// on its position within the block chain.
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: The transaction are not checked to see if they are finalized
// and the somewhat expensive BIP0034 validation is not performed.
// - BFFastAdd: The transaction are not checked to see if they are finalized
// and the somewhat expensive BIP0034 validation is not performed.
//
// The flags are also passed to checkBlockHeaderContext. See its documentation
// for how the flags modify its behavior.
@ -909,6 +877,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
return 0, nil
}
txHash := tx.Hash()
var totalSatoshiIn int64
for txInIndex, txIn := range tx.MsgTx().TxIn {
// Ensure the referenced input transaction is available.
@ -985,7 +954,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
if totalSatoshiIn < totalSatoshiOut {
str := fmt.Sprintf("total value of all transaction inputs for "+
"transaction %v is %v which is less than the amount "+
"spent of %v", tx.Hash(), totalSatoshiIn, totalSatoshiOut)
"spent of %v", txHash, totalSatoshiIn, totalSatoshiOut)
return 0, ruleError(ErrSpendTooHigh, str)
}

View file

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

View file

@ -7,7 +7,7 @@ package blockchain
import (
"math"
"github.com/lbryio/lbcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg"
)
const (
@ -26,6 +26,15 @@ const (
// vbNumBits is the total number of bits available for use with the
// version bits scheme.
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
@ -195,12 +204,6 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
expectedVersion := uint32(vbTopBits)
for id := 0; id < len(b.chainParams.Deployments); id++ {
deployment := &b.chainParams.Deployments[id]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
continue
}
cache := &b.deploymentCaches[id]
checker := deploymentChecker{deployment: deployment, chain: b}
state, err := b.thresholdState(prevNode, checker, cache)
@ -261,3 +264,38 @@ func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error {
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
}

View file

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

View file

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

View file

@ -1,11 +1,68 @@
btcec
=====
[![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)](https://travis-ci.org/btcsuite/btcec)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://godoc.org/github.com/btcsuite/btcd/btcec?status.png)](http://godoc.org/github.com/btcsuite/btcd/btcec)
btcec implements elliptic curve cryptography needed for working with
Package btcec implements elliptic curve cryptography needed for working with
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
is provided to ensure proper functionality. Package btcec was originally based
on work from ThePiachu which is licensed under the same terms as Go, but it has
signficantly diverged since then.
signficantly diverged since then. The btcsuite developers original is licensed
under the liberal ISC license.
Although this package was primarily written for btcd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use secp256k1 elliptic curve cryptography.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/btcec
```
## Examples
* [Sign Message](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.

View file

@ -930,8 +930,6 @@ func initS256() {
secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
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,
big.NewInt(1)), big.NewInt(4))
secp256k1.H = 1

View file

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

View file

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

View file

@ -125,30 +125,27 @@ var (
// the arithmetic needed for elliptic curve operations.
//
// The following depicts the internal representation:
//
// -----------------------------------------------------------------
// | n[9] | n[8] | ... | n[0] |
// | 32 bits available | 32 bits available | ... | 32 bits available |
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
// -----------------------------------------------------------------
// -----------------------------------------------------------------
// | n[9] | n[8] | ... | n[0] |
// | 32 bits available | 32 bits available | ... | 32 bits available |
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
// -----------------------------------------------------------------
//
// For example, consider the number 2^49 + 1. It would be represented as:
//
// n[0] = 1
// n[1] = 2^23
// n[2..9] = 0
// n[0] = 1
// n[1] = 2^23
// n[2..9] = 0
//
// The full 256-bit value is then calculated by looping i from 9..0 and
// doing sum(n[i] * 2^(26i)) like so:
//
// n[9] * 2^(26*9) = 0 * 2^234 = 0
// n[8] * 2^(26*8) = 0 * 2^208 = 0
// ...
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
// n[0] * 2^(26*0) = 1 * 2^0 = 1
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
// n[9] * 2^(26*9) = 0 * 2^234 = 0
// n[8] * 2^(26*8) = 0 * 2^208 = 0
// ...
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
// n[0] * 2^(26*0) = 1 * 2^0 = 1
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
type fieldVal struct {
n [10]uint32
}
@ -229,24 +226,20 @@ func (f *fieldVal) SetBytes(b *[32]byte) *fieldVal {
return f
}
// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned
// integer (meaning it is truncated to the first 32 bytes), packs it into the
// internal field value representation, and returns the updated field value.
//
// 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.
// SetByteSlice packs the passed big-endian value into the internal field value
// representation. Only the first 32-bytes are used. As a result, it is up to
// the caller to ensure numbers of the appropriate size are used or the value
// will be truncated.
//
// The field value is returned to support chaining. This enables syntax like:
// f := new(fieldVal).SetByteSlice(byteSlice)
func (f *fieldVal) SetByteSlice(b []byte) *fieldVal {
var b32 [32]byte
if len(b) > 32 {
b = b[:32]
for i := 0; i < len(b); i++ {
if i < 32 {
b32[i+(32-len(b))] = b[i]
}
}
copy(b32[32-len(b):], b)
return f.SetBytes(&b32)
}

View file

@ -7,7 +7,6 @@ package btcec
import (
"crypto/rand"
"encoding/hex"
"fmt"
"reflect"
"testing"
@ -966,156 +965,3 @@ 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
}

View file

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

View file

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

View file

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

View file

@ -232,11 +232,11 @@ func TestPubKeys(t *testing.T) {
var pkStr []byte
switch test.format {
case pubkeyUncompressed:
pkStr = pk.SerializeUncompressed()
pkStr = (*PublicKey)(pk).SerializeUncompressed()
case pubkeyCompressed:
pkStr = pk.SerializeCompressed()
pkStr = (*PublicKey)(pk).SerializeCompressed()
case pubkeyHybrid:
pkStr = pk.SerializeHybrid()
pkStr = (*PublicKey)(pk).SerializeHybrid()
}
if !bytes.Equal(test.key, pkStr) {
t.Errorf("%s pubkey: serialized keys do not match.",

View file

@ -284,25 +284,6 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
// format and thus we match bitcoind's behaviour here.
func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
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
Rx := new(big.Int).Mul(curve.Params().N,
new(big.Int).SetInt64(int64(iter/2)))
@ -353,10 +334,6 @@ func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
// step to prevent the jacobian conversion back and forth.
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
if Qx.Sign() == 0 && Qy.Sign() == 0 {
return nil, errors.New("point (Qx, Qy) equals the point at infinity")
}
return &PublicKey{
Curve: curve,
X: Qx,
@ -416,7 +393,7 @@ func SignCompact(curve *KoblitzCurve, key *PrivateKey,
// RecoverCompact verifies the compact signature "signature" of "hash" for the
// Koblitz curve in "curve". If the signature matches then the recovered public
// key will be returned as well as a boolean if the original key was compressed
// key will be returned as well as a boolen if the original key was compressed
// or not, else an error will be returned.
func RecoverCompact(curve *KoblitzCurve, signature,
hash []byte) (*PublicKey, bool, error) {

View file

@ -464,7 +464,8 @@ func TestSignatureSerialize(t *testing.T) {
func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve,
data []byte, isCompressed bool) {
priv, _ := NewPrivateKey(curve)
tmp, _ := NewPrivateKey(curve)
priv := (*PrivateKey)(tmp)
hashed := []byte("testing")
sig, err := SignCompact(curve, priv, hashed, isCompressed)
@ -549,52 +550,12 @@ var recoveryTests = []struct {
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
err: fmt.Errorf("invalid square root"),
},
{
// Point at infinity recovered
msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"),
},
{
// Low R and S values.
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",
sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004",
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) {

View file

@ -1,8 +1,70 @@
btcjson
=======
[![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)](https://travis-ci.org/btcsuite/btcd)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/btcjson)
Package btcjson implements concrete types for marshalling to and from the
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
proper functionality.
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.

View file

@ -59,23 +59,6 @@ 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.
type GenerateCmd struct {
NumBlocks uint32
@ -148,7 +131,6 @@ func init() {
MustRegisterCmd("debuglevel", (*DebugLevelCmd)(nil), flags)
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
MustRegisterCmd("generatetoaddress", (*GenerateToAddressCmd)(nil), flags)
MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags)
MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags)
MustRegisterCmd("getheaders", (*GetHeadersCmd)(nil), flags)

View file

@ -12,7 +12,7 @@ import (
"reflect"
"testing"
"github.com/lbryio/lbcd/btcjson"
"github.com/btcsuite/btcd/btcjson"
)
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal
@ -114,24 +114,6 @@ func TestBtcdExtCmds(t *testing.T) {
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",
newCmd: func() (interface{}, error) {
@ -211,7 +193,7 @@ func TestBtcdExtCmds(t *testing.T) {
for i, test := range tests {
// Marshal the command as created by the new static command
// creation function.
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)
@ -235,7 +217,7 @@ func TestBtcdExtCmds(t *testing.T) {
// Marshal the command as created by the generic new command
// creation function.
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
marshalled, err = btcjson.MarshalCmd(testID, cmd)
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)

View file

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

View file

@ -11,7 +11,7 @@ import (
"reflect"
"testing"
"github.com/lbryio/lbcd/btcjson"
"github.com/btcsuite/btcd/btcjson"
)
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and
@ -145,7 +145,7 @@ func TestBtcWalletExtCmds(t *testing.T) {
for i, test := range tests {
// Marshal the command as created by the new static command
// creation function.
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)
@ -169,7 +169,7 @@ func TestBtcWalletExtCmds(t *testing.T) {
// Marshal the command as created by the generic new command
// creation function.
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
marshalled, err = btcjson.MarshalCmd(testID, cmd)
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)

View file

@ -8,12 +8,10 @@
package btcjson
import (
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcd/wire"
)
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
@ -48,15 +46,6 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd {
}
}
// ClearBannedCmd defines the clearbanned JSON-RPC command.
type ClearBannedCmd struct{}
// NewClearBannedCmd returns a new instance which can be used to issue an clearbanned
// JSON-RPC command.
func NewClearBannedCmd() *ClearBannedCmd {
return &ClearBannedCmd{}
}
// TransactionInput represents the inputs to a transaction. Specifically a
// transaction hash and output number pair.
type TransactionInput struct {
@ -67,25 +56,20 @@ type TransactionInput struct {
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
type CreateRawTransactionCmd struct {
Inputs []TransactionInput
Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"`
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
LockTime *int64
}
// NewCreateRawTransactionCmd returns a new instance which can be used to issue
// a createrawtransaction JSON-RPC command.
//
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
// both gets interpreted as the empty slice.
func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{},
// Amounts are in BTC.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
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{
Inputs: inputs,
Outputs: outputs,
Amounts: amounts,
LockTime: lockTime,
}
}
@ -116,65 +100,6 @@ 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.
type GetAddedNodeInfoCmd struct {
DNS bool
@ -205,7 +130,8 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
// GetBlockCmd defines the getblock JSON-RPC command.
type GetBlockCmd struct {
Hash string
Verbosity *int `jsonrpcdefault:"1"`
Verbose *bool `jsonrpcdefault:"true"`
VerboseTx *bool `jsonrpcdefault:"false"`
}
// NewGetBlockCmd returns a new instance which can be used to issue a getblock
@ -213,10 +139,11 @@ type GetBlockCmd struct {
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetBlockCmd(hash string, verbosity *int) *GetBlockCmd {
func NewGetBlockCmd(hash string, verbose, verboseTx *bool) *GetBlockCmd {
return &GetBlockCmd{
Hash: hash,
Verbosity: verbosity,
Verbose: verbose,
VerboseTx: verboseTx,
}
}
@ -238,33 +165,6 @@ func NewGetBlockCountCmd() *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.
type GetBlockHashCmd struct {
Index int64
@ -293,50 +193,6 @@ 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
// (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an
// pointer argument to GetBlockTemplateCmd.
@ -360,10 +216,6 @@ type TemplateRequest struct {
// "proposal".
Data string `json:"data,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
@ -469,24 +321,6 @@ func NewGetChainTipsCmd() *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.
type GetConnectionCountCmd struct{}
@ -496,19 +330,6 @@ func NewGetConnectionCountCmd() *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.
type GetDifficultyCmd struct{}
@ -612,22 +433,6 @@ 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.
type GetPeerInfoCmd struct{}
@ -659,7 +464,7 @@ func NewGetRawMempoolCmd(verbose *bool) *GetRawMempoolCmd {
// Core even though it really should be a bool.
type GetRawTransactionCmd struct {
Txid string
Verbose *bool `jsonrpcdefault:"false"`
Verbose *int `jsonrpcdefault:"0"`
}
// NewGetRawTransactionCmd returns a new instance which can be used to issue a
@ -667,7 +472,7 @@ type GetRawTransactionCmd struct {
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetRawTransactionCmd(txHash string, verbose *bool) *GetRawTransactionCmd {
func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd {
return &GetRawTransactionCmd{
Txid: txHash,
Verbose: verbose,
@ -766,15 +571,6 @@ func NewInvalidateBlockCmd(blockHash string) *InvalidateBlockCmd {
}
}
// ListBannedCmd defines the listbanned JSON-RPC command.
type ListBannedCmd struct{}
// NewListBannedCmd returns a new instance which can be used to issue a listbanned
// JSON-RPC command.
func NewListBannedCmd() *ListBannedCmd {
return &ListBannedCmd{}
}
// PingCmd defines the ping JSON-RPC command.
type PingCmd struct{}
@ -838,60 +634,11 @@ 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.
type SendRawTransactionCmd struct {
HexTx string
FeeSetting *AllowHighFeesOrMaxFeeRate `jsonrpcdefault:"false"`
HexTx string
AllowHighFees *bool `jsonrpcdefault:"false"`
MaxFeeRate *int32
}
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
@ -901,10 +648,8 @@ type SendRawTransactionCmd struct {
// for optional parameters will use the default value.
func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransactionCmd {
return &SendRawTransactionCmd{
HexTx: hexTx,
FeeSetting: &AllowHighFeesOrMaxFeeRate{
Value: allowHighFees,
},
HexTx: hexTx,
AllowHighFees: allowHighFees,
}
}
@ -914,43 +659,8 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac
// A 0 maxFeeRate indicates that a maximum fee rate won't be enforced.
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
return &SendRawTransactionCmd{
HexTx: hexTx,
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,
HexTx: hexTx,
MaxFeeRate: &maxFeeRate,
}
}
@ -972,24 +682,6 @@ 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.
type StopCmd struct{}
@ -1101,24 +793,18 @@ func init() {
MustRegisterCmd("createrawtransaction", (*CreateRawTransactionCmd)(nil), flags)
MustRegisterCmd("decoderawtransaction", (*DecodeRawTransactionCmd)(nil), flags)
MustRegisterCmd("decodescript", (*DecodeScriptCmd)(nil), flags)
MustRegisterCmd("deriveaddresses", (*DeriveAddressesCmd)(nil), flags)
MustRegisterCmd("fundrawtransaction", (*FundRawTransactionCmd)(nil), flags)
MustRegisterCmd("getaddednodeinfo", (*GetAddedNodeInfoCmd)(nil), flags)
MustRegisterCmd("getbestblockhash", (*GetBestBlockHashCmd)(nil), flags)
MustRegisterCmd("getblock", (*GetBlockCmd)(nil), flags)
MustRegisterCmd("getblockchaininfo", (*GetBlockChainInfoCmd)(nil), flags)
MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags)
MustRegisterCmd("getblockfilter", (*GetBlockFilterCmd)(nil), flags)
MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags)
MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags)
MustRegisterCmd("getblockstats", (*GetBlockStatsCmd)(nil), flags)
MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags)
MustRegisterCmd("getcfilter", (*GetCFilterCmd)(nil), flags)
MustRegisterCmd("getcfilterheader", (*GetCFilterHeaderCmd)(nil), flags)
MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags)
MustRegisterCmd("getchaintxstats", (*GetChainTxStatsCmd)(nil), flags)
MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags)
MustRegisterCmd("getdescriptorinfo", (*GetDescriptorInfoCmd)(nil), flags)
MustRegisterCmd("getdifficulty", (*GetDifficultyCmd)(nil), flags)
MustRegisterCmd("getgenerate", (*GetGenerateCmd)(nil), flags)
MustRegisterCmd("gethashespersec", (*GetHashesPerSecCmd)(nil), flags)
@ -1129,11 +815,7 @@ func init() {
MustRegisterCmd("getnetworkinfo", (*GetNetworkInfoCmd)(nil), flags)
MustRegisterCmd("getnettotals", (*GetNetTotalsCmd)(nil), flags)
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags)
MustRegisterCmd("setban", (*SetBanCmd)(nil), flags)
MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags)
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)
@ -1148,7 +830,6 @@ func init() {
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
MustRegisterCmd("signmessagewithprivkey", (*SignMessageWithPrivKeyCmd)(nil), flags)
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)

View file

@ -6,14 +6,13 @@ package btcjson_test
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"testing"
"github.com/lbryio/lbcd/btcjson"
"github.com/lbryio/lbcd/wire"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/wire"
)
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
@ -52,28 +51,13 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
txOutputs := map[string]interface{}{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
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},
Amounts: map[string]float64{"456": .0123},
},
},
{
@ -86,137 +70,17 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
txOutputs := map[string]interface{}{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333))
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"456": .0123},
Amounts: map[string]float64{"456": .0123},
LockTime: btcjson.Int64(12312333333),
},
},
{
name: "createrawtransaction with data",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
`{"data":"6a134920616d204672616374616c456e6372797074"}`)
},
staticCmd: func() interface{} {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
},
},
{
name: "fundrawtransaction - empty opts",
newCmd: func() (i interface{}, e error) {
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",
newCmd: func() (interface{}, error) {
@ -239,51 +103,6 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"decodescript","params":["00"],"id":1}`,
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",
newCmd: func() (interface{}, error) {
@ -322,58 +141,51 @@ func TestChainSvrCmds(t *testing.T) {
},
{
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) {
return btcjson.NewCmd("getblock", "123")
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", nil)
return btcjson.NewGetBlockCmd("123", nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbosity: btcjson.Int(1),
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(false),
},
},
{
name: "getblock required optional1",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123", btcjson.Int(1))
// Intentionally use a source param that is
// more pointers than the destination to
// exercise that path.
verbosePtr := btcjson.Bool(true)
return btcjson.NewCmd("getblock", "123", &verbosePtr)
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Int(1))
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbosity: btcjson.Int(1),
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(false),
},
},
{
name: "getblock required optional2",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123", btcjson.Int(2))
return btcjson.NewCmd("getblock", "123", true, true)
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Int(2))
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true))
},
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",2],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true,true],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbosity: btcjson.Int(2),
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(true),
},
},
{
@ -398,28 +210,6 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"getblockcount","params":[],"id":1}`,
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",
newCmd: func() (interface{}, error) {
@ -445,60 +235,6 @@ func TestChainSvrCmds(t *testing.T) {
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",
newCmd: func() (interface{}, error) {
@ -625,44 +361,6 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"getchaintips","params":[],"id":1}`,
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",
newCmd: func() (interface{}, error) {
@ -817,32 +515,6 @@ func TestChainSvrCmds(t *testing.T) {
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",
newCmd: func() (interface{}, error) {
@ -891,21 +563,21 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123",
Verbose: btcjson.Bool(false),
Verbose: btcjson.Int(0),
},
},
{
name: "getrawtransaction optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getrawtransaction", "123", true)
return btcjson.NewCmd("getrawtransaction", "123", 1)
},
staticCmd: func() interface{} {
return btcjson.NewGetRawTransactionCmd("123", btcjson.Bool(true))
return btcjson.NewGetRawTransactionCmd("123", btcjson.Int(1))
},
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",true],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123",
Verbose: btcjson.Bool(true),
Verbose: btcjson.Int(1),
},
},
{
@ -1220,72 +892,32 @@ func TestChainSvrCmds(t *testing.T) {
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",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{})
return btcjson.NewCmd("sendrawtransaction", "1122")
},
staticCmd: func() interface{} {
return btcjson.NewSendRawTransactionCmd("1122", nil)
},
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122"],"id":1}`,
unmarshalled: &btcjson.SendRawTransactionCmd{
HexTx: "1122",
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
Value: btcjson.Bool(false),
},
HexTx: "1122",
AllowHighFees: btcjson.Bool(false),
},
},
{
name: "sendrawtransaction optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Bool(false)})
return btcjson.NewCmd("sendrawtransaction", "1122", false)
},
staticCmd: func() interface{} {
return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
},
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
unmarshalled: &btcjson.SendRawTransactionCmd{
HexTx: "1122",
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),
},
HexTx: "1122",
AllowHighFees: btcjson.Bool(false),
},
},
{
@ -1316,20 +948,6 @@ func TestChainSvrCmds(t *testing.T) {
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",
newCmd: func() (interface{}, error) {
@ -1468,24 +1086,13 @@ func TestChainSvrCmds(t *testing.T) {
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))
for i, test := range tests {
// Marshal the command as created by the new static command
// creation function.
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)
@ -1510,7 +1117,7 @@ func TestChainSvrCmds(t *testing.T) {
// Marshal the command as created by the generic new command
// creation function.
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
marshalled, err = btcjson.MarshalCmd(testID, cmd)
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)

View file

@ -4,16 +4,7 @@
package btcjson
import (
"bytes"
"encoding/hex"
"encoding/json"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
import "encoding/json"
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
// the verbose flag is set. When the verbose flag is not set, getblockheader
@ -25,7 +16,6 @@ type GetBlockHeaderVerboseResult struct {
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
ClaimTrie string `json:"nameclaimroot,omitempty"`
Time int64 `json:"time"`
Nonce uint64 `json:"nonce"`
Bits string `json:"bits"`
@ -34,95 +24,27 @@ type GetBlockHeaderVerboseResult struct {
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
// verbose flag is set to 1. When the verbose flag is set to 0, getblock returns a
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
// 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.
// verbose flag is set. When the verbose flag is not set, getblock returns a
// hex-encoded string.
type GetBlockVerboseResult struct {
GetBlockVerboseResultBase
Tx []string `json:"tx"`
}
// GetBlockVerboseTxResult models the data from the getblock command when the
// verbose flag is set to 2. When the verbose flag is set to 0, getblock returns a
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
// 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 GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
type GetBlockVerboseTxResult struct {
GetBlockVerboseResultBase
Tx []TxRawResult `json:"tx"`
}
// GetChainTxStatsResult models the data from the getchaintxstats command.
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"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []string `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
}
// CreateMultiSigResult models the data returned from the createmultisig
@ -218,28 +140,18 @@ type GetBlockChainInfoResult struct {
Difficulty float64 `json:"difficulty"`
MedianTime int64 `json:"mediantime"`
VerificationProgress float64 `json:"verificationprogress,omitempty"`
InitialBlockDownload bool `json:"initialblockdownload,omitempty"`
Pruned bool `json:"pruned"`
PruneHeight int32 `json:"pruneheight,omitempty"`
ChainWork string `json:"chainwork,omitempty"`
SizeOnDisk int64 `json:"size_on_disk,omitempty"`
*SoftForks
*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
// getblocktemplate command.
type GetBlockTemplateResultTx struct {
Data string `json:"data"`
Hash string `json:"hash"`
TxID string `json:"txid"`
Depends []int64 `json:"depends"`
Fee int64 `json:"fee"`
SigOps int64 `json:"sigops"`
@ -292,62 +204,32 @@ type GetBlockTemplateResult struct {
// Block proposal from BIP 0023.
Capabilities []string `json:"capabilities,omitempty"`
RejectReasion string `json:"reject-reason,omitempty"`
ClaimTrieHash string `json:"claimtrie"`
Rules []string `json:"rules,omitempty"`
}
// GetMempoolEntryResult models the data returned from the getmempoolentry's
// 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
// command.
type GetMempoolEntryResult struct {
VSize int32 `json:"vsize"`
Size int32 `json:"size"`
Weight int64 `json:"weight"`
Fee float64 `json:"fee"`
ModifiedFee float64 `json:"modifiedfee"`
Time int64 `json:"time"`
Height int64 `json:"height"`
DescendantCount int64 `json:"descendantcount"`
DescendantSize int64 `json:"descendantsize"`
DescendantFees float64 `json:"descendantfees"`
AncestorCount int64 `json:"ancestorcount"`
AncestorSize int64 `json:"ancestorsize"`
AncestorFees float64 `json:"ancestorfees"`
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"`
Size int32 `json:"size"`
Fee float64 `json:"fee"`
ModifiedFee float64 `json:"modifiedfee"`
Time int64 `json:"time"`
Height int64 `json:"height"`
StartingPriority float64 `json:"startingpriority"`
CurrentPriority float64 `json:"currentpriority"`
DescendantCount int64 `json:"descendantcount"`
DescendantSize int64 `json:"descendantsize"`
DescendantFees float64 `json:"descendantfees"`
AncestorCount int64 `json:"ancestorcount"`
AncestorSize int64 `json:"ancestorsize"`
AncestorFees float64 `json:"ancestorfees"`
Depends []string `json:"depends"`
}
// GetMempoolInfoResult models the data returned from the getmempoolinfo
// command.
type GetMempoolInfoResult struct {
Size int64 `json:"size"` // Current tx count
Bytes int64 `json:"bytes"` // Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted
Usage int64 `json:"usage"` // Total memory usage for the mempool
TotalFee float64 `json:"total_fee"` // Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction
MemPoolMinFee float64 `json:"mempoolminfee"` // Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee
MinRelayTxFee float64 `json:"minrelaytxfee"` // Current minimum relay fee for transactions
UnbroadcastCount int64 `json:"unbroadcastcount"` // Current number of transactions that haven't passed initial broadcast yet
Size int64 `json:"size"`
Bytes int64 `json:"bytes"`
}
// NetworksResult models the networks data from the getnetworkinfo command.
@ -385,16 +267,6 @@ type GetNetworkInfoResult struct {
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.
type GetPeerInfoResult struct {
ID int32 `json:"id"`
@ -442,9 +314,6 @@ type ScriptPubKeyResult struct {
Hex string `json:"hex,omitempty"`
ReqSigs int32 `json:"reqSigs,omitempty"`
Type string `json:"type"`
SubType string `json:"subtype"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
Addresses []string `json:"addresses,omitempty"`
}
@ -457,64 +326,6 @@ type GetTxOutResult struct {
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.
type GetNetTotalsResult struct {
TotalBytesRecv uint64 `json:"totalbytesrecv"`
@ -603,8 +414,6 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
type PrevOut struct {
Addresses []string `json:"addresses,omitempty"`
Value float64 `json:"value"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
}
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
@ -695,8 +504,8 @@ type GetMiningInfoResult struct {
Errors string `json:"errors"`
Generate bool `json:"generate"`
GenProcLimit int32 `json:"genproclimit"`
HashesPerSec float64 `json:"hashespersec"`
NetworkHashPS float64 `json:"networkhashps"`
HashesPerSec int64 `json:"hashespersec"`
NetworkHashPS int64 `json:"networkhashps"`
PooledTx uint64 `json:"pooledtx"`
TestNet bool `json:"testnet"`
}
@ -723,15 +532,6 @@ type InfoChainResult struct {
Errors string `json:"errors"`
}
// ListBannedResult models the data returned from the listbanned command.
type ListBannedResult struct {
Address string `json:"address"`
BanCreated int64 `json:"ban_created"`
BannedUntil int64 `json:"banned_until"`
BanDuration int64 `json:"ban_duration"`
TimeRemaining int64 `json:"time_remaining"`
}
// TxRawResult models the data from the getrawtransaction command.
type TxRawResult struct {
Hex string `json:"hex"`
@ -740,7 +540,7 @@ type TxRawResult struct {
Size int32 `json:"size,omitempty"`
Vsize int32 `json:"vsize,omitempty"`
Weight int32 `json:"weight,omitempty"`
Version uint32 `json:"version"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
@ -780,93 +580,7 @@ type TxRawDecodeResult struct {
// ValidateAddressChainResult models the data returned by the chain server
// 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 {
IsValid bool `json:"isvalid"`
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"`
IsValid bool `json:"isvalid"`
Address string `json:"address,omitempty"`
}

View file

@ -6,13 +6,9 @@ package btcjson_test
import (
"encoding/json"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/lbryio/lbcd/btcjson"
"github.com/lbryio/lbcd/chaincfg/chainhash"
btcutil "github.com/lbryio/lbcutil"
"github.com/btcsuite/btcd/btcjson"
)
// TestChainSvrCustomResults ensures any results that have custom marshalling
@ -70,7 +66,7 @@ func TestChainSvrCustomResults(t *testing.T) {
},
Sequence: 4294967295,
},
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
},
}
@ -90,112 +86,3 @@ 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
}
}
}

View file

@ -80,7 +80,7 @@ func NewStopNotifyNewTransactionsCmd() *StopNotifyNewTransactionsCmd {
// NotifyReceivedCmd defines the notifyreceived JSON-RPC command.
//
// Deprecated: Use LoadTxFilterCmd instead.
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
type NotifyReceivedCmd struct {
Addresses []string
}
@ -88,7 +88,7 @@ type NotifyReceivedCmd struct {
// NewNotifyReceivedCmd returns a new instance which can be used to issue a
// notifyreceived JSON-RPC command.
//
// Deprecated: Use NewLoadTxFilterCmd instead.
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
func NewNotifyReceivedCmd(addresses []string) *NotifyReceivedCmd {
return &NotifyReceivedCmd{
Addresses: addresses,
@ -128,7 +128,7 @@ func NewLoadTxFilterCmd(reload bool, addresses []string, outPoints []OutPoint) *
// NotifySpentCmd defines the notifyspent JSON-RPC command.
//
// Deprecated: Use LoadTxFilterCmd instead.
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
type NotifySpentCmd struct {
OutPoints []OutPoint
}
@ -136,7 +136,7 @@ type NotifySpentCmd struct {
// NewNotifySpentCmd returns a new instance which can be used to issue a
// notifyspent JSON-RPC command.
//
// Deprecated: Use NewLoadTxFilterCmd instead.
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
return &NotifySpentCmd{
OutPoints: outPoints,
@ -145,7 +145,7 @@ func NewNotifySpentCmd(outPoints []OutPoint) *NotifySpentCmd {
// StopNotifyReceivedCmd defines the stopnotifyreceived JSON-RPC command.
//
// Deprecated: Use LoadTxFilterCmd instead.
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
type StopNotifyReceivedCmd struct {
Addresses []string
}
@ -153,7 +153,7 @@ type StopNotifyReceivedCmd struct {
// NewStopNotifyReceivedCmd returns a new instance which can be used to issue a
// stopnotifyreceived JSON-RPC command.
//
// Deprecated: Use NewLoadTxFilterCmd instead.
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
return &StopNotifyReceivedCmd{
Addresses: addresses,
@ -162,7 +162,7 @@ func NewStopNotifyReceivedCmd(addresses []string) *StopNotifyReceivedCmd {
// StopNotifySpentCmd defines the stopnotifyspent JSON-RPC command.
//
// Deprecated: Use LoadTxFilterCmd instead.
// NOTE: Deprecated. Use LoadTxFilterCmd instead.
type StopNotifySpentCmd struct {
OutPoints []OutPoint
}
@ -170,7 +170,7 @@ type StopNotifySpentCmd struct {
// NewStopNotifySpentCmd returns a new instance which can be used to issue a
// stopnotifyspent JSON-RPC command.
//
// Deprecated: Use NewLoadTxFilterCmd instead.
// NOTE: Deprecated. Use NewLoadTxFilterCmd instead.
func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
return &StopNotifySpentCmd{
OutPoints: outPoints,
@ -179,7 +179,7 @@ func NewStopNotifySpentCmd(outPoints []OutPoint) *StopNotifySpentCmd {
// RescanCmd defines the rescan JSON-RPC command.
//
// Deprecated: Use RescanBlocksCmd instead.
// NOTE: Deprecated. Use RescanBlocksCmd instead.
type RescanCmd struct {
BeginBlock string
Addresses []string
@ -193,7 +193,7 @@ type RescanCmd struct {
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
//
// Deprecated: Use NewRescanBlocksCmd instead.
// NOTE: Deprecated. Use NewRescanBlocksCmd instead.
func NewRescanCmd(beginBlock string, addresses []string, outPoints []OutPoint, endBlock *string) *RescanCmd {
return &RescanCmd{
BeginBlock: beginBlock,

View file

@ -12,7 +12,7 @@ import (
"reflect"
"testing"
"github.com/lbryio/lbcd/btcjson"
"github.com/btcsuite/btcd/btcjson"
)
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands
@ -233,7 +233,7 @@ func TestChainSvrWsCmds(t *testing.T) {
for i, test := range tests {
// Marshal the command as created by the new static command
// creation function.
marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, testID, test.staticCmd())
marshalled, err := btcjson.MarshalCmd(testID, test.staticCmd())
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)
@ -257,7 +257,7 @@ func TestChainSvrWsCmds(t *testing.T) {
// Marshal the command as created by the generic new command
// creation function.
marshalled, err = btcjson.MarshalCmd(btcjson.RpcVersion1, testID, cmd)
marshalled, err = btcjson.MarshalCmd(testID, cmd)
if err != nil {
t.Errorf("MarshalCmd #%d (%s) unexpected error: %v", i,
test.name, err)

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