Compare commits
88 commits
master
...
pruned_ram
Author | SHA1 | Date | |
---|---|---|---|
|
e056f8ac23 | ||
|
742881a29a | ||
|
55abc9d25c | ||
|
dc230888ef | ||
|
ba05456830 | ||
|
07d25ba7ce | ||
|
d884f96553 | ||
|
eb165fb359 | ||
|
52f41459d5 | ||
|
3910319e80 | ||
|
db25b9b11b | ||
|
6009f9048c | ||
|
fa9239e0c5 | ||
|
edfffd979d | ||
|
02f76b2e8e | ||
|
9ebe440325 | ||
|
a4cc516896 | ||
|
690954d843 | ||
|
035ff2a799 | ||
|
79d7e65a35 | ||
|
103ab86904 | ||
|
cee79f6635 | ||
|
96f3d421df | ||
|
3a046d153c | ||
|
a56581d967 | ||
|
3c4900275c | ||
|
9d3279f215 | ||
|
40fe74adb8 | ||
|
ac1fdda8a0 | ||
|
79e392b85d | ||
|
5588af7d5b | ||
|
83b6a8dc18 | ||
|
1ba1a10e59 | ||
|
a51be72029 | ||
|
79987722bb | ||
|
1834d95b43 | ||
|
9c9bd3e3a5 | ||
|
8a5e74ebe6 | ||
|
7154e57d49 | ||
|
bf86d03f84 | ||
|
d2f8ad7657 | ||
|
ca18f3e8a2 | ||
|
0be18205c8 | ||
|
61de064575 | ||
|
e4c637b02a | ||
|
d83eaa4fed | ||
|
c7285883a6 | ||
|
fe1ce376d8 | ||
|
d19bcd60db | ||
|
7414ad7b54 | ||
|
c8cd97fe4d | ||
|
a06875fe46 | ||
|
5f872b37cf | ||
|
9af0566433 | ||
|
aa518c59bb | ||
|
1402e61807 | ||
|
a061c31208 | ||
|
983e4c6000 | ||
|
a310f8b598 | ||
|
ed2c764c9d | ||
|
4b8bd4c238 | ||
|
9080abc2c6 | ||
|
0224bf295b | ||
|
8e059c14d7 | ||
|
9d0dfbe87e | ||
|
62479740ae | ||
|
1895c9069f | ||
|
9caab1e2e1 | ||
|
0a22e00498 | ||
|
866b0cb610 | ||
|
3d9d9b1912 | ||
|
27b01f77b3 | ||
|
7d412b4e2f | ||
|
a6189cb439 | ||
|
1264d4581d | ||
|
ba7266c20c | ||
|
dce6d65452 | ||
|
43bed18649 | ||
|
b704fef973 | ||
|
5b72ef6719 | ||
|
f535c88f4a | ||
|
eb3bde09f2 | ||
|
c65dd82284 | ||
|
b7d3e11250 | ||
|
31ce21deb6 | ||
|
0e5bf1c24f | ||
|
61c0f0df99 | ||
|
82141c408c |
352 changed files with 14240 additions and 28243 deletions
|
@ -3,26 +3,23 @@ on: [push, pull_request]
|
|||
jobs:
|
||||
build:
|
||||
name: Go CI
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: self-hosted
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.14, 1.15]
|
||||
go: [1.16]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Check out source
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Linters
|
||||
run: "curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.26.0"
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GO111MODULE: "on"
|
||||
run: go build ./...
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
GO111MODULE: "on"
|
||||
run: |
|
||||
sh ./goclean.sh
|
||||
|
58
.github/workflows/create-release.yml
vendored
Normal file
58
.github/workflows/create-release.yml
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
name: Create release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
note:
|
||||
description: 'Note'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.16]
|
||||
os: [linux, darwin, windows]
|
||||
ar: [amd64, arm64]
|
||||
exclude:
|
||||
- go: 1.16
|
||||
os: windows
|
||||
ar: arm64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2
|
||||
- name: Build executables
|
||||
env:
|
||||
GOOS: ${{ matrix.os }}
|
||||
GOARCH: ${{ matrix.ar }}
|
||||
CGO_ENABLED: 0
|
||||
run: |
|
||||
go build -trimpath -ldflags="-s -w -buildid=" -v -o artifacts/ .
|
||||
go build -trimpath -ldflags="-s -w -buildid=" -v -o artifacts/ ./cmd/lbcctl/
|
||||
- name: SHA256 sum
|
||||
run: sha256sum -b artifacts/* > artifacts/lbcd.sha256
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lbcd-${{ matrix.os }}-${{ matrix.ar }}
|
||||
path: artifacts/*
|
||||
|
||||
|
||||
# for releases see https://trstringer.com/github-actions-create-release-upload-artifacts/
|
||||
|
||||
# AWS S3 support:
|
||||
# - name: Upload to Amazon S3
|
||||
# uses: ItsKarma/aws-cli@v1.70.0
|
||||
# with:
|
||||
# args: s3 sync .release s3://my-bucket-name
|
||||
# env:
|
||||
# # Make sure to add the secrets in the repo settings page
|
||||
# # AWS_REGION is set to us-east-1 by default
|
||||
# AWS_ACCESS_KEY_ID: $
|
||||
# AWS_SECRET_ACCESS_KEY: $
|
||||
# AWS_REGION: us-east-1
|
35
.github/workflows/full-sync-part-1.yml
vendored
Normal file
35
.github/workflows/full-sync-part-1.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
name: Full Sync From 0
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
note:
|
||||
description: 'Note'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Go CI
|
||||
runs-on: self-hosted
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.16]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Note ${{ github.event.inputs.note }}!"
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2
|
||||
- name: Build lbcd
|
||||
run: go build .
|
||||
- name: Create datadir
|
||||
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
|
||||
- name: Run lbcd
|
||||
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --connect=127.0.0.1 --norpc
|
||||
- name: Remove datadir
|
||||
if: always()
|
||||
run: rm -rf ${{env.TEMP_DATA_DIR}}
|
37
.github/workflows/full-sync-part-2.yml
vendored
Normal file
37
.github/workflows/full-sync-part-2.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
name: Full Sync From 814k
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
note:
|
||||
description: 'Note'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Go CI
|
||||
runs-on: self-hosted
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.16]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Note ${{ github.event.inputs.note }}!"
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2
|
||||
- name: Build lbcd
|
||||
run: go build .
|
||||
- name: Create datadir
|
||||
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
|
||||
- name: Copy initial data
|
||||
run: cp -r /home/lbry/lbcd_814k/* ${{env.TEMP_DATA_DIR}}
|
||||
- name: Run lbcd
|
||||
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --connect=127.0.0.1 --norpc
|
||||
- name: Remove datadir
|
||||
if: always()
|
||||
run: rm -rf ${{env.TEMP_DATA_DIR}}
|
57
.github/workflows/golangci-lint.yml
vendored
Normal file
57
.github/workflows/golangci-lint.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
name: golangci-lint
|
||||
|
||||
env:
|
||||
# go needs absolute directories, using the $HOME variable doesn't work here.
|
||||
GOCACHE: /home/runner/work/go/pkg/build
|
||||
GOPATH: /home/runner/work/go
|
||||
GO_VERSION: '^1.17.0'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '${{ env.GO_VERSION }}'
|
||||
|
||||
- name: checkout source
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: compile code
|
||||
run: go install -v ./...
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||
version: latest
|
||||
|
||||
# Optional: working directory, useful for monorepos
|
||||
# working-directory: somedir
|
||||
|
||||
# Optional: golangci-lint command line arguments.
|
||||
# args: --issues-exit-code=0
|
||||
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
# only-new-issues: true
|
||||
|
||||
# Optional: if set to true then the action will use pre-installed Go.
|
||||
skip-go-installation: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||
# skip-pkg-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||
# skip-build-cache: true
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Databases
|
||||
btcd.db
|
||||
lbcd.db
|
||||
*-shm
|
||||
*-wal
|
||||
|
||||
|
@ -33,6 +34,18 @@ _testmain.go
|
|||
|
||||
*.exe
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Code coverage files
|
||||
profile.tmp
|
||||
profile.cov
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Binaries
|
||||
btcd
|
||||
btcctl
|
||||
lbcd
|
||||
lbcctl
|
||||
|
|
152
.golangci.yml
Normal file
152
.golangci.yml
Normal file
|
@ -0,0 +1,152 @@
|
|||
linters-settings:
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
packages:
|
||||
# logging is allowed only by logutils.Log, logrus
|
||||
# is allowed to use only in logutils package
|
||||
- github.com/sirupsen/logrus
|
||||
packages-with-error-message:
|
||||
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
|
||||
dupl:
|
||||
threshold: 100
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
gci:
|
||||
local-prefixes: github.com/golangci/golangci-lint
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
disabled-checks:
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- whyNoLint
|
||||
- wrapperFunc
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
goimports:
|
||||
local-prefixes: github.com/golangci/golangci-lint
|
||||
gomnd:
|
||||
settings:
|
||||
mnd:
|
||||
# don't include the "operation" and "assign"
|
||||
checks:
|
||||
- argument
|
||||
- case
|
||||
- condition
|
||||
- return
|
||||
govet:
|
||||
check-shadowing: true
|
||||
settings:
|
||||
printf:
|
||||
funcs:
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||
lll:
|
||||
line-length: 140
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
nolintlint:
|
||||
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
|
||||
allow-unused: false # report any unused nolint directives
|
||||
require-explanation: false # don't require an explanation for nolint directives
|
||||
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
# - deadcode
|
||||
- depguard
|
||||
# - dogsled
|
||||
# - dupl
|
||||
# - errcheck
|
||||
# - exhaustive
|
||||
- exportloopref
|
||||
# - funlen
|
||||
# - gochecknoglobals
|
||||
# - gochecknoinits
|
||||
# - gocognit
|
||||
# - goconst
|
||||
# - gocritic
|
||||
# - gocyclo
|
||||
# - godot
|
||||
# - godox
|
||||
# - goerr113
|
||||
- gofmt
|
||||
- goimports
|
||||
# - gomnd
|
||||
- goprintffuncname
|
||||
# - gosec
|
||||
# - gosimple
|
||||
# - govet
|
||||
# - ineffassign
|
||||
# - interfacer
|
||||
# - lll
|
||||
# - maligned
|
||||
# - misspell
|
||||
- nakedret
|
||||
# - nestif
|
||||
# - noctx
|
||||
# - nolintlint
|
||||
# - prealloc
|
||||
- rowserrcheck
|
||||
# - revive
|
||||
# - scopelint
|
||||
# - staticcheck
|
||||
# - structcheck
|
||||
# - stylecheck
|
||||
# - testpackage
|
||||
# - typecheck
|
||||
- unconvert
|
||||
# - unparam
|
||||
# - unused
|
||||
# - varcheck
|
||||
# - whitespace
|
||||
# - wsl
|
||||
|
||||
issues:
|
||||
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gomnd
|
||||
|
||||
- path: pkg/golinters/errcheck.go
|
||||
text: "SA1019: errCfg.Exclude is deprecated: use ExcludeFunctions instead"
|
||||
- path: pkg/commands/run.go
|
||||
text: "SA1019: lsc.Errcheck.Exclude is deprecated: use ExcludeFunctions instead"
|
||||
|
||||
# TODO must be removed after the release of the next version (v1.41.0)
|
||||
- path: pkg/commands/run.go
|
||||
linters:
|
||||
- gomnd
|
||||
# TODO must be removed after the release of the next version (v1.41.0)
|
||||
- path: pkg/golinters/nolintlint/nolintlint.go
|
||||
linters:
|
||||
- gomnd
|
||||
# TODO must be removed after the release of the next version (v1.41.0)
|
||||
- path: pkg/printers/tab.go
|
||||
linters:
|
||||
- gomnd
|
||||
|
||||
|
||||
run:
|
||||
skip-dirs:
|
||||
- test/testdata_etc
|
||||
- internal/cache
|
||||
- internal/renameio
|
||||
- internal/robustio
|
13
Dockerfile
13
Dockerfile
|
@ -9,14 +9,14 @@
|
|||
# docker build . -t yourregistry/btcd --build-arg ARCH=arm64v8
|
||||
#
|
||||
# For more information how to use this docker image visit:
|
||||
# https://github.com/btcsuite/btcd/tree/master/docs
|
||||
# https://github.com/lbryio/lbcd/tree/master/docs
|
||||
#
|
||||
# 8333 Mainnet Bitcoin peer-to-peer port
|
||||
# 8334 Mainet RPC port
|
||||
|
||||
ARG ARCH=amd64
|
||||
|
||||
FROM golang:1.14-alpine3.12 AS build-container
|
||||
FROM golang:1.16-alpine3.14 AS build-container
|
||||
|
||||
ARG ARCH
|
||||
ENV GO111MODULE=on
|
||||
|
@ -25,17 +25,16 @@ 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/alpine:3.12
|
||||
FROM $ARCH/alpine:3.14
|
||||
|
||||
COPY --from=build-container /go/bin /bin
|
||||
|
||||
VOLUME ["/root/.btcd"]
|
||||
VOLUME ["/root/.lbcd"]
|
||||
|
||||
EXPOSE 8333 8334
|
||||
EXPOSE 9245 9246
|
||||
|
||||
ENTRYPOINT ["btcd"]
|
||||
ENTRYPOINT ["lbcd"]
|
||||
|
|
1
LICENSE
1
LICENSE
|
@ -1,5 +1,6 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2021 The LBRY developers
|
||||
Copyright (c) 2013-2017 The btcsuite developers
|
||||
Copyright (c) 2015-2016 The Decred developers
|
||||
|
||||
|
|
143
README.md
143
README.md
|
@ -1,121 +1,80 @@
|
|||
btcd
|
||||
lbcd
|
||||
====
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/btcsuite/btcd/badge.svg?branch=master)](https://coveralls.io/github/btcsuite/btcd?branch=master)
|
||||
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/lbryio/lbcd/badge.svg?branch=master)](https://coveralls.io/github/lbryio/lbcd?branch=master)
|
||||
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd)
|
||||
<!--[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd)-->
|
||||
|
||||
btcd is an alternative full node bitcoin implementation written in Go (golang).
|
||||
lbcd is a full node implementation of LBRY's blockchain written in Go (golang).
|
||||
|
||||
This project is currently under active development and is in a Beta state. It
|
||||
is extremely stable and has been in production use since October 2013.
|
||||
This project is currently under active development and is in a Beta state while we
|
||||
ensure it matches LBRYcrd's functionality. The intention is that it properly downloads, validates, and serves the block chain using the exact
|
||||
rules (including consensus bugs) for block acceptance as LBRYcrd. We have
|
||||
taken great care to avoid lbcd causing a fork to the blockchain.
|
||||
|
||||
It properly downloads, validates, and serves the block chain using the exact
|
||||
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.
|
||||
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).
|
||||
|
||||
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).
|
||||
## Security
|
||||
|
||||
One key difference between btcd and Bitcoin Core is that btcd does *NOT* include
|
||||
wallet functionality and this was a very intentional design decision. See the
|
||||
blog entry [here](https://web.archive.org/web/20171125143919/https://blog.conformal.com/btcd-not-your-moms-bitcoin-daemon)
|
||||
for more details. This means you can't actually make or receive payments
|
||||
directly with btcd. That functionality is provided by the
|
||||
[btcwallet](https://github.com/btcsuite/btcwallet) and
|
||||
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
|
||||
which are both under active development.
|
||||
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 https://lbry.com/forklist
|
||||
|
||||
## Requirements
|
||||
|
||||
[Go](http://golang.org) 1.14 or newer.
|
||||
All common operating systems are supported. lbcd requires at least 8GB of RAM
|
||||
and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time.
|
||||
Using a fast NVMe disk is recommended.
|
||||
|
||||
lbcd is not immune to data loss. It expects a clean shutdown
|
||||
via SIGINT or SIGTERM. SIGKILL, immediate VM kills, and sudden power loss
|
||||
can cause data corruption, thus requiring chain resynchronization for recovery.
|
||||
|
||||
For compilation, [Go](http://golang.org) 1.16 or newer is required.
|
||||
|
||||
## Installation
|
||||
|
||||
https://github.com/btcsuite/btcd/releases
|
||||
Acquire binary files from https://github.com/lbryio/lbcd/releases
|
||||
|
||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
||||
#### To build from Source on Linux/BSD/MacOSX/POSIX:
|
||||
|
||||
- Install Go according to the installation instructions here:
|
||||
http://golang.org/doc/install
|
||||
- Install Go according to its [installation instructions](http://golang.org/doc/install).
|
||||
- Use your favorite git tool to acquire the lbcd source.
|
||||
- lbcd has no non-Go dependencies; it can be built by simply running `go build .`
|
||||
- lbcctl can be built similarly:
|
||||
|
||||
- Ensure Go was installed properly and is a supported version:
|
||||
Both [GoLand](https://www.jetbrains.com/go/)
|
||||
and [VS Code](https://code.visualstudio.com/docs/languages/go) IDEs are supported.
|
||||
|
||||
```bash
|
||||
$ go version
|
||||
$ go env GOROOT GOPATH
|
||||
## Usage
|
||||
|
||||
By default, data and logs are stored in `~/.lbcd/`
|
||||
|
||||
To enable RPC access a username and password is required. Example:
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
- Run the following commands to obtain btcd, all dependencies, and install it:
|
||||
|
||||
```bash
|
||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
||||
$ GO111MODULE=on go install -v . ./cmd/...
|
||||
./lbcd --notls --rpcuser=x --rpcpass=y --txindex &
|
||||
./lbcctl --notls --rpcuser=x --rpcpass=y getblocktemplate
|
||||
```
|
||||
<!-- TODO: explain how to use TLS certificates. -->
|
||||
|
||||
- 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.
|
||||
## Contributing
|
||||
|
||||
## Updating
|
||||
|
||||
#### Linux/BSD/MacOSX/POSIX - Build from Source
|
||||
|
||||
- Run the following commands to update btcd, all dependencies, and install it:
|
||||
|
||||
```bash
|
||||
$ cd $GOPATH/src/github.com/btcsuite/btcd
|
||||
$ git pull
|
||||
$ GO111MODULE=on go install -v . ./cmd/...
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
btcd has several configuration options available to tweak how it runs, but all
|
||||
of the basic operations described in the intro section work with zero
|
||||
configuration.
|
||||
|
||||
#### Linux/BSD/POSIX/Source
|
||||
|
||||
```bash
|
||||
$ ./btcd
|
||||
```
|
||||
|
||||
## IRC
|
||||
|
||||
- irc.freenode.net
|
||||
- channel #btcd
|
||||
- [webchat](https://webchat.freenode.net/?channels=btcd)
|
||||
|
||||
## Issue Tracker
|
||||
|
||||
The [integrated github issue tracker](https://github.com/btcsuite/btcd/issues)
|
||||
is used for this project.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation is a work-in-progress. It is located in the [docs](https://github.com/btcsuite/btcd/tree/master/docs) folder.
|
||||
|
||||
## Release Verification
|
||||
Contributions to this project are welcome, encouraged, and compensated.
|
||||
The [integrated github issue tracker](https://github.com/lbryio/lbcd/issues)
|
||||
is used for this project. All pull requests will be considered.
|
||||
|
||||
<!-- ## Release Verification
|
||||
Please see our [documentation on the current build/verification
|
||||
process](https://github.com/btcsuite/btcd/tree/master/release) for all our
|
||||
process](https://github.com/lbryio/lbcd/tree/master/release) for all our
|
||||
releases for information on how to verify the integrity of published releases
|
||||
using our reproducible build system.
|
||||
-->
|
||||
|
||||
## License
|
||||
|
||||
btcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||
lbcd is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||
|
|
|
@ -23,8 +23,8 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// AddrManager provides a concurrency safe address manager for caching potential
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/addrmgr"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// naTest is used to describe a test to be performed against the NetAddressKey
|
||||
|
|
|
@ -7,7 +7,7 @@ package addrmgr
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
func TstKnownAddressIsBad(ka *KnownAddress) bool {
|
||||
|
|
|
@ -7,7 +7,7 @@ package addrmgr
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// KnownAddress tracks information about a known network address that is used
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package addrmgr_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
func TestChance(t *testing.T) {
|
||||
now := time.Unix(time.Now().Unix(), 0)
|
||||
var tests = []struct {
|
||||
addr *addrmgr.KnownAddress
|
||||
expected float64
|
||||
}{
|
||||
{
|
||||
//Test normal case
|
||||
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
|
||||
1.0,
|
||||
}, {
|
||||
//Test case in which lastseen < 0
|
||||
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(20 * time.Second)},
|
||||
0, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
|
||||
1.0,
|
||||
}, {
|
||||
//Test case in which lastattempt < 0
|
||||
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, time.Now().Add(30*time.Minute), time.Now(), false, 0),
|
||||
1.0 * .01,
|
||||
}, {
|
||||
//Test case in which lastattempt < ten minutes
|
||||
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, time.Now().Add(-5*time.Minute), time.Now(), false, 0),
|
||||
1.0 * .01,
|
||||
}, {
|
||||
//Test case with several failed attempts.
|
||||
addrmgr.TstNewKnownAddress(&wire.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
2, time.Now().Add(-30*time.Minute), time.Now(), false, 0),
|
||||
1 / 1.5 / 1.5,
|
||||
},
|
||||
}
|
||||
|
||||
err := .0001
|
||||
for i, test := range tests {
|
||||
chance := addrmgr.TstKnownAddressChance(test.addr)
|
||||
if math.Abs(test.expected-chance) >= err {
|
||||
t.Errorf("case %d: got %f, expected %f", i, chance, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsBad(t *testing.T) {
|
||||
now := time.Unix(time.Now().Unix(), 0)
|
||||
future := now.Add(35 * time.Minute)
|
||||
monthOld := now.Add(-43 * time.Hour * 24)
|
||||
secondsOld := now.Add(-2 * time.Second)
|
||||
minutesOld := now.Add(-27 * time.Minute)
|
||||
hoursOld := now.Add(-5 * time.Hour)
|
||||
zeroTime := time.Time{}
|
||||
|
||||
futureNa := &wire.NetAddress{Timestamp: future}
|
||||
minutesOldNa := &wire.NetAddress{Timestamp: minutesOld}
|
||||
monthOldNa := &wire.NetAddress{Timestamp: monthOld}
|
||||
currentNa := &wire.NetAddress{Timestamp: secondsOld}
|
||||
|
||||
//Test addresses that have been tried in the last minute.
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(futureNa, 3, secondsOld, zeroTime, false, 0)) {
|
||||
t.Errorf("test case 1: addresses that have been tried in the last minute are not bad.")
|
||||
}
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(monthOldNa, 3, secondsOld, zeroTime, false, 0)) {
|
||||
t.Errorf("test case 2: addresses that have been tried in the last minute are not bad.")
|
||||
}
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 3, secondsOld, zeroTime, false, 0)) {
|
||||
t.Errorf("test case 3: addresses that have been tried in the last minute are not bad.")
|
||||
}
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 3, secondsOld, monthOld, true, 0)) {
|
||||
t.Errorf("test case 4: addresses that have been tried in the last minute are not bad.")
|
||||
}
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(currentNa, 2, secondsOld, secondsOld, true, 0)) {
|
||||
t.Errorf("test case 5: addresses that have been tried in the last minute are not bad.")
|
||||
}
|
||||
|
||||
//Test address that claims to be from the future.
|
||||
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(futureNa, 0, minutesOld, hoursOld, true, 0)) {
|
||||
t.Errorf("test case 6: addresses that claim to be from the future are bad.")
|
||||
}
|
||||
|
||||
//Test address that has not been seen in over a month.
|
||||
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(monthOldNa, 0, minutesOld, hoursOld, true, 0)) {
|
||||
t.Errorf("test case 7: addresses more than a month old are bad.")
|
||||
}
|
||||
|
||||
//It has failed at least three times and never succeeded.
|
||||
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 3, minutesOld, zeroTime, true, 0)) {
|
||||
t.Errorf("test case 8: addresses that have never succeeded are bad.")
|
||||
}
|
||||
|
||||
//It has failed ten times in the last week
|
||||
if !addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 10, minutesOld, monthOld, true, 0)) {
|
||||
t.Errorf("test case 9: addresses that have not succeeded in too long are bad.")
|
||||
}
|
||||
|
||||
//Test an address that should work.
|
||||
if addrmgr.TstKnownAddressIsBad(addrmgr.TstNewKnownAddress(minutesOldNa, 2, minutesOld, hoursOld, true, 0)) {
|
||||
t.Errorf("test case 10: This should be a valid address.")
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/addrmgr"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/addrmgr"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestIPTypes ensures the various functions which determine the type of an IP
|
||||
|
|
|
@ -1,30 +1,9 @@
|
|||
blockchain
|
||||
==========
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain)
|
||||
|
||||
Package blockchain implements bitcoin block handling and chain selection rules.
|
||||
The test coverage is currently only around 60%, but will be increasing over
|
||||
time. See `test_coverage.txt` for the gocov coverage report. Alternatively, if
|
||||
you are running a POSIX OS, you can run the `cov_report.sh` script for a
|
||||
real-time report. Package blockchain is licensed under the liberal ISC license.
|
||||
|
||||
There is an associated blog post about the release of this package
|
||||
[here](https://blog.conformal.com/btcchain-the-bitcoin-chain-package-from-bctd/).
|
||||
|
||||
This package has intentionally been designed so it can be used as a standalone
|
||||
package for any projects needing to handle processing of blocks into the bitcoin
|
||||
block chain.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/blockchain
|
||||
```
|
||||
|
||||
## Bitcoin Chain Processing Overview
|
||||
### Bitcoin Chain Processing Overview
|
||||
|
||||
Before a block is allowed into the block chain, it must go through an intensive
|
||||
series of validation rules. The following list serves as a general outline of
|
||||
|
@ -57,47 +36,4 @@ is by no means exhaustive:
|
|||
transaction values
|
||||
- Run the transaction scripts to verify the spender is allowed to spend the
|
||||
coins
|
||||
- Insert the block into the block database
|
||||
|
||||
## Examples
|
||||
|
||||
* [ProcessBlock Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BlockChain-ProcessBlock)
|
||||
Demonstrates how to create a new chain instance and use ProcessBlock to
|
||||
attempt to add a block to the chain. This example intentionally
|
||||
attempts to insert a duplicate genesis block to illustrate how an invalid
|
||||
block is handled.
|
||||
|
||||
* [CompactToBig Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-CompactToBig)
|
||||
Demonstrates how to convert the compact "bits" in a block header which
|
||||
represent the target difficulty to a big integer and display it using the
|
||||
typical hex notation.
|
||||
|
||||
* [BigToCompact Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BigToCompact)
|
||||
Demonstrates how to convert a target difficulty into the
|
||||
compact "bits" in a block header which represent that target difficulty.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Package blockchain is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
- Insert the block into the block database
|
|
@ -7,8 +7,8 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// maybeAcceptBlock potentially accepts a block into the block chain and, if
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
|
||||
// function.
|
||||
func BenchmarkIsCoinBase(b *testing.B) {
|
||||
tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsCoinBase(tx)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
|
||||
// function.
|
||||
func BenchmarkIsCoinBaseTx(b *testing.B) {
|
||||
tx := Block100000.Transactions[1]
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsCoinBaseTx(tx)
|
||||
}
|
||||
}
|
|
@ -10,10 +10,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// blockStatus is a bit field representing the validation state of the block.
|
||||
|
@ -93,6 +93,7 @@ type blockNode struct {
|
|||
nonce uint32
|
||||
timestamp int64
|
||||
merkleRoot chainhash.Hash
|
||||
claimTrie chainhash.Hash
|
||||
|
||||
// status is a bitfield representing the validation state of the block. The
|
||||
// status field, unlike the other fields, may be written to and so should
|
||||
|
@ -114,6 +115,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
|
|||
nonce: blockHeader.Nonce,
|
||||
timestamp: blockHeader.Timestamp.Unix(),
|
||||
merkleRoot: blockHeader.MerkleRoot,
|
||||
claimTrie: blockHeader.ClaimTrie,
|
||||
}
|
||||
if parent != nil {
|
||||
node.parent = parent
|
||||
|
@ -144,6 +146,7 @@ func (node *blockNode) Header() wire.BlockHeader {
|
|||
Version: node.version,
|
||||
PrevBlock: *prevHash,
|
||||
MerkleRoot: node.merkleRoot,
|
||||
ClaimTrie: node.claimTrie,
|
||||
Timestamp: time.Unix(node.timestamp, 0),
|
||||
Bits: node.bits,
|
||||
Nonce: node.nonce,
|
||||
|
|
|
@ -11,12 +11,14 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
|
||||
"github.com/lbryio/lbcd/claimtrie"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -180,6 +182,8 @@ type BlockChain struct {
|
|||
// certain blockchain events.
|
||||
notificationsLock sync.RWMutex
|
||||
notifications []NotificationCallback
|
||||
|
||||
claimTrie *claimtrie.ClaimTrie
|
||||
}
|
||||
|
||||
// HaveBlock returns whether or not the chain instance has the block represented
|
||||
|
@ -571,7 +575,8 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
|||
}
|
||||
|
||||
// No warnings about unknown rules until the chain is current.
|
||||
if b.isCurrent() {
|
||||
current := b.isCurrent()
|
||||
if current {
|
||||
// Warn if any unknown new rules are either about to activate or
|
||||
// have already been activated.
|
||||
if err := b.warnUnknownRuleActivations(node); err != nil {
|
||||
|
@ -579,6 +584,13 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
|
|||
}
|
||||
}
|
||||
|
||||
// Handle LBRY Claim Scripts
|
||||
if b.claimTrie != nil {
|
||||
if err := b.ParseClaimScripts(block, node, view, current); err != nil {
|
||||
return ruleError(ErrBadClaimTrie, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Write any block status changes to DB before updating best state.
|
||||
err := b.index.flushToDB()
|
||||
if err != nil {
|
||||
|
@ -761,6 +773,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
|||
return err
|
||||
}
|
||||
|
||||
if b.claimTrie != nil {
|
||||
if err = b.claimTrie.ResetHeight(node.parent.height); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Prune fully spent entries and mark all entries in the view unmodified
|
||||
// now that the modifications have been committed to the database.
|
||||
view.commit()
|
||||
|
@ -1208,7 +1226,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
|
|||
// factors are used to guess, but the key factors that allow the chain to
|
||||
// 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 has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for reads).
|
||||
func (b *BlockChain) isCurrent() bool {
|
||||
|
@ -1219,13 +1237,13 @@ func (b *BlockChain) isCurrent() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Not current if the latest best block has a timestamp before 24 hours
|
||||
// Not current if the latest best block has a timestamp before 7 hours
|
||||
// ago.
|
||||
//
|
||||
// The chain appears to be current if none of the checks reported
|
||||
// otherwise.
|
||||
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
|
||||
return b.bestChain.Tip().timestamp >= minus24Hours
|
||||
hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
|
||||
return b.bestChain.Tip().timestamp >= hours
|
||||
}
|
||||
|
||||
// IsCurrent returns whether or not the chain believes it is current. Several
|
||||
|
@ -1614,6 +1632,11 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
|||
return headers
|
||||
}
|
||||
|
||||
// ClaimTrie returns the claimTrie associated wit hthe chain.
|
||||
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
||||
return b.claimTrie
|
||||
}
|
||||
|
||||
// IndexManager provides a generic interface that the is called when blocks are
|
||||
// connected and disconnected to and from the tip of the main chain for the
|
||||
// purpose of supporting optional indexes.
|
||||
|
@ -1700,6 +1723,8 @@ type Config struct {
|
|||
// This field can be nil if the caller is not interested in using a
|
||||
// signature cache.
|
||||
HashCache *txscript.HashCache
|
||||
|
||||
ClaimTrie *claimtrie.ClaimTrie
|
||||
}
|
||||
|
||||
// New returns a BlockChain instance using the provided configuration details.
|
||||
|
@ -1736,7 +1761,6 @@ func New(config *Config) (*BlockChain, error) {
|
|||
params := config.ChainParams
|
||||
targetTimespan := int64(params.TargetTimespan / time.Second)
|
||||
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
|
||||
adjustmentFactor := params.RetargetAdjustmentFactor
|
||||
b := BlockChain{
|
||||
checkpoints: config.Checkpoints,
|
||||
checkpointsByHeight: checkpointsByHeight,
|
||||
|
@ -1745,8 +1769,8 @@ func New(config *Config) (*BlockChain, error) {
|
|||
timeSource: config.TimeSource,
|
||||
sigCache: config.SigCache,
|
||||
indexManager: config.IndexManager,
|
||||
minRetargetTimespan: targetTimespan / adjustmentFactor,
|
||||
maxRetargetTimespan: targetTimespan * adjustmentFactor,
|
||||
minRetargetTimespan: targetTimespan - (targetTimespan / 8),
|
||||
maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
|
||||
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
||||
index: newBlockIndex(config.DB, params),
|
||||
hashCache: config.HashCache,
|
||||
|
@ -1755,6 +1779,7 @@ func New(config *Config) (*BlockChain, error) {
|
|||
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
||||
warningCaches: newThresholdCaches(vbNumBits),
|
||||
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
|
||||
claimTrie: config.ClaimTrie,
|
||||
}
|
||||
|
||||
// Initialize the chain state from the passed database. When the db
|
||||
|
@ -1764,6 +1789,20 @@ func New(config *Config) (*BlockChain, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Helper function to insert the output in genesis block in to the
|
||||
// transaction database.
|
||||
fn := func(dbTx database.Tx) error {
|
||||
genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock)
|
||||
view := NewUtxoViewpoint()
|
||||
if err := view.connectTransactions(genesisBlock, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return dbPutUtxoView(dbTx, view)
|
||||
}
|
||||
if err := b.db.Update(fn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Perform any upgrades to the various chain-specific buckets as needed.
|
||||
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
|
||||
return nil, err
|
||||
|
@ -1783,6 +1822,14 @@ func New(config *Config) (*BlockChain, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if b.claimTrie != nil {
|
||||
err := rebuildMissingClaimTrieData(&b, config.Interrupt)
|
||||
if err != nil {
|
||||
b.claimTrie.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
bestNode := b.bestChain.Tip()
|
||||
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
|
||||
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
|
||||
|
@ -1790,3 +1837,63 @@ func New(config *Config) (*BlockChain, error) {
|
|||
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func rebuildMissingClaimTrieData(b *BlockChain, done <-chan struct{}) error {
|
||||
target := b.bestChain.Height()
|
||||
if b.claimTrie.Height() == target {
|
||||
return nil
|
||||
}
|
||||
if b.claimTrie.Height() > target {
|
||||
return b.claimTrie.ResetHeight(target)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
lastReport := time.Now()
|
||||
// TODO: move this view inside the loop (or recreate it every 5 sec.)
|
||||
// as accumulating all inputs has potential to use a huge amount of RAM
|
||||
// but we need to get the spent inputs working for that to be possible
|
||||
view := NewUtxoViewpoint()
|
||||
for h := int32(0); h < target; h++ {
|
||||
select {
|
||||
case <-done:
|
||||
return fmt.Errorf("rebuild unfinished at height %d", b.claimTrie.Height())
|
||||
default:
|
||||
}
|
||||
|
||||
n := b.bestChain.NodeByHeight(h + 1)
|
||||
|
||||
var block *btcutil.Block
|
||||
err := b.db.View(func(dbTx database.Tx) error {
|
||||
var err error
|
||||
block, err = dbFetchBlockByNode(dbTx, n)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = view.fetchInputUtxos(b.db, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = view.connectTransactions(block, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if h >= b.claimTrie.Height() {
|
||||
err = b.ParseClaimScripts(block, n, view, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if time.Since(lastReport) > time.Second*5 {
|
||||
lastReport = time.Now()
|
||||
log.Infof("Rebuilding claim trie data to %d. At: %d", target, h)
|
||||
}
|
||||
}
|
||||
log.Infof("Completed rebuilding claim trie data to %d. Took %s ",
|
||||
b.claimTrie.Height(), time.Since(start))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,966 +0,0 @@
|
|||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// TestHaveBlock tests the HaveBlock API to ensure proper functionality.
|
||||
func TestHaveBlock(t *testing.T) {
|
||||
// Load up blocks such that there is a side chain.
|
||||
// (genesis block) -> 1 -> 2 -> 3 -> 4
|
||||
// \-> 3a
|
||||
testFiles := []string{
|
||||
"blk_0_to_4.dat.bz2",
|
||||
"blk_3A.dat.bz2",
|
||||
}
|
||||
|
||||
var blocks []*btcutil.Block
|
||||
for _, file := range testFiles {
|
||||
blockTmp, err := loadBlocks(file)
|
||||
if err != nil {
|
||||
t.Errorf("Error loading file: %v\n", err)
|
||||
return
|
||||
}
|
||||
blocks = append(blocks, blockTmp...)
|
||||
}
|
||||
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("haveblock",
|
||||
&chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup chain instance: %v", err)
|
||||
return
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
// Since we're not dealing with the real block chain, set the coinbase
|
||||
// maturity to 1.
|
||||
chain.TstSetCoinbaseMaturity(1)
|
||||
|
||||
for i := 1; i < len(blocks); i++ {
|
||||
_, isOrphan, err := chain.ProcessBlock(blocks[i], BFNone)
|
||||
if err != nil {
|
||||
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
|
||||
return
|
||||
}
|
||||
if isOrphan {
|
||||
t.Errorf("ProcessBlock incorrectly returned block %v "+
|
||||
"is an orphan\n", i)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Insert an orphan block.
|
||||
_, isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000),
|
||||
BFNone)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to process block: %v", err)
|
||||
return
|
||||
}
|
||||
if !isOrphan {
|
||||
t.Errorf("ProcessBlock indicated block is an not orphan when " +
|
||||
"it should be\n")
|
||||
return
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
hash string
|
||||
want bool
|
||||
}{
|
||||
// Genesis block should be present (in the main chain).
|
||||
{hash: chaincfg.MainNetParams.GenesisHash.String(), want: true},
|
||||
|
||||
// Block 3a should be present (on a side chain).
|
||||
{hash: "00000000474284d20067a4d33f6a02284e6ef70764a3a26d6a5b9df52ef663dd", want: true},
|
||||
|
||||
// Block 100000 should be present (as an orphan).
|
||||
{hash: "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506", want: true},
|
||||
|
||||
// Random hashes should not be available.
|
||||
{hash: "123", want: false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
hash, err := chainhash.NewHashFromStr(test.hash)
|
||||
if err != nil {
|
||||
t.Errorf("NewHashFromStr: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
result, err := chain.HaveBlock(hash)
|
||||
if err != nil {
|
||||
t.Errorf("HaveBlock #%d unexpected error: %v", i, err)
|
||||
return
|
||||
}
|
||||
if result != test.want {
|
||||
t.Errorf("HaveBlock #%d got %v want %v", i, result,
|
||||
test.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCalcSequenceLock tests the LockTimeToSequence function, and the
|
||||
// CalcSequenceLock method of a Chain instance. The tests exercise several
|
||||
// combinations of inputs to the CalcSequenceLock function in order to ensure
|
||||
// the returned SequenceLocks are correct for each test instance.
|
||||
func TestCalcSequenceLock(t *testing.T) {
|
||||
netParams := &chaincfg.SimNetParams
|
||||
|
||||
// We need to activate CSV in order to test the processing logic, so
|
||||
// manually craft the block version that's used to signal the soft-fork
|
||||
// activation.
|
||||
csvBit := netParams.Deployments[chaincfg.DeploymentCSV].BitNumber
|
||||
blockVersion := int32(0x20000000 | (uint32(1) << csvBit))
|
||||
|
||||
// Generate enough synthetic blocks to activate CSV.
|
||||
chain := newFakeChain(netParams)
|
||||
node := chain.bestChain.Tip()
|
||||
blockTime := node.Header().Timestamp
|
||||
numBlocksToActivate := (netParams.MinerConfirmationWindow * 3)
|
||||
for i := uint32(0); i < numBlocksToActivate; i++ {
|
||||
blockTime = blockTime.Add(time.Second)
|
||||
node = newFakeNode(node, blockVersion, 0, blockTime)
|
||||
chain.index.AddNode(node)
|
||||
chain.bestChain.SetTip(node)
|
||||
}
|
||||
|
||||
// Create a utxo view with a fake utxo for the inputs used in the
|
||||
// transactions created below. This utxo is added such that it has an
|
||||
// age of 4 blocks.
|
||||
targetTx := btcutil.NewTx(&wire.MsgTx{
|
||||
TxOut: []*wire.TxOut{{
|
||||
PkScript: nil,
|
||||
Value: 10,
|
||||
}},
|
||||
})
|
||||
utxoView := NewUtxoViewpoint()
|
||||
utxoView.AddTxOuts(targetTx, int32(numBlocksToActivate)-4)
|
||||
utxoView.SetBestHash(&node.hash)
|
||||
|
||||
// Create a utxo that spends the fake utxo created above for use in the
|
||||
// transactions created in the tests. It has an age of 4 blocks. Note
|
||||
// that the sequence lock heights are always calculated from the same
|
||||
// point of view that they were originally calculated from for a given
|
||||
// utxo. That is to say, the height prior to it.
|
||||
utxo := wire.OutPoint{
|
||||
Hash: *targetTx.Hash(),
|
||||
Index: 0,
|
||||
}
|
||||
prevUtxoHeight := int32(numBlocksToActivate) - 4
|
||||
|
||||
// Obtain the median time past from the PoV of the input created above.
|
||||
// The MTP for the input is the MTP from the PoV of the block *prior*
|
||||
// to the one that included it.
|
||||
medianTime := node.RelativeAncestor(5).CalcPastMedianTime().Unix()
|
||||
|
||||
// The median time calculated from the PoV of the best block in the
|
||||
// test chain. For unconfirmed inputs, this value will be used since
|
||||
// the MTP will be calculated from the PoV of the yet-to-be-mined
|
||||
// block.
|
||||
nextMedianTime := node.CalcPastMedianTime().Unix()
|
||||
nextBlockHeight := int32(numBlocksToActivate) + 1
|
||||
|
||||
// Add an additional transaction which will serve as our unconfirmed
|
||||
// output.
|
||||
unConfTx := &wire.MsgTx{
|
||||
TxOut: []*wire.TxOut{{
|
||||
PkScript: nil,
|
||||
Value: 5,
|
||||
}},
|
||||
}
|
||||
unConfUtxo := wire.OutPoint{
|
||||
Hash: unConfTx.TxHash(),
|
||||
Index: 0,
|
||||
}
|
||||
|
||||
// Adding a utxo with a height of 0x7fffffff indicates that the output
|
||||
// is currently unmined.
|
||||
utxoView.AddTxOuts(btcutil.NewTx(unConfTx), 0x7fffffff)
|
||||
|
||||
tests := []struct {
|
||||
tx *wire.MsgTx
|
||||
view *UtxoViewpoint
|
||||
mempool bool
|
||||
want *SequenceLock
|
||||
}{
|
||||
// A transaction of version one should disable sequence locks
|
||||
// as the new sequence number semantics only apply to
|
||||
// transactions version 2 or higher.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 3),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: -1,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
// A transaction with a single input with max sequence number.
|
||||
// This sequence number has the high bit set, so sequence locks
|
||||
// should be disabled.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: wire.MaxTxInSequenceNum,
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: -1,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
// A transaction with a single input whose lock time is
|
||||
// expressed in seconds. However, the specified lock time is
|
||||
// below the required floor for time based lock times since
|
||||
// they have time granularity of 512 seconds. As a result, the
|
||||
// seconds lock-time should be just before the median time of
|
||||
// the targeted block.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: medianTime - 1,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
// A transaction with a single input whose lock time is
|
||||
// expressed in seconds. The number of seconds should be 1023
|
||||
// seconds after the median past time of the last block in the
|
||||
// chain.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 1024),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: medianTime + 1023,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
// A transaction with multiple inputs. The first input has a
|
||||
// lock time expressed in seconds. The second input has a
|
||||
// sequence lock in blocks with a value of 4. The last input
|
||||
// has a sequence number with a value of 5, but has the disable
|
||||
// bit set. So the first lock should be selected as it's the
|
||||
// latest lock that isn't disabled.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2560),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 4),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 5) |
|
||||
wire.SequenceLockTimeDisabled,
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
|
||||
BlockHeight: prevUtxoHeight + 3,
|
||||
},
|
||||
},
|
||||
// Transaction with a single input. The input's sequence number
|
||||
// encodes a relative lock-time in blocks (3 blocks). The
|
||||
// sequence lock should have a value of -1 for seconds, but a
|
||||
// height of 2 meaning it can be included at height 3.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 3),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: -1,
|
||||
BlockHeight: prevUtxoHeight + 2,
|
||||
},
|
||||
},
|
||||
// A transaction with two inputs with lock times expressed in
|
||||
// seconds. The selected sequence lock value for seconds should
|
||||
// be the time further in the future.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 5120),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2560),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: medianTime + (10 << wire.SequenceLockTimeGranularity) - 1,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
// A transaction with two inputs with lock times expressed in
|
||||
// blocks. The selected sequence lock value for blocks should
|
||||
// be the height further in the future, so a height of 10
|
||||
// indicating it can be included at height 11.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 1),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 11),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: -1,
|
||||
BlockHeight: prevUtxoHeight + 10,
|
||||
},
|
||||
},
|
||||
// A transaction with multiple inputs. Two inputs are time
|
||||
// based, and the other two are block based. The lock lying
|
||||
// further into the future for both inputs should be chosen.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2560),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 6656),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 3),
|
||||
}, {
|
||||
PreviousOutPoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 9),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
want: &SequenceLock{
|
||||
Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
|
||||
BlockHeight: prevUtxoHeight + 8,
|
||||
},
|
||||
},
|
||||
// A transaction with a single unconfirmed input. As the input
|
||||
// is confirmed, the height of the input should be interpreted
|
||||
// as the height of the *next* block. So, a 2 block relative
|
||||
// lock means the sequence lock should be for 1 block after the
|
||||
// *next* block height, indicating it can be included 2 blocks
|
||||
// after that.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: unConfUtxo,
|
||||
Sequence: LockTimeToSequence(false, 2),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
mempool: true,
|
||||
want: &SequenceLock{
|
||||
Seconds: -1,
|
||||
BlockHeight: nextBlockHeight + 1,
|
||||
},
|
||||
},
|
||||
// A transaction with a single unconfirmed input. The input has
|
||||
// a time based lock, so the lock time should be based off the
|
||||
// MTP of the *next* block.
|
||||
{
|
||||
tx: &wire.MsgTx{
|
||||
Version: 2,
|
||||
TxIn: []*wire.TxIn{{
|
||||
PreviousOutPoint: unConfUtxo,
|
||||
Sequence: LockTimeToSequence(true, 1024),
|
||||
}},
|
||||
},
|
||||
view: utxoView,
|
||||
mempool: true,
|
||||
want: &SequenceLock{
|
||||
Seconds: nextMedianTime + 1023,
|
||||
BlockHeight: -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %v SequenceLock tests", len(tests))
|
||||
for i, test := range tests {
|
||||
utilTx := btcutil.NewTx(test.tx)
|
||||
seqLock, err := chain.CalcSequenceLock(utilTx, test.view, test.mempool)
|
||||
if err != nil {
|
||||
t.Fatalf("test #%d, unable to calc sequence lock: %v", i, err)
|
||||
}
|
||||
|
||||
if seqLock.Seconds != test.want.Seconds {
|
||||
t.Fatalf("test #%d got %v seconds want %v seconds",
|
||||
i, seqLock.Seconds, test.want.Seconds)
|
||||
}
|
||||
if seqLock.BlockHeight != test.want.BlockHeight {
|
||||
t.Fatalf("test #%d got height of %v want height of %v ",
|
||||
i, seqLock.BlockHeight, test.want.BlockHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nodeHashes is a convenience function that returns the hashes for all of the
|
||||
// passed indexes of the provided nodes. It is used to construct expected hash
|
||||
// slices in the tests.
|
||||
func nodeHashes(nodes []*blockNode, indexes ...int) []chainhash.Hash {
|
||||
hashes := make([]chainhash.Hash, 0, len(indexes))
|
||||
for _, idx := range indexes {
|
||||
hashes = append(hashes, nodes[idx].hash)
|
||||
}
|
||||
return hashes
|
||||
}
|
||||
|
||||
// nodeHeaders is a convenience function that returns the headers for all of
|
||||
// the passed indexes of the provided nodes. It is used to construct expected
|
||||
// located headers in the tests.
|
||||
func nodeHeaders(nodes []*blockNode, indexes ...int) []wire.BlockHeader {
|
||||
headers := make([]wire.BlockHeader, 0, len(indexes))
|
||||
for _, idx := range indexes {
|
||||
headers = append(headers, nodes[idx].Header())
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
// TestLocateInventory ensures that locating inventory via the LocateHeaders and
|
||||
// LocateBlocks functions behaves as expected.
|
||||
func TestLocateInventory(t *testing.T) {
|
||||
// Construct a synthetic block chain with a block index consisting of
|
||||
// the following structure.
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
// \-> 16a -> 17a
|
||||
tip := tstTip
|
||||
chain := newFakeChain(&chaincfg.MainNetParams)
|
||||
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
|
||||
branch1Nodes := chainedNodes(branch0Nodes[14], 2)
|
||||
for _, node := range branch0Nodes {
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
for _, node := range branch1Nodes {
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
chain.bestChain.SetTip(tip(branch0Nodes))
|
||||
|
||||
// Create chain views for different branches of the overall chain to
|
||||
// simulate a local and remote node on different parts of the chain.
|
||||
localView := newChainView(tip(branch0Nodes))
|
||||
remoteView := newChainView(tip(branch1Nodes))
|
||||
|
||||
// Create a chain view for a completely unrelated block chain to
|
||||
// simulate a remote node on a totally different chain.
|
||||
unrelatedBranchNodes := chainedNodes(nil, 5)
|
||||
unrelatedView := newChainView(tip(unrelatedBranchNodes))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
locator BlockLocator // locator for requested inventory
|
||||
hashStop chainhash.Hash // stop hash for locator
|
||||
maxAllowed uint32 // max to locate, 0 = wire const
|
||||
headers []wire.BlockHeader // expected located headers
|
||||
hashes []chainhash.Hash // expected located hashes
|
||||
}{
|
||||
{
|
||||
// Empty block locators and unknown stop hash. No
|
||||
// inventory should be located.
|
||||
name: "no locators, no stop",
|
||||
locator: nil,
|
||||
hashStop: chainhash.Hash{},
|
||||
headers: nil,
|
||||
hashes: nil,
|
||||
},
|
||||
{
|
||||
// Empty block locators and stop hash in side chain.
|
||||
// The expected result is the requested block.
|
||||
name: "no locators, stop in side",
|
||||
locator: nil,
|
||||
hashStop: tip(branch1Nodes).hash,
|
||||
headers: nodeHeaders(branch1Nodes, 1),
|
||||
hashes: nodeHashes(branch1Nodes, 1),
|
||||
},
|
||||
{
|
||||
// Empty block locators and stop hash in main chain.
|
||||
// The expected result is the requested block.
|
||||
name: "no locators, stop in main",
|
||||
locator: nil,
|
||||
hashStop: branch0Nodes[12].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 12),
|
||||
hashes: nodeHashes(branch0Nodes, 12),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash local node doesn't know about. The
|
||||
// expected result is the blocks after the fork point in
|
||||
// the main chain and the stop hash has no effect.
|
||||
name: "remote side chain, unknown stop",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: chainhash.Hash{0x01},
|
||||
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash in side chain. The expected result is the
|
||||
// blocks after the fork point in the main chain and the
|
||||
// stop hash has no effect.
|
||||
name: "remote side chain, stop in side",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: tip(branch1Nodes).hash,
|
||||
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash in main chain, but before fork point. The
|
||||
// expected result is the blocks after the fork point in
|
||||
// the main chain and the stop hash has no effect.
|
||||
name: "remote side chain, stop in main before",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: branch0Nodes[13].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash in main chain, but exactly at the fork
|
||||
// point. The expected result is the blocks after the
|
||||
// fork point in the main chain and the stop hash has no
|
||||
// effect.
|
||||
name: "remote side chain, stop in main exact",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: branch0Nodes[14].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash in main chain just after the fork point.
|
||||
// The expected result is the blocks after the fork
|
||||
// point in the main chain up to and including the stop
|
||||
// hash.
|
||||
name: "remote side chain, stop in main after",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: branch0Nodes[15].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 15),
|
||||
hashes: nodeHashes(branch0Nodes, 15),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on side chain and a
|
||||
// stop hash in main chain some time after the fork
|
||||
// point. The expected result is the blocks after the
|
||||
// fork point in the main chain up to and including the
|
||||
// stop hash.
|
||||
name: "remote side chain, stop in main after more",
|
||||
locator: remoteView.BlockLocator(nil),
|
||||
hashStop: branch0Nodes[16].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 15, 16),
|
||||
hashes: nodeHashes(branch0Nodes, 15, 16),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash local node doesn't know about.
|
||||
// The expected result is the blocks after the known
|
||||
// point in the main chain and the stop hash has no
|
||||
// effect.
|
||||
name: "remote main chain past, unknown stop",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: chainhash.Hash{0x01},
|
||||
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash in a side chain. The expected
|
||||
// result is the blocks after the known point in the
|
||||
// main chain and the stop hash has no effect.
|
||||
name: "remote main chain past, stop in side",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: tip(branch1Nodes).hash,
|
||||
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash in the main chain before that
|
||||
// point. The expected result is the blocks after the
|
||||
// known point in the main chain and the stop hash has
|
||||
// no effect.
|
||||
name: "remote main chain past, stop in main before",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: branch0Nodes[11].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash in the main chain exactly at that
|
||||
// point. The expected result is the blocks after the
|
||||
// known point in the main chain and the stop hash has
|
||||
// no effect.
|
||||
name: "remote main chain past, stop in main exact",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: branch0Nodes[12].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash in the main chain just after
|
||||
// that point. The expected result is the blocks after
|
||||
// the known point in the main chain and the stop hash
|
||||
// has no effect.
|
||||
name: "remote main chain past, stop in main after",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: branch0Nodes[13].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 13),
|
||||
hashes: nodeHashes(branch0Nodes, 13),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being on main chain in the
|
||||
// past and a stop hash in the main chain some time
|
||||
// after that point. The expected result is the blocks
|
||||
// after the known point in the main chain and the stop
|
||||
// hash has no effect.
|
||||
name: "remote main chain past, stop in main after more",
|
||||
locator: localView.BlockLocator(branch0Nodes[12]),
|
||||
hashStop: branch0Nodes[15].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 13, 14, 15),
|
||||
hashes: nodeHashes(branch0Nodes, 13, 14, 15),
|
||||
},
|
||||
{
|
||||
// Locators based on remote being at exactly the same
|
||||
// point in the main chain and a stop hash local node
|
||||
// doesn't know about. The expected result is no
|
||||
// located inventory.
|
||||
name: "remote main chain same, unknown stop",
|
||||
locator: localView.BlockLocator(nil),
|
||||
hashStop: chainhash.Hash{0x01},
|
||||
headers: nil,
|
||||
hashes: nil,
|
||||
},
|
||||
{
|
||||
// Locators based on remote being at exactly the same
|
||||
// point in the main chain and a stop hash at exactly
|
||||
// the same point. The expected result is no located
|
||||
// inventory.
|
||||
name: "remote main chain same, stop same point",
|
||||
locator: localView.BlockLocator(nil),
|
||||
hashStop: tip(branch0Nodes).hash,
|
||||
headers: nil,
|
||||
hashes: nil,
|
||||
},
|
||||
{
|
||||
// Locators from remote that don't include any blocks
|
||||
// the local node knows. This would happen if the
|
||||
// remote node is on a completely separate chain that
|
||||
// isn't rooted with the same genesis block. The
|
||||
// expected result is the blocks after the genesis
|
||||
// block.
|
||||
name: "remote unrelated chain",
|
||||
locator: unrelatedView.BlockLocator(nil),
|
||||
hashStop: chainhash.Hash{},
|
||||
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Locators from remote for second block in main chain
|
||||
// and no stop hash, but with an overridden max limit.
|
||||
// The expected result is the blocks after the second
|
||||
// block limited by the max.
|
||||
name: "remote genesis",
|
||||
locator: locatorHashes(branch0Nodes, 0),
|
||||
hashStop: chainhash.Hash{},
|
||||
maxAllowed: 3,
|
||||
headers: nodeHeaders(branch0Nodes, 1, 2, 3),
|
||||
hashes: nodeHashes(branch0Nodes, 1, 2, 3),
|
||||
},
|
||||
{
|
||||
// Poorly formed locator.
|
||||
//
|
||||
// Locator from remote that only includes a single
|
||||
// block on a side chain the local node knows. The
|
||||
// expected result is the blocks after the genesis
|
||||
// block since even though the block is known, it is on
|
||||
// a side chain and there are no more locators to find
|
||||
// the fork point.
|
||||
name: "weak locator, single known side block",
|
||||
locator: locatorHashes(branch1Nodes, 1),
|
||||
hashStop: chainhash.Hash{},
|
||||
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Poorly formed locator.
|
||||
//
|
||||
// Locator from remote that only includes multiple
|
||||
// blocks on a side chain the local node knows however
|
||||
// none in the main chain. The expected result is the
|
||||
// blocks after the genesis block since even though the
|
||||
// blocks are known, they are all on a side chain and
|
||||
// there are no more locators to find the fork point.
|
||||
name: "weak locator, multiple known side blocks",
|
||||
locator: locatorHashes(branch1Nodes, 1),
|
||||
hashStop: chainhash.Hash{},
|
||||
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
// Poorly formed locator.
|
||||
//
|
||||
// Locator from remote that only includes multiple
|
||||
// blocks on a side chain the local node knows however
|
||||
// none in the main chain but includes a stop hash in
|
||||
// the main chain. The expected result is the blocks
|
||||
// after the genesis block up to the stop hash since
|
||||
// even though the blocks are known, they are all on a
|
||||
// side chain and there are no more locators to find the
|
||||
// fork point.
|
||||
name: "weak locator, multiple known side blocks, stop in main",
|
||||
locator: locatorHashes(branch1Nodes, 1),
|
||||
hashStop: branch0Nodes[5].hash,
|
||||
headers: nodeHeaders(branch0Nodes, 0, 1, 2, 3, 4, 5),
|
||||
hashes: nodeHashes(branch0Nodes, 0, 1, 2, 3, 4, 5),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
// Ensure the expected headers are located.
|
||||
var headers []wire.BlockHeader
|
||||
if test.maxAllowed != 0 {
|
||||
// Need to use the unexported function to override the
|
||||
// max allowed for headers.
|
||||
chain.chainLock.RLock()
|
||||
headers = chain.locateHeaders(test.locator,
|
||||
&test.hashStop, test.maxAllowed)
|
||||
chain.chainLock.RUnlock()
|
||||
} else {
|
||||
headers = chain.LocateHeaders(test.locator,
|
||||
&test.hashStop)
|
||||
}
|
||||
if !reflect.DeepEqual(headers, test.headers) {
|
||||
t.Errorf("%s: unxpected headers -- got %v, want %v",
|
||||
test.name, headers, test.headers)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the expected block hashes are located.
|
||||
maxAllowed := uint32(wire.MaxBlocksPerMsg)
|
||||
if test.maxAllowed != 0 {
|
||||
maxAllowed = test.maxAllowed
|
||||
}
|
||||
hashes := chain.LocateBlocks(test.locator, &test.hashStop,
|
||||
maxAllowed)
|
||||
if !reflect.DeepEqual(hashes, test.hashes) {
|
||||
t.Errorf("%s: unxpected hashes -- got %v, want %v",
|
||||
test.name, hashes, test.hashes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestHeightToHashRange ensures that fetching a range of block hashes by start
|
||||
// height and end hash works as expected.
|
||||
func TestHeightToHashRange(t *testing.T) {
|
||||
// Construct a synthetic block chain with a block index consisting of
|
||||
// the following structure.
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
// \-> 16a -> 17a -> 18a (unvalidated)
|
||||
tip := tstTip
|
||||
chain := newFakeChain(&chaincfg.MainNetParams)
|
||||
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
|
||||
branch1Nodes := chainedNodes(branch0Nodes[14], 3)
|
||||
for _, node := range branch0Nodes {
|
||||
chain.index.SetStatusFlags(node, statusValid)
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
for _, node := range branch1Nodes {
|
||||
if node.height < 18 {
|
||||
chain.index.SetStatusFlags(node, statusValid)
|
||||
}
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
chain.bestChain.SetTip(tip(branch0Nodes))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
startHeight int32 // locator for requested inventory
|
||||
endHash chainhash.Hash // stop hash for locator
|
||||
maxResults int // max to locate, 0 = wire const
|
||||
hashes []chainhash.Hash // expected located hashes
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "blocks below tip",
|
||||
startHeight: 11,
|
||||
endHash: branch0Nodes[14].hash,
|
||||
maxResults: 10,
|
||||
hashes: nodeHashes(branch0Nodes, 10, 11, 12, 13, 14),
|
||||
},
|
||||
{
|
||||
name: "blocks on main chain",
|
||||
startHeight: 15,
|
||||
endHash: branch0Nodes[17].hash,
|
||||
maxResults: 10,
|
||||
hashes: nodeHashes(branch0Nodes, 14, 15, 16, 17),
|
||||
},
|
||||
{
|
||||
name: "blocks on stale chain",
|
||||
startHeight: 15,
|
||||
endHash: branch1Nodes[1].hash,
|
||||
maxResults: 10,
|
||||
hashes: append(nodeHashes(branch0Nodes, 14),
|
||||
nodeHashes(branch1Nodes, 0, 1)...),
|
||||
},
|
||||
{
|
||||
name: "invalid start height",
|
||||
startHeight: 19,
|
||||
endHash: branch0Nodes[17].hash,
|
||||
maxResults: 10,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "too many results",
|
||||
startHeight: 1,
|
||||
endHash: branch0Nodes[17].hash,
|
||||
maxResults: 10,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "unvalidated block",
|
||||
startHeight: 15,
|
||||
endHash: branch1Nodes[2].hash,
|
||||
maxResults: 10,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
hashes, err := chain.HeightToHashRange(test.startHeight, &test.endHash,
|
||||
test.maxResults)
|
||||
if err != nil {
|
||||
if !test.expectError {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(hashes, test.hashes) {
|
||||
t.Errorf("%s: unxpected hashes -- got %v, want %v",
|
||||
test.name, hashes, test.hashes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestIntervalBlockHashes ensures that fetching block hashes at specified
|
||||
// intervals by end hash works as expected.
|
||||
func TestIntervalBlockHashes(t *testing.T) {
|
||||
// Construct a synthetic block chain with a block index consisting of
|
||||
// the following structure.
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
// \-> 16a -> 17a -> 18a (unvalidated)
|
||||
tip := tstTip
|
||||
chain := newFakeChain(&chaincfg.MainNetParams)
|
||||
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 18)
|
||||
branch1Nodes := chainedNodes(branch0Nodes[14], 3)
|
||||
for _, node := range branch0Nodes {
|
||||
chain.index.SetStatusFlags(node, statusValid)
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
for _, node := range branch1Nodes {
|
||||
if node.height < 18 {
|
||||
chain.index.SetStatusFlags(node, statusValid)
|
||||
}
|
||||
chain.index.AddNode(node)
|
||||
}
|
||||
chain.bestChain.SetTip(tip(branch0Nodes))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
endHash chainhash.Hash
|
||||
interval int
|
||||
hashes []chainhash.Hash
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "blocks on main chain",
|
||||
endHash: branch0Nodes[17].hash,
|
||||
interval: 8,
|
||||
hashes: nodeHashes(branch0Nodes, 7, 15),
|
||||
},
|
||||
{
|
||||
name: "blocks on stale chain",
|
||||
endHash: branch1Nodes[1].hash,
|
||||
interval: 8,
|
||||
hashes: append(nodeHashes(branch0Nodes, 7),
|
||||
nodeHashes(branch1Nodes, 0)...),
|
||||
},
|
||||
{
|
||||
name: "no results",
|
||||
endHash: branch0Nodes[17].hash,
|
||||
interval: 20,
|
||||
hashes: []chainhash.Hash{},
|
||||
},
|
||||
{
|
||||
name: "unvalidated block",
|
||||
endHash: branch1Nodes[2].hash,
|
||||
interval: 8,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
hashes, err := chain.IntervalBlockHashes(&test.endHash, test.interval)
|
||||
if err != nil {
|
||||
if !test.expectError {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(hashes, test.hashes) {
|
||||
t.Errorf("%s: unxpected hashes -- got %v, want %v",
|
||||
test.name, hashes, test.hashes)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,10 +12,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// testNoncePrng provides a deterministic prng for the nonce in generated fake
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// CheckpointConfirmations is the number of blocks before the end of the current
|
||||
|
|
183
blockchain/claimtrie.go
Normal file
183
blockchain/claimtrie.go
Normal file
|
@ -0,0 +1,183 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
|
||||
"github.com/lbryio/lbcd/claimtrie"
|
||||
"github.com/lbryio/lbcd/claimtrie/change"
|
||||
"github.com/lbryio/lbcd/claimtrie/node"
|
||||
"github.com/lbryio/lbcd/claimtrie/normalization"
|
||||
)
|
||||
|
||||
func (b *BlockChain) SetClaimtrieHeader(block *btcutil.Block, view *UtxoViewpoint) error {
|
||||
b.chainLock.Lock()
|
||||
defer b.chainLock.Unlock()
|
||||
|
||||
err := b.ParseClaimScripts(block, nil, view, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "in parse claim scripts")
|
||||
}
|
||||
|
||||
block.MsgBlock().Header.ClaimTrie = *b.claimTrie.MerkleHash()
|
||||
err = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
|
||||
|
||||
return errors.Wrapf(err, "in reset height")
|
||||
}
|
||||
|
||||
func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view *UtxoViewpoint, shouldFlush bool) error {
|
||||
ht := block.Height()
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
h := handler{ht, tx, view, map[string][]byte{}}
|
||||
if err := h.handleTxIns(b.claimTrie); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := h.handleTxOuts(b.claimTrie); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := b.claimTrie.AppendBlock()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "in append block")
|
||||
}
|
||||
|
||||
if shouldFlush {
|
||||
b.claimTrie.FlushToDisk()
|
||||
}
|
||||
|
||||
hash := b.claimTrie.MerkleHash()
|
||||
if bn != nil && bn.claimTrie != *hash {
|
||||
// undo our AppendBlock call as we've decided that our interpretation of the block data is incorrect,
|
||||
// or that the person who made the block assembled the pieces incorrectly.
|
||||
_ = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
|
||||
return errors.Errorf("height: %d, computed hash: %s != header's ClaimTrie: %s", ht, *hash, bn.claimTrie)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
ht int32
|
||||
tx *btcutil.Tx
|
||||
view *UtxoViewpoint
|
||||
spent map[string][]byte
|
||||
}
|
||||
|
||||
func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error {
|
||||
if IsCoinBase(h.tx) {
|
||||
return nil
|
||||
}
|
||||
for _, txIn := range h.tx.MsgTx().TxIn {
|
||||
op := txIn.PreviousOutPoint
|
||||
e := h.view.LookupEntry(op)
|
||||
if e == nil {
|
||||
return errors.Errorf("missing input in view for %s", op.String())
|
||||
}
|
||||
cs, err := txscript.DecodeClaimScript(e.pkScript)
|
||||
if err == txscript.ErrNotClaimScript {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id change.ClaimID
|
||||
name := cs.Name() // name of the previous one (that we're now spending)
|
||||
|
||||
switch cs.Opcode() {
|
||||
case txscript.OP_CLAIMNAME: // OP code from previous transaction
|
||||
id = change.NewClaimID(op) // claimID of the previous item now being spent
|
||||
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
err = ct.SpendClaim(name, op, id)
|
||||
case txscript.OP_UPDATECLAIM:
|
||||
copy(id[:], cs.ClaimID())
|
||||
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
err = ct.SpendClaim(name, op, id)
|
||||
case txscript.OP_SUPPORTCLAIM:
|
||||
copy(id[:], cs.ClaimID())
|
||||
err = ct.SpendSupport(name, op, id)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "handleTxIns")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error {
|
||||
for i, txOut := range h.tx.MsgTx().TxOut {
|
||||
op := *wire.NewOutPoint(h.tx.Hash(), uint32(i))
|
||||
cs, err := txscript.DecodeClaimScript(txOut.PkScript)
|
||||
if err == txscript.ErrNotClaimScript {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id change.ClaimID
|
||||
name := cs.Name()
|
||||
amt := txOut.Value
|
||||
|
||||
switch cs.Opcode() {
|
||||
case txscript.OP_CLAIMNAME:
|
||||
id = change.NewClaimID(op)
|
||||
err = ct.AddClaim(name, op, id, amt)
|
||||
case txscript.OP_SUPPORTCLAIM:
|
||||
copy(id[:], cs.ClaimID())
|
||||
err = ct.AddSupport(name, op, amt, id)
|
||||
case txscript.OP_UPDATECLAIM:
|
||||
// old code wouldn't run the update if name or claimID didn't match existing data
|
||||
// that was a safety feature, but it should have rejected the transaction instead
|
||||
// TODO: reject transactions with invalid update commands
|
||||
copy(id[:], cs.ClaimID())
|
||||
normName := normalization.NormalizeIfNecessary(name, ct.Height())
|
||||
if !bytes.Equal(h.spent[id.Key()], normName) {
|
||||
node.LogOnce(fmt.Sprintf("Invalid update operation: name or ID mismatch at %d for: %s, %s",
|
||||
ct.Height(), normName, id.String()))
|
||||
continue
|
||||
}
|
||||
|
||||
delete(h.spent, id.Key())
|
||||
err = ct.UpdateClaim(name, op, amt, id)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "handleTxOuts")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BlockChain) GetNamesChangedInBlock(height int32) ([]string, error) {
|
||||
b.chainLock.RLock()
|
||||
defer b.chainLock.RUnlock()
|
||||
|
||||
return b.claimTrie.NamesChangedInBlock(height)
|
||||
}
|
||||
|
||||
func (b *BlockChain) GetClaimsForName(height int32, name string) (string, *node.Node, error) {
|
||||
|
||||
normalizedName := normalization.NormalizeIfNecessary([]byte(name), height)
|
||||
|
||||
b.chainLock.RLock()
|
||||
defer b.chainLock.RUnlock()
|
||||
|
||||
n, err := b.claimTrie.NodeAt(height, normalizedName)
|
||||
if err != nil {
|
||||
return string(normalizedName), nil, err
|
||||
}
|
||||
|
||||
if n == nil {
|
||||
return string(normalizedName), nil, fmt.Errorf("name does not exist at height %d: %s", height, name)
|
||||
}
|
||||
|
||||
n.SortClaimsByBid()
|
||||
return string(normalizedName), n, nil
|
||||
}
|
|
@ -14,13 +14,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
_ "github.com/lbryio/lbcd/database/ffldb"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -69,7 +69,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
|||
|
||||
fi, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
|
||||
if strings.HasSuffix(filename, ".bz2") {
|
||||
|
@ -107,12 +107,12 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
|
|||
|
||||
block, err = btcutil.NewBlockFromBytes(rbytes)
|
||||
if err != nil {
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
|
||||
return
|
||||
return blocks, err
|
||||
}
|
||||
|
||||
// chainSetup is used to create a new db and chain instance with the genesis
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -159,7 +159,6 @@ func CalcWork(bits uint32) *big.Int {
|
|||
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
|
||||
// Convert types used in the calculations below.
|
||||
durationVal := int64(duration / time.Second)
|
||||
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
|
||||
|
||||
// The test network rules allow minimum difficulty blocks after more
|
||||
// than twice the desired amount of time needed to generate a block has
|
||||
|
@ -178,7 +177,8 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
|
|||
// multiplied by the max adjustment factor.
|
||||
newTarget := CompactToBig(bits)
|
||||
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
|
||||
newTarget.Mul(newTarget, adjustmentFactor)
|
||||
adj := new(big.Int).Div(newTarget, big.NewInt(2))
|
||||
newTarget.Add(newTarget, adj)
|
||||
durationVal -= b.maxRetargetTimespan
|
||||
}
|
||||
|
||||
|
@ -224,47 +224,45 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
|||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// Return the previous block's difficulty requirements if this block
|
||||
// is not at a difficulty retarget interval.
|
||||
if (lastNode.height+1)%b.blocksPerRetarget != 0 {
|
||||
// For networks that support it, allow special reduction of the
|
||||
// required difficulty once too much time has elapsed without
|
||||
// mining a block.
|
||||
if b.chainParams.ReduceMinDifficulty {
|
||||
// Return minimum difficulty when more than the desired
|
||||
// amount of time has elapsed without mining a block.
|
||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||
time.Second)
|
||||
allowMinTime := lastNode.timestamp + reductionTime
|
||||
if newBlockTime.Unix() > allowMinTime {
|
||||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// The block was mined within the desired timeframe, so
|
||||
// return the difficulty for the last block which did
|
||||
// not have the special minimum difficulty rule applied.
|
||||
return b.findPrevTestNetDifficulty(lastNode), nil
|
||||
// For networks that support it, allow special reduction of the
|
||||
// required difficulty once too much time has elapsed without
|
||||
// mining a block.
|
||||
if b.chainParams.ReduceMinDifficulty {
|
||||
// Return minimum difficulty when more than the desired
|
||||
// amount of time has elapsed without mining a block.
|
||||
reductionTime := int64(b.chainParams.MinDiffReductionTime /
|
||||
time.Second)
|
||||
allowMinTime := lastNode.timestamp + reductionTime
|
||||
if newBlockTime.Unix() > allowMinTime {
|
||||
return b.chainParams.PowLimitBits, nil
|
||||
}
|
||||
|
||||
// For the main network (or any unrecognized networks), simply
|
||||
// return the previous block's difficulty requirements.
|
||||
return lastNode.bits, nil
|
||||
// The block was mined within the desired timeframe, so
|
||||
// return the difficulty for the last block which did
|
||||
// not have the special minimum difficulty rule applied.
|
||||
return b.findPrevTestNetDifficulty(lastNode), nil
|
||||
}
|
||||
|
||||
// Get the block node at the previous retarget (targetTimespan days
|
||||
// worth of blocks).
|
||||
firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1)
|
||||
blocksBack := b.blocksPerRetarget
|
||||
if blocksBack > lastNode.height {
|
||||
blocksBack = lastNode.height
|
||||
}
|
||||
firstNode := lastNode.RelativeAncestor(blocksBack)
|
||||
if firstNode == nil {
|
||||
return 0, AssertError("unable to obtain previous retarget block")
|
||||
}
|
||||
|
||||
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
|
||||
|
||||
// Limit the amount of adjustment that can occur to the previous
|
||||
// difficulty.
|
||||
actualTimespan := lastNode.timestamp - firstNode.timestamp
|
||||
adjustedTimespan := actualTimespan
|
||||
if actualTimespan < b.minRetargetTimespan {
|
||||
adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
|
||||
if adjustedTimespan < b.minRetargetTimespan {
|
||||
adjustedTimespan = b.minRetargetTimespan
|
||||
} else if actualTimespan > b.maxRetargetTimespan {
|
||||
} else if adjustedTimespan > b.maxRetargetTimespan {
|
||||
adjustedTimespan = b.maxRetargetTimespan
|
||||
}
|
||||
|
||||
|
@ -275,7 +273,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
|
|||
// result.
|
||||
oldTarget := CompactToBig(lastNode.bits)
|
||||
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
|
||||
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
|
||||
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
|
||||
|
||||
// Limit new value to the proof of work limit.
|
||||
|
|
|
@ -220,6 +220,10 @@ const (
|
|||
// current chain tip. This is not a block validation rule, but is required
|
||||
// for block proposals submitted via getblocktemplate RPC.
|
||||
ErrPrevBlockNotBest
|
||||
|
||||
// ErrBadClaimTrie indicates the calculated ClaimTrie root does not match
|
||||
// the expected value.
|
||||
ErrBadClaimTrie
|
||||
)
|
||||
|
||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||
|
@ -267,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
||||
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
||||
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
||||
ErrBadClaimTrie: "ErrBadClaimTrie",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
// Copyright (c) 2014-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// This example demonstrates how to create a new chain instance and use
|
||||
// ProcessBlock to attempt to add a block to the chain. As the package
|
||||
// overview documentation describes, this includes all of the Bitcoin consensus
|
||||
// rules. This example intentionally attempts to insert a duplicate genesis
|
||||
// block to illustrate how an invalid block is handled.
|
||||
func ExampleBlockChain_ProcessBlock() {
|
||||
// Create a new database to store the accepted blocks into. Typically
|
||||
// this would be opening an existing database and would not be deleting
|
||||
// and creating a new database like this, but it is done here so this is
|
||||
// a complete working example and does not leave temporary files laying
|
||||
// around.
|
||||
dbPath := filepath.Join(os.TempDir(), "exampleprocessblock")
|
||||
_ = os.RemoveAll(dbPath)
|
||||
db, err := database.Create("ffldb", dbPath, chaincfg.MainNetParams.Net)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create database: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(dbPath)
|
||||
defer db.Close()
|
||||
|
||||
// Create a new BlockChain instance using the underlying database for
|
||||
// the main bitcoin network. This example does not demonstrate some
|
||||
// of the other available configuration options such as specifying a
|
||||
// notification callback and signature cache. Also, the caller would
|
||||
// ordinarily keep a reference to the median time source and add time
|
||||
// values obtained from other peers on the network so the local time is
|
||||
// adjusted to be in agreement with other peers.
|
||||
chain, err := blockchain.New(&blockchain.Config{
|
||||
DB: db,
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
TimeSource: blockchain.NewMedianTime(),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create chain instance: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Process a block. For this example, we are going to intentionally
|
||||
// cause an error by trying to process the genesis block which already
|
||||
// exists.
|
||||
genesisBlock := btcutil.NewBlock(chaincfg.MainNetParams.GenesisBlock)
|
||||
isMainChain, isOrphan, err := chain.ProcessBlock(genesisBlock,
|
||||
blockchain.BFNone)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to process block: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Block accepted. Is it on the main chain?: %v", isMainChain)
|
||||
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
|
||||
|
||||
// Output:
|
||||
// Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
||||
}
|
||||
|
||||
// This example demonstrates how to convert the compact "bits" in a block header
|
||||
// which represent the target difficulty to a big integer and display it using
|
||||
// the typical hex notation.
|
||||
func ExampleCompactToBig() {
|
||||
// Convert the bits from block 300000 in the main block chain.
|
||||
bits := uint32(419465580)
|
||||
targetDifficulty := blockchain.CompactToBig(bits)
|
||||
|
||||
// Display it in hex.
|
||||
fmt.Printf("%064x\n", targetDifficulty.Bytes())
|
||||
|
||||
// Output:
|
||||
// 0000000000000000896c00000000000000000000000000000000000000000000
|
||||
}
|
||||
|
||||
// This example demonstrates how to convert a target difficulty into the compact
|
||||
// "bits" in a block header which represent that target difficulty .
|
||||
func ExampleBigToCompact() {
|
||||
// Convert the target difficulty from block 300000 in the main block
|
||||
// chain to compact form.
|
||||
t := "0000000000000000896c00000000000000000000000000000000000000000000"
|
||||
targetDifficulty, success := new(big.Int).SetString(t, 16)
|
||||
if !success {
|
||||
fmt.Println("invalid target difficulty")
|
||||
return
|
||||
}
|
||||
bits := blockchain.BigToCompact(targetDifficulty)
|
||||
|
||||
fmt.Println(bits)
|
||||
|
||||
// Output:
|
||||
// 419465580
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
// Copyright (c) 2016 The Decred developers
|
||||
// Copyright (c) 2016-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/blockchain/fullblocktests"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
_ "github.com/btcsuite/btcd/database/ffldb"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// testDbType is the database backend type to use for the tests.
|
||||
testDbType = "ffldb"
|
||||
|
||||
// testDbRoot is the root directory used to create all test databases.
|
||||
testDbRoot = "testdbs"
|
||||
|
||||
// blockDataNet is the expected network in the test block data.
|
||||
blockDataNet = wire.MainNet
|
||||
)
|
||||
|
||||
// filesExists returns whether or not the named file or directory exists.
|
||||
func fileExists(name string) bool {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isSupportedDbType returns whether or not the passed database type is
|
||||
// currently supported.
|
||||
func isSupportedDbType(dbType string) bool {
|
||||
supportedDrivers := database.SupportedDrivers()
|
||||
for _, driver := range supportedDrivers {
|
||||
if dbType == driver {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// chainSetup is used to create a new db and chain instance with the genesis
|
||||
// block already inserted. In addition to the new chain instance, it returns
|
||||
// a teardown function the caller should invoke when done testing to clean up.
|
||||
func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain, func(), error) {
|
||||
if !isSupportedDbType(testDbType) {
|
||||
return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
|
||||
}
|
||||
|
||||
// Handle memory database specially since it doesn't need the disk
|
||||
// specific handling.
|
||||
var db database.DB
|
||||
var teardown func()
|
||||
if testDbType == "memdb" {
|
||||
ndb, err := database.Create(testDbType)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating db: %v", err)
|
||||
}
|
||||
db = ndb
|
||||
|
||||
// Setup a teardown function for cleaning up. This function is
|
||||
// returned to the caller to be invoked when it is done testing.
|
||||
teardown = func() {
|
||||
db.Close()
|
||||
}
|
||||
} else {
|
||||
// Create the root directory for test databases.
|
||||
if !fileExists(testDbRoot) {
|
||||
if err := os.MkdirAll(testDbRoot, 0700); err != nil {
|
||||
err := fmt.Errorf("unable to create test db "+
|
||||
"root: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new database to store the accepted blocks into.
|
||||
dbPath := filepath.Join(testDbRoot, dbName)
|
||||
_ = os.RemoveAll(dbPath)
|
||||
ndb, err := database.Create(testDbType, dbPath, blockDataNet)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating db: %v", err)
|
||||
}
|
||||
db = ndb
|
||||
|
||||
// Setup a teardown function for cleaning up. This function is
|
||||
// returned to the caller to be invoked when it is done testing.
|
||||
teardown = func() {
|
||||
db.Close()
|
||||
os.RemoveAll(dbPath)
|
||||
os.RemoveAll(testDbRoot)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the chain params to ensure any modifications the tests do to
|
||||
// the chain parameters do not affect the global instance.
|
||||
paramsCopy := *params
|
||||
|
||||
// Create the main chain instance.
|
||||
chain, err := blockchain.New(&blockchain.Config{
|
||||
DB: db,
|
||||
ChainParams: ¶msCopy,
|
||||
Checkpoints: nil,
|
||||
TimeSource: blockchain.NewMedianTime(),
|
||||
SigCache: txscript.NewSigCache(1000),
|
||||
})
|
||||
if err != nil {
|
||||
teardown()
|
||||
err := fmt.Errorf("failed to create chain instance: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
return chain, teardown, nil
|
||||
}
|
||||
|
||||
// TestFullBlocks ensures all tests generated by the fullblocktests package
|
||||
// have the expected result when processed via ProcessBlock.
|
||||
func TestFullBlocks(t *testing.T) {
|
||||
tests, err := fullblocktests.Generate(false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate tests: %v", err)
|
||||
}
|
||||
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("fullblocktest",
|
||||
&chaincfg.RegressionNetParams)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup chain instance: %v", err)
|
||||
return
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
// testAcceptedBlock attempts to process the block in the provided test
|
||||
// instance and ensures that it was accepted according to the flags
|
||||
// specified in the test.
|
||||
testAcceptedBlock := func(item fullblocktests.AcceptedBlock) {
|
||||
blockHeight := item.Height
|
||||
block := btcutil.NewBlock(item.Block)
|
||||
block.SetHeight(blockHeight)
|
||||
t.Logf("Testing block %s (hash %s, height %d)",
|
||||
item.Name, block.Hash(), blockHeight)
|
||||
|
||||
isMainChain, isOrphan, err := chain.ProcessBlock(block,
|
||||
blockchain.BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("block %q (hash %s, height %d) should "+
|
||||
"have been accepted: %v", item.Name,
|
||||
block.Hash(), blockHeight, err)
|
||||
}
|
||||
|
||||
// Ensure the main chain and orphan flags match the values
|
||||
// specified in the test.
|
||||
if isMainChain != item.IsMainChain {
|
||||
t.Fatalf("block %q (hash %s, height %d) unexpected main "+
|
||||
"chain flag -- got %v, want %v", item.Name,
|
||||
block.Hash(), blockHeight, isMainChain,
|
||||
item.IsMainChain)
|
||||
}
|
||||
if isOrphan != item.IsOrphan {
|
||||
t.Fatalf("block %q (hash %s, height %d) unexpected "+
|
||||
"orphan flag -- got %v, want %v", item.Name,
|
||||
block.Hash(), blockHeight, isOrphan,
|
||||
item.IsOrphan)
|
||||
}
|
||||
}
|
||||
|
||||
// testRejectedBlock attempts to process the block in the provided test
|
||||
// instance and ensures that it was rejected with the reject code
|
||||
// specified in the test.
|
||||
testRejectedBlock := func(item fullblocktests.RejectedBlock) {
|
||||
blockHeight := item.Height
|
||||
block := btcutil.NewBlock(item.Block)
|
||||
block.SetHeight(blockHeight)
|
||||
t.Logf("Testing block %s (hash %s, height %d)",
|
||||
item.Name, block.Hash(), blockHeight)
|
||||
|
||||
_, _, err := chain.ProcessBlock(block, blockchain.BFNone)
|
||||
if err == nil {
|
||||
t.Fatalf("block %q (hash %s, height %d) should not "+
|
||||
"have been accepted", item.Name, block.Hash(),
|
||||
blockHeight)
|
||||
}
|
||||
|
||||
// Ensure the error code is of the expected type and the reject
|
||||
// code matches the value specified in the test instance.
|
||||
rerr, ok := err.(blockchain.RuleError)
|
||||
if !ok {
|
||||
t.Fatalf("block %q (hash %s, height %d) returned "+
|
||||
"unexpected error type -- got %T, want "+
|
||||
"blockchain.RuleError", item.Name, block.Hash(),
|
||||
blockHeight, err)
|
||||
}
|
||||
if rerr.ErrorCode != item.RejectCode {
|
||||
t.Fatalf("block %q (hash %s, height %d) does not have "+
|
||||
"expected reject code -- got %v, want %v",
|
||||
item.Name, block.Hash(), blockHeight,
|
||||
rerr.ErrorCode, item.RejectCode)
|
||||
}
|
||||
}
|
||||
|
||||
// testRejectedNonCanonicalBlock attempts to decode the block in the
|
||||
// provided test instance and ensures that it failed to decode with a
|
||||
// message error.
|
||||
testRejectedNonCanonicalBlock := func(item fullblocktests.RejectedNonCanonicalBlock) {
|
||||
headerLen := len(item.RawBlock)
|
||||
if headerLen > 80 {
|
||||
headerLen = 80
|
||||
}
|
||||
blockHash := chainhash.DoubleHashH(item.RawBlock[0:headerLen])
|
||||
blockHeight := item.Height
|
||||
t.Logf("Testing block %s (hash %s, height %d)", item.Name,
|
||||
blockHash, blockHeight)
|
||||
|
||||
// Ensure there is an error due to deserializing the block.
|
||||
var msgBlock wire.MsgBlock
|
||||
err := msgBlock.BtcDecode(bytes.NewReader(item.RawBlock), 0, wire.BaseEncoding)
|
||||
if _, ok := err.(*wire.MessageError); !ok {
|
||||
t.Fatalf("block %q (hash %s, height %d) should have "+
|
||||
"failed to decode", item.Name, blockHash,
|
||||
blockHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// testOrphanOrRejectedBlock attempts to process the block in the
|
||||
// provided test instance and ensures that it was either accepted as an
|
||||
// orphan or rejected with a rule violation.
|
||||
testOrphanOrRejectedBlock := func(item fullblocktests.OrphanOrRejectedBlock) {
|
||||
blockHeight := item.Height
|
||||
block := btcutil.NewBlock(item.Block)
|
||||
block.SetHeight(blockHeight)
|
||||
t.Logf("Testing block %s (hash %s, height %d)",
|
||||
item.Name, block.Hash(), blockHeight)
|
||||
|
||||
_, isOrphan, err := chain.ProcessBlock(block, blockchain.BFNone)
|
||||
if err != nil {
|
||||
// Ensure the error code is of the expected type.
|
||||
if _, ok := err.(blockchain.RuleError); !ok {
|
||||
t.Fatalf("block %q (hash %s, height %d) "+
|
||||
"returned unexpected error type -- "+
|
||||
"got %T, want blockchain.RuleError",
|
||||
item.Name, block.Hash(), blockHeight,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
if !isOrphan {
|
||||
t.Fatalf("block %q (hash %s, height %d) was accepted, "+
|
||||
"but is not considered an orphan", item.Name,
|
||||
block.Hash(), blockHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// testExpectedTip ensures the current tip of the blockchain is the
|
||||
// block specified in the provided test instance.
|
||||
testExpectedTip := func(item fullblocktests.ExpectedTip) {
|
||||
blockHeight := item.Height
|
||||
block := btcutil.NewBlock(item.Block)
|
||||
block.SetHeight(blockHeight)
|
||||
t.Logf("Testing tip for block %s (hash %s, height %d)",
|
||||
item.Name, block.Hash(), blockHeight)
|
||||
|
||||
// Ensure hash and height match.
|
||||
best := chain.BestSnapshot()
|
||||
if best.Hash != item.Block.BlockHash() ||
|
||||
best.Height != blockHeight {
|
||||
|
||||
t.Fatalf("block %q (hash %s, height %d) should be "+
|
||||
"the current tip -- got (hash %s, height %d)",
|
||||
item.Name, block.Hash(), blockHeight, best.Hash,
|
||||
best.Height)
|
||||
}
|
||||
}
|
||||
|
||||
for testNum, test := range tests {
|
||||
for itemNum, item := range test {
|
||||
switch item := item.(type) {
|
||||
case fullblocktests.AcceptedBlock:
|
||||
testAcceptedBlock(item)
|
||||
case fullblocktests.RejectedBlock:
|
||||
testRejectedBlock(item)
|
||||
case fullblocktests.RejectedNonCanonicalBlock:
|
||||
testRejectedNonCanonicalBlock(item)
|
||||
case fullblocktests.OrphanOrRejectedBlock:
|
||||
testOrphanOrRejectedBlock(item)
|
||||
case fullblocktests.ExpectedTip:
|
||||
testExpectedTip(item)
|
||||
default:
|
||||
t.Fatalf("test #%d, item #%d is not one of "+
|
||||
"the supported test instance types -- "+
|
||||
"got type: %T", testNum, itemNum, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
fullblocktests
|
||||
==============
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/fullblocktests)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/fullblocktests)
|
||||
|
||||
Package fullblocktests provides a set of full block tests to be used for testing
|
||||
the consensus validation rules. The tests are intended to be flexible enough to
|
||||
|
@ -20,7 +20,7 @@ of blocks that exercise the consensus validation rules.
|
|||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/blockchain/fullblocktests
|
||||
$ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -18,24 +18,24 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// Intentionally defined here rather than using constants from codebase
|
||||
// to ensure consensus changes are detected.
|
||||
maxBlockSigOps = 20000
|
||||
maxBlockSize = 1000000
|
||||
maxBlockSize = 2000000
|
||||
minCoinbaseScriptLen = 2
|
||||
maxCoinbaseScriptLen = 100
|
||||
medianTimeBlocks = 11
|
||||
maxScriptElementSize = 520
|
||||
maxScriptElementSize = 20000
|
||||
|
||||
// numLargeReorgBlocks is the number of blocks to use in the large block
|
||||
// reorg test (when enabled). This is the equivalent of 1 week's worth
|
||||
|
@ -1875,7 +1875,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
|||
//
|
||||
// Comment assumptions:
|
||||
// maxBlockSigOps = 20000
|
||||
// maxScriptElementSize = 520
|
||||
// maxScriptElementSize = 20000
|
||||
//
|
||||
// [0-19999] : OP_CHECKSIG
|
||||
// [20000] : OP_PUSHDATA4
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// newHashFromStr converts the passed big-endian hex string into a
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
indexers
|
||||
========
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers)
|
||||
[![GoDoc](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers)
|
||||
|
||||
Package indexers implements optional block chain indexes.
|
||||
|
||||
|
@ -23,7 +23,7 @@ via an RPC interface.
|
|||
## Installation
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/blockchain/indexers
|
||||
$ go get -u github.com/lbryio/lbcd/blockchain/indexers
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// addrIndexBucket provides a mock address index database bucket by implementing
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/btcsuite/btclog"
|
||||
"github.com/btcsuite/btcutil"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// blockProgressLogger provides periodic logging for other services in order
|
||||
|
|
|
@ -7,14 +7,14 @@ package indexers
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/gcs"
|
||||
"github.com/btcsuite/btcutil/gcs/builder"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
"github.com/lbryio/lbcutil/gcs"
|
||||
"github.com/lbryio/lbcutil/gcs/builder"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,11 +8,11 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -8,11 +8,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/blockchain"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -183,7 +183,7 @@ func (m *medianTime) AddTimeSample(sourceID string, timeVal time.Time) {
|
|||
// Warn if none of the time samples are close.
|
||||
if !remoteHasCloseTime {
|
||||
log.Warnf("Please check your date and time " +
|
||||
"are correct! btcd will not work " +
|
||||
"are correct! lbcd will not work " +
|
||||
"properly with an invalid time")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -230,8 +230,8 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error {
|
|||
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
|
||||
if len(coinbaseWitness) != 1 {
|
||||
str := fmt.Sprintf("the coinbase transaction has %d items in "+
|
||||
"its witness stack when only one is allowed",
|
||||
len(coinbaseWitness))
|
||||
"its witness stack when only one is allowed. Height: %d",
|
||||
len(coinbaseWitness), blk.Height())
|
||||
return ruleError(ErrInvalidWitnessCommitment, str)
|
||||
}
|
||||
witnessNonce := coinbaseWitness[0]
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// TestMerkle tests the BuildMerkleTreeStore API.
|
||||
func TestMerkle(t *testing.T) {
|
||||
block := btcutil.NewBlock(&Block100000)
|
||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||
wantMerkle := &Block100000.Header.MerkleRoot
|
||||
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
||||
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
|
||||
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
)
|
||||
|
||||
// TestNotifications ensures that notification callbacks are fired on events.
|
||||
func TestNotifications(t *testing.T) {
|
||||
blocks, err := loadBlocks("blk_0_to_4.dat.bz2")
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading file: %v\n", err)
|
||||
}
|
||||
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("notifications",
|
||||
&chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup chain instance: %v", err)
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
notificationCount := 0
|
||||
callback := func(notification *Notification) {
|
||||
if notification.Type == NTBlockAccepted {
|
||||
notificationCount++
|
||||
}
|
||||
}
|
||||
|
||||
// Register callback multiple times then assert it is called that many
|
||||
// times.
|
||||
const numSubscribers = 3
|
||||
for i := 0; i < numSubscribers; i++ {
|
||||
chain.Subscribe(callback)
|
||||
}
|
||||
|
||||
_, _, err = chain.ProcessBlock(blocks[1], BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessBlock fail on block 1: %v\n", err)
|
||||
}
|
||||
|
||||
if notificationCount != numSubscribers {
|
||||
t.Fatalf("Expected notification callback to be executed %d "+
|
||||
"times, found %d", numSubscribers, notificationCount)
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// txValidateItem holds a transaction along with which input to validate.
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
)
|
||||
|
||||
// TestCheckBlockScripts ensures that validating the all of the scripts in a
|
||||
// known-good block doesn't return an error.
|
||||
func TestCheckBlockScripts(t *testing.T) {
|
||||
testBlockNum := 277647
|
||||
blockDataFile := fmt.Sprintf("%d.dat.bz2", testBlockNum)
|
||||
blocks, err := loadBlocks(blockDataFile)
|
||||
if err != nil {
|
||||
t.Errorf("Error loading file: %v\n", err)
|
||||
return
|
||||
}
|
||||
if len(blocks) > 1 {
|
||||
t.Errorf("The test block file must only have one block in it")
|
||||
return
|
||||
}
|
||||
if len(blocks) == 0 {
|
||||
t.Errorf("The test block file may not be empty")
|
||||
return
|
||||
}
|
||||
|
||||
storeDataFile := fmt.Sprintf("%d.utxostore.bz2", testBlockNum)
|
||||
view, err := loadUtxoView(storeDataFile)
|
||||
if err != nil {
|
||||
t.Errorf("Error loading txstore: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
scriptFlags := txscript.ScriptBip16
|
||||
err = checkBlockScripts(blocks[0], view, scriptFlags, nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Transaction script validation failed: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// ThresholdState define the various threshold states used when voting on
|
||||
|
@ -302,6 +302,12 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
|
|||
}
|
||||
|
||||
deployment := &b.chainParams.Deployments[deploymentID]
|
||||
|
||||
// added to mimic LBRYcrd:
|
||||
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
|
||||
return ThresholdActive, nil
|
||||
}
|
||||
|
||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||
cache := &b.deploymentCaches[deploymentID]
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// TestThresholdStateStringer tests the stringized output for the
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -7,11 +7,11 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// txoFlags is a bitmask defining additional information and state for a
|
||||
|
|
|
@ -11,11 +11,11 @@ import (
|
|||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -40,7 +40,7 @@ const (
|
|||
|
||||
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
||||
// value is halved every SubsidyHalvingInterval blocks.
|
||||
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
|
||||
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -192,17 +192,44 @@ func isBIP0030Node(node *blockNode) bool {
|
|||
// At the target block generation rate for the main network, this is
|
||||
// approximately every 4 years.
|
||||
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
|
||||
if chainParams.SubsidyReductionInterval == 0 {
|
||||
return baseSubsidy
|
||||
h := int64(height)
|
||||
if h == 0 {
|
||||
return btcutil.SatoshiPerBitcoin * 4e8
|
||||
}
|
||||
if h <= 5100 {
|
||||
return btcutil.SatoshiPerBitcoin
|
||||
}
|
||||
if h <= 55000 {
|
||||
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
|
||||
}
|
||||
|
||||
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
|
||||
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
|
||||
lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval)
|
||||
reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2
|
||||
for !withinLevelBounds(reduction, lv) {
|
||||
if ((reduction*reduction + reduction) >> 1) > lv {
|
||||
reduction--
|
||||
} else {
|
||||
reduction++
|
||||
}
|
||||
}
|
||||
subsidyReduction := btcutil.SatoshiPerBitcoin * reduction
|
||||
if subsidyReduction >= baseSubsidy {
|
||||
return 0
|
||||
}
|
||||
return baseSubsidy - subsidyReduction
|
||||
}
|
||||
|
||||
func withinLevelBounds(reduction int64, lv int64) bool {
|
||||
if ((reduction*reduction + reduction) >> 1) > lv {
|
||||
return false
|
||||
}
|
||||
reduction++
|
||||
return ((reduction*reduction + reduction) >> 1) > lv
|
||||
}
|
||||
|
||||
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
||||
// ensure it is sane. These checks are context free.
|
||||
func CheckTransactionSanity(tx *btcutil.Tx) error {
|
||||
// ensure it is sane.
|
||||
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
|
||||
// A transaction must have at least one input.
|
||||
msgTx := tx.MsgTx()
|
||||
if len(msgTx.TxIn) == 0 {
|
||||
|
@ -261,6 +288,11 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
|||
btcutil.MaxSatoshi)
|
||||
return ruleError(ErrBadTxOutValue, str)
|
||||
}
|
||||
|
||||
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
|
||||
if err != nil {
|
||||
return ruleError(ErrBadTxOutValue, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate transaction inputs.
|
||||
|
@ -324,7 +356,7 @@ func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags Behavio
|
|||
// to avoid proof of work checks is set.
|
||||
if flags&BFNoPoWCheck != BFNoPoWCheck {
|
||||
// The block hash must be less than the claimed target.
|
||||
hash := header.BlockHash()
|
||||
hash := header.BlockPoWHash()
|
||||
hashNum := HashToBig(&hash)
|
||||
if hashNum.Cmp(target) > 0 {
|
||||
str := fmt.Sprintf("block hash of %064x is higher than "+
|
||||
|
@ -515,7 +547,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
|
|||
// Do some preliminary checks on each transaction to ensure they are
|
||||
// sane before continuing.
|
||||
for _, tx := range transactions {
|
||||
err := CheckTransactionSanity(tx)
|
||||
err := CheckTransactionSanity(tx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,487 +0,0 @@
|
|||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
)
|
||||
|
||||
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
|
||||
// works as expected in all possible combinations/scenarios.
|
||||
func TestSequenceLocksActive(t *testing.T) {
|
||||
seqLock := func(h int32, s int64) *SequenceLock {
|
||||
return &SequenceLock{
|
||||
Seconds: s,
|
||||
BlockHeight: h,
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
seqLock *SequenceLock
|
||||
blockHeight int32
|
||||
mtp time.Time
|
||||
|
||||
want bool
|
||||
}{
|
||||
// Block based sequence lock with equal block height.
|
||||
{seqLock: seqLock(1000, -1), blockHeight: 1001, mtp: time.Unix(9, 0), want: true},
|
||||
|
||||
// Time based sequence lock with mtp past the absolute time.
|
||||
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(31, 0), want: true},
|
||||
|
||||
// Block based sequence lock with current height below seq lock block height.
|
||||
{seqLock: seqLock(1000, -1), blockHeight: 90, mtp: time.Unix(9, 0), want: false},
|
||||
|
||||
// Time based sequence lock with current time before lock time.
|
||||
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(29, 0), want: false},
|
||||
|
||||
// Block based sequence lock at the same height, so shouldn't yet be active.
|
||||
{seqLock: seqLock(1000, -1), blockHeight: 1000, mtp: time.Unix(9, 0), want: false},
|
||||
|
||||
// Time based sequence lock with current time equal to lock time, so shouldn't yet be active.
|
||||
{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(30, 0), want: false},
|
||||
}
|
||||
|
||||
t.Logf("Running %d sequence locks tests", len(tests))
|
||||
for i, test := range tests {
|
||||
got := SequenceLockActive(test.seqLock,
|
||||
test.blockHeight, test.mtp)
|
||||
if got != test.want {
|
||||
t.Fatalf("SequenceLockActive #%d got %v want %v", i,
|
||||
got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to
|
||||
// ensure it fails.
|
||||
func TestCheckConnectBlockTemplate(t *testing.T) {
|
||||
// Create a new database and chain instance to run tests against.
|
||||
chain, teardownFunc, err := chainSetup("checkconnectblocktemplate",
|
||||
&chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to setup chain instance: %v", err)
|
||||
return
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
// Since we're not dealing with the real block chain, set the coinbase
|
||||
// maturity to 1.
|
||||
chain.TstSetCoinbaseMaturity(1)
|
||||
|
||||
// Load up blocks such that there is a side chain.
|
||||
// (genesis block) -> 1 -> 2 -> 3 -> 4
|
||||
// \-> 3a
|
||||
testFiles := []string{
|
||||
"blk_0_to_4.dat.bz2",
|
||||
"blk_3A.dat.bz2",
|
||||
}
|
||||
|
||||
var blocks []*btcutil.Block
|
||||
for _, file := range testFiles {
|
||||
blockTmp, err := loadBlocks(file)
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading file: %v\n", err)
|
||||
}
|
||||
blocks = append(blocks, blockTmp...)
|
||||
}
|
||||
|
||||
for i := 1; i <= 3; i++ {
|
||||
isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
|
||||
"processing block %d: %v", i, err)
|
||||
}
|
||||
if !isMainChain {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
|
||||
"to main chain", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Block 3 should fail to connect since it's already inserted.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[3])
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 3")
|
||||
}
|
||||
|
||||
// Block 4 should connect successfully to tip of chain.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[4])
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
|
||||
"block 4: %v", err)
|
||||
}
|
||||
|
||||
// Block 3a should fail to connect since does not build on chain tip.
|
||||
err = chain.CheckConnectBlockTemplate(blocks[5])
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 3a")
|
||||
}
|
||||
|
||||
// Block 4 should connect even if proof of work is invalid.
|
||||
invalidPowBlock := *blocks[4].MsgBlock()
|
||||
invalidPowBlock.Header.Nonce++
|
||||
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidPowBlock))
|
||||
if err != nil {
|
||||
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
|
||||
"block 4 with bad nonce: %v", err)
|
||||
}
|
||||
|
||||
// Invalid block building on chain tip should fail to connect.
|
||||
invalidBlock := *blocks[4].MsgBlock()
|
||||
invalidBlock.Header.Bits--
|
||||
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidBlock))
|
||||
if err == nil {
|
||||
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
|
||||
"on block 4 with invalid difficulty bits")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
||||
// as expected.
|
||||
func TestCheckBlockSanity(t *testing.T) {
|
||||
powLimit := chaincfg.MainNetParams.PowLimit
|
||||
block := btcutil.NewBlock(&Block100000)
|
||||
timeSource := NewMedianTime()
|
||||
err := CheckBlockSanity(block, powLimit, timeSource)
|
||||
if err != nil {
|
||||
t.Errorf("CheckBlockSanity: %v", err)
|
||||
}
|
||||
|
||||
// Ensure a block that has a timestamp with a precision higher than one
|
||||
// second fails.
|
||||
timestamp := block.MsgBlock().Header.Timestamp
|
||||
block.MsgBlock().Header.Timestamp = timestamp.Add(time.Nanosecond)
|
||||
err = CheckBlockSanity(block, powLimit, timeSource)
|
||||
if err == nil {
|
||||
t.Errorf("CheckBlockSanity: error is nil when it shouldn't be")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckSerializedHeight tests the checkSerializedHeight function with
|
||||
// various serialized heights and also does negative tests to ensure errors
|
||||
// and handled properly.
|
||||
func TestCheckSerializedHeight(t *testing.T) {
|
||||
// Create an empty coinbase template to be used in the tests below.
|
||||
coinbaseOutpoint := wire.NewOutPoint(&chainhash.Hash{}, math.MaxUint32)
|
||||
coinbaseTx := wire.NewMsgTx(1)
|
||||
coinbaseTx.AddTxIn(wire.NewTxIn(coinbaseOutpoint, nil, nil))
|
||||
|
||||
// Expected rule errors.
|
||||
missingHeightError := RuleError{
|
||||
ErrorCode: ErrMissingCoinbaseHeight,
|
||||
}
|
||||
badHeightError := RuleError{
|
||||
ErrorCode: ErrBadCoinbaseHeight,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
sigScript []byte // Serialized data
|
||||
wantHeight int32 // Expected height
|
||||
err error // Expected error type
|
||||
}{
|
||||
// No serialized height length.
|
||||
{[]byte{}, 0, missingHeightError},
|
||||
// Serialized height length with no height bytes.
|
||||
{[]byte{0x02}, 0, missingHeightError},
|
||||
// Serialized height length with too few height bytes.
|
||||
{[]byte{0x02, 0x4a}, 0, missingHeightError},
|
||||
// Serialized height that needs 2 bytes to encode.
|
||||
{[]byte{0x02, 0x4a, 0x52}, 21066, nil},
|
||||
// Serialized height that needs 2 bytes to encode, but backwards
|
||||
// endianness.
|
||||
{[]byte{0x02, 0x4a, 0x52}, 19026, badHeightError},
|
||||
// Serialized height that needs 3 bytes to encode.
|
||||
{[]byte{0x03, 0x40, 0x0d, 0x03}, 200000, nil},
|
||||
// Serialized height that needs 3 bytes to encode, but backwards
|
||||
// endianness.
|
||||
{[]byte{0x03, 0x40, 0x0d, 0x03}, 1074594560, badHeightError},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
msgTx := coinbaseTx.Copy()
|
||||
msgTx.TxIn[0].SignatureScript = test.sigScript
|
||||
tx := btcutil.NewTx(msgTx)
|
||||
|
||||
err := checkSerializedHeight(tx, test.wantHeight)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("checkSerializedHeight #%d wrong error type "+
|
||||
"got: %v <%T>, want: %T", i, err, err, test.err)
|
||||
continue
|
||||
}
|
||||
|
||||
if rerr, ok := err.(RuleError); ok {
|
||||
trerr := test.err.(RuleError)
|
||||
if rerr.ErrorCode != trerr.ErrorCode {
|
||||
t.Errorf("checkSerializedHeight #%d wrong "+
|
||||
"error code got: %v, want: %v", i,
|
||||
rerr.ErrorCode, trerr.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Block100000 defines block 100,000 of the block chain. It is used to
|
||||
// test Block operations.
|
||||
var Block100000 = wire.MsgBlock{
|
||||
Header: wire.BlockHeader{
|
||||
Version: 1,
|
||||
PrevBlock: chainhash.Hash([32]byte{ // Make go vet happy.
|
||||
0x50, 0x12, 0x01, 0x19, 0x17, 0x2a, 0x61, 0x04,
|
||||
0x21, 0xa6, 0xc3, 0x01, 0x1d, 0xd3, 0x30, 0xd9,
|
||||
0xdf, 0x07, 0xb6, 0x36, 0x16, 0xc2, 0xcc, 0x1f,
|
||||
0x1c, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}), // 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
|
||||
MerkleRoot: chainhash.Hash([32]byte{ // Make go vet happy.
|
||||
0x66, 0x57, 0xa9, 0x25, 0x2a, 0xac, 0xd5, 0xc0,
|
||||
0xb2, 0x94, 0x09, 0x96, 0xec, 0xff, 0x95, 0x22,
|
||||
0x28, 0xc3, 0x06, 0x7c, 0xc3, 0x8d, 0x48, 0x85,
|
||||
0xef, 0xb5, 0xa4, 0xac, 0x42, 0x47, 0xe9, 0xf3,
|
||||
}), // f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
|
||||
Timestamp: time.Unix(1293623863, 0), // 2010-12-29 11:57:43 +0000 UTC
|
||||
Bits: 0x1b04864c, // 453281356
|
||||
Nonce: 0x10572b0f, // 274148111
|
||||
},
|
||||
Transactions: []*wire.MsgTx{
|
||||
{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{},
|
||||
Index: 0xffffffff,
|
||||
},
|
||||
SignatureScript: []byte{
|
||||
0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
|
||||
},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 0x12a05f200, // 5000000000
|
||||
PkScript: []byte{
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0x1b, 0x0e, 0x8c, 0x25, 0x67, 0xc1, 0x25,
|
||||
0x36, 0xaa, 0x13, 0x35, 0x7b, 0x79, 0xa0, 0x73,
|
||||
0xdc, 0x44, 0x44, 0xac, 0xb8, 0x3c, 0x4e, 0xc7,
|
||||
0xa0, 0xe2, 0xf9, 0x9d, 0xd7, 0x45, 0x75, 0x16,
|
||||
0xc5, 0x81, 0x72, 0x42, 0xda, 0x79, 0x69, 0x24,
|
||||
0xca, 0x4e, 0x99, 0x94, 0x7d, 0x08, 0x7f, 0xed,
|
||||
0xf9, 0xce, 0x46, 0x7c, 0xb9, 0xf7, 0xc6, 0x28,
|
||||
0x70, 0x78, 0xf8, 0x01, 0xdf, 0x27, 0x6f, 0xdf,
|
||||
0x84, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
},
|
||||
{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
|
||||
0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
|
||||
0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
|
||||
0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
|
||||
0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
|
||||
}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
|
||||
Index: 0,
|
||||
},
|
||||
SignatureScript: []byte{
|
||||
0x49, // OP_DATA_73
|
||||
0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
|
||||
0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
|
||||
0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
|
||||
0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
|
||||
0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
|
||||
0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
|
||||
0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
|
||||
0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
|
||||
0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
|
||||
0x01, // 73-byte signature
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
|
||||
0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
|
||||
0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
|
||||
0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
|
||||
0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
|
||||
0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
|
||||
0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
|
||||
0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
|
||||
0xd3, // 65-byte pubkey
|
||||
},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 0x2123e300, // 556000000
|
||||
PkScript: []byte{
|
||||
0x76, // OP_DUP
|
||||
0xa9, // OP_HASH160
|
||||
0x14, // OP_DATA_20
|
||||
0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
|
||||
0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
|
||||
0xf7, 0xf5, 0x8b, 0x32,
|
||||
0x88, // OP_EQUALVERIFY
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
{
|
||||
Value: 0x108e20f00, // 4444000000
|
||||
PkScript: []byte{
|
||||
0x76, // OP_DUP
|
||||
0xa9, // OP_HASH160
|
||||
0x14, // OP_DATA_20
|
||||
0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
|
||||
0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
|
||||
0x52, 0xde, 0x3d, 0x7c,
|
||||
0x88, // OP_EQUALVERIFY
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
},
|
||||
{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
|
||||
0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
|
||||
0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
|
||||
0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
|
||||
0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
|
||||
}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
|
||||
Index: 1,
|
||||
},
|
||||
SignatureScript: []byte{
|
||||
0x47, // OP_DATA_71
|
||||
0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
|
||||
0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
|
||||
0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
|
||||
0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
|
||||
0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
|
||||
0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
|
||||
0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
|
||||
0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
|
||||
0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
|
||||
0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
|
||||
0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
|
||||
0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
|
||||
0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
|
||||
0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
|
||||
0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
|
||||
0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
|
||||
0x0f, // 65-byte pubkey
|
||||
},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 0xf4240, // 1000000
|
||||
PkScript: []byte{
|
||||
0x76, // OP_DUP
|
||||
0xa9, // OP_HASH160
|
||||
0x14, // OP_DATA_20
|
||||
0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
|
||||
0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
|
||||
0xad, 0xbe, 0x7e, 0x10,
|
||||
0x88, // OP_EQUALVERIFY
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
{
|
||||
Value: 0x11d260c0, // 299000000
|
||||
PkScript: []byte{
|
||||
0x76, // OP_DUP
|
||||
0xa9, // OP_HASH160
|
||||
0x14, // OP_DATA_20
|
||||
0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
|
||||
0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
|
||||
0xb3, 0x40, 0x9c, 0xd9,
|
||||
0x88, // OP_EQUALVERIFY
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
},
|
||||
{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
|
||||
0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
|
||||
0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
|
||||
0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
|
||||
0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
|
||||
}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
|
||||
Index: 0,
|
||||
},
|
||||
SignatureScript: []byte{
|
||||
0x49, // OP_DATA_73
|
||||
0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
|
||||
0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
|
||||
0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
|
||||
0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
|
||||
0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
|
||||
0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
|
||||
0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
|
||||
0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
|
||||
0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
|
||||
0x01, // 73-byte signature
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
|
||||
0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
|
||||
0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
|
||||
0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
|
||||
0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
|
||||
0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
|
||||
0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
|
||||
0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
|
||||
0xbb, // 65-byte pubkey
|
||||
},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 0xf4240, // 1000000
|
||||
PkScript: []byte{
|
||||
0x76, // OP_DUP
|
||||
0xa9, // OP_HASH160
|
||||
0x14, // OP_DATA_20
|
||||
0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
|
||||
0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
|
||||
0xf2, 0xeb, 0x9e, 0xe0,
|
||||
0x88, // OP_EQUALVERIFY
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
},
|
||||
},
|
||||
}
|
|
@ -7,7 +7,7 @@ package blockchain
|
|||
import (
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lbryio/lbcd/chaincfg"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -195,6 +195,12 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
|
|||
expectedVersion := uint32(vbTopBits)
|
||||
for id := 0; id < len(b.chainParams.Deployments); id++ {
|
||||
deployment := &b.chainParams.Deployments[id]
|
||||
|
||||
// added to mimic LBRYcrd:
|
||||
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
|
||||
continue
|
||||
}
|
||||
|
||||
cache := &b.deploymentCaches[id]
|
||||
checker := deploymentChecker{deployment: deployment, chain: b}
|
||||
state, err := b.thresholdState(prevNode, checker, cache)
|
||||
|
|
|
@ -7,9 +7,9 @@ package blockchain
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -20,11 +20,11 @@ const (
|
|||
// weight of a "base" byte is 4, while the weight of a witness byte is
|
||||
// 1. As a result, for a block to be valid, the BlockWeight MUST be
|
||||
// less than, or equal to MaxBlockWeight.
|
||||
MaxBlockWeight = 4000000
|
||||
MaxBlockWeight = 8000000
|
||||
|
||||
// MaxBlockBaseSize is the maximum number of bytes within a block
|
||||
// which can be allocated to non-witness data.
|
||||
MaxBlockBaseSize = 1000000
|
||||
MaxBlockBaseSize = 8000000
|
||||
|
||||
// MaxBlockSigOpsCost is the maximum number of signature operations
|
||||
// allowed for a block. It is calculated via a weighted algorithm which
|
||||
|
|
25
btcd.go
25
btcd.go
|
@ -15,9 +15,12 @@ import (
|
|||
"runtime/debug"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain/indexers"
|
||||
"github.com/btcsuite/btcd/database"
|
||||
"github.com/btcsuite/btcd/limits"
|
||||
"github.com/lbryio/lbcd/blockchain/indexers"
|
||||
"github.com/lbryio/lbcd/claimtrie/param"
|
||||
"github.com/lbryio/lbcd/database"
|
||||
"github.com/lbryio/lbcd/limits"
|
||||
|
||||
"github.com/felixge/fgprof"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -65,6 +68,7 @@ func btcdMain(serverChan chan<- *server) error {
|
|||
|
||||
// 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)
|
||||
|
@ -144,6 +148,10 @@ 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)
|
||||
|
@ -158,6 +166,10 @@ 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 {
|
||||
|
@ -196,6 +208,13 @@ func removeRegressionDB(dbPath string) error {
|
|||
}
|
||||
}
|
||||
|
||||
dbPath = filepath.Join(cfg.DataDir, activeNetParams.Name, "claim_dbs")
|
||||
btcdLog.Infof("Removing regression test claim databases from '%s'", dbPath)
|
||||
err = os.RemoveAll(dbPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,68 +1,11 @@
|
|||
btcec
|
||||
=====
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/btcec?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/btcec)
|
||||
|
||||
Package btcec implements elliptic curve cryptography needed for working with
|
||||
btcec implements elliptic curve cryptography needed for working with
|
||||
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
|
||||
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
|
||||
is provided to ensure proper functionality. Package btcec was originally based
|
||||
on work from ThePiachu which is licensed under the same terms as Go, but it has
|
||||
signficantly diverged since then. The btcsuite developers original is licensed
|
||||
under the liberal ISC license.
|
||||
|
||||
Although this package was primarily written for btcd, it has intentionally been
|
||||
designed so it can be used as a standalone package for any projects needing to
|
||||
use secp256k1 elliptic curve cryptography.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/btcec
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
|
||||
Demonstrates signing a message with a secp256k1 private key that is first
|
||||
parsed form raw bytes and serializing the generated signature.
|
||||
|
||||
* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
|
||||
Demonstrates verifying a secp256k1 signature against a public key that is
|
||||
first parsed from raw bytes. The signature is also parsed from raw bytes.
|
||||
|
||||
* [Encryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
|
||||
Demonstrates encrypting a message for a public key that is first parsed from
|
||||
raw bytes, then decrypting it using the corresponding private key.
|
||||
|
||||
* [Decryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
|
||||
Demonstrates decrypting a message using a private key that is first parsed
|
||||
from raw bytes.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
|
||||
except for btcec.go and btcec_test.go which is under the same license as Go.
|
||||
|
||||
signficantly diverged since then.
|
|
@ -8,8 +8,8 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
// This example demonstrates signing a message with a secp256k1 private key that
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// This file is ignored during the regular build due to the following build tag.
|
||||
// It is called by go generate and used to automatically generate pre-computed
|
||||
// tables used to accelerate operations.
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lbryio/lbcd/btcec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// This file is ignored during the regular build due to the following build tag.
|
||||
// This build tag is set during go generate.
|
||||
//go:build gensecp256k1
|
||||
// +build gensecp256k1
|
||||
|
||||
package btcec
|
||||
|
|
|
@ -1,70 +1,8 @@
|
|||
btcjson
|
||||
=======
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson)
|
||||
|
||||
Package btcjson implements concrete types for marshalling to and from the
|
||||
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
|
||||
proper functionality.
|
||||
|
||||
Although this package was primarily written for the btcsuite, it has
|
||||
intentionally been designed so it can be used as a standalone package for any
|
||||
projects needing to marshal to and from bitcoin JSON-RPC requests and responses.
|
||||
|
||||
Note that although it's possible to use this package directly to implement an
|
||||
RPC client, it is not recommended since it is only intended as an infrastructure
|
||||
package. Instead, RPC clients should use the
|
||||
[btcrpcclient](https://github.com/btcsuite/btcrpcclient) package which provides
|
||||
a full blown RPC client with many features such as automatic connection
|
||||
management, websocket support, automatic notification re-registration on
|
||||
reconnect, and conversion from the raw underlying RPC types (strings, floats,
|
||||
ints, etc) to higher-level types with many nice and useful properties.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/btcjson
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Marshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalCmd)
|
||||
Demonstrates how to create and marshal a command into a JSON-RPC request.
|
||||
|
||||
* [Unmarshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-UnmarshalCmd)
|
||||
Demonstrates how to unmarshal a JSON-RPC request and then unmarshal the
|
||||
concrete request into a concrete command.
|
||||
|
||||
* [Marshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalResponse)
|
||||
Demonstrates how to marshal a JSON-RPC response.
|
||||
|
||||
* [Unmarshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-package--UnmarshalResponse)
|
||||
Demonstrates how to unmarshal a JSON-RPC response and then unmarshal the
|
||||
result field in the response to a concrete type.
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Package btcjson is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
proper functionality.
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcdExtCustomResults ensures any results that have custom marshalling
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
|
||||
|
@ -388,7 +388,7 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`,
|
||||
unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", nil},
|
||||
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil},
|
||||
},
|
||||
{
|
||||
name: "getblockfilter optional filtertype",
|
||||
|
@ -399,7 +399,7 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`,
|
||||
unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
|
||||
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
|
||||
},
|
||||
{
|
||||
name: "getblockhash",
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
|
||||
|
@ -25,6 +25,7 @@ type GetBlockHeaderVerboseResult struct {
|
|||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
ClaimTrie string `json:"claimtrie,omitempty"`
|
||||
Time int64 `json:"time"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
|
@ -65,6 +66,27 @@ type GetBlockStatsResult struct {
|
|||
UTXOSizeIncrease int64 `json:"utxo_size_inc"`
|
||||
}
|
||||
|
||||
type GetBlockVerboseResultBase struct {
|
||||
Hash string `json:"hash"`
|
||||
Confirmations int64 `json:"confirmations"`
|
||||
StrippedSize int32 `json:"strippedsize"`
|
||||
Size int32 `json:"size"`
|
||||
Weight int32 `json:"weight"`
|
||||
Height int64 `json:"height"`
|
||||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
Time int64 `json:"time"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
Difficulty float64 `json:"difficulty"`
|
||||
PreviousHash string `json:"previousblockhash,omitempty"`
|
||||
NextHash string `json:"nextblockhash,omitempty"`
|
||||
|
||||
ClaimTrie string `json:"claimTrie,omitempty"`
|
||||
TxCount int `json:"nTx"` // For backwards compatibility only
|
||||
}
|
||||
|
||||
// GetBlockVerboseResult models the data from the getblock command when the
|
||||
// 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
|
||||
|
@ -72,23 +94,8 @@ type GetBlockStatsResult struct {
|
|||
// getblock returns an object whose tx field is an array of raw transactions.
|
||||
// Use GetBlockVerboseTxResult to unmarshal data received from passing verbose=2 to getblock.
|
||||
type GetBlockVerboseResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Confirmations int64 `json:"confirmations"`
|
||||
StrippedSize int32 `json:"strippedsize"`
|
||||
Size int32 `json:"size"`
|
||||
Weight int32 `json:"weight"`
|
||||
Height int64 `json:"height"`
|
||||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
Tx []string `json:"tx,omitempty"`
|
||||
RawTx []TxRawResult `json:"rawtx,omitempty"` // Note: this field is always empty when verbose != 2.
|
||||
Time int64 `json:"time"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
Difficulty float64 `json:"difficulty"`
|
||||
PreviousHash string `json:"previousblockhash"`
|
||||
NextHash string `json:"nextblockhash,omitempty"`
|
||||
GetBlockVerboseResultBase
|
||||
Tx []string `json:"tx"`
|
||||
}
|
||||
|
||||
// GetBlockVerboseTxResult models the data from the getblock command when the
|
||||
|
@ -98,23 +105,8 @@ type GetBlockVerboseResult struct {
|
|||
// getblock returns an object whose tx field is an array of raw transactions.
|
||||
// Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
|
||||
type GetBlockVerboseTxResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Confirmations int64 `json:"confirmations"`
|
||||
StrippedSize int32 `json:"strippedsize"`
|
||||
Size int32 `json:"size"`
|
||||
Weight int32 `json:"weight"`
|
||||
Height int64 `json:"height"`
|
||||
Version int32 `json:"version"`
|
||||
VersionHex string `json:"versionHex"`
|
||||
MerkleRoot string `json:"merkleroot"`
|
||||
Tx []TxRawResult `json:"tx,omitempty"`
|
||||
RawTx []TxRawResult `json:"rawtx,omitempty"` // Deprecated: removed in Bitcoin Core
|
||||
Time int64 `json:"time"`
|
||||
Nonce uint32 `json:"nonce"`
|
||||
Bits string `json:"bits"`
|
||||
Difficulty float64 `json:"difficulty"`
|
||||
PreviousHash string `json:"previousblockhash"`
|
||||
NextHash string `json:"nextblockhash,omitempty"`
|
||||
GetBlockVerboseResultBase
|
||||
Tx []TxRawResult `json:"tx"`
|
||||
}
|
||||
|
||||
// GetChainTxStatsResult models the data from the getchaintxstats command.
|
||||
|
@ -296,6 +288,10 @@ type GetBlockTemplateResult struct {
|
|||
// Block proposal from BIP 0023.
|
||||
Capabilities []string `json:"capabilities,omitempty"`
|
||||
RejectReasion string `json:"reject-reason,omitempty"`
|
||||
|
||||
ClaimTrieHash string `json:"claimtrie"`
|
||||
|
||||
Rules []string `json:"rules,omitempty"`
|
||||
}
|
||||
|
||||
// GetMempoolEntryResult models the data returned from the getmempoolentry's
|
||||
|
@ -428,6 +424,9 @@ type ScriptPubKeyResult struct {
|
|||
Hex string `json:"hex,omitempty"`
|
||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||
Type string `json:"type"`
|
||||
SubType string `json:"subtype"`
|
||||
IsClaim bool `json:"isclaim"`
|
||||
IsSupport bool `json:"issupport"`
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -586,6 +585,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
|||
type PrevOut struct {
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
Value float64 `json:"value"`
|
||||
IsClaim bool `json:"isclaim"`
|
||||
IsSupport bool `json:"issupport"`
|
||||
}
|
||||
|
||||
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// TestChainSvrCustomResults ensures any results that have custom marshalling
|
||||
|
@ -70,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
|
|||
},
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
|
||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsNtfns tests all of the chain server websocket-specific
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestChainSvrWsResults ensures any results that have custom marshalling
|
||||
|
|
95
btcjson/claimcmds.go
Normal file
95
btcjson/claimcmds.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package btcjson
|
||||
|
||||
func init() {
|
||||
// No special flags for commands in this file.
|
||||
flags := UsageFlag(0)
|
||||
|
||||
MustRegisterCmd("getchangesinblock", (*GetChangesInBlockCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsforname", (*GetClaimsForNameCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebyid", (*GetClaimsForNameByIDCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
|
||||
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
|
||||
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)
|
||||
}
|
||||
|
||||
// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
|
||||
// optional inputs have to be at the bottom of the struct
|
||||
// optional outputs require ",omitempty"
|
||||
// traditional bitcoin fields are all lowercase
|
||||
|
||||
type GetChangesInBlockCmd struct {
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
}
|
||||
|
||||
type GetChangesInBlockResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Height int32 `json:"height"`
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameCmd struct {
|
||||
Name string `json:"name"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameByIDCmd struct {
|
||||
Name string `json:"name"`
|
||||
PartialClaimIDs []string `json:"partialclaimids"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameByBidCmd struct {
|
||||
Name string `json:"name"`
|
||||
Bids []int32 `json:"bids"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameBySeqCmd struct {
|
||||
Name string `json:"name"`
|
||||
Sequences []int32 `json:"sequences" jsonrpcusage:"[sequence,...]"`
|
||||
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
|
||||
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
|
||||
}
|
||||
|
||||
type GetClaimsForNameResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Height int32 `json:"height"`
|
||||
NormalizedName string `json:"normalizedname"`
|
||||
Claims []ClaimResult `json:"claims"`
|
||||
// UnclaimedSupports []SupportResult `json:"unclaimedSupports"` how would this work with other constraints?
|
||||
}
|
||||
|
||||
type SupportResult struct {
|
||||
TXID string `json:"txid"`
|
||||
N uint32 `json:"n"`
|
||||
Height int32 `json:"height"`
|
||||
ValidAtHeight int32 `json:"validatheight"`
|
||||
Amount int64 `json:"amount"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type ClaimResult struct {
|
||||
ClaimID string `json:"claimid"`
|
||||
TXID string `json:"txid"`
|
||||
N uint32 `json:"n"`
|
||||
Bid int32 `json:"bid"`
|
||||
Sequence int32 `json:"sequence"`
|
||||
Height int32 `json:"height"`
|
||||
ValidAtHeight int32 `json:"validatheight"`
|
||||
EffectiveAmount int64 `json:"effectiveamount"`
|
||||
Supports []SupportResult `json:"supports,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type GetNormalizedCmd struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type GetNormalizedResult struct {
|
||||
NormalizedName string `json:"normalizedname"`
|
||||
}
|
|
@ -1,430 +0,0 @@
|
|||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcjson_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
)
|
||||
|
||||
// TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected
|
||||
// methods and errors.
|
||||
func TestCmdMethod(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cmd interface{}
|
||||
method string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "unregistered type",
|
||||
cmd: (*int)(nil),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "nil pointer of registered type",
|
||||
cmd: (*btcjson.GetBlockCmd)(nil),
|
||||
method: "getblock",
|
||||
},
|
||||
{
|
||||
name: "nil instance of registered type",
|
||||
cmd: &btcjson.GetBlockCountCmd{},
|
||||
method: "getblockcount",
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
method, err := btcjson.CmdMethod(test.cmd)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
|
||||
"want %T", i, test.name, err, test.err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code "+
|
||||
"- got %v (%v), want %v", i, test.name,
|
||||
gotErrorCode, err,
|
||||
test.err.(btcjson.Error).ErrorCode)
|
||||
continue
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure method matches the expected value.
|
||||
if method != test.method {
|
||||
t.Errorf("Test #%d (%s) mismatched method - got %v, "+
|
||||
"want %v", i, test.name, method, test.method)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodUsageFlags tests the MethodUsage function ensure it returns the
|
||||
// expected flags and errors.
|
||||
func TestMethodUsageFlags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
err error
|
||||
flags btcjson.UsageFlag
|
||||
}{
|
||||
{
|
||||
name: "unregistered type",
|
||||
method: "bogusmethod",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "getblock",
|
||||
method: "getblock",
|
||||
flags: 0,
|
||||
},
|
||||
{
|
||||
name: "walletpassphrase",
|
||||
method: "walletpassphrase",
|
||||
flags: btcjson.UFWalletOnly,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
flags, err := btcjson.MethodUsageFlags(test.method)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
|
||||
"want %T", i, test.name, err, test.err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code "+
|
||||
"- got %v (%v), want %v", i, test.name,
|
||||
gotErrorCode, err,
|
||||
test.err.(btcjson.Error).ErrorCode)
|
||||
continue
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure flags match the expected value.
|
||||
if flags != test.flags {
|
||||
t.Errorf("Test #%d (%s) mismatched flags - got %v, "+
|
||||
"want %v", i, test.name, flags, test.flags)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodUsageText tests the MethodUsageText function ensure it returns the
|
||||
// expected text.
|
||||
func TestMethodUsageText(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
err error
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "unregistered type",
|
||||
method: "bogusmethod",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "getblockcount",
|
||||
method: "getblockcount",
|
||||
expected: "getblockcount",
|
||||
},
|
||||
{
|
||||
name: "getblock",
|
||||
method: "getblock",
|
||||
expected: `getblock "hash" (verbosity=1)`,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
usage, err := btcjson.MethodUsageText(test.method)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
|
||||
"want %T", i, test.name, err, test.err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.(btcjson.Error).ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code "+
|
||||
"- got %v (%v), want %v", i, test.name,
|
||||
gotErrorCode, err,
|
||||
test.err.(btcjson.Error).ErrorCode)
|
||||
continue
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure usage matches the expected value.
|
||||
if usage != test.expected {
|
||||
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
|
||||
"want %v", i, test.name, usage, test.expected)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the usage again to exercise caching.
|
||||
usage, err = btcjson.MethodUsageText(test.method)
|
||||
if err != nil {
|
||||
t.Errorf("Test #%d (%s) unexpected error: %v", i,
|
||||
test.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure usage still matches the expected value.
|
||||
if usage != test.expected {
|
||||
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
|
||||
"want %v", i, test.name, usage, test.expected)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestFieldUsage tests the internal fieldUsage function ensure it returns the
|
||||
// expected text.
|
||||
func TestFieldUsage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
field reflect.StructField
|
||||
defValue *reflect.Value
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "jsonrpcusage tag override",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test int `jsonrpcusage:"testvalue"`
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: "testvalue",
|
||||
},
|
||||
{
|
||||
name: "generic interface",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test interface{}
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `test`,
|
||||
},
|
||||
{
|
||||
name: "string without default value",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `"test"`,
|
||||
},
|
||||
{
|
||||
name: "string with default value",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: func() *reflect.Value {
|
||||
value := "default"
|
||||
rv := reflect.ValueOf(&value)
|
||||
return &rv
|
||||
}(),
|
||||
expected: `test="default"`,
|
||||
},
|
||||
{
|
||||
name: "array of strings",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test []string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `["test",...]`,
|
||||
},
|
||||
{
|
||||
name: "array of strings with plural field name 1",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Keys []string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `["key",...]`,
|
||||
},
|
||||
{
|
||||
name: "array of strings with plural field name 2",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Addresses []string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `["address",...]`,
|
||||
},
|
||||
{
|
||||
name: "array of strings with plural field name 3",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Capabilities []string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `["capability",...]`,
|
||||
},
|
||||
{
|
||||
name: "array of structs",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Txid string
|
||||
}
|
||||
type s struct {
|
||||
Capabilities []s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `[{"txid":"value"},...]`,
|
||||
},
|
||||
{
|
||||
name: "array of ints",
|
||||
field: func() reflect.StructField {
|
||||
type s struct {
|
||||
Test []int
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `[test,...]`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with jsonrpcusage tag override",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Test string `jsonrpcusage:"testusage"`
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{testusage}`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with string",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Txid string
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{"txid":"value"}`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with int",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Vout int
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{"vout":n}`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with float",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Amount float64
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{"amount":n.nnn}`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with sub struct",
|
||||
field: func() reflect.StructField {
|
||||
type s3 struct {
|
||||
Amount float64
|
||||
}
|
||||
type s2 struct {
|
||||
Template s3
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{"template":{"amount":n.nnn}}`,
|
||||
},
|
||||
{
|
||||
name: "sub struct with slice",
|
||||
field: func() reflect.StructField {
|
||||
type s2 struct {
|
||||
Capabilities []string
|
||||
}
|
||||
type s struct {
|
||||
Test s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil)).Elem().Field(0)
|
||||
}(),
|
||||
defValue: nil,
|
||||
expected: `{"capabilities":["capability",...]}`,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Ensure usage matches the expected value.
|
||||
usage := btcjson.TstFieldUsage(test.field, test.defValue)
|
||||
if usage != test.expected {
|
||||
t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
|
||||
"want %v", i, test.name, usage, test.expected)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,593 +0,0 @@
|
|||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcjson_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
)
|
||||
|
||||
// TestAssignField tests the assignField function handles supported combinations
|
||||
// properly.
|
||||
func TestAssignField(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
dest interface{}
|
||||
src interface{}
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
name: "same types",
|
||||
dest: int8(0),
|
||||
src: int8(100),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "same types - more source pointers",
|
||||
dest: int8(0),
|
||||
src: func() interface{} {
|
||||
i := int8(100)
|
||||
return &i
|
||||
}(),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "same types - more dest pointers",
|
||||
dest: func() interface{} {
|
||||
i := int8(0)
|
||||
return &i
|
||||
}(),
|
||||
src: int8(100),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - more source pointers",
|
||||
dest: int16(0),
|
||||
src: func() interface{} {
|
||||
i := int8(100)
|
||||
return &i
|
||||
}(),
|
||||
expected: int16(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - both pointers",
|
||||
dest: func() interface{} {
|
||||
i := int8(0)
|
||||
return &i
|
||||
}(),
|
||||
src: func() interface{} {
|
||||
i := int16(100)
|
||||
return &i
|
||||
}(),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - int16 -> int8",
|
||||
dest: int8(0),
|
||||
src: int16(100),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - int16 -> uint8",
|
||||
dest: uint8(0),
|
||||
src: int16(100),
|
||||
expected: uint8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - uint16 -> int8",
|
||||
dest: int8(0),
|
||||
src: uint16(100),
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - uint16 -> uint8",
|
||||
dest: uint8(0),
|
||||
src: uint16(100),
|
||||
expected: uint8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - float32 -> float64",
|
||||
dest: float64(0),
|
||||
src: float32(1.5),
|
||||
expected: float64(1.5),
|
||||
},
|
||||
{
|
||||
name: "convertible types - float64 -> float32",
|
||||
dest: float32(0),
|
||||
src: float64(1.5),
|
||||
expected: float32(1.5),
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> bool",
|
||||
dest: false,
|
||||
src: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> int8",
|
||||
dest: int8(0),
|
||||
src: "100",
|
||||
expected: int8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> uint8",
|
||||
dest: uint8(0),
|
||||
src: "100",
|
||||
expected: uint8(100),
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> float32",
|
||||
dest: float32(0),
|
||||
src: "1.5",
|
||||
expected: float32(1.5),
|
||||
},
|
||||
{
|
||||
name: "convertible types - typecase string -> string",
|
||||
dest: "",
|
||||
src: func() interface{} {
|
||||
type foo string
|
||||
return foo("foo")
|
||||
}(),
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> array",
|
||||
dest: [2]string{},
|
||||
src: `["test","test2"]`,
|
||||
expected: [2]string{"test", "test2"},
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> slice",
|
||||
dest: []string{},
|
||||
src: `["test","test2"]`,
|
||||
expected: []string{"test", "test2"},
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> struct",
|
||||
dest: struct{ A int }{},
|
||||
src: `{"A":100}`,
|
||||
expected: struct{ A int }{100},
|
||||
},
|
||||
{
|
||||
name: "convertible types - string -> map",
|
||||
dest: map[string]float64{},
|
||||
src: `{"1Address":1.5}`,
|
||||
expected: map[string]float64{"1Address": 1.5},
|
||||
},
|
||||
{
|
||||
name: `null optional field - "null" -> *int32`,
|
||||
dest: btcjson.Int32(0),
|
||||
src: "null",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: `null optional field - "null" -> *string`,
|
||||
dest: btcjson.String(""),
|
||||
src: "null",
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
|
||||
src := reflect.ValueOf(test.src)
|
||||
err := btcjson.TstAssignField(1, "testField", dst, src)
|
||||
if err != nil {
|
||||
t.Errorf("Test #%d (%s) unexpected error: %v", i,
|
||||
test.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check case where null string is used on optional field
|
||||
if dst.Kind() == reflect.Ptr && test.src == "null" {
|
||||
if !dst.IsNil() {
|
||||
t.Errorf("Test #%d (%s) unexpected value - got %v, "+
|
||||
"want nil", i, test.name, dst.Interface())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Inidirect through to the base types to ensure their values
|
||||
// are the same.
|
||||
for dst.Kind() == reflect.Ptr {
|
||||
dst = dst.Elem()
|
||||
}
|
||||
if !reflect.DeepEqual(dst.Interface(), test.expected) {
|
||||
t.Errorf("Test #%d (%s) unexpected value - got %v, "+
|
||||
"want %v", i, test.name, dst.Interface(),
|
||||
test.expected)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestAssignFieldErrors tests the assignField function error paths.
|
||||
func TestAssignFieldErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
dest interface{}
|
||||
src interface{}
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "general incompatible int -> string",
|
||||
dest: "\x00",
|
||||
src: int(0),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow source int -> dest int",
|
||||
dest: int8(0),
|
||||
src: int(128),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow source int -> dest uint",
|
||||
dest: uint8(0),
|
||||
src: int(256),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "int -> float",
|
||||
dest: float32(0),
|
||||
src: int(256),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow source uint64 -> dest int64",
|
||||
dest: int64(0),
|
||||
src: uint64(1 << 63),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow source uint -> dest int",
|
||||
dest: int8(0),
|
||||
src: uint(128),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow source uint -> dest uint",
|
||||
dest: uint8(0),
|
||||
src: uint(256),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "uint -> float",
|
||||
dest: float32(0),
|
||||
src: uint(256),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "float -> int",
|
||||
dest: int(0),
|
||||
src: float32(1.0),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow float64 -> float32",
|
||||
dest: float32(0),
|
||||
src: float64(math.MaxFloat64),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> bool",
|
||||
dest: true,
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> int",
|
||||
dest: int8(0),
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow string -> int",
|
||||
dest: int8(0),
|
||||
src: "128",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> uint",
|
||||
dest: uint8(0),
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow string -> uint",
|
||||
dest: uint8(0),
|
||||
src: "256",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> float",
|
||||
dest: float32(0),
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "overflow string -> float",
|
||||
dest: float32(0),
|
||||
src: "1.7976931348623157e+308",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> array",
|
||||
dest: [3]int{},
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> slice",
|
||||
dest: []int{},
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> struct",
|
||||
dest: struct{ A int }{},
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid string -> map",
|
||||
dest: map[string]int{},
|
||||
src: "foo",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
|
||||
src := reflect.ValueOf(test.src)
|
||||
err := btcjson.TstAssignField(1, "testField", dst, src)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
|
||||
"want %T", i, test.name, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v (%v), want %v", i, test.name, gotErrorCode,
|
||||
err, test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewCmdErrors ensures the error paths of NewCmd behave as expected.
|
||||
func TestNewCmdErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
args []interface{}
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "unregistered command",
|
||||
method: "boguscommand",
|
||||
args: []interface{}{},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "too few parameters to command with required + optional",
|
||||
method: "getblock",
|
||||
args: []interface{}{},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
|
||||
},
|
||||
{
|
||||
name: "too many parameters to command with no optional",
|
||||
method: "getblockcount",
|
||||
args: []interface{}{"123"},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
|
||||
},
|
||||
{
|
||||
name: "incorrect parameter type",
|
||||
method: "getblock",
|
||||
args: []interface{}{1},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
_, err := btcjson.NewCmd(test.method, test.args...)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
|
||||
"want %T", i, test.name, err, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v (%v), want %v", i, test.name, gotErrorCode,
|
||||
err, test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMarshalCmd tests the MarshalCmd function.
|
||||
func TestMarshalCmd(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
id interface{}
|
||||
cmd interface{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "include all parameters",
|
||||
id: 1,
|
||||
cmd: btcjson.NewGetNetworkHashPSCmd(btcjson.Int(100), btcjson.Int(2000)),
|
||||
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[100,2000],"id":1}`,
|
||||
},
|
||||
{
|
||||
name: "include padding null parameter",
|
||||
id: 1,
|
||||
cmd: btcjson.NewGetNetworkHashPSCmd(nil, btcjson.Int(2000)),
|
||||
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[null,2000],"id":1}`,
|
||||
},
|
||||
{
|
||||
name: "omit single unnecessary null parameter",
|
||||
id: 1,
|
||||
cmd: btcjson.NewGetNetworkHashPSCmd(btcjson.Int(100), nil),
|
||||
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[100],"id":1}`,
|
||||
},
|
||||
{
|
||||
name: "omit unnecessary null parameters",
|
||||
id: 1,
|
||||
cmd: btcjson.NewGetNetworkHashPSCmd(nil, nil),
|
||||
expected: `{"jsonrpc":"1.0","method":"getnetworkhashps","params":[],"id":1}`,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
bytes, err := btcjson.MarshalCmd(btcjson.RpcVersion1, test.id, test.cmd)
|
||||
if err != nil {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%v)",
|
||||
i, test.name, err, err)
|
||||
continue
|
||||
}
|
||||
marshalled := string(bytes)
|
||||
if marshalled != test.expected {
|
||||
t.Errorf("Test #%d (%s) mismatched marshall result - got "+
|
||||
"%v, want %v", i, test.name, marshalled, test.expected)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMarshalCmdErrors tests the error paths of the MarshalCmd function.
|
||||
func TestMarshalCmdErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
id interface{}
|
||||
cmd interface{}
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "unregistered type",
|
||||
id: 1,
|
||||
cmd: (*int)(nil),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "nil instance of registered type",
|
||||
id: 1,
|
||||
cmd: (*btcjson.GetBlockCmd)(nil),
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "nil instance of registered type",
|
||||
id: []int{0, 1},
|
||||
cmd: &btcjson.GetBlockCountCmd{},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
_, err := btcjson.MarshalCmd(btcjson.RpcVersion1, test.id, test.cmd)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
|
||||
"want %T", i, test.name, err, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v (%v), want %v", i, test.name, gotErrorCode,
|
||||
err, test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmarshalCmdErrors tests the error paths of the UnmarshalCmd function.
|
||||
func TestUnmarshalCmdErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
request btcjson.Request
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "unregistered type",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "bogusmethod",
|
||||
Params: nil,
|
||||
ID: nil,
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "incorrect number of params",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getblockcount",
|
||||
Params: []json.RawMessage{[]byte(`"bogusparam"`)},
|
||||
ID: nil,
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
|
||||
},
|
||||
{
|
||||
name: "invalid type for a parameter",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getblock",
|
||||
Params: []json.RawMessage{[]byte("1")},
|
||||
ID: nil,
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid JSON for a parameter",
|
||||
request: btcjson.Request{
|
||||
Jsonrpc: btcjson.RpcVersion1,
|
||||
Method: "getblock",
|
||||
Params: []json.RawMessage{[]byte(`"1`)},
|
||||
ID: nil,
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
_, err := btcjson.UnmarshalCmd(&test.request)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
|
||||
"want %T", i, test.name, err, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v (%v), want %v", i, test.name, gotErrorCode,
|
||||
err, test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcjson_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
)
|
||||
|
||||
// TestErrorCodeStringer tests the stringized output for the ErrorCode type.
|
||||
func TestErrorCodeStringer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
in btcjson.ErrorCode
|
||||
want string
|
||||
}{
|
||||
{btcjson.ErrDuplicateMethod, "ErrDuplicateMethod"},
|
||||
{btcjson.ErrInvalidUsageFlags, "ErrInvalidUsageFlags"},
|
||||
{btcjson.ErrInvalidType, "ErrInvalidType"},
|
||||
{btcjson.ErrEmbeddedType, "ErrEmbeddedType"},
|
||||
{btcjson.ErrUnexportedField, "ErrUnexportedField"},
|
||||
{btcjson.ErrUnsupportedFieldType, "ErrUnsupportedFieldType"},
|
||||
{btcjson.ErrNonOptionalField, "ErrNonOptionalField"},
|
||||
{btcjson.ErrNonOptionalDefault, "ErrNonOptionalDefault"},
|
||||
{btcjson.ErrMismatchedDefault, "ErrMismatchedDefault"},
|
||||
{btcjson.ErrUnregisteredMethod, "ErrUnregisteredMethod"},
|
||||
{btcjson.ErrNumParams, "ErrNumParams"},
|
||||
{btcjson.ErrMissingDescription, "ErrMissingDescription"},
|
||||
{0xffff, "Unknown ErrorCode (65535)"},
|
||||
}
|
||||
|
||||
// Detect additional error codes that don't have the stringer added.
|
||||
if len(tests)-1 != int(btcjson.TstNumErrorCodes) {
|
||||
t.Errorf("It appears an error code was added without adding an " +
|
||||
"associated stringer test")
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
result := test.in.String()
|
||||
if result != test.want {
|
||||
t.Errorf("String #%d\n got: %s want: %s", i, result,
|
||||
test.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestError tests the error output for the Error type.
|
||||
func TestError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
in btcjson.Error
|
||||
want string
|
||||
}{
|
||||
{
|
||||
btcjson.Error{Description: "some error"},
|
||||
"some error",
|
||||
},
|
||||
{
|
||||
btcjson.Error{Description: "human-readable error"},
|
||||
"human-readable error",
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
result := test.in.Error()
|
||||
if result != test.want {
|
||||
t.Errorf("Error #%d\n got: %s want: %s", i, result,
|
||||
test.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// This example demonstrates how to create and marshal a command into a JSON-RPC
|
||||
|
|
|
@ -1,737 +0,0 @@
|
|||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcjson_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
)
|
||||
|
||||
// TestHelpReflectInternals ensures the various help functions which deal with
|
||||
// reflect types work as expected for various Go types.
|
||||
func TestHelpReflectInternals(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reflectType reflect.Type
|
||||
indentLevel int
|
||||
key string
|
||||
examples []string
|
||||
isComplex bool
|
||||
help string
|
||||
isInvalid bool
|
||||
}{
|
||||
{
|
||||
name: "int",
|
||||
reflectType: reflect.TypeOf(int(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "*int",
|
||||
reflectType: reflect.TypeOf((*int)(nil)),
|
||||
key: "json-type-value",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-value) fdk",
|
||||
isInvalid: true,
|
||||
},
|
||||
{
|
||||
name: "int8",
|
||||
reflectType: reflect.TypeOf(int8(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "int16",
|
||||
reflectType: reflect.TypeOf(int16(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "int32",
|
||||
reflectType: reflect.TypeOf(int32(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "int64",
|
||||
reflectType: reflect.TypeOf(int64(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "uint",
|
||||
reflectType: reflect.TypeOf(uint(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "uint8",
|
||||
reflectType: reflect.TypeOf(uint8(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "uint16",
|
||||
reflectType: reflect.TypeOf(uint16(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "uint32",
|
||||
reflectType: reflect.TypeOf(uint32(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "uint64",
|
||||
reflectType: reflect.TypeOf(uint64(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n"},
|
||||
help: "n (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "float32",
|
||||
reflectType: reflect.TypeOf(float32(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n.nnn"},
|
||||
help: "n.nnn (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "float64",
|
||||
reflectType: reflect.TypeOf(float64(0)),
|
||||
key: "json-type-numeric",
|
||||
examples: []string{"n.nnn"},
|
||||
help: "n.nnn (json-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
reflectType: reflect.TypeOf(""),
|
||||
key: "json-type-string",
|
||||
examples: []string{`"json-example-string"`},
|
||||
help: "\"json-example-string\" (json-type-string) fdk",
|
||||
},
|
||||
{
|
||||
name: "bool",
|
||||
reflectType: reflect.TypeOf(true),
|
||||
key: "json-type-bool",
|
||||
examples: []string{"json-example-bool"},
|
||||
help: "json-example-bool (json-type-bool) fdk",
|
||||
},
|
||||
{
|
||||
name: "array of int",
|
||||
reflectType: reflect.TypeOf([1]int{0}),
|
||||
key: "json-type-arrayjson-type-numeric",
|
||||
examples: []string{"[n,...]"},
|
||||
help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "slice of int",
|
||||
reflectType: reflect.TypeOf([]int{0}),
|
||||
key: "json-type-arrayjson-type-numeric",
|
||||
examples: []string{"[n,...]"},
|
||||
help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
|
||||
},
|
||||
{
|
||||
name: "struct",
|
||||
reflectType: reflect.TypeOf(struct{}{}),
|
||||
key: "json-type-object",
|
||||
examples: []string{"{", "}\t\t"},
|
||||
isComplex: true,
|
||||
help: "{\n} ",
|
||||
},
|
||||
{
|
||||
name: "struct indent level 1",
|
||||
reflectType: reflect.TypeOf(struct{ field int }{}),
|
||||
indentLevel: 1,
|
||||
key: "json-type-object",
|
||||
examples: []string{
|
||||
" \"field\": n,\t(json-type-numeric)\t-field",
|
||||
" },\t\t",
|
||||
},
|
||||
help: "{\n" +
|
||||
" \"field\": n, (json-type-numeric) -field\n" +
|
||||
"} ",
|
||||
isComplex: true,
|
||||
},
|
||||
{
|
||||
name: "array of struct indent level 0",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
field int
|
||||
}
|
||||
return reflect.TypeOf([]s{})
|
||||
}(),
|
||||
key: "json-type-arrayjson-type-object",
|
||||
examples: []string{
|
||||
"[{",
|
||||
" \"field\": n,\t(json-type-numeric)\ts-field",
|
||||
"},...]",
|
||||
},
|
||||
help: "[{\n" +
|
||||
" \"field\": n, (json-type-numeric) s-field\n" +
|
||||
"},...]",
|
||||
isComplex: true,
|
||||
},
|
||||
{
|
||||
name: "array of struct indent level 1",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
field int
|
||||
}
|
||||
return reflect.TypeOf([]s{})
|
||||
}(),
|
||||
indentLevel: 1,
|
||||
key: "json-type-arrayjson-type-object",
|
||||
examples: []string{
|
||||
" \"field\": n,\t(json-type-numeric)\ts-field",
|
||||
" },...],\t\t",
|
||||
},
|
||||
help: "[{\n" +
|
||||
" \"field\": n, (json-type-numeric) s-field\n" +
|
||||
"},...]",
|
||||
isComplex: true,
|
||||
},
|
||||
{
|
||||
name: "map",
|
||||
reflectType: reflect.TypeOf(map[string]string{}),
|
||||
key: "json-type-object",
|
||||
examples: []string{"{",
|
||||
" \"fdk--key\": fdk--value, (json-type-object) fdk--desc",
|
||||
" ...", "}",
|
||||
},
|
||||
help: "{\n" +
|
||||
" \"fdk--key\": fdk--value, (json-type-object) fdk--desc\n" +
|
||||
" ...\n" +
|
||||
"}",
|
||||
isComplex: true,
|
||||
},
|
||||
{
|
||||
name: "complex",
|
||||
reflectType: reflect.TypeOf(complex64(0)),
|
||||
key: "json-type-value",
|
||||
examples: []string{"json-example-unknown"},
|
||||
help: "json-example-unknown (json-type-value) fdk",
|
||||
isInvalid: true,
|
||||
},
|
||||
}
|
||||
|
||||
xT := func(key string) string {
|
||||
return key
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Ensure the description key is the expected value.
|
||||
key := btcjson.TstReflectTypeToJSONType(xT, test.reflectType)
|
||||
if key != test.key {
|
||||
t.Errorf("Test #%d (%s) unexpected key - got: %v, "+
|
||||
"want: %v", i, test.name, key, test.key)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the generated example is as expected.
|
||||
examples, isComplex := btcjson.TstReflectTypeToJSONExample(xT,
|
||||
test.reflectType, test.indentLevel, "fdk")
|
||||
if isComplex != test.isComplex {
|
||||
t.Errorf("Test #%d (%s) unexpected isComplex - got: %v, "+
|
||||
"want: %v", i, test.name, isComplex,
|
||||
test.isComplex)
|
||||
continue
|
||||
}
|
||||
if len(examples) != len(test.examples) {
|
||||
t.Errorf("Test #%d (%s) unexpected result length - "+
|
||||
"got: %v, want: %v", i, test.name, len(examples),
|
||||
len(test.examples))
|
||||
continue
|
||||
}
|
||||
for j, example := range examples {
|
||||
if example != test.examples[j] {
|
||||
t.Errorf("Test #%d (%s) example #%d unexpected "+
|
||||
"example - got: %v, want: %v", i,
|
||||
test.name, j, example, test.examples[j])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the generated result type help is as expected.
|
||||
helpText := btcjson.TstResultTypeHelp(xT, test.reflectType, "fdk")
|
||||
if helpText != test.help {
|
||||
t.Errorf("Test #%d (%s) unexpected result help - "+
|
||||
"got: %v, want: %v", i, test.name, helpText,
|
||||
test.help)
|
||||
continue
|
||||
}
|
||||
|
||||
isValid := btcjson.TstIsValidResultType(test.reflectType.Kind())
|
||||
if isValid != !test.isInvalid {
|
||||
t.Errorf("Test #%d (%s) unexpected result type validity "+
|
||||
"- got: %v", i, test.name, isValid)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestResultStructHelp ensures the expected help text format is returned for
|
||||
// various Go struct types.
|
||||
func TestResultStructHelp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reflectType reflect.Type
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "empty struct",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct{}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "struct with primitive field",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
field int
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"field\": n,\t(json-type-numeric)\ts-field",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "struct with primitive field and json tag",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field int `json:"f"`
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"f\": n,\t(json-type-numeric)\ts-f",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "struct with array of primitive field",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
field []int
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"field\": [n,...],\t(json-type-arrayjson-type-numeric)\ts-field",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "struct with sub-struct field",
|
||||
reflectType: func() reflect.Type {
|
||||
type s2 struct {
|
||||
subField int
|
||||
}
|
||||
type s struct {
|
||||
field s2
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"field\": {\t(json-type-object)\ts-field",
|
||||
"{",
|
||||
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
|
||||
"}\t\t",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "struct with sub-struct field pointer",
|
||||
reflectType: func() reflect.Type {
|
||||
type s2 struct {
|
||||
subField int
|
||||
}
|
||||
type s struct {
|
||||
field *s2
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"field\": {\t(json-type-object)\ts-field",
|
||||
"{",
|
||||
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
|
||||
"}\t\t",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "struct with array of structs field",
|
||||
reflectType: func() reflect.Type {
|
||||
type s2 struct {
|
||||
subField int
|
||||
}
|
||||
type s struct {
|
||||
field []s2
|
||||
}
|
||||
return reflect.TypeOf(s{})
|
||||
}(),
|
||||
expected: []string{
|
||||
"\"field\": [{\t(json-type-arrayjson-type-object)\ts-field",
|
||||
"[{",
|
||||
" \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
|
||||
"},...]",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
xT := func(key string) string {
|
||||
return key
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
results := btcjson.TstResultStructHelp(xT, test.reflectType, 0)
|
||||
if len(results) != len(test.expected) {
|
||||
t.Errorf("Test #%d (%s) unexpected result length - "+
|
||||
"got: %v, want: %v", i, test.name, len(results),
|
||||
len(test.expected))
|
||||
continue
|
||||
}
|
||||
for j, result := range results {
|
||||
if result != test.expected[j] {
|
||||
t.Errorf("Test #%d (%s) result #%d unexpected "+
|
||||
"result - got: %v, want: %v", i,
|
||||
test.name, j, result, test.expected[j])
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestHelpArgInternals ensures the various help functions which deal with
|
||||
// arguments work as expected for various argument types.
|
||||
func TestHelpArgInternals(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
reflectType reflect.Type
|
||||
defaults map[int]reflect.Value
|
||||
help string
|
||||
}{
|
||||
{
|
||||
name: "command with no args",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct{}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "",
|
||||
},
|
||||
{
|
||||
name: "command with one required arg",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field int
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. field (json-type-numeric, help-required) test-field\n",
|
||||
},
|
||||
{
|
||||
name: "command with one optional arg, no default",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Optional *int
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. optional (json-type-numeric, help-optional) test-optional\n",
|
||||
},
|
||||
{
|
||||
name: "command with one optional arg with default",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Optional *string
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: func() map[int]reflect.Value {
|
||||
defVal := "test"
|
||||
return map[int]reflect.Value{
|
||||
0: reflect.ValueOf(&defVal),
|
||||
}
|
||||
}(),
|
||||
help: "1. optional (json-type-string, help-optional, help-default=\"test\") test-optional\n",
|
||||
},
|
||||
{
|
||||
name: "command with struct field",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s2 struct {
|
||||
F int8
|
||||
}
|
||||
type s struct {
|
||||
Field s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. field (json-type-object, help-required) test-field\n" +
|
||||
"{\n" +
|
||||
" \"f\": n, (json-type-numeric) s2-f\n" +
|
||||
"} \n",
|
||||
},
|
||||
{
|
||||
name: "command with map field",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field map[string]float64
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. field (json-type-object, help-required) test-field\n" +
|
||||
"{\n" +
|
||||
" \"test-field--key\": test-field--value, (json-type-object) test-field--desc\n" +
|
||||
" ...\n" +
|
||||
"}\n",
|
||||
},
|
||||
{
|
||||
name: "command with slice of primitives field",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field []int64
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. field (json-type-arrayjson-type-numeric, help-required) test-field\n",
|
||||
},
|
||||
{
|
||||
name: "command with slice of structs field",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s2 struct {
|
||||
F int64
|
||||
}
|
||||
type s struct {
|
||||
Field []s2
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
defaults: nil,
|
||||
help: "1. field (json-type-arrayjson-type-object, help-required) test-field\n" +
|
||||
"[{\n" +
|
||||
" \"f\": n, (json-type-numeric) s2-f\n" +
|
||||
"},...]\n",
|
||||
},
|
||||
}
|
||||
|
||||
xT := func(key string) string {
|
||||
return key
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
help := btcjson.TstArgHelp(xT, test.reflectType, test.defaults,
|
||||
test.method)
|
||||
if help != test.help {
|
||||
t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
|
||||
"want:\n%v", i, test.name, help, test.help)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodHelp ensures the method help function works as expected for various
|
||||
// command structs.
|
||||
func TestMethodHelp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
reflectType reflect.Type
|
||||
defaults map[int]reflect.Value
|
||||
resultTypes []interface{}
|
||||
help string
|
||||
}{
|
||||
{
|
||||
name: "command with no args or results",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct{}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
help: "test\n\ntest--synopsis\n\n" +
|
||||
"help-arguments:\nhelp-arguments-none\n\n" +
|
||||
"help-result:\nhelp-result-nothing\n",
|
||||
},
|
||||
{
|
||||
name: "command with no args and one primitive result",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct{}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
resultTypes: []interface{}{(*int64)(nil)},
|
||||
help: "test\n\ntest--synopsis\n\n" +
|
||||
"help-arguments:\nhelp-arguments-none\n\n" +
|
||||
"help-result:\nn (json-type-numeric) test--result0\n",
|
||||
},
|
||||
{
|
||||
name: "command with no args and two results",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct{}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
resultTypes: []interface{}{(*int64)(nil), nil},
|
||||
help: "test\n\ntest--synopsis\n\n" +
|
||||
"help-arguments:\nhelp-arguments-none\n\n" +
|
||||
"help-result (test--condition0):\nn (json-type-numeric) test--result0\n\n" +
|
||||
"help-result (test--condition1):\nhelp-result-nothing\n",
|
||||
},
|
||||
{
|
||||
name: "command with primitive arg and no results",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field bool
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
help: "test field\n\ntest--synopsis\n\n" +
|
||||
"help-arguments:\n1. field (json-type-bool, help-required) test-field\n\n" +
|
||||
"help-result:\nhelp-result-nothing\n",
|
||||
},
|
||||
{
|
||||
name: "command with primitive optional and no results",
|
||||
method: "test",
|
||||
reflectType: func() reflect.Type {
|
||||
type s struct {
|
||||
Field *bool
|
||||
}
|
||||
return reflect.TypeOf((*s)(nil))
|
||||
}(),
|
||||
help: "test (field)\n\ntest--synopsis\n\n" +
|
||||
"help-arguments:\n1. field (json-type-bool, help-optional) test-field\n\n" +
|
||||
"help-result:\nhelp-result-nothing\n",
|
||||
},
|
||||
}
|
||||
|
||||
xT := func(key string) string {
|
||||
return key
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
help := btcjson.TestMethodHelp(xT, test.reflectType,
|
||||
test.defaults, test.method, test.resultTypes)
|
||||
if help != test.help {
|
||||
t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
|
||||
"want:\n%v", i, test.name, help, test.help)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGenerateHelpErrors ensures the GenerateHelp function returns the expected
|
||||
// errors.
|
||||
func TestGenerateHelpErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
resultTypes []interface{}
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "unregistered command",
|
||||
method: "boguscommand",
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
|
||||
},
|
||||
{
|
||||
name: "non-pointer result type",
|
||||
method: "help",
|
||||
resultTypes: []interface{}{0},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid result type",
|
||||
method: "help",
|
||||
resultTypes: []interface{}{(*complex64)(nil)},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "missing description",
|
||||
method: "help",
|
||||
resultTypes: []interface{}{(*string)(nil), nil},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrMissingDescription},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
_, err := btcjson.GenerateHelp(test.method, nil,
|
||||
test.resultTypes...)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T (%v), "+
|
||||
"want %T", i, test.name, err, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v (%v), want %v", i, test.name, gotErrorCode,
|
||||
err, test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGenerateHelp performs a very basic test to ensure GenerateHelp is working
|
||||
// as expected. The internal are testd much more thoroughly in other tests, so
|
||||
// there is no need to add more tests here.
|
||||
func TestGenerateHelp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
descs := map[string]string{
|
||||
"help--synopsis": "test",
|
||||
"help-command": "test",
|
||||
}
|
||||
help, err := btcjson.GenerateHelp("help", descs)
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateHelp: unexpected error: %v", err)
|
||||
}
|
||||
wantHelp := "help (\"command\")\n\n" +
|
||||
"test\n\nArguments:\n1. command (string, optional) test\n\n" +
|
||||
"Result:\nNothing\n"
|
||||
if help != wantHelp {
|
||||
t.Fatalf("GenerateHelp: unexpected help - got\n%v\nwant\n%v",
|
||||
help, wantHelp)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestHelpers tests the various helper functions which create pointers to
|
||||
|
|
|
@ -226,8 +226,12 @@ func NewResponse(rpcVersion RPCVersion, id interface{}, marshalledResult []byte,
|
|||
// JSON-RPC client.
|
||||
func MarshalResponse(rpcVersion RPCVersion, id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) {
|
||||
if !rpcVersion.IsValid() {
|
||||
str := fmt.Sprintf("rpcversion '%s' is invalid", rpcVersion)
|
||||
return nil, makeError(ErrInvalidType, str)
|
||||
if rpcVersion == "" {
|
||||
rpcVersion = RpcVersion1
|
||||
} else {
|
||||
str := fmt.Sprintf("rpcversion '%s' is unsupported", rpcVersion)
|
||||
return nil, makeError(ErrInvalidType, str)
|
||||
}
|
||||
}
|
||||
|
||||
marshalledResult, err := json.Marshal(result)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestIsValidIDType ensures the IsValidIDType function behaves as expected.
|
||||
|
|
|
@ -1,263 +0,0 @@
|
|||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcjson_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
)
|
||||
|
||||
// TestUsageFlagStringer tests the stringized output for the UsageFlag type.
|
||||
func TestUsageFlagStringer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
in btcjson.UsageFlag
|
||||
want string
|
||||
}{
|
||||
{0, "0x0"},
|
||||
{btcjson.UFWalletOnly, "UFWalletOnly"},
|
||||
{btcjson.UFWebsocketOnly, "UFWebsocketOnly"},
|
||||
{btcjson.UFNotification, "UFNotification"},
|
||||
{btcjson.UFWalletOnly | btcjson.UFWebsocketOnly,
|
||||
"UFWalletOnly|UFWebsocketOnly"},
|
||||
{btcjson.UFWalletOnly | btcjson.UFWebsocketOnly | (1 << 31),
|
||||
"UFWalletOnly|UFWebsocketOnly|0x80000000"},
|
||||
}
|
||||
|
||||
// Detect additional usage flags that don't have the stringer added.
|
||||
numUsageFlags := 0
|
||||
highestUsageFlagBit := btcjson.TstHighestUsageFlagBit
|
||||
for highestUsageFlagBit > 1 {
|
||||
numUsageFlags++
|
||||
highestUsageFlagBit >>= 1
|
||||
}
|
||||
if len(tests)-3 != numUsageFlags {
|
||||
t.Errorf("It appears a usage flag was added without adding " +
|
||||
"an associated stringer test")
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
result := test.in.String()
|
||||
if result != test.want {
|
||||
t.Errorf("String #%d\n got: %s want: %s", i, result,
|
||||
test.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegisterCmdErrors ensures the RegisterCmd function returns the expected
|
||||
// error when provided with invalid types.
|
||||
func TestRegisterCmdErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
cmdFunc func() interface{}
|
||||
flags btcjson.UsageFlag
|
||||
err btcjson.Error
|
||||
}{
|
||||
{
|
||||
name: "duplicate method",
|
||||
method: "getblock",
|
||||
cmdFunc: func() interface{} {
|
||||
return struct{}{}
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrDuplicateMethod},
|
||||
},
|
||||
{
|
||||
name: "invalid usage flags",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
return 0
|
||||
},
|
||||
flags: btcjson.TstHighestUsageFlagBit,
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidUsageFlags},
|
||||
},
|
||||
{
|
||||
name: "invalid type",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
return 0
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid type 2",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
return &[]string{}
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "embedded field",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ int }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrEmbeddedType},
|
||||
},
|
||||
{
|
||||
name: "unexported field",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ a int }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnexportedField},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 1",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A **int }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 2",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A chan int }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 3",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A complex64 }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 4",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A complex128 }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 5",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A func() }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "unsupported field type 6",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct{ A interface{} }
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrUnsupportedFieldType},
|
||||
},
|
||||
{
|
||||
name: "required after optional",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct {
|
||||
A *int
|
||||
B int
|
||||
}
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrNonOptionalField},
|
||||
},
|
||||
{
|
||||
name: "non-optional with default",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct {
|
||||
A int `jsonrpcdefault:"1"`
|
||||
}
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrNonOptionalDefault},
|
||||
},
|
||||
{
|
||||
name: "mismatched default",
|
||||
method: "registertestcmd",
|
||||
cmdFunc: func() interface{} {
|
||||
type test struct {
|
||||
A *int `jsonrpcdefault:"1.7"`
|
||||
}
|
||||
return (*test)(nil)
|
||||
},
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrMismatchedDefault},
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
err := btcjson.RegisterCmd(test.method, test.cmdFunc(),
|
||||
test.flags)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
t.Errorf("Test #%d (%s) wrong error - got %T, "+
|
||||
"want %T", i, test.name, err, test.err)
|
||||
continue
|
||||
}
|
||||
gotErrorCode := err.(btcjson.Error).ErrorCode
|
||||
if gotErrorCode != test.err.ErrorCode {
|
||||
t.Errorf("Test #%d (%s) mismatched error code - got "+
|
||||
"%v, want %v", i, test.name, gotErrorCode,
|
||||
test.err.ErrorCode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMustRegisterCmdPanic ensures the MustRegisterCmd function panics when
|
||||
// used to register an invalid type.
|
||||
func TestMustRegisterCmdPanic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Setup a defer to catch the expected panic to ensure it actually
|
||||
// paniced.
|
||||
defer func() {
|
||||
if err := recover(); err == nil {
|
||||
t.Error("MustRegisterCmd did not panic as expected")
|
||||
}
|
||||
}()
|
||||
|
||||
// Intentionally try to register an invalid type to force a panic.
|
||||
btcjson.MustRegisterCmd("panicme", 0, 0)
|
||||
}
|
||||
|
||||
// TestRegisteredCmdMethods tests the RegisteredCmdMethods function ensure it
|
||||
// works as expected.
|
||||
func TestRegisteredCmdMethods(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Ensure the registered methods are returned.
|
||||
methods := btcjson.RegisteredCmdMethods()
|
||||
if len(methods) == 0 {
|
||||
t.Fatal("RegisteredCmdMethods: no methods")
|
||||
}
|
||||
|
||||
// Ensure the returned methods are sorted.
|
||||
sortedMethods := make([]string, len(methods))
|
||||
copy(sortedMethods, methods)
|
||||
sort.Strings(sortedMethods)
|
||||
if !reflect.DeepEqual(sortedMethods, methods) {
|
||||
t.Fatal("RegisteredCmdMethods: methods are not sorted")
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// AddMultisigAddressCmd defines the addmutisigaddress JSON-RPC command.
|
||||
|
@ -1029,7 +1029,7 @@ type WalletCreateFundedPsbtOpts struct {
|
|||
ChangeType *ChangeType `json:"change_type,omitempty"`
|
||||
IncludeWatching *bool `json:"includeWatching,omitempty"`
|
||||
LockUnspents *bool `json:"lockUnspents,omitempty"`
|
||||
FeeRate *int64 `json:"feeRate,omitempty"`
|
||||
FeeRate *float64 `json:"feeRate,omitempty"`
|
||||
SubtractFeeFromOutputs *[]int64 `json:"subtractFeeFromOutputs,omitempty"`
|
||||
Replaceable *bool `json:"replaceable,omitempty"`
|
||||
ConfTarget *int64 `json:"conf_target,omitempty"`
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
btcutil "github.com/lbryio/lbcutil"
|
||||
)
|
||||
|
||||
// TestWalletSvrCmds tests all of the wallet server commands marshal and
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
)
|
||||
|
||||
// CreateWalletResult models the result of the createwallet command.
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lbryio/lbcd/txscript"
|
||||
)
|
||||
|
||||
// TestGetAddressInfoResult ensures that custom unmarshalling of
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestWalletSvrWsCmds tests all of the wallet server websocket-specific
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/lbryio/lbcd/btcjson"
|
||||
)
|
||||
|
||||
// TestWalletSvrWsNtfns tests all of the chain server websocket-specific
|
||||
|
|
|
@ -1,85 +1,8 @@
|
|||
chaincfg
|
||||
========
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/chaincfg)
|
||||
|
||||
Package chaincfg defines chain configuration parameters for the three standard
|
||||
Bitcoin networks and provides the ability for callers to define their own custom
|
||||
Bitcoin networks.
|
||||
|
||||
Although this package was primarily written for btcd, it has intentionally been
|
||||
designed so it can be used as a standalone package for any projects needing to
|
||||
use parameters for the standard Bitcoin networks or for projects needing to
|
||||
define their own network.
|
||||
|
||||
## Sample Use
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
)
|
||||
|
||||
var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network")
|
||||
|
||||
// By default (without -testnet), use mainnet.
|
||||
var chainParams = &chaincfg.MainNetParams
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Modify active network parameters if operating on testnet.
|
||||
if *testnet {
|
||||
chainParams = &chaincfg.TestNet3Params
|
||||
}
|
||||
|
||||
// later...
|
||||
|
||||
// Create and print new payment address, specific to the active network.
|
||||
pubKeyHash := make([]byte, 20)
|
||||
addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, chainParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(addr)
|
||||
}
|
||||
```
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/chaincfg
|
||||
```
|
||||
|
||||
## GPG Verification Key
|
||||
|
||||
All official release tags are signed by Conformal so users can ensure the code
|
||||
has not been tampered with and is coming from the btcsuite developers. To
|
||||
verify the signature perform the following:
|
||||
|
||||
- Download the public key from the Conformal website at
|
||||
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
|
||||
|
||||
- Import the public key into your GPG keyring:
|
||||
```bash
|
||||
gpg --import GIT-GPG-KEY-conformal.txt
|
||||
```
|
||||
|
||||
- Verify the release tag with the following command where `TAG_NAME` is a
|
||||
placeholder for the specific tag:
|
||||
```bash
|
||||
git tag -v TAG_NAME
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Package chaincfg is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
LBRY networks and provides the ability for callers to define their own custom
|
||||
LBRY networks.
|
|
@ -1,9 +1,9 @@
|
|||
chainhash
|
||||
=========
|
||||
|
||||
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
|
||||
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
|
||||
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/chaincfg/chainhash)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/chaincfg/chainhash)
|
||||
=======
|
||||
|
||||
chainhash provides a generic hash type and associated functions that allows the
|
||||
|
@ -12,7 +12,7 @@ specific hash algorithm to be abstracted.
|
|||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcd/chaincfg/chainhash
|
||||
$ go get -u github.com/lbryio/lbcd/chaincfg/chainhash
|
||||
```
|
||||
|
||||
## GPG Verification Key
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
|
||||
package chainhash
|
||||
|
||||
import "crypto/sha256"
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
// HashB calculates hash(b) and returns the resulting bytes.
|
||||
func HashB(b []byte) []byte {
|
||||
|
@ -31,3 +36,26 @@ func DoubleHashH(b []byte) Hash {
|
|||
first := sha256.Sum256(b)
|
||||
return Hash(sha256.Sum256(first[:]))
|
||||
}
|
||||
|
||||
// LbryPoWHashH calculates returns the PoW Hash.
|
||||
//
|
||||
// doubled := SHA256(SHA256(b))
|
||||
// expanded := SHA512(doubled)
|
||||
// left := RIPEMD160(expanded[0:32])
|
||||
// right := RIPEMD160(expanded[32:64])
|
||||
// result := SHA256(SHA256(left||right))
|
||||
func LbryPoWHashH(b []byte) Hash {
|
||||
doubled := DoubleHashB(b)
|
||||
expanded := sha512.Sum512(doubled)
|
||||
|
||||
r := ripemd160.New()
|
||||
r.Reset()
|
||||
r.Write(expanded[:sha256.Size])
|
||||
left := r.Sum(nil)
|
||||
|
||||
r.Reset()
|
||||
r.Write(expanded[sha256.Size:])
|
||||
|
||||
combined := r.Sum(left)
|
||||
return DoubleHashH(combined)
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
// "fmt"
|
||||
// "log"
|
||||
//
|
||||
// "github.com/btcsuite/btcutil"
|
||||
// "github.com/btcsuite/btcd/chaincfg"
|
||||
// btcutil "github.com/lbryio/lbcutil"
|
||||
// "github.com/lbryio/lbcd/chaincfg"
|
||||
// )
|
||||
//
|
||||
// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network")
|
||||
|
|
|
@ -7,8 +7,8 @@ package chaincfg
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lbryio/lbcd/chaincfg/chainhash"
|
||||
"github.com/lbryio/lbcd/wire"
|
||||
)
|
||||
|
||||
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
|
||||
|
@ -22,33 +22,22 @@ var genesisCoinbaseTx = wire.MsgTx{
|
|||
Index: 0xffffffff,
|
||||
},
|
||||
SignatureScript: []byte{
|
||||
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */
|
||||
0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */
|
||||
0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */
|
||||
0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */
|
||||
0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */
|
||||
0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */
|
||||
0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/
|
||||
0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */
|
||||
0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/
|
||||
0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */
|
||||
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x17,
|
||||
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
|
||||
},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 0x12a05f200,
|
||||
Value: 0x8e1bc9bf040000, // 400000000 * COIN
|
||||
PkScript: []byte{
|
||||
0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */
|
||||
0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */
|
||||
0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */
|
||||
0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */
|
||||
0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */
|
||||
0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */
|
||||
0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */
|
||||
0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */
|
||||
0x1d, 0x5f, 0xac, /* |._.| */
|
||||
0x76, 0xa9, 0x14, 0x34, 0x59, 0x91, 0xdb, 0xf5,
|
||||
0x7b, 0xfb, 0x01, 0x4b, 0x87, 0x00, 0x6a, 0xcd,
|
||||
0xfa, 0xfb, 0xfc, 0x5f, 0xe8, 0x29, 0x2f, 0x88,
|
||||
0xac,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -58,19 +47,28 @@ var genesisCoinbaseTx = wire.MsgTx{
|
|||
// genesisHash is the hash of the first block in the block chain for the main
|
||||
// network (genesis block).
|
||||
var genesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
|
||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
|
||||
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
|
||||
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
|
||||
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x63, 0xf4, 0x34, 0x6a, 0x4d, 0xb3, 0x4f, 0xdf,
|
||||
0xce, 0x29, 0xa7, 0x0f, 0x5e, 0x8d, 0x11, 0xf0,
|
||||
0x65, 0xf6, 0xb9, 0x16, 0x02, 0xb7, 0x03, 0x6c,
|
||||
0x7f, 0x22, 0xf3, 0xa0, 0x3b, 0x28, 0x89, 0x9c,
|
||||
})
|
||||
|
||||
// genesisMerkleRoot is the hash of the first transaction in the genesis block
|
||||
// for the main network.
|
||||
var genesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
|
||||
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2,
|
||||
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61,
|
||||
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32,
|
||||
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a,
|
||||
0xcc, 0x59, 0xe5, 0x9f, 0xf9, 0x7a, 0xc0, 0x92,
|
||||
0xb5, 0x5e, 0x42, 0x3a, 0xa5, 0x49, 0x51, 0x51,
|
||||
0xed, 0x6f, 0xb8, 0x05, 0x70, 0xa5, 0xbb, 0x78,
|
||||
0xcd, 0x5b, 0xd1, 0xc3, 0x82, 0x1c, 0x21, 0xb8,
|
||||
})
|
||||
|
||||
// genesisClaimTrie is the hash of the first transaction in the genesis block
|
||||
// for the main network.
|
||||
var genesisClaimTrie = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
})
|
||||
|
||||
// genesisBlock defines the genesis block of the block chain which serves as the
|
||||
|
@ -79,10 +77,11 @@ var genesisBlock = wire.MsgBlock{
|
|||
Header: wire.BlockHeader{
|
||||
Version: 1,
|
||||
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
|
||||
MerkleRoot: genesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
|
||||
Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC
|
||||
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 0x7c2bac1d, // 2083236893
|
||||
MerkleRoot: genesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
|
||||
ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
|
||||
Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
|
||||
Bits: 0x1f00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 0x00000507, // 1287
|
||||
},
|
||||
Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
|
||||
}
|
||||
|
@ -90,10 +89,10 @@ var genesisBlock = wire.MsgBlock{
|
|||
// regTestGenesisHash is the hash of the first block in the block chain for the
|
||||
// regression test network (genesis block).
|
||||
var regTestGenesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
|
||||
0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59,
|
||||
0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf,
|
||||
0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f,
|
||||
0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f,
|
||||
0x56, 0x75, 0x68, 0x69, 0x76, 0x67, 0x4f, 0x50,
|
||||
0xa0, 0xa1, 0x95, 0x3d, 0x17, 0x2e, 0x9e, 0xcf,
|
||||
0x4a, 0x4a, 0x62, 0x1d, 0xc9, 0xa4, 0xc3, 0x79,
|
||||
0x5d, 0xec, 0xd4, 0x99, 0x12, 0xcf, 0x3f, 0x6e,
|
||||
})
|
||||
|
||||
// regTestGenesisMerkleRoot is the hash of the first transaction in the genesis
|
||||
|
@ -107,10 +106,11 @@ var regTestGenesisBlock = wire.MsgBlock{
|
|||
Header: wire.BlockHeader{
|
||||
Version: 1,
|
||||
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
|
||||
MerkleRoot: regTestGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
|
||||
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
|
||||
MerkleRoot: regTestGenesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
|
||||
ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
|
||||
Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
|
||||
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 2,
|
||||
Nonce: 1,
|
||||
},
|
||||
Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
|
||||
}
|
||||
|
@ -135,10 +135,11 @@ var testNet3GenesisBlock = wire.MsgBlock{
|
|||
Header: wire.BlockHeader{
|
||||
Version: 1,
|
||||
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
|
||||
MerkleRoot: testNet3GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
|
||||
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
|
||||
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 0x18aea41a, // 414098458
|
||||
MerkleRoot: testNet3GenesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
|
||||
ClaimTrie: genesisClaimTrie, // 0000000000000000000000000000000000000000000000000000000000000001
|
||||
Timestamp: time.Unix(1446058291, 0), // 28 Oct 2015 18:51:31 +0000 UTC
|
||||
Bits: 0x1f00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 0x00000507, // 1287
|
||||
},
|
||||
Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
|
||||
}
|
||||
|
|
|
@ -1,351 +0,0 @@
|
|||
// Copyright (c) 2014-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chaincfg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
// TestGenesisBlock tests the genesis block of the main network for validity by
|
||||
// checking the encoded bytes and hashes.
|
||||
func TestGenesisBlock(t *testing.T) {
|
||||
// Encode the genesis block to raw bytes.
|
||||
var buf bytes.Buffer
|
||||
err := MainNetParams.GenesisBlock.Serialize(&buf)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGenesisBlock: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the encoded block matches the expected bytes.
|
||||
if !bytes.Equal(buf.Bytes(), genesisBlockBytes) {
|
||||
t.Fatalf("TestGenesisBlock: Genesis block does not appear valid - "+
|
||||
"got %v, want %v", spew.Sdump(buf.Bytes()),
|
||||
spew.Sdump(genesisBlockBytes))
|
||||
}
|
||||
|
||||
// Check hash of the block against expected hash.
|
||||
hash := MainNetParams.GenesisBlock.BlockHash()
|
||||
if !MainNetParams.GenesisHash.IsEqual(&hash) {
|
||||
t.Fatalf("TestGenesisBlock: Genesis block hash does not "+
|
||||
"appear valid - got %v, want %v", spew.Sdump(hash),
|
||||
spew.Sdump(MainNetParams.GenesisHash))
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegTestGenesisBlock tests the genesis block of the regression test
|
||||
// network for validity by checking the encoded bytes and hashes.
|
||||
func TestRegTestGenesisBlock(t *testing.T) {
|
||||
// Encode the genesis block to raw bytes.
|
||||
var buf bytes.Buffer
|
||||
err := RegressionNetParams.GenesisBlock.Serialize(&buf)
|
||||
if err != nil {
|
||||
t.Fatalf("TestRegTestGenesisBlock: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the encoded block matches the expected bytes.
|
||||
if !bytes.Equal(buf.Bytes(), regTestGenesisBlockBytes) {
|
||||
t.Fatalf("TestRegTestGenesisBlock: Genesis block does not "+
|
||||
"appear valid - got %v, want %v",
|
||||
spew.Sdump(buf.Bytes()),
|
||||
spew.Sdump(regTestGenesisBlockBytes))
|
||||
}
|
||||
|
||||
// Check hash of the block against expected hash.
|
||||
hash := RegressionNetParams.GenesisBlock.BlockHash()
|
||||
if !RegressionNetParams.GenesisHash.IsEqual(&hash) {
|
||||
t.Fatalf("TestRegTestGenesisBlock: Genesis block hash does "+
|
||||
"not appear valid - got %v, want %v", spew.Sdump(hash),
|
||||
spew.Sdump(RegressionNetParams.GenesisHash))
|
||||
}
|
||||
}
|
||||
|
||||
// TestTestNet3GenesisBlock tests the genesis block of the test network (version
|
||||
// 3) for validity by checking the encoded bytes and hashes.
|
||||
func TestTestNet3GenesisBlock(t *testing.T) {
|
||||
// Encode the genesis block to raw bytes.
|
||||
var buf bytes.Buffer
|
||||
err := TestNet3Params.GenesisBlock.Serialize(&buf)
|
||||
if err != nil {
|
||||
t.Fatalf("TestTestNet3GenesisBlock: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the encoded block matches the expected bytes.
|
||||
if !bytes.Equal(buf.Bytes(), testNet3GenesisBlockBytes) {
|
||||
t.Fatalf("TestTestNet3GenesisBlock: Genesis block does not "+
|
||||
"appear valid - got %v, want %v",
|
||||
spew.Sdump(buf.Bytes()),
|
||||
spew.Sdump(testNet3GenesisBlockBytes))
|
||||
}
|
||||
|
||||
// Check hash of the block against expected hash.
|
||||
hash := TestNet3Params.GenesisBlock.BlockHash()
|
||||
if !TestNet3Params.GenesisHash.IsEqual(&hash) {
|
||||
t.Fatalf("TestTestNet3GenesisBlock: Genesis block hash does "+
|
||||
"not appear valid - got %v, want %v", spew.Sdump(hash),
|
||||
spew.Sdump(TestNet3Params.GenesisHash))
|
||||
}
|
||||
}
|
||||
|
||||
// TestSimNetGenesisBlock tests the genesis block of the simulation test network
|
||||
// for validity by checking the encoded bytes and hashes.
|
||||
func TestSimNetGenesisBlock(t *testing.T) {
|
||||
// Encode the genesis block to raw bytes.
|
||||
var buf bytes.Buffer
|
||||
err := SimNetParams.GenesisBlock.Serialize(&buf)
|
||||
if err != nil {
|
||||
t.Fatalf("TestSimNetGenesisBlock: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the encoded block matches the expected bytes.
|
||||
if !bytes.Equal(buf.Bytes(), simNetGenesisBlockBytes) {
|
||||
t.Fatalf("TestSimNetGenesisBlock: Genesis block does not "+
|
||||
"appear valid - got %v, want %v",
|
||||
spew.Sdump(buf.Bytes()),
|
||||
spew.Sdump(simNetGenesisBlockBytes))
|
||||
}
|
||||
|
||||
// Check hash of the block against expected hash.
|
||||
hash := SimNetParams.GenesisBlock.BlockHash()
|
||||
if !SimNetParams.GenesisHash.IsEqual(&hash) {
|
||||
t.Fatalf("TestSimNetGenesisBlock: Genesis block hash does "+
|
||||
"not appear valid - got %v, want %v", spew.Sdump(hash),
|
||||
spew.Sdump(SimNetParams.GenesisHash))
|
||||
}
|
||||
}
|
||||
|
||||
// TestSigNetGenesisBlock tests the genesis block of the signet test network for
|
||||
// validity by checking the encoded bytes and hashes.
|
||||
func TestSigNetGenesisBlock(t *testing.T) {
|
||||
// Encode the genesis block to raw bytes.
|
||||
var buf bytes.Buffer
|
||||
err := SigNetParams.GenesisBlock.Serialize(&buf)
|
||||
if err != nil {
|
||||
t.Fatalf("TestSigNetGenesisBlock: %v", err)
|
||||
}
|
||||
|
||||
// Ensure the encoded block matches the expected bytes.
|
||||
if !bytes.Equal(buf.Bytes(), sigNetGenesisBlockBytes) {
|
||||
t.Fatalf("TestSigNetGenesisBlock: Genesis block does not "+
|
||||
"appear valid - got %v, want %v",
|
||||
spew.Sdump(buf.Bytes()),
|
||||
spew.Sdump(sigNetGenesisBlockBytes))
|
||||
}
|
||||
|
||||
// Check hash of the block against expected hash.
|
||||
hash := SigNetParams.GenesisBlock.BlockHash()
|
||||
if !SigNetParams.GenesisHash.IsEqual(&hash) {
|
||||
t.Fatalf("TestSigNetGenesisBlock: Genesis block hash does "+
|
||||
"not appear valid - got %v, want %v", spew.Sdump(hash),
|
||||
spew.Sdump(SigNetParams.GenesisHash))
|
||||
}
|
||||
}
|
||||
|
||||
// genesisBlockBytes are the wire encoded bytes for the genesis block of the
|
||||
// main network as of protocol version 60002.
|
||||
var genesisBlockBytes = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
|
||||
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
|
||||
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
|
||||
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
|
||||
0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, 0x49, /* |K.^J)._I| */
|
||||
0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c, /* |......+|| */
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
|
||||
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
|
||||
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
|
||||
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
|
||||
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
|
||||
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
|
||||
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
|
||||
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
|
||||
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
|
||||
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
|
||||
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
|
||||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
|
||||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
|
||||
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
|
||||
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
|
||||
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
|
||||
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
|
||||
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
|
||||
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
|
||||
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
|
||||
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
|
||||
}
|
||||
|
||||
// regTestGenesisBlockBytes are the wire encoded bytes for the genesis block of
|
||||
// the regression test network as of protocol version 60002.
|
||||
var regTestGenesisBlockBytes = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
|
||||
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
|
||||
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
|
||||
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
|
||||
0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */
|
||||
0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
|
||||
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
|
||||
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
|
||||
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
|
||||
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
|
||||
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
|
||||
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
|
||||
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
|
||||
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
|
||||
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
|
||||
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
|
||||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
|
||||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
|
||||
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
|
||||
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
|
||||
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
|
||||
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
|
||||
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
|
||||
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
|
||||
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
|
||||
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
|
||||
}
|
||||
|
||||
// testNet3GenesisBlockBytes are the wire encoded bytes for the genesis block of
|
||||
// the test network (version 3) as of protocol version 60002.
|
||||
var testNet3GenesisBlockBytes = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
|
||||
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
|
||||
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
|
||||
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
|
||||
0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */
|
||||
0xff, 0xff, 0x00, 0x1d, 0x1a, 0xa4, 0xae, 0x18, /* |......+|| */
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
|
||||
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
|
||||
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
|
||||
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
|
||||
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
|
||||
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
|
||||
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
|
||||
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
|
||||
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
|
||||
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
|
||||
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
|
||||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
|
||||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
|
||||
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
|
||||
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
|
||||
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
|
||||
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
|
||||
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
|
||||
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
|
||||
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
|
||||
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
|
||||
}
|
||||
|
||||
// simNetGenesisBlockBytes are the wire encoded bytes for the genesis block of
|
||||
// the simulation test network as of protocol version 70002.
|
||||
var simNetGenesisBlockBytes = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */
|
||||
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */
|
||||
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */
|
||||
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */
|
||||
0x4b, 0x1e, 0x5e, 0x4a, 0x45, 0x06, 0x86, 0x53, /* |K.^J)._I| */
|
||||
0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
|
||||
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */
|
||||
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */
|
||||
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */
|
||||
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */
|
||||
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */
|
||||
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */
|
||||
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */
|
||||
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */
|
||||
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */
|
||||
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */
|
||||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */
|
||||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */
|
||||
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */
|
||||
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */
|
||||
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */
|
||||
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */
|
||||
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */
|
||||
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */
|
||||
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */
|
||||
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
|
||||
}
|
||||
|
||||
// sigNetGenesisBlockBytes are the wire encoded bytes for the genesis block of
|
||||
// the signet test network as of protocol version 70002.
|
||||
var sigNetGenesisBlockBytes = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |...@....| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |........| */
|
||||
0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |....;...| */
|
||||
0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |z{..z.,>| */
|
||||
0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |gv.a....| */
|
||||
0x4b, 0x1e, 0x5e, 0x4a, 0x00, 0x8f, 0x4d, 0x5f, /* |..Q2:...| */
|
||||
0xae, 0x77, 0x03, 0x1e, 0x8a, 0xd2, 0x22, 0x03, /* |K.^J..M_| */
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |.w....".| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */
|
||||
0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |........| */
|
||||
0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..M.....| */
|
||||
0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |..EThe T| */
|
||||
0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |imes 03/| */
|
||||
0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* |Jan/2009| */
|
||||
0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* | Chancel| */
|
||||
0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |lor on b| */
|
||||
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |rink of| */
|
||||
0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |second b| */
|
||||
0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |ailout f| */
|
||||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |or banks| */
|
||||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |........| */
|
||||
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |*....CA.| */
|
||||
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |g....UH'| */
|
||||
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |.g..q0..| */
|
||||
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |\..(.9..| */
|
||||
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |yb...a..| */
|
||||
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |I..?L.8.| */
|
||||
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |.U......| */
|
||||
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |\8M....W| */
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue