diff --git a/.github/workflows/basic-check.yml b/.github/workflows/basic-check.yml index 7493189a..c0ef7b2a 100644 --- a/.github/workflows/basic-check.yml +++ b/.github/workflows/basic-check.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [1.19] + go: [1.18.1, 1.17.7] steps: - name: Set up Go uses: actions/setup-go@v2 diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 00000000..4fe5c215 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,88 @@ +name: Docker + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +on: + push: + branches: [ master ] + # Publish semver tags as releases. + tags: [ 'latest' ] + pull_request: + branches: [ master ] + +env: + # github.repository as / + IMAGE_NAME: madiator2011/lbcd + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@d6a3abf1bdea83574e28d40543793018b6035605 + with: + cosign-release: 'v1.7.1' + + + # Workaround: https://github.com/docker/build-push-action/issues/461 + - name: Setup Docker buildx + uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: madiator2011/lbcd + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + COSIGN_EXPERIMENTAL: "true" + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: cosign sign ${{ steps.meta.outputs.tags }}@${{ steps.build-and-push.outputs.digest }} diff --git a/.github/workflows/full-sync-part-1.yml b/.github/workflows/full-sync-part-1.yml index fd7164fe..a13bf2f7 100644 --- a/.github/workflows/full-sync-part-1.yml +++ b/.github/workflows/full-sync-part-1.yml @@ -14,7 +14,7 @@ jobs: runs-on: self-hosted strategy: matrix: - go: [1.19] + go: [1.18.1] steps: - run: | echo "Note ${{ github.event.inputs.note }}!" @@ -29,7 +29,7 @@ jobs: - name: Create datadir run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV - name: Run lbcd - run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc + 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}} diff --git a/.github/workflows/full-sync-part-2.yml b/.github/workflows/full-sync-part-2.yml index 5babd4e7..756bfa66 100644 --- a/.github/workflows/full-sync-part-2.yml +++ b/.github/workflows/full-sync-part-2.yml @@ -14,7 +14,7 @@ jobs: runs-on: self-hosted strategy: matrix: - go: [1.19] + go: [1.18.1] steps: - run: | echo "Note ${{ github.event.inputs.note }}!" @@ -31,7 +31,7 @@ jobs: - name: Copy initial data run: cp -r /home/lbry/lbcd_814k/* ${{env.TEMP_DATA_DIR}} - name: Run lbcd - run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc + 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}} diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 83e4cbee..70df90d6 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -4,7 +4,7 @@ env: # go needs absolute directories, using the $HOME variable doesn't work here. GOCACHE: /home/runner/work/go/pkg/build GOPATH: /home/runner/work/go - GO_VERSION: '^1.19' + GO_VERSION: '^1.18.1' on: push: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 281f88a2..64444cf1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,16 +28,7 @@ jobs: name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.19 - - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry docker.io - if: github.event_name != 'pull_request' - uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + go-version: 1.18.1 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 diff --git a/.goreleaser.yml b/.goreleaser.yml index f68a4732..db30c7fe 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -17,15 +17,13 @@ builds: - -trimpath ldflags: - -s -w - - -buildid= - - -X github.com/lbryio/lbcd/version.appTag={{ .Tag }} + - -X main.appBuild={{.Commit}} targets: - linux_amd64 - linux_arm64 - darwin_amd64 - darwin_arm64 - windows_amd64 - mod_timestamp: '{{ .CommitTimestamp }}' - main: ./cmd/lbcctl id: "lbcctl" @@ -34,8 +32,7 @@ builds: - -trimpath ldflags: - -s -w - - -buildid= - - -X github.com/lbryio/lbcd/version.appTag={{ .Tag }} + - -X main.appBuild={{.Commit}} env: - CGO_ENABLED=0 targets: @@ -44,11 +41,10 @@ builds: - darwin_amd64 - darwin_arm64 - windows_amd64 - mod_timestamp: '{{ .CommitTimestamp }}' checksum: name_template: 'checksums.txt' snapshot: - name_template: "{{ .Version }}+{{ .Commit }}" + name_template: "{{ incpatch .Version }}-next" changelog: sort: asc filters: @@ -56,13 +52,6 @@ changelog: - '^docs:' - '^test:' -dockers: - - use: buildx - dockerfile: Dockerfile.goreleaser - image_templates: - - "docker.io/lbry/lbcd:{{ .Tag }}" - - "docker.io/lbry/lbcd:latest" - release: draft: true prerelease: auto diff --git a/Dockerfile b/Dockerfile index 3065cd9b..d52b168a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ ARG ARCH=amd64 -FROM golang:1.19 AS build-container +FROM golang:1.18.1 AS build-container ARG ARCH diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser deleted file mode 100644 index 2a8943df..00000000 --- a/Dockerfile.goreleaser +++ /dev/null @@ -1,9 +0,0 @@ -FROM debian:bullseye-20220418-slim - -COPY lbcd lbcctl /bin/ - -VOLUME ["/root/.lbcd"] - -EXPOSE 9245 9246 - -ENTRYPOINT ["lbcd"] diff --git a/README.md b/README.md index ee8f1c53..16800c6f 100644 --- a/README.md +++ b/README.md @@ -5,310 +5,17 @@ [![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) -**lbcd** is a full node implementation of LBRY's blockchain written in Go (golang). +`lbcd` is a full node implementation of LBRY's blockchain written in Go (golang). -Software stack developed by LBRY teams has been all migrated to **lbcd**. +This project is currently under active development and is in a Beta state 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. -We're working with exchanges and pool oerators to migrate from **lbrycrd** to **lbcd**. - -If you're integrating with **lbcd+lbcwallet**, please check the Wiki for current [supported RPCs](wiki/RPC-availability). - -Note: **lbcd** does *NOT* include wallet functionality. That functionality is provided by the +Note: `lbcd` does *NOT* include wallet functionality. That functionality is provided by the [lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk). -## Requirements - -All common operating systems are supported. lbcd requires at least 8GB of RAM -and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time. -Using a fast NVMe disk is recommended. - -## Installation - -Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases) - -For compilation, [Go](http://golang.org) 1.19 or newer is required. -Install Go according to its [installation instructions](http://golang.org/doc/install). - -``` sh -# lbcd (full node) -$ go install github.com/lbryio/lbcd@latest - -# lbcctl (rpc client utility) -$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest -``` - -## Usage - -Default application folder `${LBCDDIR}`: - -- Linux: `~/.lbcd/` -- MacOS: `/Users//Library/Application Support/Lbcd/` - -### Start the **lbcd** - -``` sh -./lbcd -``` - -**lbcd** loads config file at `"${LBCDDIR}/lbcd.conf"`. - -If no config is found, it creates a [default one](sample-lbcd.conf), which includes all available options with default settings except randomly generated *RPC credentials* (see below). - -### RPC server - -RPC credentials (`rpcuser` and `rpcpass`) is required to enable RPC server. It can be specify in the `"${LBCDDIR}/lbcd.conf"`, using command line options: - -``` sh -./lbcd --rpcuser=rpcuser --rpcpass=rpcpass - -2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on 0.0.0.0:9245 -2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on [::]:9245 -``` - -### Working with TLS (Default) - -By default, **lbcd** runs RPC server with TLS enabled, and generates the `rpc.cert` and `rpc.key` under `${LBCDDIR}`, if not exist already. - -To interact with the RPC server, a client has to either specify the `rpc.cert`, or disable the certification verification for TLS. - -Interact with **lbcd** RPC using `lbcctl` - -``` sh -$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount - -# or disable the certificate verification -$ ./lbcctl --skipverify getblockcount - -1200062 -``` - -Interact with **lbcd** RPC using `curl` - -``` sh -$ curl --user rpcuser:rpcpass \ - --cacert "${LBCDDIR}/rpc.cert" \ - --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \ - -H 'content-type: text/plain;' \ - https://127.0.0.1:9245/ - -# or disable the certificate verification -$ curl --user rpcuser:rpcpass \ - --insecure \ - --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \ - -H 'content-type: text/plain;' \ - https://127.0.0.1:9245/ -``` - -``` json -{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"} -``` - -### Working without TLS - -TLS can be disabled using the `--notls` option: - -``` sh -$ ./lbcd --notls -``` - -``` sh -$ ./lbcctl --notls getblockcount - -1200062 -``` - -``` sh -$ curl --user rpcuser:rpcpass \ - --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \ - -H 'content-type: text/plain;' \ - http://127.0.0.1:9245/ -``` - -``` json -{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"} -``` - -## Using Snapshots (optional) - -[Snapshots](https://snapshots.lbry.com/blockchain/) are created bi-weekly to help new users catch up current block height. - -The snapshots are archived and compressed in [zstd](https://facebook.github.io/zstd/) format for it's compression ratio and speed. - -Download the snapshot, and uncompress it: - -``` sh -time curl -O https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst -zstd -d --stdout lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | tar xf - -C "${LBCDDIR}" -``` - -If preferred, a user can download and uncompress the snapshot on the fly: -By the time the download is finished, the snapshots should be almost uncompressed already. - -``` sh -mkdir -p "${LBCDDIR}" - -time curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | zstd -d --stdout | tar xf - -C "${LBCDDIR}" - -# % Total % Received % Xferd Average Speed Time Time Time Current -# Dload Upload Total Spent Left Speed -# 100 64.9G 100 64.9G 0 0 37.0M 0 0:29:49 0:29:49 --:--:-- 33.0M -# -# real 29m49.962s -# user 6m53.710s -# sys 8m56.545s -``` - -## Working with RPCs - -Using `lbcctl -l` to list available RPCs: - -``` sh -$ lbcctl -l - -Chain Server Commands: -addnode "addr" "add|remove|onetry" -createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime) -debuglevel "levelspec" -decoderawtransaction "hextx" -decodescript "hexscript" -deriveaddresses "descriptor" ({"value":value}) -fundrawtransaction "hextx" {"changeaddress":changeaddress,"changeposition":changeposition,"changetype":changetype,"includewatching":includewatching,"lockunspents":lockunspents,"feerate":feerate,"subtractfeefromoutputs":[subtractfeefromoutput,...],"replaceable":replaceable,"conftarget":conftarget,"estimatemode":estimatemode} (iswitness) -generate numblocks - -[skipped] - -Wallet Server Commands (--wallet): -addmultisigaddress nrequired ["key",...] ("account") -addwitnessaddress "address" -backupwallet "destination" -createmultisig nrequired ["key",...] -createnewaccount "account" -createwallet "walletname" (disableprivatekeys=false blank=false passphrase="" avoidreuse=false) -dumpprivkey "address" -dumpwallet "filename" -encryptwallet "passphrase" -estimatefee numblocks -estimatepriority numblocks -estimatesmartfee conftarget (estimatemode="CONSERVATIVE") -getaccount "address" -getaccountaddress "account" -getaddressesbyaccount "account" - -[skipped] -``` - -Using `lbcctl help rpcname` to show the RPC spec: - -``` sh -$ lbcctl help getblock - -getblock "hash" (verbosity=1) - -Returns information about a block given its hash. - -Arguments: -1. hash (string, required) The hash of the block -2. verbosity (numeric, optional, default=1) Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2) - -Result (verbosity=0): -"value" (string) Hex-encoded bytes of the serialized block - -Result (verbosity=1): -{ - "getblockverboseresultbase": { (object) - "hash": "value", (string) The hash of the block (same as provided) - "confirmations": n, (numeric) The number of confirmations - "strippedsize": n, (numeric) The size of the block without witness data - "size": n, (numeric) The size of the block - "weight": n, (numeric) The weight of the block - "height": n, (numeric) The height of the block in the block chain - "version": n, (numeric) The block version - "versionHex": "value", (string) The block version in hexadecimal - "merkleroot": "value", (string) Root hash of the merkle tree - "time": n, (numeric) The block time in seconds since 1 Jan 1970 GMT - "mediantime": n, (numeric) The median block time in seconds since 1 Jan 1970 GMT - "nonce": n, (numeric) The block nonce - "bits": "value", (string) The bits which represent the block difficulty - "difficulty": n.nnn, (numeric) The proof-of-work difficulty as a multiple of the minimum difficulty - "chainwork": "value", (string) Expected number of hashes required to produce the chain up to this block (in hex) - "previousblockhash": "value", (string) The hash of the previous block - "nextblockhash": "value", (string) The hash of the next block (only if there is one) - "nameclaimroot": "value", (string) Root hash of the claim trie - "nTx": n, (numeric) The number of transactions (aka, count of TX) - }, - "tx": ["value",...], (array of string) The transaction hashes (only when verbosity=1) -} -``` - -## **lbcd** & **lbcwallet** - -*Wallet* related functianlities and RPCs are provided by a separate programe - [**lbcwallet**](https://github.com/lbryio/lbcwallet). - -Once setup, lbcwallet can serve wallet related RPCs as well as proxy lbcd RPCs to an assocated lbcd now. -It's sufficient for user to connect just the **lbcwallet** instead of both. - -``` mermaid -sequenceDiagram - actor C as lbcctl - participant W as lbcwallet (port: 9244) - participant D as lbcd (port: 9245) - - rect rgb(200,200,200) - Note over C,D: lbcctl getblockcount - C ->>+ D: getblockcount - D -->>- C: response - end - - rect rgb(200,200,200) - Note over C,W: lbcctl --wallet balance - C ->>+ W: getbalance - W -->>- C: response - end - - rect rgb(200,200,200) - Note over C,D: lbcctl --wallet getblockcount (lbcd RPC service proxied by lbcwallet) - C ->>+ W: getblockcount - W ->>+ D: getblockcount - D -->>- W: response - W -->>- C: response - end -``` - -While **lbcd** can run standalone as a full node, **lbcwallet** requires an associated **lbcd** instance for scanning and sync'ing block data. - -``` mermaid -sequenceDiagram - participant W as lbcwallet (RPC port: 9244) - participant D as lbcd (RPC port: 9245, P2P port: 9246) - participant D2 as other lbcd node(s) (P2P port: 9246) - - rect rgb(200,200,200) - Note over W,D: Asynchronous websocket notifications - W ->> D: subscribe to notifications - D -->> W: notification - D -->> W: notification - end - - rect rgb(200,200,200) - Note over W,D: lbcd RPCs - W ->>+ D: getblockheader - D ->>- W: response - end - - rect rgb(200,200,200) - Note over D,D2: P2P messages over port 9246 - D -->> D2: P2P message - D2 -->> D: P2P message - end - -``` - -## Data integrity - -**lbcd** is not immune to data loss. It expects a clean shutdown via SIGINT or -SIGTERM. SIGKILL, immediate VM kills, and sudden power loss can cause data -corruption, thus requiring chain resynchronization for recovery. - ## Security We take security seriously. Please contact [security](mailto:security@lbry.com) regarding any security issues. @@ -317,6 +24,97 @@ Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it. We maintain a mailing list for notifications of upgrades, security issues, and soft/hard forks. To join, visit [fork list](https://lbry.com/forklist) +## Requirements + +All common operating systems are supported. lbcd requires at least 8GB of RAM +and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time. +Using a fast NVMe disk is recommended. + +`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 + +Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases) + +### To build from Source on Linux/BSD/MacOSX/POSIX + +Install Go according to its [installation instructions](http://golang.org/doc/install). + +``` sh +git clone https://github.com/lbryio/lbcd +cd lbcd + +# Build lbcd +go build . + +# Build lbcctl +go build ./cmd/lbcctl +``` + +Both [GoLand](https://www.jetbrains.com/go/) +and [VS Code](https://code.visualstudio.com/docs/languages/go) IDEs are supported. + +## Usage + +By default, data and logs are stored in ``: + +- Linux: `~/.lbcd/` +- MacOS: `/Users//Library/Application Support/Lbcd/` + +To enable RPC access a username and password is required. Example: + +``` sh +./lbcd --txindex --rpcuser=rpcuser --rpcpass=rpcpass +``` + +Interact with lbcd via RPC using `lbcctl` + +``` sh +./lbcctl --rpcuser=rpcuser --rpcpass=rpcpass getblockcount +./lbcctl --rpcuser=rpcuser --rpcpass=rpcpass getblocktemplate +``` + +By default, the RPCs are served over TLS. `lbcd` generates (if not exists) `rpc.cert` and +`rpc.key` under `` where `lbcctl` would search and use them. + +The RPCs can also be served without TLS *(on localhost only)* using (`--notls`) + +``` sh +./lbcd --txindex --rpcuser=rpcuser --rpcpass=rpcpass --notls +./lbcctl --rpcuser=rpcuser --rpcpass=rpcpass --notls getblockcount +``` + +## Working with Different Networks + +By default, `lbcd` and `lbcctl` use the following ports for different networks respectively: + +| Network | RPC Port | Network Port | +| ------- | -------- | ------------ | +| mainnet | 9245 | 9246 | +| testnet | 19245 | 19246 | +| regtest | 29245 | 29246 | + +Running `lbcd` and `lbcctl` with `--testnet` or `--regtest` would use different chain params as well as default RPC and Network ports. + +``` sh +./lbcd --txindex --rpcuser=rpcuser --rpcpass=rpcpass --regtest +./lbcctl --rpcuser=rpcuser --rpcpass=rpcpass --regtest getblockcount +``` + +The default Network and RPC ports of `lbcd` can be overriden using `--listen` and `--rpclisten` +`lbcctl` can also connect to RPC server specified by `--rpcserver` + +``` sh +./lbcd --txindex --rpcuser=rpcuser --rpcpass=rpcpass --regtest --listen=127.0.0.1:29248 --rpclisten=127.0.0.1:29247 +./lbcctl --rpcuser=rpcuser --rpcpass=rpcpass --regtest --rpcserver=127.0.0.1:29247 getblockcount +``` + +Note: Wallet related RPCs are provided by [lbcwallet](https://github.com/lbryio/lbcwallet). + ## Contributing Contributions to this project are welcome, encouraged, and compensated. diff --git a/addrmgr/doc.go b/addrmgr/doc.go index c500fbb5..8ddc8bfd 100644 --- a/addrmgr/doc.go +++ b/addrmgr/doc.go @@ -5,7 +5,7 @@ /* Package addrmgr implements concurrency safe Bitcoin address manager. -# Address Manager Overview +Address Manager Overview In order maintain the peer-to-peer Bitcoin network, there needs to be a source of addresses to connect to as nodes come and go. The Bitcoin protocol provides diff --git a/blockchain/chain.go b/blockchain/chain.go index b2690422..9a6ec216 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -8,7 +8,6 @@ package blockchain import ( "container/list" "fmt" - "math/big" "sync" "time" @@ -37,9 +36,8 @@ const ( // from the block being located. // // For example, assume a block chain with a side chain as depicted below: -// -// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18 -// \-> 16a -> 17a +// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18 +// \-> 16a -> 17a // // The block locator for block 17a would be the hashes of blocks: // [17a 16a 15 14 13 12 11 10 9 8 7 6 4 genesis] @@ -489,7 +487,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView // LockTimeToSequence converts the passed relative locktime to a sequence // number in accordance to BIP-68. // See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki -// - (Compatibility) +// * (Compatibility) func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 { // If we're expressing the relative lock time in blocks, then the // corresponding sequence number is simply the desired input age. @@ -1108,8 +1106,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // a reorganization to become the main chain). // // The flags modify the behavior of this function as follows: -// - BFFastAdd: Avoids several expensive transaction validation operations. -// This is useful when using checkpoints. +// - BFFastAdd: Avoids several expensive transaction validation operations. +// This is useful when using checkpoints. // // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) { @@ -1250,8 +1248,8 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla // isCurrent returns whether or not the chain believes it is current. Several // factors are used to guess, but the key factors that allow the chain to // believe it is current are: -// - Latest block height is after the latest checkpoint (if enabled) -// - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin) +// - Latest block height is after the latest checkpoint (if enabled) +// - Latest block has a timestamp newer than ~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 { @@ -1274,8 +1272,8 @@ func (b *BlockChain) isCurrent() bool { // IsCurrent returns whether or not the chain believes it is current. Several // factors are used to guess, but the key factors that allow the chain to // believe it is current are: -// - Latest block height is after the latest checkpoint (if enabled) -// - Latest block has a timestamp newer than 24 hours ago +// - Latest block height is after the latest checkpoint (if enabled) +// - Latest block has a timestamp newer than 24 hours ago // // This function is safe for concurrent access. func (b *BlockChain) IsCurrent() bool { @@ -1375,57 +1373,6 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro return &node.hash, nil } -// BlockAttributes desribes a Block in relation to others on the main chain. -type BlockAttributes struct { - Height int32 - Confirmations int32 - MedianTime time.Time - ChainWork *big.Int - PrevHash *chainhash.Hash - NextHash *chainhash.Hash -} - -// BlockAttributesByHash returns BlockAttributes for the block with the given hash -// relative to other blocks in the main chain. A BestState snapshot describing -// the main chain is also returned for convenience. -// -// This function is safe for concurrent access. -func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) ( - attrs *BlockAttributes, best *BestState, err error) { - best = b.BestSnapshot() - node := b.index.LookupNode(hash) - if node == nil { - str := fmt.Sprintf("block %s not found", hash) - return nil, best, errNotInMainChain(str) - } - - attrs = &BlockAttributes{ - Height: node.height, - Confirmations: 1 + best.Height - node.height, - MedianTime: node.CalcPastMedianTime(), - ChainWork: node.workSum, - } - if !b.bestChain.Contains(node) { - attrs.Confirmations = -1 - } - - // Populate prev block hash if there is one. - if node.height > 0 { - attrs.PrevHash = prevHash - } - - // Populate next block hash if there is one. - if node.height < best.Height { - nextHash, err := b.BlockHashByHeight(node.height + 1) - if err != nil { - return nil, best, err - } - attrs.NextHash = nextHash - } - - return attrs, best, nil -} - // HeightRange returns a range of block hashes for the given start and end // heights. It is inclusive of the start height and exclusive of the end // height. The end height will be limited to the current main chain height. @@ -1561,11 +1508,11 @@ func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int, // // In addition, there are two special cases: // -// - When no locators are provided, the stop hash is treated as a request for -// that block, so it will either return the node associated with the stop hash -// if it is known, or nil if it is unknown -// - When locators are provided, but none of them are known, nodes starting -// after the genesis block will be returned +// - When no locators are provided, the stop hash is treated as a request for +// that block, so it will either return the node associated with the stop hash +// if it is known, or nil if it is unknown +// - When locators are provided, but none of them are known, nodes starting +// after the genesis block will be returned // // This is primarily a helper function for the locateBlocks and locateHeaders // functions. @@ -1649,11 +1596,11 @@ func (b *BlockChain) locateBlocks(locator BlockLocator, hashStop *chainhash.Hash // // In addition, there are two special cases: // -// - When no locators are provided, the stop hash is treated as a request for -// that block, so it will either return the stop hash itself if it is known, -// or nil if it is unknown -// - When locators are provided, but none of them are known, hashes starting -// after the genesis block will be returned +// - When no locators are provided, the stop hash is treated as a request for +// that block, so it will either return the stop hash itself if it is known, +// or nil if it is unknown +// - When locators are provided, but none of them are known, hashes starting +// after the genesis block will be returned // // This function is safe for concurrent access. func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash { @@ -1694,11 +1641,11 @@ func (b *BlockChain) locateHeaders(locator BlockLocator, hashStop *chainhash.Has // // In addition, there are two special cases: // -// - When no locators are provided, the stop hash is treated as a request for -// that header, so it will either return the header for the stop hash itself -// if it is known, or nil if it is unknown -// - When locators are provided, but none of them are known, headers starting -// after the genesis block will be returned +// - When no locators are provided, the stop hash is treated as a request for +// that header, so it will either return the header for the stop hash itself +// if it is known, or nil if it is unknown +// - When locators are provided, but none of them are known, headers starting +// after the genesis block will be returned // // This function is safe for concurrent access. func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader { diff --git a/blockchain/chainview.go b/blockchain/chainview.go index dd70ab2d..a4c3692c 100644 --- a/blockchain/chainview.go +++ b/blockchain/chainview.go @@ -36,13 +36,11 @@ func fastLog2Floor(n uint32) uint8 { // for comparing chains. // // For example, assume a block chain with a side chain as depicted below: -// -// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -// \-> 4a -> 5a -> 6a +// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 +// \-> 4a -> 5a -> 6a // // The chain view for the branch ending in 6a consists of: -// -// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a +// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a type chainView struct { mtx sync.Mutex nodes []*blockNode @@ -260,14 +258,12 @@ func (c *chainView) next(node *blockNode) *blockNode { // view. // // For example, assume a block chain with a side chain as depicted below: -// -// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -// \-> 4a -> 5a -> 6a +// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 +// \-> 4a -> 5a -> 6a // // Further, assume the view is for the longer chain depicted above. That is to // say it consists of: -// -// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 +// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 // // Invoking this function with block node 5 would return block node 6 while // invoking it with block node 5a would return nil since that node is not part @@ -325,14 +321,12 @@ func (c *chainView) findFork(node *blockNode) *blockNode { // the chain view. It will return nil if there is no common block. // // For example, assume a block chain with a side chain as depicted below: -// -// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8 -// \-> 6a -> 7a +// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8 +// \-> 6a -> 7a // // Further, assume the view is for the longer chain depicted above. That is to // say it consists of: -// -// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8. +// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8. // // Invoking this function with block node 7a would return block node 5 while // invoking it with block node 7 would return itself since it is already part of diff --git a/blockchain/checkpoints.go b/blockchain/checkpoints.go index 800167d2..e9b2d5a2 100644 --- a/blockchain/checkpoints.go +++ b/blockchain/checkpoints.go @@ -185,14 +185,14 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool { // checkpoint candidate. // // The factors used to determine a good checkpoint are: -// - The block must be in the main chain -// - The block must be at least 'CheckpointConfirmations' blocks prior to the -// current end of the main chain -// - The timestamps for the blocks before and after the checkpoint must have -// timestamps which are also before and after the checkpoint, respectively -// (due to the median time allowance this is not always the case) -// - The block must not contain any strange transaction such as those with -// nonstandard scripts +// - The block must be in the main chain +// - The block must be at least 'CheckpointConfirmations' blocks prior to the +// current end of the main chain +// - The timestamps for the blocks before and after the checkpoint must have +// timestamps which are also before and after the checkpoint, respectively +// (due to the median time allowance this is not always the case) +// - The block must not contain any strange transaction such as those with +// nonstandard scripts // // The intent is that candidates are reviewed by a developer to make the final // decision and then manually added to the list of checkpoints for a network. diff --git a/blockchain/difficulty.go b/blockchain/difficulty.go index 1ceb0da1..051998ba 100644 --- a/blockchain/difficulty.go +++ b/blockchain/difficulty.go @@ -42,21 +42,18 @@ func HashToBig(hash *chainhash.Hash) *big.Int { // Like IEEE754 floating point, there are three basic components: the sign, // the exponent, and the mantissa. They are broken out as follows: // -// - the most significant 8 bits represent the unsigned base 256 exponent +// * the most significant 8 bits represent the unsigned base 256 exponent +// * bit 23 (the 24th bit) represents the sign bit +// * the least significant 23 bits represent the mantissa // -// - bit 23 (the 24th bit) represents the sign bit -// -// - the least significant 23 bits represent the mantissa -// -// ------------------------------------------------- -// | Exponent | Sign | Mantissa | -// ------------------------------------------------- -// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | -// ------------------------------------------------- +// ------------------------------------------------- +// | Exponent | Sign | Mantissa | +// ------------------------------------------------- +// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | +// ------------------------------------------------- // // The formula to calculate N is: -// -// N = (-1^sign) * mantissa * 256^(exponent-3) +// N = (-1^sign) * mantissa * 256^(exponent-3) // // This compact form is only used in bitcoin to encode unsigned 256-bit numbers // which represent difficulty targets, thus there really is not a need for a diff --git a/blockchain/doc.go b/blockchain/doc.go index d57acc29..24417541 100644 --- a/blockchain/doc.go +++ b/blockchain/doc.go @@ -26,42 +26,42 @@ caller a high level of flexibility in how they want to react to certain events such as orphan blocks which need their parents requested and newly connected main chain blocks which might result in wallet updates. -# Bitcoin Chain Processing Overview +Bitcoin Chain Processing Overview Before a block is allowed into the block chain, it must go through an intensive series of validation rules. The following list serves as a general outline of those rules to provide some intuition into what is going on under the hood, but is by no means exhaustive: - - Reject duplicate blocks - - Perform a series of sanity checks on the block and its transactions such as - verifying proof of work, timestamps, number and character of transactions, - transaction amounts, script complexity, and merkle root calculations - - Compare the block against predetermined checkpoints for expected timestamps - and difficulty based on elapsed time since the checkpoint - - Save the most recent orphan blocks for a limited time in case their parent - blocks become available - - Stop processing if the block is an orphan as the rest of the processing - depends on the block's position within the block chain - - Perform a series of more thorough checks that depend on the block's position - within the block chain such as verifying block difficulties adhere to - difficulty retarget rules, timestamps are after the median of the last - several blocks, all transactions are finalized, checkpoint blocks match, and - block versions are in line with the previous blocks - - Determine how the block fits into the chain and perform different actions - accordingly in order to ensure any side chains which have higher difficulty - than the main chain become the new main chain - - When a block is being connected to the main chain (either through - reorganization of a side chain to the main chain or just extending the - main chain), perform further checks on the block's transactions such as - verifying transaction duplicates, script complexity for the combination of - connected scripts, coinbase maturity, double spends, and connected - transaction values - - Run the transaction scripts to verify the spender is allowed to spend the - coins - - Insert the block into the block database + - Reject duplicate blocks + - Perform a series of sanity checks on the block and its transactions such as + verifying proof of work, timestamps, number and character of transactions, + transaction amounts, script complexity, and merkle root calculations + - Compare the block against predetermined checkpoints for expected timestamps + and difficulty based on elapsed time since the checkpoint + - Save the most recent orphan blocks for a limited time in case their parent + blocks become available + - Stop processing if the block is an orphan as the rest of the processing + depends on the block's position within the block chain + - Perform a series of more thorough checks that depend on the block's position + within the block chain such as verifying block difficulties adhere to + difficulty retarget rules, timestamps are after the median of the last + several blocks, all transactions are finalized, checkpoint blocks match, and + block versions are in line with the previous blocks + - Determine how the block fits into the chain and perform different actions + accordingly in order to ensure any side chains which have higher difficulty + than the main chain become the new main chain + - When a block is being connected to the main chain (either through + reorganization of a side chain to the main chain or just extending the + main chain), perform further checks on the block's transactions such as + verifying transaction duplicates, script complexity for the combination of + connected scripts, coinbase maturity, double spends, and connected + transaction values + - Run the transaction scripts to verify the spender is allowed to spend the + coins + - Insert the block into the block database -# Errors +Errors Errors returned by this package are either the raw errors provided by underlying calls or of type blockchain.RuleError. This allows the caller to differentiate @@ -70,12 +70,12 @@ violations through type assertions. In addition, callers can programmatically determine the specific rule violation by examining the ErrorCode field of the type asserted blockchain.RuleError. -# Bitcoin Improvement Proposals +Bitcoin Improvement Proposals This package includes spec changes outlined by the following BIPs: - BIP0016 (https://en.bitcoin.it/wiki/BIP_0016) - BIP0030 (https://en.bitcoin.it/wiki/BIP_0030) - BIP0034 (https://en.bitcoin.it/wiki/BIP_0034) + BIP0016 (https://en.bitcoin.it/wiki/BIP_0016) + BIP0030 (https://en.bitcoin.it/wiki/BIP_0030) + BIP0034 (https://en.bitcoin.it/wiki/BIP_0034) */ package blockchain diff --git a/blockchain/fullblocktests/generate.go b/blockchain/fullblocktests/generate.go index 1e53e8fe..56f4601a 100644 --- a/blockchain/fullblocktests/generate.go +++ b/blockchain/fullblocktests/generate.go @@ -464,9 +464,9 @@ func createSpendTxForTx(tx *wire.MsgTx, fee btcutil.Amount) *wire.MsgTx { // - A coinbase that pays the required subsidy to an OP_TRUE script // - When a spendable output is provided: // - A transaction that spends from the provided output the following outputs: -// - One that pays the inputs amount minus 1 atom to an OP_TRUE script -// - One that contains an OP_RETURN output with a random uint64 in order to -// ensure the transaction has a unique hash +// - One that pays the inputs amount minus 1 atom to an OP_TRUE script +// - One that contains an OP_RETURN output with a random uint64 in order to +// ensure the transaction has a unique hash // // Additionally, if one or more munge functions are specified, they will be // invoked with the block prior to solving it. This provides callers with the diff --git a/blockchain/indexers/blocklogger.go b/blockchain/indexers/blocklogger.go index f7ec1408..845618e7 100644 --- a/blockchain/indexers/blocklogger.go +++ b/blockchain/indexers/blocklogger.go @@ -27,9 +27,8 @@ type blockProgressLogger struct { // newBlockProgressLogger returns a new block progress logger. // The progress message is templated as follows: -// -// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} -// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) +// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} +// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger { return &blockProgressLogger{ lastBlockLogTime: time.Now(), diff --git a/blockchain/merkle.go b/blockchain/merkle.go index 107c93cf..92b59c5e 100644 --- a/blockchain/merkle.go +++ b/blockchain/merkle.go @@ -11,7 +11,6 @@ import ( "github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/lbryio/lbcd/txscript" - "github.com/lbryio/lbcd/wire" btcutil "github.com/lbryio/lbcutil" ) @@ -87,7 +86,7 @@ func HashMerkleBranches(left *chainhash.Hash, right *chainhash.Hash) *chainhash. // // The above stored as a linear array is as follows: // -// [h1 h2 h3 h4 h12 h34 root] +// [h1 h2 h3 h4 h12 h34 root] // // As the above shows, the merkle root is always the last element in the array. // @@ -228,20 +227,6 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error { // coinbase transaction MUST have exactly one witness element within // its witness data and that element must be exactly // CoinbaseWitnessDataLen bytes. - // - // Some popular pool software, for example yiimp, uses pre-BIP0141 - // coinbase struture. In this case, we don't just accept it, but also - // turn it into post-BIP0141 format. - if len(coinbaseTx.MsgTx().TxIn[0].Witness) == 0 { - log.Infof("pre-BIP0141 coinbase transaction detected. Height: %d", blk.Height()) - - var witnessNonce [CoinbaseWitnessDataLen]byte - coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]} - blk.MsgBlock().Transactions[0].TxIn[0].Witness = wire.TxWitness{witnessNonce[:]} - - // Clear cached serialized block. - blk.SetBytes(nil) - } coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness if len(coinbaseWitness) != 1 { str := fmt.Sprintf("the coinbase transaction has %d items in "+ diff --git a/blockchain/notifications.go b/blockchain/notifications.go index 5139e89e..25cc4f1f 100644 --- a/blockchain/notifications.go +++ b/blockchain/notifications.go @@ -50,9 +50,9 @@ func (n NotificationType) String() string { // Notification defines notification that is sent to the caller via the callback // function provided during the call to New and consists of a notification type // as well as associated data that depends on the type as follows: -// - NTBlockAccepted: *btcutil.Block -// - NTBlockConnected: *btcutil.Block -// - NTBlockDisconnected: *btcutil.Block +// - NTBlockAccepted: *btcutil.Block +// - NTBlockConnected: *btcutil.Block +// - NTBlockDisconnected: *btcutil.Block type Notification struct { Type NotificationType Data interface{} diff --git a/blockchain/upgrade.go b/blockchain/upgrade.go index 258b40d7..a899cb4e 100644 --- a/blockchain/upgrade.go +++ b/blockchain/upgrade.go @@ -232,25 +232,24 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t // // The legacy format is as follows: // -//
[,...] +//
[,...] // -// Field Type Size -// version VLQ variable -// block height VLQ variable -// header code VLQ variable -// unspentness bitmap []byte variable -// compressed txouts -// compressed amount VLQ variable -// compressed script []byte variable +// Field Type Size +// version VLQ variable +// block height VLQ variable +// header code VLQ variable +// unspentness bitmap []byte variable +// compressed txouts +// compressed amount VLQ variable +// compressed script []byte variable // // The serialized header code format is: -// -// bit 0 - containing transaction is a coinbase -// bit 1 - output zero is unspent -// bit 2 - output one is unspent -// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2 -// are unset, it encodes N-1 since there must be at least one unspent -// output. +// bit 0 - containing transaction is a coinbase +// bit 1 - output zero is unspent +// bit 2 - output one is unspent +// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2 +// are unset, it encodes N-1 since there must be at least one unspent +// output. // // The rationale for the header code scheme is as follows: // - Transactions which only pay to a single output and a change output are @@ -270,65 +269,65 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t // From tx in main blockchain: // Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098 // -// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 -// <><><><------------------------------------------------------------------> -// | | \--------\ | -// | height | compressed txout 0 -// version header code +// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 +// <><><><------------------------------------------------------------------> +// | | \--------\ | +// | height | compressed txout 0 +// version header code // -// - version: 1 -// - height: 1 -// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness) -// - unspentness: Nothing since it is zero bytes -// - compressed txout 0: -// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) -// - 0x04: special script type pay-to-pubkey -// - 0x96...52: x-coordinate of the pubkey +// - version: 1 +// - height: 1 +// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness) +// - unspentness: Nothing since it is zero bytes +// - compressed txout 0: +// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) +// - 0x04: special script type pay-to-pubkey +// - 0x96...52: x-coordinate of the pubkey // // Example 2: // From tx in main blockchain: // Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f // -// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 -// <><----><><><------------------------------------------><--------------------------------------------> -// | | | \-------------------\ | | -// version | \--------\ unspentness | compressed txout 2 -// height header code compressed txout 0 +// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 +// <><----><><><------------------------------------------><--------------------------------------------> +// | | | \-------------------\ | | +// version | \--------\ unspentness | compressed txout 2 +// height header code compressed txout 0 // -// - version: 1 -// - height: 113931 -// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap) -// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent) -// NOTE: It's +2 since the first two outputs are encoded in the header code -// - compressed txout 0: -// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC) -// - 0x00: special script type pay-to-pubkey-hash -// - 0xe2...8a: pubkey hash -// - compressed txout 2: -// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC) -// - 0x00: special script type pay-to-pubkey-hash -// - 0xb8...58: pubkey hash +// - version: 1 +// - height: 113931 +// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap) +// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent) +// NOTE: It's +2 since the first two outputs are encoded in the header code +// - compressed txout 0: +// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0xe2...8a: pubkey hash +// - compressed txout 2: +// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0xb8...58: pubkey hash // // Example 3: // From tx in main blockchain: // Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620 // -// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 -// <><----><><----><--------------------------------------------------> -// | | | \-----------------\ | -// version | \--------\ unspentness | -// height header code compressed txout 22 +// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 +// <><----><><----><--------------------------------------------------> +// | | | \-----------------\ | +// version | \--------\ unspentness | +// height header code compressed txout 22 // -// - version: 1 -// - height: 338156 -// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap) -// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded. -// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent) -// NOTE: It's +2 since the first two outputs are encoded in the header code -// - compressed txout 22: -// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) -// - 0x01: special script type pay-to-script-hash -// - 0x1d...e6: script hash +// - version: 1 +// - height: 338156 +// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap) +// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded. +// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent) +// NOTE: It's +2 since the first two outputs are encoded in the header code +// - compressed txout 22: +// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) +// - 0x01: special script type pay-to-script-hash +// - 0x1d...e6: script hash func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) { // Deserialize the version. // diff --git a/blockchain/validate.go b/blockchain/validate.go index eaa290b5..85946611 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -334,8 +334,8 @@ func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error { // target difficulty as claimed. // // The flags modify the behavior of this function as follows: -// - BFNoPoWCheck: The check to ensure the block hash is less than the target -// difficulty is not performed. +// - BFNoPoWCheck: The check to ensure the block hash is less than the target +// difficulty is not performed. func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error { // The target difficulty must be larger than zero. target := CompactToBig(header.Bits) @@ -669,8 +669,8 @@ func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error { // which depend on its position within the block chain. // // The flags modify the behavior of this function as follows: -// - BFFastAdd: All checks except those involving comparing the header against -// the checkpoints are not performed. +// - BFFastAdd: All checks except those involving comparing the header against +// the checkpoints are not performed. // // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode *blockNode, flags BehaviorFlags) error { @@ -748,8 +748,8 @@ func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode // on its position within the block chain. // // The flags modify the behavior of this function as follows: -// - BFFastAdd: The transaction are not checked to see if they are finalized -// and the somewhat expensive BIP0034 validation is not performed. +// - BFFastAdd: The transaction are not checked to see if they are finalized +// and the somewhat expensive BIP0034 validation is not performed. // // The flags are also passed to checkBlockHeaderContext. See its documentation // for how the flags modify its behavior. diff --git a/btcec/btcec_test.go b/btcec/btcec_test.go index dffc1217..42a69037 100644 --- a/btcec/btcec_test.go +++ b/btcec/btcec_test.go @@ -527,7 +527,7 @@ type baseMultTest struct { x, y string } -// TODO: add more test vectors +//TODO: add more test vectors var s256BaseMultTests = []baseMultTest{ { "AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522", @@ -556,7 +556,7 @@ var s256BaseMultTests = []baseMultTest{ }, } -// TODO: test different curves as well? +//TODO: test different curves as well? func TestBaseMult(t *testing.T) { s256 := S256() for i, e := range s256BaseMultTests { diff --git a/btcec/field.go b/btcec/field.go index d13d899b..98105ed8 100644 --- a/btcec/field.go +++ b/btcec/field.go @@ -125,30 +125,27 @@ var ( // the arithmetic needed for elliptic curve operations. // // The following depicts the internal representation: -// -// ----------------------------------------------------------------- -// | n[9] | n[8] | ... | n[0] | -// | 32 bits available | 32 bits available | ... | 32 bits available | -// | 22 bits for value | 26 bits for value | ... | 26 bits for value | -// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow | -// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) | -// ----------------------------------------------------------------- +// ----------------------------------------------------------------- +// | n[9] | n[8] | ... | n[0] | +// | 32 bits available | 32 bits available | ... | 32 bits available | +// | 22 bits for value | 26 bits for value | ... | 26 bits for value | +// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow | +// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) | +// ----------------------------------------------------------------- // // For example, consider the number 2^49 + 1. It would be represented as: -// -// n[0] = 1 -// n[1] = 2^23 -// n[2..9] = 0 +// n[0] = 1 +// n[1] = 2^23 +// n[2..9] = 0 // // The full 256-bit value is then calculated by looping i from 9..0 and // doing sum(n[i] * 2^(26i)) like so: -// -// n[9] * 2^(26*9) = 0 * 2^234 = 0 -// n[8] * 2^(26*8) = 0 * 2^208 = 0 -// ... -// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49 -// n[0] * 2^(26*0) = 1 * 2^0 = 1 -// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1 +// n[9] * 2^(26*9) = 0 * 2^234 = 0 +// n[8] * 2^(26*8) = 0 * 2^208 = 0 +// ... +// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49 +// n[0] * 2^(26*0) = 1 * 2^0 = 1 +// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1 type fieldVal struct { n [10]uint32 } diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index d6263fff..95993dac 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -48,15 +48,6 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd { } } -// ClearBannedCmd defines the clearbanned JSON-RPC command. -type ClearBannedCmd struct{} - -// NewClearBannedCmd returns a new instance which can be used to issue an clearbanned -// JSON-RPC command. -func NewClearBannedCmd() *ClearBannedCmd { - return &ClearBannedCmd{} -} - // TransactionInput represents the inputs to a transaction. Specifically a // transaction hash and output number pair. type TransactionInput struct { @@ -67,7 +58,7 @@ type TransactionInput struct { // CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command. type CreateRawTransactionCmd struct { Inputs []TransactionInput - Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"` + Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC LockTime *int64 } @@ -76,7 +67,7 @@ type CreateRawTransactionCmd struct { // // Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent, // both gets interpreted as the empty slice. -func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{}, +func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64, lockTime *int64) *CreateRawTransactionCmd { // to make sure we're serializing this to the empty list and not null, we // explicitly initialize the list @@ -85,7 +76,7 @@ func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]in } return &CreateRawTransactionCmd{ Inputs: inputs, - Outputs: outputs, + Amounts: amounts, LockTime: lockTime, } } @@ -766,15 +757,6 @@ func NewInvalidateBlockCmd(blockHash string) *InvalidateBlockCmd { } } -// ListBannedCmd defines the listbanned JSON-RPC command. -type ListBannedCmd struct{} - -// NewListBannedCmd returns a new instance which can be used to issue a listbanned -// JSON-RPC command. -func NewListBannedCmd() *ListBannedCmd { - return &ListBannedCmd{} -} - // PingCmd defines the ping JSON-RPC command. type PingCmd struct{} @@ -921,39 +903,6 @@ func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTr } } -// SetBanSubCmd defines the type used in the setban JSON-RPC command for the -// sub command field. -type SetBanSubCmd string - -const ( - // SBAdd indicates the specified host should be added as a persistent - // peer. - SBAdd SetBanSubCmd = "add" - - // SBRemove indicates the specified peer should be removed. - SBRemove SetBanSubCmd = "remove" -) - -// SetBanCmd defines the setban JSON-RPC command. -type SetBanCmd struct { - Addr string - SubCmd SetBanSubCmd `jsonrpcusage:"\"add|remove\""` - BanTime *int `jsonrpcdefault:"0"` - Absolute *bool `jsonrpcdefault:"false"` -} - -// NewSetBanCmd returns a new instance which can be used to issue an setban -// JSON-RPC command. -func NewSetBanCmd(addr string, subCmd SetBanSubCmd, banTime *int, - absolute *bool) *SetBanCmd { - return &SetBanCmd{ - Addr: addr, - SubCmd: subCmd, - BanTime: banTime, - Absolute: absolute, - } -} - // SetGenerateCmd defines the setgenerate JSON-RPC command. type SetGenerateCmd struct { Generate bool @@ -1131,9 +1080,6 @@ func init() { MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags) MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags) MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags) - MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags) - MustRegisterCmd("setban", (*SetBanCmd)(nil), flags) - MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags) MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags) MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags) MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags) diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index 4cdcb131..824e87d7 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -52,13 +52,13 @@ func TestChainSvrCmds(t *testing.T) { txInputs := []btcjson.TransactionInput{ {Txid: "123", Vout: 1}, } - txOutputs := map[string]interface{}{"456": .0123} - return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil) + amounts := map[string]float64{"456": .0123} + return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil) }, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`, unmarshalled: &btcjson.CreateRawTransactionCmd{ Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}}, - Outputs: map[string]interface{}{"456": .0123}, + Amounts: map[string]float64{"456": .0123}, }, }, { @@ -67,13 +67,13 @@ func TestChainSvrCmds(t *testing.T) { return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`) }, staticCmd: func() interface{} { - txOutputs := map[string]interface{}{"456": .0123} - return btcjson.NewCreateRawTransactionCmd(nil, txOutputs, nil) + amounts := map[string]float64{"456": .0123} + return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil) }, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`, unmarshalled: &btcjson.CreateRawTransactionCmd{ Inputs: []btcjson.TransactionInput{}, - Outputs: map[string]interface{}{"456": .0123}, + Amounts: map[string]float64{"456": .0123}, }, }, { @@ -86,35 +86,16 @@ func TestChainSvrCmds(t *testing.T) { txInputs := []btcjson.TransactionInput{ {Txid: "123", Vout: 1}, } - txOutputs := map[string]interface{}{"456": .0123} - return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333)) + amounts := map[string]float64{"456": .0123} + return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333)) }, marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`, unmarshalled: &btcjson.CreateRawTransactionCmd{ Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}}, - Outputs: map[string]interface{}{"456": .0123}, + Amounts: map[string]float64{"456": .0123}, LockTime: btcjson.Int64(12312333333), }, }, - { - name: "createrawtransaction with data", - newCmd: func() (interface{}, error) { - return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`, - `{"data":"6a134920616d204672616374616c456e6372797074"}`) - }, - staticCmd: func() interface{} { - txInputs := []btcjson.TransactionInput{ - {Txid: "123", Vout: 1}, - } - txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"} - return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil) - }, - marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`, - unmarshalled: &btcjson.CreateRawTransactionCmd{ - Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}}, - Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}, - }, - }, { name: "fundrawtransaction - empty opts", newCmd: func() (i interface{}, e error) { diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index edc4b52e..ffa0a103 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -35,37 +35,35 @@ type GetBlockHeaderVerboseResult struct { } // GetBlockStatsResult models the data from the getblockstats command. -// Pointers are used instead of values to allow for optional fields. type GetBlockStatsResult struct { - AverageFee *int64 `json:"avgfee,omitempty"` - AverageFeeRate *int64 `json:"avgfeerate,omitempty"` - AverageTxSize *int64 `json:"avgtxsize,omitempty"` - FeeratePercentiles *[]int64 `json:"feerate_percentiles,omitempty"` - Hash *string `json:"blockhash,omitempty"` - Height *int64 `json:"height,omitempty"` - Ins *int64 `json:"ins,omitempty"` - MaxFee *int64 `json:"maxfee,omitempty"` - MaxFeeRate *int64 `json:"maxfeerate,omitempty"` - MaxTxSize *int64 `json:"maxtxsize,omitempty"` - MedianFee *int64 `json:"medianfee,omitempty"` - MedianTime *int64 `json:"mediantime,omitempty"` - MedianTxSize *int64 `json:"mediantxsize,omitempty"` - MinFee *int64 `json:"minfee,omitempty"` - MinFeeRate *int64 `json:"minfeerate,omitempty"` - MinTxSize *int64 `json:"mintxsize,omitempty"` - Outs *int64 `json:"outs,omitempty"` - SegWitTotalSize *int64 `json:"swtotal_size,omitempty"` - SegWitTotalWeight *int64 `json:"swtotal_weight,omitempty"` - SegWitTxs *int64 `json:"swtxs,omitempty"` - Subsidy *int64 `json:"subsidy,omitempty"` - Time *int64 `json:"time,omitempty"` - TotalOut *int64 `json:"total_out,omitempty"` - TotalSize *int64 `json:"total_size,omitempty"` - TotalWeight *int64 `json:"total_weight,omitempty"` - TotalFee *int64 `json:"totalfee,omitempty"` - Txs *int64 `json:"txs,omitempty"` - UTXOIncrease *int64 `json:"utxo_increase,omitempty"` - UTXOSizeIncrease *int64 `json:"utxo_size_inc,omitempty"` + AverageFee int64 `json:"avgfee"` + AverageFeeRate int64 `json:"avgfeerate"` + AverageTxSize int64 `json:"avgtxsize"` + FeeratePercentiles []int64 `json:"feerate_percentiles"` + Hash string `json:"blockhash"` + Height int64 `json:"height"` + Ins int64 `json:"ins"` + MaxFee int64 `json:"maxfee"` + MaxFeeRate int64 `json:"maxfeerate"` + MaxTxSize int64 `json:"maxtxsize"` + MedianFee int64 `json:"medianfee"` + MedianTime int64 `json:"mediantime"` + MedianTxSize int64 `json:"mediantxsize"` + MinFee int64 `json:"minfee"` + MinFeeRate int64 `json:"minfeerate"` + MinTxSize int64 `json:"mintxsize"` + Outs int64 `json:"outs"` + SegWitTotalSize int64 `json:"swtotal_size"` + SegWitTotalWeight int64 `json:"swtotal_weight"` + SegWitTxs int64 `json:"swtxs"` + Subsidy int64 `json:"subsidy"` + Time int64 `json:"time"` + TotalOut int64 `json:"total_out"` + TotalSize int64 `json:"total_size"` + TotalWeight int64 `json:"total_weight"` + Txs int64 `json:"txs"` + UTXOIncrease int64 `json:"utxo_increase"` + UTXOSizeIncrease int64 `json:"utxo_size_inc"` } type GetBlockVerboseResultBase struct { @@ -79,11 +77,9 @@ type GetBlockVerboseResultBase struct { VersionHex string `json:"versionHex"` MerkleRoot string `json:"merkleroot"` Time int64 `json:"time"` - MedianTime int64 `json:"mediantime"` Nonce uint32 `json:"nonce"` Bits string `json:"bits"` Difficulty float64 `json:"difficulty"` - ChainWork string `json:"chainwork"` PreviousHash string `json:"previousblockhash,omitempty"` NextHash string `json:"nextblockhash,omitempty"` @@ -341,13 +337,8 @@ type GetChainTipsResult struct { // GetMempoolInfoResult models the data returned from the getmempoolinfo // command. type GetMempoolInfoResult struct { - Size int64 `json:"size"` // Current tx count - Bytes int64 `json:"bytes"` // Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted - Usage int64 `json:"usage"` // Total memory usage for the mempool - TotalFee float64 `json:"total_fee"` // Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction - MemPoolMinFee float64 `json:"mempoolminfee"` // Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee - MinRelayTxFee float64 `json:"minrelaytxfee"` // Current minimum relay fee for transactions - UnbroadcastCount int64 `json:"unbroadcastcount"` // Current number of transactions that haven't passed initial broadcast yet + Size int64 `json:"size"` + Bytes int64 `json:"bytes"` } // NetworksResult models the networks data from the getnetworkinfo command. @@ -723,15 +714,6 @@ type InfoChainResult struct { Errors string `json:"errors"` } -// ListBannedResult models the data returned from the listbanned command. -type ListBannedResult struct { - Address string `json:"address"` - BanCreated int64 `json:"ban_created"` - BannedUntil int64 `json:"banned_until"` - BanDuration int64 `json:"ban_duration"` - TimeRemaining int64 `json:"time_remaining"` -} - // TxRawResult models the data from the getrawtransaction command. type TxRawResult struct { Hex string `json:"hex"` diff --git a/btcjson/doc.go b/btcjson/doc.go index e2e52cd2..165b9ef9 100644 --- a/btcjson/doc.go +++ b/btcjson/doc.go @@ -5,7 +5,7 @@ /* Package btcjson provides primitives for working with the bitcoin JSON-RPC API. -# Overview +Overview When communicating via the JSON-RPC protocol, all of the commands need to be marshalled to and from the the wire in the appropriate format. This package @@ -14,7 +14,7 @@ provides data structures and primitives to ease this process. In addition, it also provides some additional features such as custom command registration, command categorization, and reflection-based help generation. -# JSON-RPC Protocol Overview +JSON-RPC Protocol Overview This information is not necessary in order to use this package, but it does provide some intuition into what the marshalling and unmarshalling that is @@ -47,39 +47,39 @@ with it) doesn't always follow the spec and will sometimes return an error string in the result field with a null error for certain commands. However, for the most part, the error field will be set as described on failure. -# Marshalling and Unmarshalling +Marshalling and Unmarshalling Based upon the discussion above, it should be easy to see how the types of this package map into the required parts of the protocol - Request Objects (type Request) - - Commands (type Cmd) - - Notifications (type Ntfn) + - Commands (type Cmd) + - Notifications (type Ntfn) - Response Objects (type Response) - - Result (type Result) + - Result (type Result) To simplify the marshalling of the requests and responses, the MarshalCmd and MarshalResponse functions are provided. They return the raw bytes ready to be sent across the wire. Unmarshalling a received Request object is a two step process: - 1. Unmarshal the raw bytes into a Request struct instance via json.Unmarshal - 2. Use UnmarshalCmd on the Result field of the unmarshalled Request to create - a concrete command or notification instance with all struct fields set - accordingly + 1) Unmarshal the raw bytes into a Request struct instance via json.Unmarshal + 2) Use UnmarshalCmd on the Result field of the unmarshalled Request to create + a concrete command or notification instance with all struct fields set + accordingly This approach is used since it provides the caller with access to the additional fields in the request that are not part of the command such as the ID. Unmarshalling a received Response object is also a two step process: - 1. Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal - 2. Depending on the ID, unmarshal the Result field of the unmarshalled - Response to create a concrete type instance + 1) Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal + 2) Depending on the ID, unmarshal the Result field of the unmarshalled + Response to create a concrete type instance As above, this approach is used since it provides the caller with access to the fields in the response such as the ID and Error. -# Command Creation +Command Creation This package provides two approaches for creating a new command. This first, and preferred, method is to use one of the NewCmd functions. This allows @@ -93,7 +93,7 @@ obviously, run-time which means any mistakes won't be found until the code is actually executed. However, it is quite useful for user-supplied commands that are intentionally dynamic. -# Custom Command Registration +Custom Command Registration The command handling of this package is built around the concept of registered commands. This is true for the wide variety of commands already provided by the @@ -104,7 +104,7 @@ function for this purpose. A list of all registered methods can be obtained with the RegisteredCmdMethods function. -# Command Inspection +Command Inspection All registered commands are registered with flags that identify information such as whether the command applies to a chain server, wallet server, or is a @@ -112,7 +112,7 @@ notification along with the method name to use. These flags can be obtained with the MethodUsageFlags flags, and the method can be obtained with the CmdMethod function. -# Help Generation +Help Generation To facilitate providing consistent help to users of the RPC server, this package exposes the GenerateHelp and function which uses reflection on registered @@ -122,7 +122,7 @@ generate the final help text. In addition, the MethodUsageText function is provided to generate consistent one-line usage for registered commands and notifications using reflection. -# Errors +Errors There are 2 distinct type of errors supported by this package: diff --git a/btcjson/help.go b/btcjson/help.go index 4188b53f..04d85635 100644 --- a/btcjson/help.go +++ b/btcjson/help.go @@ -476,12 +476,11 @@ func isValidResultType(kind reflect.Kind) bool { // an error will use the key in place of the description. // // The following outlines the required keys: -// -// "--synopsis" Synopsis for the command -// "-" Description for each command argument -// "-" Description for each object field -// "--condition<#>" Description for each result condition -// "--result<#>" Description for each primitive result num +// "--synopsis" Synopsis for the command +// "-" Description for each command argument +// "-" Description for each object field +// "--condition<#>" Description for each result condition +// "--result<#>" Description for each primitive result num // // Notice that the "special" keys synopsis, condition<#>, and result<#> are // preceded by a double dash to ensure they don't conflict with field names. @@ -493,17 +492,16 @@ func isValidResultType(kind reflect.Kind) bool { // For example, consider the 'help' command itself. There are two possible // returns depending on the provided parameters. So, the help would be // generated by calling the function as follows: -// -// GenerateHelp("help", descs, (*string)(nil), (*string)(nil)). +// GenerateHelp("help", descs, (*string)(nil), (*string)(nil)). // // The following keys would then be required in the provided descriptions map: // -// "help--synopsis": "Returns a list of all commands or help for ...." -// "help-command": "The command to retrieve help for", -// "help--condition0": "no command provided" -// "help--condition1": "command specified" -// "help--result0": "List of commands" -// "help--result1": "Help for specified command" +// "help--synopsis": "Returns a list of all commands or help for ...." +// "help-command": "The command to retrieve help for", +// "help--condition0": "no command provided" +// "help--condition1": "command specified" +// "help--result0": "List of commands" +// "help--result1": "Help for specified command" func GenerateHelp(method string, descs map[string]string, resultTypes ...interface{}) (string, error) { // Look up details about the provided method and error out if not // registered. diff --git a/btcjson/walletsvrcmds.go b/btcjson/walletsvrcmds.go index 1549d3d4..8569c1d5 100644 --- a/btcjson/walletsvrcmds.go +++ b/btcjson/walletsvrcmds.go @@ -176,13 +176,12 @@ func NewGetAccountCmd(address string) *GetAccountCmd { // GetAccountAddressCmd defines the getaccountaddress JSON-RPC command. type GetAccountAddressCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - AddressType *string `jsonrpcdefault:"\"legacy\""` + Account string } // NewGetAccountAddressCmd returns a new instance which can be used to issue a // getaccountaddress JSON-RPC command. -func NewGetAccountAddressCmd(account *string) *GetAccountAddressCmd { +func NewGetAccountAddressCmd(account string) *GetAccountAddressCmd { return &GetAccountAddressCmd{ Account: account, } @@ -190,13 +189,12 @@ func NewGetAccountAddressCmd(account *string) *GetAccountAddressCmd { // GetAddressesByAccountCmd defines the getaddressesbyaccount JSON-RPC command. type GetAddressesByAccountCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - AddressType *string `jsonrpcdefault:"\"*\""` + Account string } // NewGetAddressesByAccountCmd returns a new instance which can be used to issue // a getaddressesbyaccount JSON-RPC command. -func NewGetAddressesByAccountCmd(account *string) *GetAddressesByAccountCmd { +func NewGetAddressesByAccountCmd(account string) *GetAddressesByAccountCmd { return &GetAddressesByAccountCmd{ Account: account, } @@ -217,9 +215,8 @@ func NewGetAddressInfoCmd(address string) *GetAddressInfoCmd { // GetBalanceCmd defines the getbalance JSON-RPC command. type GetBalanceCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - MinConf *int `jsonrpcdefault:"1"` - AddressType *string `jsonrpcdefault:"\"*\""` + Account *string + MinConf *int `jsonrpcdefault:"1"` } // NewGetBalanceCmd returns a new instance which can be used to issue a @@ -245,8 +242,8 @@ func NewGetBalancesCmd() *GetBalancesCmd { // GetNewAddressCmd defines the getnewaddress JSON-RPC command. type GetNewAddressCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - AddressType *string `jsonrpcdefault:"\"legacy\""` + Account *string + AddressType *string // must be one of legacy / p2pkh or p2sh-p2wkh / p2sh-segwit, or p2wkh / bech32 } // NewGetNewAddressCmd returns a new instance which can be used to issue a @@ -262,8 +259,7 @@ func NewGetNewAddressCmd(account *string) *GetNewAddressCmd { // GetRawChangeAddressCmd defines the getrawchangeaddress JSON-RPC command. type GetRawChangeAddressCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - AddressType *string `jsonrpcdefault:"\"legacy\""` + Account *string } // NewGetRawChangeAddressCmd returns a new instance which can be used to issue a @@ -279,8 +275,8 @@ func NewGetRawChangeAddressCmd(account *string) *GetRawChangeAddressCmd { // GetReceivedByAccountCmd defines the getreceivedbyaccount JSON-RPC command. type GetReceivedByAccountCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - MinConf *int `jsonrpcdefault:"1"` + Account string + MinConf *int `jsonrpcdefault:"1"` } // NewGetReceivedByAccountCmd returns a new instance which can be used to issue @@ -288,7 +284,7 @@ type GetReceivedByAccountCmd struct { // // The parameters which are pointers indicate they are optional. Passing nil // for optional parameters will use the default value. -func NewGetReceivedByAccountCmd(account *string, minConf *int) *GetReceivedByAccountCmd { +func NewGetReceivedByAccountCmd(account string, minConf *int) *GetReceivedByAccountCmd { return &GetReceivedByAccountCmd{ Account: account, MinConf: minConf, @@ -411,8 +407,7 @@ func NewKeyPoolRefillCmd(newSize *uint) *KeyPoolRefillCmd { // ListAccountsCmd defines the listaccounts JSON-RPC command. type ListAccountsCmd struct { - MinConf *int `jsonrpcdefault:"1"` - AddressType *string `jsonrpcdefault:"\"*\""` + MinConf *int `jsonrpcdefault:"1"` } // NewListAccountsCmd returns a new instance which can be used to issue a @@ -506,10 +501,10 @@ func NewListSinceBlockCmd(blockHash *string, targetConfirms *int, includeWatchOn // ListTransactionsCmd defines the listtransactions JSON-RPC command. type ListTransactionsCmd struct { - Account *string `jsonrpcdefault:"\"default\""` - Count *int `jsonrpcdefault:"10"` - From *int `jsonrpcdefault:"0"` - IncludeWatchOnly *bool `jsonrpcdefault:"false"` + Account *string + Count *int `jsonrpcdefault:"10"` + From *int `jsonrpcdefault:"0"` + IncludeWatchOnly *bool `jsonrpcdefault:"false"` } // NewListTransactionsCmd returns a new instance which can be used to issue a @@ -561,13 +556,36 @@ func NewLockUnspentCmd(unlock bool, transactions []TransactionInput) *LockUnspen } } +// MoveCmd defines the move JSON-RPC command. +type MoveCmd struct { + FromAccount string + ToAccount string + Amount float64 // In BTC + MinConf *int `jsonrpcdefault:"1"` + Comment *string +} + +// NewMoveCmd returns a new instance which can be used to issue a move JSON-RPC +// command. +// +// The parameters which are pointers indicate they are optional. Passing nil +// for optional parameters will use the default value. +func NewMoveCmd(fromAccount, toAccount string, amount float64, minConf *int, comment *string) *MoveCmd { + return &MoveCmd{ + FromAccount: fromAccount, + ToAccount: toAccount, + Amount: amount, + MinConf: minConf, + Comment: comment, + } +} + // SendFromCmd defines the sendfrom JSON-RPC command. type SendFromCmd struct { FromAccount string ToAddress string Amount float64 // In BTC MinConf *int `jsonrpcdefault:"1"` - AddressType *string `jsonrpcdefault:"\"*\""` Comment *string CommentTo *string } @@ -577,15 +595,12 @@ type SendFromCmd struct { // // The parameters which are pointers indicate they are optional. Passing nil // for optional parameters will use the default value. -func NewSendFromCmd(fromAccount, toAddress string, amount float64, - minConf *int, addrType *string, comment, commentTo *string) *SendFromCmd { - +func NewSendFromCmd(fromAccount, toAddress string, amount float64, minConf *int, comment, commentTo *string) *SendFromCmd { return &SendFromCmd{ FromAccount: fromAccount, ToAddress: toAddress, Amount: amount, MinConf: minConf, - AddressType: addrType, Comment: comment, CommentTo: commentTo, } @@ -596,7 +611,6 @@ type SendManyCmd struct { FromAccount string Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC MinConf *int `jsonrpcdefault:"1"` - AddressType *string `jsonrpcdefault:"\"*\""` Comment *string } @@ -605,24 +619,21 @@ type SendManyCmd struct { // // The parameters which are pointers indicate they are optional. Passing nil // for optional parameters will use the default value. -func NewSendManyCmd(fromAccount string, amounts map[string]float64, - minConf *int, addrType *string, comment *string) *SendManyCmd { +func NewSendManyCmd(fromAccount string, amounts map[string]float64, minConf *int, comment *string) *SendManyCmd { return &SendManyCmd{ FromAccount: fromAccount, Amounts: amounts, MinConf: minConf, - AddressType: addrType, Comment: comment, } } // SendToAddressCmd defines the sendtoaddress JSON-RPC command. type SendToAddressCmd struct { - Address string - Amount float64 - AddressType *string `jsonrpcdefault:"\"*\""` - Comment *string - CommentTo *string + Address string + Amount float64 + Comment *string + CommentTo *string } // NewSendToAddressCmd returns a new instance which can be used to issue a @@ -630,14 +641,27 @@ type SendToAddressCmd struct { // // The parameters which are pointers indicate they are optional. Passing nil // for optional parameters will use the default value. -func NewSendToAddressCmd(address string, amount float64, addrType *string, - comment, commentTo *string) *SendToAddressCmd { +func NewSendToAddressCmd(address string, amount float64, comment, commentTo *string) *SendToAddressCmd { return &SendToAddressCmd{ - Address: address, - Amount: amount, - AddressType: addrType, - Comment: comment, - CommentTo: commentTo, + Address: address, + Amount: amount, + Comment: comment, + CommentTo: commentTo, + } +} + +// SetAccountCmd defines the setaccount JSON-RPC command. +type SetAccountCmd struct { + Address string + Account string +} + +// NewSetAccountCmd returns a new instance which can be used to issue a +// setaccount JSON-RPC command. +func NewSetAccountCmd(address, account string) *SetAccountCmd { + return &SetAccountCmd{ + Address: address, + Account: account, } } @@ -848,8 +872,7 @@ func (s *ScriptPubKey) UnmarshalJSON(data []byte) error { // // Descriptors are typically ranged when specified in the form of generic HD // chain paths. -// -// Example of a ranged descriptor: pkh(tpub.../*) +// Example of a ranged descriptor: pkh(tpub.../*) // // The value can be an int to specify the end of the range, or the range // itself, as []int{begin, end}. @@ -975,24 +998,6 @@ func NewImportMultiCmd(requests []ImportMultiRequest, options *ImportMultiOption } } -// RescanBlockchainCmd defines the RescanBlockchain JSON-RPC command. -type RescanBlockchainCmd struct { - StartHeight *int32 `jsonrpcdefault:"0"` - StopHeight *int32 -} - -// NewRescanBlockchainCmd returns a new instance which can be used to issue -// an RescanBlockchain JSON-RPC command. -// -// The parameters which are pointers indicate they are optional. Passing nil -// for optional parameters will use the default value. -func NewRescanBlockchainCmd(startHeight *int32, stopHeight *int32) *RescanBlockchainCmd { - return &RescanBlockchainCmd{ - StartHeight: startHeight, - StopHeight: stopHeight, - } -} - // PsbtInput represents an input to include in the PSBT created by the // WalletCreateFundedPsbtCmd command. type PsbtInput struct { @@ -1114,10 +1119,11 @@ func init() { MustRegisterCmd("listunspent", (*ListUnspentCmd)(nil), flags) MustRegisterCmd("loadwallet", (*LoadWalletCmd)(nil), flags) MustRegisterCmd("lockunspent", (*LockUnspentCmd)(nil), flags) - MustRegisterCmd("rescanblockchain", (*RescanBlockchainCmd)(nil), flags) + MustRegisterCmd("move", (*MoveCmd)(nil), flags) MustRegisterCmd("sendfrom", (*SendFromCmd)(nil), flags) MustRegisterCmd("sendmany", (*SendManyCmd)(nil), flags) MustRegisterCmd("sendtoaddress", (*SendToAddressCmd)(nil), flags) + MustRegisterCmd("setaccount", (*SetAccountCmd)(nil), flags) MustRegisterCmd("settxfee", (*SetTxFeeCmd)(nil), flags) MustRegisterCmd("signmessage", (*SignMessageCmd)(nil), flags) MustRegisterCmd("signrawtransaction", (*SignRawTransactionCmd)(nil), flags) diff --git a/btcjson/walletsvrcmds_test.go b/btcjson/walletsvrcmds_test.go index b4b976d4..d33888d4 100644 --- a/btcjson/walletsvrcmds_test.go +++ b/btcjson/walletsvrcmds_test.go @@ -287,12 +287,11 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("getaccountaddress", "acct") }, staticCmd: func() interface{} { - return btcjson.NewGetAccountAddressCmd(btcjson.String("acct")) + return btcjson.NewGetAccountAddressCmd("acct") }, marshalled: `{"jsonrpc":"1.0","method":"getaccountaddress","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetAccountAddressCmd{ - Account: btcjson.String("acct"), - AddressType: btcjson.String("legacy"), + Account: "acct", }, }, { @@ -301,12 +300,11 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("getaddressesbyaccount", "acct") }, staticCmd: func() interface{} { - return btcjson.NewGetAddressesByAccountCmd(btcjson.String("acct")) + return btcjson.NewGetAddressesByAccountCmd("acct") }, marshalled: `{"jsonrpc":"1.0","method":"getaddressesbyaccount","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetAddressesByAccountCmd{ - Account: btcjson.String("acct"), - AddressType: btcjson.String("*"), + Account: "acct", }, }, { @@ -332,9 +330,8 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":[],"id":1}`, unmarshalled: &btcjson.GetBalanceCmd{ - Account: btcjson.String("default"), - MinConf: btcjson.Int(1), - AddressType: btcjson.String("*"), + Account: nil, + MinConf: btcjson.Int(1), }, }, { @@ -347,9 +344,8 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetBalanceCmd{ - Account: btcjson.String("acct"), - MinConf: btcjson.Int(1), - AddressType: btcjson.String("*"), + Account: btcjson.String("acct"), + MinConf: btcjson.Int(1), }, }, { @@ -362,9 +358,8 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getbalance","params":["acct",6],"id":1}`, unmarshalled: &btcjson.GetBalanceCmd{ - Account: btcjson.String("acct"), - MinConf: btcjson.Int(6), - AddressType: btcjson.String("*"), + Account: btcjson.String("acct"), + MinConf: btcjson.Int(6), }, }, { @@ -388,8 +383,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getnewaddress","params":[],"id":1}`, unmarshalled: &btcjson.GetNewAddressCmd{ - Account: btcjson.String("default"), - AddressType: btcjson.String("legacy"), + Account: nil, }, }, { @@ -402,8 +396,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getnewaddress","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetNewAddressCmd{ - Account: btcjson.String("acct"), - AddressType: btcjson.String("legacy"), + Account: btcjson.String("acct"), }, }, { @@ -416,8 +409,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getrawchangeaddress","params":[],"id":1}`, unmarshalled: &btcjson.GetRawChangeAddressCmd{ - Account: btcjson.String("default"), - AddressType: btcjson.String("legacy"), + Account: nil, }, }, { @@ -430,8 +422,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getrawchangeaddress","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetRawChangeAddressCmd{ - Account: btcjson.String("acct"), - AddressType: btcjson.String("legacy"), + Account: btcjson.String("acct"), }, }, { @@ -440,11 +431,11 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("getreceivedbyaccount", "acct") }, staticCmd: func() interface{} { - return btcjson.NewGetReceivedByAccountCmd(btcjson.String("acct"), nil) + return btcjson.NewGetReceivedByAccountCmd("acct", nil) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaccount","params":["acct"],"id":1}`, unmarshalled: &btcjson.GetReceivedByAccountCmd{ - Account: btcjson.String("acct"), + Account: "acct", MinConf: btcjson.Int(1), }, }, @@ -454,11 +445,11 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("getreceivedbyaccount", "acct", 6) }, staticCmd: func() interface{} { - return btcjson.NewGetReceivedByAccountCmd(btcjson.String("acct"), btcjson.Int(6)) + return btcjson.NewGetReceivedByAccountCmd("acct", btcjson.Int(6)) }, marshalled: `{"jsonrpc":"1.0","method":"getreceivedbyaccount","params":["acct",6],"id":1}`, unmarshalled: &btcjson.GetReceivedByAccountCmd{ - Account: btcjson.String("acct"), + Account: "acct", MinConf: btcjson.Int(6), }, }, @@ -610,8 +601,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"listaccounts","params":[],"id":1}`, unmarshalled: &btcjson.ListAccountsCmd{ - MinConf: btcjson.Int(1), - AddressType: btcjson.String("*"), + MinConf: btcjson.Int(1), }, }, { @@ -624,8 +614,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"listaccounts","params":[6],"id":1}`, unmarshalled: &btcjson.ListAccountsCmd{ - MinConf: btcjson.Int(6), - AddressType: btcjson.String("*"), + MinConf: btcjson.Int(6), }, }, { @@ -855,7 +844,7 @@ func TestWalletSvrCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"listtransactions","params":[],"id":1}`, unmarshalled: &btcjson.ListTransactionsCmd{ - Account: btcjson.String("default"), + Account: nil, Count: btcjson.Int(10), From: btcjson.Int(0), IncludeWatchOnly: btcjson.Bool(false), @@ -1007,13 +996,64 @@ func TestWalletSvrCmds(t *testing.T) { }, }, }, + { + name: "move", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("move", "from", "to", 0.5) + }, + staticCmd: func() interface{} { + return btcjson.NewMoveCmd("from", "to", 0.5, nil, nil) + }, + marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5],"id":1}`, + unmarshalled: &btcjson.MoveCmd{ + FromAccount: "from", + ToAccount: "to", + Amount: 0.5, + MinConf: btcjson.Int(1), + Comment: nil, + }, + }, + { + name: "move optional1", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("move", "from", "to", 0.5, 6) + }, + staticCmd: func() interface{} { + return btcjson.NewMoveCmd("from", "to", 0.5, btcjson.Int(6), nil) + }, + marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5,6],"id":1}`, + unmarshalled: &btcjson.MoveCmd{ + FromAccount: "from", + ToAccount: "to", + Amount: 0.5, + MinConf: btcjson.Int(6), + Comment: nil, + }, + }, + { + name: "move optional2", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("move", "from", "to", 0.5, 6, "comment") + }, + staticCmd: func() interface{} { + return btcjson.NewMoveCmd("from", "to", 0.5, btcjson.Int(6), btcjson.String("comment")) + }, + marshalled: `{"jsonrpc":"1.0","method":"move","params":["from","to",0.5,6,"comment"],"id":1}`, + unmarshalled: &btcjson.MoveCmd{ + FromAccount: "from", + ToAccount: "to", + Amount: 0.5, + MinConf: btcjson.Int(6), + Comment: btcjson.String("comment"), + }, + }, { name: "sendfrom", newCmd: func() (interface{}, error) { return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5) }, staticCmd: func() interface{} { - return btcjson.NewSendFromCmd("from", "1Address", 0.5, nil, nil, nil, nil) + return btcjson.NewSendFromCmd("from", "1Address", 0.5, nil, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5],"id":1}`, unmarshalled: &btcjson.SendFromCmd{ @@ -1021,7 +1061,6 @@ func TestWalletSvrCmds(t *testing.T) { ToAddress: "1Address", Amount: 0.5, MinConf: btcjson.Int(1), - AddressType: btcjson.String("*"), Comment: nil, CommentTo: nil, }, @@ -1032,7 +1071,7 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6) }, staticCmd: func() interface{} { - return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), nil, nil, nil) + return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6],"id":1}`, unmarshalled: &btcjson.SendFromCmd{ @@ -1040,7 +1079,6 @@ func TestWalletSvrCmds(t *testing.T) { ToAddress: "1Address", Amount: 0.5, MinConf: btcjson.Int(6), - AddressType: btcjson.String("*"), Comment: nil, CommentTo: nil, }, @@ -1048,59 +1086,37 @@ func TestWalletSvrCmds(t *testing.T) { { name: "sendfrom optional2", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "legacy") + return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "comment") }, staticCmd: func() interface{} { - return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), btcjson.String("legacy"), - nil, nil) + return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), + btcjson.String("comment"), nil) }, - marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"legacy"],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"comment"],"id":1}`, unmarshalled: &btcjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: btcjson.Int(6), - AddressType: btcjson.String("legacy"), - Comment: nil, + Comment: btcjson.String("comment"), CommentTo: nil, }, }, { name: "sendfrom optional3", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "legacy", "comment") + return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "comment", "commentto") }, staticCmd: func() interface{} { - return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), btcjson.String("legacy"), - btcjson.String("comment"), nil) - }, - marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"legacy","comment"],"id":1}`, - unmarshalled: &btcjson.SendFromCmd{ - FromAccount: "from", - ToAddress: "1Address", - Amount: 0.5, - MinConf: btcjson.Int(6), - AddressType: btcjson.String("legacy"), - Comment: btcjson.String("comment"), - CommentTo: nil, - }, - }, - { - name: "sendfrom optional4", - newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendfrom", "from", "1Address", 0.5, 6, "legacy", "comment", "commentto") - }, - staticCmd: func() interface{} { - return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), btcjson.String("legacy"), + return btcjson.NewSendFromCmd("from", "1Address", 0.5, btcjson.Int(6), btcjson.String("comment"), btcjson.String("commentto")) }, - marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"legacy","comment","commentto"],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"sendfrom","params":["from","1Address",0.5,6,"comment","commentto"],"id":1}`, unmarshalled: &btcjson.SendFromCmd{ FromAccount: "from", ToAddress: "1Address", Amount: 0.5, MinConf: btcjson.Int(6), - AddressType: btcjson.String("legacy"), Comment: btcjson.String("comment"), CommentTo: btcjson.String("commentto"), }, @@ -1112,14 +1128,13 @@ func TestWalletSvrCmds(t *testing.T) { }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} - return btcjson.NewSendManyCmd("from", amounts, nil, nil, nil) + return btcjson.NewSendManyCmd("from", amounts, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5}],"id":1}`, unmarshalled: &btcjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: btcjson.Int(1), - AddressType: btcjson.String("*"), Comment: nil, }, }, @@ -1130,50 +1145,30 @@ func TestWalletSvrCmds(t *testing.T) { }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} - return btcjson.NewSendManyCmd("from", amounts, btcjson.Int(6), nil, nil) + return btcjson.NewSendManyCmd("from", amounts, btcjson.Int(6), nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6],"id":1}`, unmarshalled: &btcjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: btcjson.Int(6), - AddressType: btcjson.String("*"), Comment: nil, }, }, { name: "sendmany optional2", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendmany", "from", `{"1Address":0.5}`, 6, "legacy") + return btcjson.NewCmd("sendmany", "from", `{"1Address":0.5}`, 6, "comment") }, staticCmd: func() interface{} { amounts := map[string]float64{"1Address": 0.5} - return btcjson.NewSendManyCmd("from", amounts, btcjson.Int(6), btcjson.String("legacy"), nil) + return btcjson.NewSendManyCmd("from", amounts, btcjson.Int(6), btcjson.String("comment")) }, - marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6,"legacy"],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6,"comment"],"id":1}`, unmarshalled: &btcjson.SendManyCmd{ FromAccount: "from", Amounts: map[string]float64{"1Address": 0.5}, MinConf: btcjson.Int(6), - AddressType: btcjson.String("legacy"), - Comment: nil, - }, - }, - { - name: "sendmany optional3", - newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendmany", "from", `{"1Address":0.5}`, 6, "legacy", "comment") - }, - staticCmd: func() interface{} { - amounts := map[string]float64{"1Address": 0.5} - return btcjson.NewSendManyCmd("from", amounts, btcjson.Int(6), btcjson.String("legacy"), btcjson.String("comment")) - }, - marshalled: `{"jsonrpc":"1.0","method":"sendmany","params":["from",{"1Address":0.5},6,"legacy","comment"],"id":1}`, - unmarshalled: &btcjson.SendManyCmd{ - FromAccount: "from", - Amounts: map[string]float64{"1Address": 0.5}, - MinConf: btcjson.Int(6), - AddressType: btcjson.String("legacy"), Comment: btcjson.String("comment"), }, }, @@ -1183,50 +1178,45 @@ func TestWalletSvrCmds(t *testing.T) { return btcjson.NewCmd("sendtoaddress", "1Address", 0.5) }, staticCmd: func() interface{} { - return btcjson.NewSendToAddressCmd("1Address", 0.5, nil, nil, nil) + return btcjson.NewSendToAddressCmd("1Address", 0.5, nil, nil) }, marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5],"id":1}`, unmarshalled: &btcjson.SendToAddressCmd{ - Address: "1Address", - Amount: 0.5, - AddressType: btcjson.String("*"), - Comment: nil, - CommentTo: nil, + Address: "1Address", + Amount: 0.5, + Comment: nil, + CommentTo: nil, }, }, { name: "sendtoaddress optional1", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendtoaddress", "1Address", 0.5, "legacy") + return btcjson.NewCmd("sendtoaddress", "1Address", 0.5, "comment", "commentto") }, staticCmd: func() interface{} { - return btcjson.NewSendToAddressCmd("1Address", 0.5, btcjson.String("legacy"), nil, nil) + return btcjson.NewSendToAddressCmd("1Address", 0.5, btcjson.String("comment"), + btcjson.String("commentto")) }, - marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5,"legacy"],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5,"comment","commentto"],"id":1}`, unmarshalled: &btcjson.SendToAddressCmd{ - Address: "1Address", - Amount: 0.5, - AddressType: btcjson.String("legacy"), - Comment: nil, - CommentTo: nil, + Address: "1Address", + Amount: 0.5, + Comment: btcjson.String("comment"), + CommentTo: btcjson.String("commentto"), }, }, { - name: "sendtoaddress optional2", + name: "setaccount", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendtoaddress", "1Address", 0.5, "legacy", "comment", "commentto") + return btcjson.NewCmd("setaccount", "1Address", "acct") }, staticCmd: func() interface{} { - return btcjson.NewSendToAddressCmd("1Address", 0.5, btcjson.String("legacy"), btcjson.String("comment"), - btcjson.String("commentto")) + return btcjson.NewSetAccountCmd("1Address", "acct") }, - marshalled: `{"jsonrpc":"1.0","method":"sendtoaddress","params":["1Address",0.5,"legacy","comment","commentto"],"id":1}`, - unmarshalled: &btcjson.SendToAddressCmd{ - Address: "1Address", - Amount: 0.5, - AddressType: btcjson.String("legacy"), - Comment: btcjson.String("comment"), - CommentTo: btcjson.String("commentto"), + marshalled: `{"jsonrpc":"1.0","method":"setaccount","params":["1Address","acct"],"id":1}`, + unmarshalled: &btcjson.SetAccountCmd{ + Address: "1Address", + Account: "acct", }, }, { diff --git a/btcjson/walletsvrresults.go b/btcjson/walletsvrresults.go index 83ae269d..2b7354e7 100644 --- a/btcjson/walletsvrresults.go +++ b/btcjson/walletsvrresults.go @@ -47,32 +47,13 @@ type embeddedAddressInfo struct { // Reference: https://bitcoincore.org/en/doc/0.20.0/rpc/wallet/getaddressinfo // // The GetAddressInfoResult has three segments: -// 1. General information about the address. -// 2. Metadata (Timestamp, HDKeyPath, HDSeedID) and wallet fields -// (IsMine, IsWatchOnly). -// 3. Information about the embedded address in case of P2SH or P2WSH. -// Same structure as (1). +// 1. General information about the address. +// 2. Metadata (Timestamp, HDKeyPath, HDSeedID) and wallet fields +// (IsMine, IsWatchOnly). +// 3. Information about the embedded address in case of P2SH or P2WSH. +// Same structure as (1). type GetAddressInfoResult struct { - // The following fields are identical to embeddedAddressInfo. - // However, the utility to generate RPC help message can't handle - // embedded field properly. So, spell out the attributes individually. - Address string `json:"address"` - ScriptPubKey string `json:"scriptPubKey"` - Descriptor *string `json:"desc,omitempty"` - IsScript bool `json:"isscript"` - IsChange bool `json:"ischange"` - IsWitness bool `json:"iswitness"` - WitnessVersion int `json:"witness_version,omitempty"` - WitnessProgram *string `json:"witness_program,omitempty"` - ScriptType *txscript.ScriptClass `json:"script,omitempty"` - Hex *string `json:"hex,omitempty"` - PubKeys *[]string `json:"pubkeys,omitempty"` - SignaturesRequired *int `json:"sigsrequired,omitempty"` - PubKey *string `json:"pubkey,omitempty"` - IsCompressed *bool `json:"iscompressed,omitempty"` - HDMasterFingerprint *string `json:"hdmasterfingerprint,omitempty"` - Labels []string `json:"labels"` - + embeddedAddressInfo IsMine bool `json:"ismine"` IsWatchOnly bool `json:"iswatchonly"` Timestamp *int `json:"timestamp,omitempty"` @@ -174,7 +155,6 @@ type GetTransactionResult struct { TimeReceived int64 `json:"timereceived"` Details []GetTransactionDetailsResult `json:"details"` Hex string `json:"hex"` - Generated bool `json:"generated"` } type ScanningOrFalse struct { @@ -289,6 +269,7 @@ type ListReceivedByAccountResult struct { // ListReceivedByAddressResult models the data from the listreceivedbyaddress // command. type ListReceivedByAddressResult struct { + Account string `json:"account"` Address string `json:"address"` Amount float64 `json:"amount"` Confirmations uint64 `json:"confirmations"` @@ -317,12 +298,6 @@ type ListUnspentResult struct { IsStake bool `json:"isstake"` } -// RescanBlockchainResult models the data returned from the rescanblockchain command. -type RescanBlockchainResult struct { - StartHeight int32 `json:"start_height"` - StoptHeight int32 `json:"stop_height"` -} - // SignRawTransactionError models the data that contains script verification // errors from the signrawtransaction request. type SignRawTransactionError struct { diff --git a/btcjson/walletsvrresults_test.go b/btcjson/walletsvrresults_test.go index 0db2eafc..510c367c 100644 --- a/btcjson/walletsvrresults_test.go +++ b/btcjson/walletsvrresults_test.go @@ -37,8 +37,10 @@ func TestGetAddressInfoResult(t *testing.T) { name: "GetAddressInfoResult - ScriptType", result: `{"script":"nonstandard","address":"1abc"}`, want: GetAddressInfoResult{ - Address: "1abc", - ScriptType: nonStandard, + embeddedAddressInfo: embeddedAddressInfo{ + Address: "1abc", + ScriptType: nonStandard, + }, }, }, { diff --git a/btcjson/walletsvrwscmds.go b/btcjson/walletsvrwscmds.go index c1fa9151..e1e60fbe 100644 --- a/btcjson/walletsvrwscmds.go +++ b/btcjson/walletsvrwscmds.go @@ -40,7 +40,7 @@ func NewExportWatchingWalletCmd(account *string, download *bool) *ExportWatching // GetUnconfirmedBalanceCmd defines the getunconfirmedbalance JSON-RPC command. type GetUnconfirmedBalanceCmd struct { - Account *string `jsonrpcdefault:"\"default\""` + Account *string } // NewGetUnconfirmedBalanceCmd returns a new instance which can be used to issue @@ -58,7 +58,7 @@ func NewGetUnconfirmedBalanceCmd(account *string) *GetUnconfirmedBalanceCmd { // command. type ListAddressTransactionsCmd struct { Addresses []string - Account *string `jsonrpcdefault:"\"default\""` + Account *string } // NewListAddressTransactionsCmd returns a new instance which can be used to @@ -75,7 +75,7 @@ func NewListAddressTransactionsCmd(addresses []string, account *string) *ListAdd // ListAllTransactionsCmd defines the listalltransactions JSON-RPC command. type ListAllTransactionsCmd struct { - Account *string `jsonrpcdefault:"\"default\""` + Account *string } // NewListAllTransactionsCmd returns a new instance which can be used to issue a @@ -114,8 +114,9 @@ func NewWalletIsLockedCmd() *WalletIsLockedCmd { } func init() { - // The commands in this file are only usable with a wallet server. - flags := UFWalletOnly + // The commands in this file are only usable with a wallet server via + // websockets. + flags := UFWalletOnly | UFWebsocketOnly MustRegisterCmd("createencryptedwallet", (*CreateEncryptedWalletCmd)(nil), flags) MustRegisterCmd("exportwatchingwallet", (*ExportWatchingWalletCmd)(nil), flags) diff --git a/btcjson/walletsvrwscmds_test.go b/btcjson/walletsvrwscmds_test.go index 6d2fa252..3c9751fc 100644 --- a/btcjson/walletsvrwscmds_test.go +++ b/btcjson/walletsvrwscmds_test.go @@ -71,7 +71,7 @@ func TestWalletSvrWsCmds(t *testing.T) { { name: "exportwatchingwallet optional2", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("exportwatchingwallet", btcjson.String("acct"), true) + return btcjson.NewCmd("exportwatchingwallet", "acct", true) }, staticCmd: func() interface{} { return btcjson.NewExportWatchingWalletCmd(btcjson.String("acct"), @@ -93,7 +93,7 @@ func TestWalletSvrWsCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"getunconfirmedbalance","params":[],"id":1}`, unmarshalled: &btcjson.GetUnconfirmedBalanceCmd{ - Account: btcjson.String("default"), + Account: nil, }, }, { @@ -120,7 +120,7 @@ func TestWalletSvrWsCmds(t *testing.T) { marshalled: `{"jsonrpc":"1.0","method":"listaddresstransactions","params":[["1Address"]],"id":1}`, unmarshalled: &btcjson.ListAddressTransactionsCmd{ Addresses: []string{"1Address"}, - Account: btcjson.String("default"), + Account: nil, }, }, { @@ -148,7 +148,7 @@ func TestWalletSvrWsCmds(t *testing.T) { }, marshalled: `{"jsonrpc":"1.0","method":"listalltransactions","params":[],"id":1}`, unmarshalled: &btcjson.ListAllTransactionsCmd{ - Account: btcjson.String("default"), + Account: nil, }, }, { diff --git a/chaincfg/chainhash/hashfuncs.go b/chaincfg/chainhash/hashfuncs.go index 70ac038d..194c60e3 100644 --- a/chaincfg/chainhash/hashfuncs.go +++ b/chaincfg/chainhash/hashfuncs.go @@ -39,11 +39,11 @@ func DoubleHashH(b []byte) Hash { // 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)) +// 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) diff --git a/chaincfg/doc.go b/chaincfg/doc.go index 66b0a67a..fb5fa677 100644 --- a/chaincfg/doc.go +++ b/chaincfg/doc.go @@ -18,40 +18,40 @@ // When a network parameter is needed, it may then be looked up through this // variable (either directly, or hidden in a library call). // -// package main +// package main // -// import ( -// "flag" -// "fmt" -// "log" +// import ( +// "flag" +// "fmt" +// "log" // -// btcutil "github.com/lbryio/lbcutil" -// "github.com/lbryio/lbcd/chaincfg" -// ) +// btcutil "github.com/lbryio/lbcutil" +// "github.com/lbryio/lbcd/chaincfg" +// ) // -// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") +// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") // -// // By default (without -testnet), use mainnet. -// var chainParams = &chaincfg.MainNetParams +// // By default (without -testnet), use mainnet. +// var chainParams = &chaincfg.MainNetParams // -// func main() { -// flag.Parse() +// func main() { +// flag.Parse() // -// // Modify active network parameters if operating on testnet. -// if *testnet { -// chainParams = &chaincfg.TestNet3Params -// } +// // Modify active network parameters if operating on testnet. +// if *testnet { +// chainParams = &chaincfg.TestNet3Params +// } // -// // later... +// // 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) -// } +// // 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) +// } // // If an application does not use one of the three standard Bitcoin networks, // a new Params struct may be created which defines the parameters for the diff --git a/chaincfg/params.go b/chaincfg/params.go index 47291453..1efb9b3d 100644 --- a/chaincfg/params.go +++ b/chaincfg/params.go @@ -794,9 +794,8 @@ func IsBech32SegwitPrefix(prefix string) bool { // ErrInvalidHDKeyID error will be returned. // // Reference: -// -// SLIP-0132 : Registered HD version bytes for BIP-0032 -// https://github.com/satoshilabs/slips/blob/master/slip-0132.md +// SLIP-0132 : Registered HD version bytes for BIP-0032 +// https://github.com/satoshilabs/slips/blob/master/slip-0132.md func RegisterHDKeyID(hdPublicKeyID []byte, hdPrivateKeyID []byte) error { if len(hdPublicKeyID) != 4 || len(hdPrivateKeyID) != 4 { return ErrInvalidHDKeyID diff --git a/claimtrie/change/change.go b/claimtrie/change/change.go index 95a0e3d5..aac349c6 100644 --- a/claimtrie/change/change.go +++ b/claimtrie/change/change.go @@ -78,10 +78,9 @@ func (c *Change) Marshal(enc *bytes.Buffer) error { binary.BigEndian.PutUint32(temp[:4], uint32(len(c.SpentChildren))) enc.Write(temp[:4]) for key := range c.SpentChildren { - keySize := uint16(len(key)) - binary.BigEndian.PutUint16(temp[:2], keySize) // technically limited to 255; not sure we trust it + binary.BigEndian.PutUint16(temp[:2], uint16(len(key))) // technically limited to 255; not sure we trust it enc.Write(temp[:2]) - enc.WriteString(key[:keySize]) + enc.WriteString(key) } } else { binary.BigEndian.PutUint32(temp[:4], 0) diff --git a/claimtrie/claimtrie.go b/claimtrie/claimtrie.go index 1d848e13..68ef6488 100644 --- a/claimtrie/claimtrie.go +++ b/claimtrie/claimtrie.go @@ -4,7 +4,9 @@ import ( "bytes" "fmt" "path/filepath" + "runtime" "sort" + "sync" "github.com/pkg/errors" @@ -47,9 +49,6 @@ type ClaimTrie struct { // Registrered cleanup functions which are invoked in the Close() in reverse order. cleanups []func() error - - // claimLogger communicates progress of claimtrie rebuild. - claimLogger *claimProgressLogger } func New(cfg config.Config) (*ClaimTrie, error) { @@ -247,17 +246,17 @@ func (ct *ClaimTrie) AppendBlock(temporary bool) error { names = append(names, expirations...) names = removeDuplicates(names) - for _, name := range names { + nhns := ct.makeNameHashNext(names, false, nil) + for nhn := range nhns { - hash, next := ct.nodeManager.Hash(name) - ct.merkleTrie.Update(name, hash, true) - if next <= 0 { + ct.merkleTrie.Update(nhn.Name, nhn.Hash, true) + if nhn.Next <= 0 { continue } - newName := normalization.NormalizeIfNecessary(name, next) + newName := normalization.NormalizeIfNecessary(nhn.Name, nhn.Next) updateNames = append(updateNames, newName) - updateHeights = append(updateHeights, next) + updateHeights = append(updateHeights, nhn.Next) } if !temporary && len(updateNames) > 0 { err = ct.temporalRepo.SetNodesAt(updateNames, updateHeights) @@ -331,52 +330,31 @@ func (ct *ClaimTrie) ResetHeight(height int32) error { if passedHashFork { names = nil // force them to reconsider all names } - - var fullRebuildRequired bool - err = ct.merkleTrie.SetRoot(hash) if err == merkletrie.ErrFullRebuildRequired { - fullRebuildRequired = true - } else if err != nil { - return errors.Wrapf(err, "setRoot") - } - - if fullRebuildRequired { ct.runFullTrieRebuild(names, nil) } if !ct.MerkleHash().IsEqual(hash) { - return errors.Errorf("unable to restore the hash at height %d"+ - " (fullTriedRebuilt: %t)", height, fullRebuildRequired) + return errors.Errorf("unable to restore the hash at height %d", height) } return errors.WithStack(ct.blockRepo.Delete(height+1, oldHeight)) } func (ct *ClaimTrie) runFullTrieRebuild(names [][]byte, interrupt <-chan struct{}) { + var nhns chan NameHashNext if names == nil { - node.Log("Building the entire claim trie in RAM...") - ct.claimLogger = newClaimProgressLogger("Processed", node.GetLogger()) - - ct.nodeManager.IterateNames(func(name []byte) bool { - if interruptRequested(interrupt) { - return false - } - clone := make([]byte, len(name)) - copy(clone, name) - hash, _ := ct.nodeManager.Hash(clone) - ct.merkleTrie.Update(clone, hash, false) - ct.claimLogger.LogName(name) - return true - }) + node.LogOnce("Building the entire claim trie in RAM...") + nhns = ct.makeNameHashNext(nil, true, interrupt) } else { - for _, name := range names { - hash, _ := ct.nodeManager.Hash(name) - ct.merkleTrie.Update(name, hash, false) - } + nhns = ct.makeNameHashNext(names, false, interrupt) } + for nhn := range nhns { + ct.merkleTrie.Update(nhn.Name, nhn.Hash, false) + } } // MerkleHash returns the Merkle Hash of the claimTrie. @@ -442,6 +420,12 @@ func (ct *ClaimTrie) FlushToDisk() { } } +type NameHashNext struct { + Name []byte + Hash *chainhash.Hash + Next int32 +} + func interruptRequested(interrupted <-chan struct{}) bool { select { case <-interrupted: // should never block on nil @@ -451,3 +435,53 @@ func interruptRequested(interrupted <-chan struct{}) bool { return false } + +func (ct *ClaimTrie) makeNameHashNext(names [][]byte, all bool, interrupt <-chan struct{}) chan NameHashNext { + inputs := make(chan []byte, 512) + outputs := make(chan NameHashNext, 512) + + var wg sync.WaitGroup + hashComputationWorker := func() { + for name := range inputs { + hash, next := ct.nodeManager.Hash(name) + outputs <- NameHashNext{name, hash, next} + } + wg.Done() + } + + threads := int(0.8 * float32(runtime.NumCPU())) + if threads < 1 { + threads = 1 + } + for threads > 0 { + threads-- + wg.Add(1) + go hashComputationWorker() + } + go func() { + if all { + ct.nodeManager.IterateNames(func(name []byte) bool { + if interruptRequested(interrupt) { + return false + } + clone := make([]byte, len(name)) + copy(clone, name) // iteration name buffer is reused on future loops + inputs <- clone + return true + }) + } else { + for _, name := range names { + if interruptRequested(interrupt) { + break + } + inputs <- name + } + } + close(inputs) + }() + go func() { + wg.Wait() + close(outputs) + }() + return outputs +} diff --git a/claimtrie/cmd/cmd/block.go b/claimtrie/cmd/cmd/block.go index b22c0b65..d0ee7719 100644 --- a/claimtrie/cmd/cmd/block.go +++ b/claimtrie/cmd/cmd/block.go @@ -23,14 +23,12 @@ func NewBlocCommands() *cobra.Command { return cmd } -func NewBlockBestCommand() *cobra.Command { - var showHash bool - var showHeight bool +func NewBlockBestCommand() *cobra.Command { cmd := &cobra.Command{ Use: "best", - Short: "Show the block hash and height of the best block", + Short: "Show the height and hash of the best block", RunE: func(cmd *cobra.Command, args []string) error { db, err := loadBlocksDB() @@ -45,23 +43,12 @@ func NewBlockBestCommand() *cobra.Command { } state := chain.BestSnapshot() - - switch { - case showHeight && showHash: - fmt.Printf("%s:%d\n", state.Hash, state.Height) - case !showHeight && showHash: - fmt.Printf("%s\n", state.Hash) - case showHeight && !showHash: - fmt.Printf("%d\n", state.Height) - } + fmt.Printf("Block %7d: %s\n", state.Height, state.Hash.String()) return nil }, } - cmd.Flags().BoolVar(&showHeight, "showheight", true, "Display block height") - cmd.Flags().BoolVar(&showHash, "showhash", true, "Display block hash") - return cmd } @@ -69,12 +56,10 @@ func NewBlockListCommand() *cobra.Command { var fromHeight int32 var toHeight int32 - var showHash bool - var showHeight bool cmd := &cobra.Command{ Use: "list", - Short: "List block hash and height between blocks ", + Short: "List merkle hash of blocks between ", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { @@ -98,14 +83,7 @@ func NewBlockListCommand() *cobra.Command { if err != nil { return errors.Wrapf(err, "load hash for %d", ht) } - switch { - case showHeight && showHash: - fmt.Printf("%s:%d\n", hash, ht) - case !showHeight && showHash: - fmt.Printf("%s\n", hash) - case showHeight && !showHash: - fmt.Printf("%d\n", ht) - } + fmt.Printf("Block %7d: %s\n", ht, hash.String()) } return nil @@ -114,8 +92,6 @@ func NewBlockListCommand() *cobra.Command { cmd.Flags().Int32Var(&fromHeight, "from", 0, "From height (inclusive)") cmd.Flags().Int32Var(&toHeight, "to", 0, "To height (inclusive)") - cmd.Flags().BoolVar(&showHeight, "showheight", true, "Display block height") - cmd.Flags().BoolVar(&showHash, "showhash", true, "Display block hash") cmd.Flags().SortFlags = false return cmd diff --git a/claimtrie/cmd/cmd/helper.go b/claimtrie/cmd/cmd/helper.go index eb8266c8..e75da402 100644 --- a/claimtrie/cmd/cmd/helper.go +++ b/claimtrie/cmd/cmd/helper.go @@ -15,7 +15,7 @@ import ( func loadBlocksDB() (database.DB, error) { dbPath := filepath.Join(dataDir, netName, "blocks_ffldb") - log.Debugf("Loading blocks database: %s", dbPath) + log.Infof("Loading blocks database: %s", dbPath) db, err := database.Open("ffldb", dbPath, chainPramas().Net) if err != nil { return nil, errors.Wrapf(err, "open blocks database") @@ -27,7 +27,7 @@ func loadBlocksDB() (database.DB, error) { func loadChain(db database.DB) (*blockchain.BlockChain, error) { paramsCopy := chaincfg.MainNetParams - log.Debugf("Loading chain from database") + log.Infof("Loading chain from database") startTime := time.Now() chain, err := blockchain.New(&blockchain.Config{ @@ -40,7 +40,7 @@ func loadChain(db database.DB) (*blockchain.BlockChain, error) { return nil, errors.Wrapf(err, "create blockchain") } - log.Debugf("Loaded chain from database (%s)", time.Since(startTime)) + log.Infof("Loaded chain from database (%s)", time.Since(startTime)) return chain, err diff --git a/claimtrie/cmd/cmd/root.go b/claimtrie/cmd/cmd/root.go index 885c3ef9..8b2fb75f 100644 --- a/claimtrie/cmd/cmd/root.go +++ b/claimtrie/cmd/cmd/root.go @@ -3,21 +3,20 @@ package cmd import ( "os" + "github.com/btcsuite/btclog" "github.com/lbryio/lbcd/claimtrie/config" "github.com/lbryio/lbcd/claimtrie/param" "github.com/lbryio/lbcd/limits" "github.com/lbryio/lbcd/wire" - "github.com/btcsuite/btclog" "github.com/spf13/cobra" ) var ( - log = btclog.NewBackend(os.Stdout).Logger("CMDL") - cfg = config.DefaultConfig - netName string - dataDir string - debugLevel string + log btclog.Logger + cfg = config.DefaultConfig + netName string + dataDir string ) var rootCmd = NewRootCommand() @@ -29,9 +28,6 @@ func NewRootCommand() *cobra.Command { Short: "ClaimTrie Command Line Interface", SilenceUsage: true, PersistentPreRun: func(cmd *cobra.Command, args []string) { - level, _ := btclog.LevelFromString(debugLevel) - log.SetLevel(level) - switch netName { case "mainnet": param.SetNetwork(wire.MainNet) @@ -41,20 +37,21 @@ func NewRootCommand() *cobra.Command { param.SetNetwork(wire.TestNet) } }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - os.Stdout.Sync() - }, } cmd.PersistentFlags().StringVar(&netName, "netname", "mainnet", "Net name") cmd.PersistentFlags().StringVarP(&dataDir, "datadir", "b", cfg.DataDir, "Data dir") - cmd.PersistentFlags().StringVarP(&debugLevel, "debuglevel", "d", cfg.DebugLevel, "Debug level") return cmd } func Execute() { + backendLogger := btclog.NewBackend(os.Stdout) + defer os.Stdout.Sync() + log = backendLogger.Logger("CMDL") + log.SetLevel(btclog.LevelDebug) + // Up some limits. if err := limits.SetLimits(); err != nil { log.Errorf("failed to set limits: %v\n", err) diff --git a/claimtrie/config/config.go b/claimtrie/config/config.go index 67de7396..4920ca17 100644 --- a/claimtrie/config/config.go +++ b/claimtrie/config/config.go @@ -8,10 +8,11 @@ import ( ) var DefaultConfig = Config{ - Params: param.MainNet, - RamTrie: true, // as it stands the other trie uses more RAM, more time, and 40GB+ of disk space - DebugLevel: "info", - DataDir: filepath.Join(btcutil.AppDataDir("lbcd", false), "data"), + Params: param.MainNet, + + RamTrie: true, // as it stands the other trie uses more RAM, more time, and 40GB+ of disk space + + DataDir: filepath.Join(btcutil.AppDataDir("chain", false), "data"), BlockRepoPebble: pebbleConfig{ Path: "blocks_pebble_db", @@ -29,10 +30,11 @@ var DefaultConfig = Config{ // Config is the container of all configurations. type Config struct { - Params param.ClaimTrieParams - RamTrie bool - DataDir string - DebugLevel string + Params param.ClaimTrieParams + + RamTrie bool + + DataDir string BlockRepoPebble pebbleConfig NodeRepoPebble pebbleConfig diff --git a/claimtrie/logger.go b/claimtrie/logger.go deleted file mode 100644 index ef004ea0..00000000 --- a/claimtrie/logger.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2015-2017 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package claimtrie - -import ( - "sync" - "time" - - "github.com/btcsuite/btclog" -) - -// claimProgressLogger provides periodic logging for other services in order -// to show users progress of certain "actions" involving some or all current -// claim names. Ex: rebuilding claimtrie. -type claimProgressLogger struct { - totalLogName int64 - recentLogName int64 - lastLogNameTime time.Time - - subsystemLogger btclog.Logger - progressAction string - sync.Mutex -} - -// newClaimProgressLogger returns a new name progress logger. -// The progress message is templated as follows: -// -// {progressAction} {numProcessed} {names|name} in the last {timePeriod} (total {totalProcessed}) -func newClaimProgressLogger(progressMessage string, logger btclog.Logger) *claimProgressLogger { - return &claimProgressLogger{ - lastLogNameTime: time.Now(), - progressAction: progressMessage, - subsystemLogger: logger, - } -} - -// LogName logs a new claim name as an information message to show progress -// to the user. In order to prevent spam, it limits logging to one message -// every 10 seconds with duration and totals included. -func (n *claimProgressLogger) LogName(name []byte) { - n.Lock() - defer n.Unlock() - - n.totalLogName++ - n.recentLogName++ - - now := time.Now() - duration := now.Sub(n.lastLogNameTime) - if duration < time.Second*10 { - return - } - - // Truncate the duration to 10s of milliseconds. - durationMillis := int64(duration / time.Millisecond) - tDuration := 10 * time.Millisecond * time.Duration(durationMillis/10) - - // Log information about progress. - nameStr := "names" - if n.recentLogName == 1 { - nameStr = "name" - } - n.subsystemLogger.Infof("%s %d claim %s in the last %s (total %d)", - n.progressAction, n.recentLogName, nameStr, tDuration, n.totalLogName) - - n.recentLogName = 0 - n.lastLogNameTime = now -} - -func (n *claimProgressLogger) SetLastLogTime(time time.Time) { - n.lastLogNameTime = time -} diff --git a/claimtrie/merkletrie/vertex.go b/claimtrie/merkletrie/vertex.go index d3326990..77f1f04a 100644 --- a/claimtrie/merkletrie/vertex.go +++ b/claimtrie/merkletrie/vertex.go @@ -17,11 +17,10 @@ func newVertex(hash *chainhash.Hash) *vertex { // TODO: more professional to use msgpack here? // nbuf decodes the on-disk format of a node, which has the following form: -// -// ch(1B) hash(32B) -// ... -// ch(1B) hash(32B) -// vhash(32B) +// ch(1B) hash(32B) +// ... +// ch(1B) hash(32B) +// vhash(32B) type nbuf []byte func (nb nbuf) entries() int { diff --git a/claimtrie/node/cache.go b/claimtrie/node/cache.go deleted file mode 100644 index 905ecd1d..00000000 --- a/claimtrie/node/cache.go +++ /dev/null @@ -1,85 +0,0 @@ -package node - -import ( - "container/list" - - "github.com/lbryio/lbcd/claimtrie/change" -) - -type cacheLeaf struct { - node *Node - element *list.Element - changes []change.Change - height int32 -} - -type Cache struct { - nodes map[string]*cacheLeaf - order *list.List - limit int -} - -func (nc *Cache) insert(name []byte, n *Node, height int32) { - key := string(name) - - existing := nc.nodes[key] - if existing != nil { - existing.node = n - existing.height = height - existing.changes = nil - nc.order.MoveToFront(existing.element) - return - } - - for nc.order.Len() >= nc.limit { - // TODO: maybe ensure that we don't remove nodes that have a lot of changes? - delete(nc.nodes, nc.order.Back().Value.(string)) - nc.order.Remove(nc.order.Back()) - } - - element := nc.order.PushFront(key) - nc.nodes[key] = &cacheLeaf{node: n, element: element, height: height} -} - -func (nc *Cache) fetch(name []byte, height int32) (*Node, []change.Change, int32) { - key := string(name) - - existing := nc.nodes[key] - if existing != nil && existing.height <= height { - nc.order.MoveToFront(existing.element) - return existing.node, existing.changes, existing.height - } - return nil, nil, -1 -} - -func (nc *Cache) addChanges(changes []change.Change, height int32) { - for _, c := range changes { - key := string(c.Name) - existing := nc.nodes[key] - if existing != nil && existing.height <= height { - existing.changes = append(existing.changes, c) - } - } -} - -func (nc *Cache) drop(names [][]byte) { - for _, name := range names { - key := string(name) - existing := nc.nodes[key] - if existing != nil { - // we can't roll it backwards because we don't know its previous height value; just toast it - delete(nc.nodes, key) - nc.order.Remove(existing.element) - } - } -} - -func (nc *Cache) clear() { - nc.nodes = map[string]*cacheLeaf{} - nc.order = list.New() - // we'll let the GC sort out the remains... -} - -func NewCache(limit int) *Cache { - return &Cache{limit: limit, nodes: map[string]*cacheLeaf{}, order: list.New()} -} diff --git a/claimtrie/node/log.go b/claimtrie/node/log.go index ab93d97d..86293b58 100644 --- a/claimtrie/node/log.go +++ b/claimtrie/node/log.go @@ -29,10 +29,6 @@ func UseLogger(logger btclog.Logger) { log = logger } -func GetLogger() btclog.Logger { - return log -} - var loggedStrings = map[string]bool{} // is this gonna get too large? var loggedStringsMutex sync.Mutex @@ -46,10 +42,6 @@ func LogOnce(s string) { log.Info(s) } -func Log(s string) { - log.Info(s) -} - func Warn(s string) { log.Warn(s) } diff --git a/claimtrie/node/manager.go b/claimtrie/node/manager.go index 7081ac25..814bfc80 100644 --- a/claimtrie/node/manager.go +++ b/claimtrie/node/manager.go @@ -21,7 +21,6 @@ type Manager interface { IterateNames(predicate func(name []byte) bool) Hash(name []byte) (*chainhash.Hash, int32) Flush() error - ClearCache() } type BaseManager struct { @@ -31,62 +30,31 @@ type BaseManager struct { changes []change.Change tempChanges map[string][]change.Change - - cache *Cache } func NewBaseManager(repo Repo) (*BaseManager, error) { nm := &BaseManager{ - repo: repo, - cache: NewCache(10000), // TODO: how many should we cache? + repo: repo, } return nm, nil } -func (nm *BaseManager) ClearCache() { - nm.cache.clear() -} - func (nm *BaseManager) NodeAt(height int32, name []byte) (*Node, error) { - n, changes, oldHeight := nm.cache.fetch(name, height) - if n == nil { - changes, err := nm.repo.LoadChanges(name) - if err != nil { - return nil, errors.Wrap(err, "in load changes") - } + changes, err := nm.repo.LoadChanges(name) + if err != nil { + return nil, errors.Wrap(err, "in load changes") + } - if nm.tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block - changes = append(changes, nm.tempChanges[string(name)]...) - } + if nm.tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block + changes = append(changes, nm.tempChanges[string(name)]...) + } - n, err = nm.newNodeFromChanges(changes, height) - if err != nil { - return nil, errors.Wrap(err, "in new node") - } - // TODO: how can we tell what needs to be cached? - if nm.tempChanges == nil && height == nm.height && n != nil && (len(changes) > 4 || len(name) < 12) { - nm.cache.insert(name, n, height) - } - } else { - if nm.tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block - changes = append(changes, nm.tempChanges[string(name)]...) - n = n.Clone() - } else if height != nm.height { - n = n.Clone() - } - updated, err := nm.updateFromChanges(n, changes, height) - if err != nil { - return nil, errors.Wrap(err, "in update from changes") - } - if !updated { - n.AdjustTo(oldHeight, height, name) - } - if nm.tempChanges == nil && height == nm.height { - nm.cache.insert(name, n, height) - } + n, err := nm.newNodeFromChanges(changes, height) + if err != nil { + return nil, errors.Wrap(err, "in new node") } return n, nil @@ -98,13 +66,17 @@ func (nm *BaseManager) node(name []byte) (*Node, error) { return nm.NodeAt(nm.height, name) } -func (nm *BaseManager) updateFromChanges(n *Node, changes []change.Change, height int32) (bool, error) { +// newNodeFromChanges returns a new Node constructed from the changes. +// The changes must preserve their order received. +func (nm *BaseManager) newNodeFromChanges(changes []change.Change, height int32) (*Node, error) { - count := len(changes) - if count == 0 { - return false, nil + if len(changes) == 0 { + return nil, nil } + + n := New() previous := changes[0].Height + count := len(changes) for i, chg := range changes { if chg.Height < previous { @@ -123,37 +95,15 @@ func (nm *BaseManager) updateFromChanges(n *Node, changes []change.Change, heigh delay := nm.getDelayForName(n, chg) err := n.ApplyChange(chg, delay) if err != nil { - return false, errors.Wrap(err, "in apply change") + return nil, errors.Wrap(err, "in apply change") } } if count <= 0 { - // we applied no changes, which means we shouldn't exist if we had all the changes - // or might mean nothing significant if we are applying a partial changeset - return false, nil - } - lastChange := changes[count-1] - n.AdjustTo(lastChange.Height, height, lastChange.Name) - return true, nil -} - -// newNodeFromChanges returns a new Node constructed from the changes. -// The changes must preserve their order received. -func (nm *BaseManager) newNodeFromChanges(changes []change.Change, height int32) (*Node, error) { - - if len(changes) == 0 { return nil, nil } - - n := New() - updated, err := nm.updateFromChanges(n, changes, height) - if err != nil { - return nil, errors.Wrap(err, "in update from changes") - } - if updated { - return n, nil - } - return nil, nil + lastChange := changes[count-1] + return n.AdjustTo(lastChange.Height, height, lastChange.Name), nil } func (nm *BaseManager) AppendChange(chg change.Change) { @@ -270,7 +220,6 @@ func (nm *BaseManager) IncrementHeightTo(height int32, temporary bool) ([][]byte } if !temporary { - nm.cache.addChanges(nm.changes, height) if err := nm.repo.AppendChanges(nm.changes); err != nil { // destroys names return nil, errors.Wrap(err, "in append changes") } @@ -306,8 +255,6 @@ func (nm *BaseManager) DecrementHeightTo(affectedNames [][]byte, height int32) ( return affectedNames, errors.Wrap(err, "in drop changes") } } - - nm.cache.drop(affectedNames) } nm.height = height diff --git a/claimtrie/node/node.go b/claimtrie/node/node.go index ff45fc11..fe6db947 100644 --- a/claimtrie/node/node.go +++ b/claimtrie/node/node.go @@ -110,7 +110,7 @@ func (n *Node) ApplyChange(chg change.Change, delay int32) error { } // AdjustTo activates claims and computes takeovers until it reaches the specified height. -func (n *Node) AdjustTo(height, maxHeight int32, name []byte) { +func (n *Node) AdjustTo(height, maxHeight int32, name []byte) *Node { changed := n.handleExpiredAndActivated(height) > 0 n.updateTakeoverHeight(height, name, changed) if maxHeight > height { @@ -120,6 +120,7 @@ func (n *Node) AdjustTo(height, maxHeight int32, name []byte) { height = h } } + return n } func (n *Node) updateTakeoverHeight(height int32, name []byte, refindBest bool) { @@ -339,28 +340,3 @@ func (n *Node) SortClaimsByBid() { return OutPointLess(n.Claims[j].OutPoint, n.Claims[i].OutPoint) }) } - -func (n *Node) Clone() *Node { - clone := New() - if n.SupportSums != nil { - clone.SupportSums = map[string]int64{} - for key, value := range n.SupportSums { - clone.SupportSums[key] = value - } - } - clone.Supports = make(ClaimList, len(n.Supports)) - for i, support := range n.Supports { - clone.Supports[i] = &Claim{} - *clone.Supports[i] = *support - } - clone.Claims = make(ClaimList, len(n.Claims)) - for i, claim := range n.Claims { - clone.Claims[i] = &Claim{} - *clone.Claims[i] = *claim - } - clone.TakenOverAt = n.TakenOverAt - if n.BestClaim != nil { - clone.BestClaim = clone.Claims.find(byID(n.BestClaim.ClaimID)) - } - return clone -} diff --git a/claimtrie/node/noderepo/pebble.go b/claimtrie/node/noderepo/pebble.go index 32ca2c04..cb5d25e4 100644 --- a/claimtrie/node/noderepo/pebble.go +++ b/claimtrie/node/noderepo/pebble.go @@ -2,9 +2,7 @@ package noderepo import ( "bytes" - "io" "sort" - "sync" "github.com/cockroachdb/pebble" "github.com/lbryio/lbcd/claimtrie/change" @@ -15,76 +13,9 @@ type Pebble struct { db *pebble.DB } -type pooledMerger struct { - values [][]byte - index []int - pool *sync.Pool - buffer []byte -} - -func (a *pooledMerger) Len() int { return len(a.index) } -func (a *pooledMerger) Less(i, j int) bool { return a.index[i] < a.index[j] } -func (a *pooledMerger) Swap(i, j int) { - a.index[i], a.index[j] = a.index[j], a.index[i] - a.values[i], a.values[j] = a.values[j], a.values[i] -} - -func (a *pooledMerger) MergeNewer(value []byte) error { - vc := a.pool.Get().([]byte)[:0] - vc = append(vc, value...) - a.values = append(a.values, vc) - a.index = append(a.index, len(a.values)) - return nil -} - -func (a *pooledMerger) MergeOlder(value []byte) error { - vc := a.pool.Get().([]byte)[:0] - vc = append(vc, value...) - a.values = append(a.values, vc) - a.index = append(a.index, -len(a.values)) - return nil -} - -func (a *pooledMerger) Finish(includesBase bool) ([]byte, io.Closer, error) { - sort.Sort(a) - - a.buffer = a.pool.Get().([]byte)[:0] - for i := range a.values { - a.buffer = append(a.buffer, a.values[i]...) - } - - return a.buffer, a, nil -} - -func (a *pooledMerger) Close() error { - for i := range a.values { - a.pool.Put(a.values[i]) - } - a.pool.Put(a.buffer) - return nil -} - func NewPebble(path string) (*Pebble, error) { - mp := &sync.Pool{ - New: func() interface{} { - return make([]byte, 0, 256) - }, - } - - db, err := pebble.Open(path, &pebble.Options{ - Merger: &pebble.Merger{ - Merge: func(key, value []byte) (pebble.ValueMerger, error) { - p := &pooledMerger{pool: mp} - return p, p.MergeNewer(value) - }, - Name: pebble.DefaultMerger.Name, // yes, it's a lie - }, - Cache: pebble.NewCache(64 << 20), - BytesPerSync: 8 << 20, - MaxOpenFiles: 2000, - }) - + db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(64 << 20), BytesPerSync: 8 << 20, MaxOpenFiles: 2000}) repo := &Pebble{db: db} return repo, errors.Wrapf(err, "unable to open %s", path) diff --git a/claimtrie/node/normalizing_manager.go b/claimtrie/node/normalizing_manager.go index 604fa34d..2f6c4cfe 100644 --- a/claimtrie/node/normalizing_manager.go +++ b/claimtrie/node/normalizing_manager.go @@ -34,7 +34,6 @@ func (nm *NormalizingManager) IncrementHeightTo(height int32, temporary bool) ([ func (nm *NormalizingManager) DecrementHeightTo(affectedNames [][]byte, height int32) ([][]byte, error) { if nm.normalizedAt > height { nm.normalizedAt = -1 - nm.ClearCache() } return nm.Manager.DecrementHeightTo(affectedNames, height) } @@ -111,7 +110,5 @@ func (nm *NormalizingManager) addNormalizationForkChangesIfNecessary(height int3 return true } - - nm.Manager.ClearCache() nm.Manager.IterateNames(predicate) } diff --git a/cmd/lbcctl/config.go b/cmd/lbcctl/config.go index 81b26103..ef961df9 100644 --- a/cmd/lbcctl/config.go +++ b/cmd/lbcctl/config.go @@ -16,7 +16,6 @@ import ( flags "github.com/jessevdk/go-flags" "github.com/lbryio/lbcd/btcjson" "github.com/lbryio/lbcd/chaincfg" - "github.com/lbryio/lbcd/version" btcutil "github.com/lbryio/lbcutil" ) @@ -111,8 +110,6 @@ type config struct { SigNet bool `long:"signet" description:"Connect to signet (default RPC server: localhost:49245)"` Wallet bool `long:"wallet" description:"Connect to wallet RPC server instead (default: localhost:9244, testnet: localhost:19244, regtest: localhost:29244)"` ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` - Timed bool `short:"t" long:"timed" description:"Display RPC response time"` - Quiet bool `short:"q" long:"quiet" description:"Do not output results to stdout"` } // normalizeAddress returns addr with the passed default port appended if @@ -177,10 +174,10 @@ func cleanAndExpandPath(path string) string { // line options. // // The configuration proceeds as follows: -// 1. Start with a default config with sane settings -// 2. Pre-parse the command line to check for an alternative config file -// 3. Load configuration file overwriting defaults with any specified options -// 4. Parse CLI options and overwrite/add any specified options +// 1) Start with a default config with sane settings +// 2) Pre-parse the command line to check for an alternative config file +// 3) Load configuration file overwriting defaults with any specified options +// 4) Parse CLI options and overwrite/add any specified options // // The above results in functioning properly without any config settings // while still allowing the user to override settings with config files and @@ -217,7 +214,7 @@ func loadConfig() (*config, []string, error) { appName = strings.TrimSuffix(appName, filepath.Ext(appName)) usageMessage := fmt.Sprintf("Use %s -h to show options", appName) if preCfg.ShowVersion { - fmt.Println(appName, "version", version.Full()) + fmt.Println(appName, "version", version()) os.Exit(0) } diff --git a/cmd/lbcctl/lbcctl.go b/cmd/lbcctl/lbcctl.go index 40132c65..79349186 100644 --- a/cmd/lbcctl/lbcctl.go +++ b/cmd/lbcctl/lbcctl.go @@ -9,7 +9,6 @@ import ( "os" "path/filepath" "strings" - "time" "github.com/lbryio/lbcd/btcjson" ) @@ -134,8 +133,6 @@ func main() { os.Exit(1) } - started := time.Now() - // Send the JSON-RPC request to the server using the user-specified // connection configuration. result, err := sendPostRequest(marshalledJSON, cfg) @@ -144,16 +141,6 @@ func main() { os.Exit(1) } - if cfg.Timed { - elapsed := time.Since(started) - defer fmt.Fprintf(os.Stderr, "%s\n", elapsed) - } - - var output io.Writer = os.Stdout - if cfg.Quiet { - output = io.Discard - } - // Choose how to display the result based on its type. strResult := string(result) if strings.HasPrefix(strResult, "{") || strings.HasPrefix(strResult, "[") { @@ -163,7 +150,7 @@ func main() { err) os.Exit(1) } - fmt.Fprintln(output, dst.String()) + fmt.Println(dst.String()) } else if strings.HasPrefix(strResult, `"`) { var str string @@ -172,9 +159,9 @@ func main() { err) os.Exit(1) } - fmt.Fprintln(output, str) + fmt.Println(str) } else if strResult != "null" { - fmt.Fprintln(output, strResult) + fmt.Println(strResult) } } diff --git a/cmd/lbcctl/version.go b/cmd/lbcctl/version.go new file mode 100644 index 00000000..588ccf34 --- /dev/null +++ b/cmd/lbcctl/version.go @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "strings" +) + +// semanticAlphabet +const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + +// These constants define the application version and follow the semantic +// versioning 2.0.0 spec (http://semver.org/). +const ( + appMajor uint = 0 + appMinor uint = 22 + appPatch uint = 200 + + // appPreRelease MUST only contain characters from semanticAlphabet + // per the semantic versioning spec. + appPreRelease = "beta" +) + +// appBuild is defined as a variable so it can be overridden during the build +// process with '-ldflags "-X main.appBuild foo' if needed. It MUST only +// contain characters from semanticAlphabet per the semantic versioning spec. +var appBuild string + +// version returns the application version as a properly formed string per the +// semantic versioning 2.0.0 spec (http://semver.org/). +func version() string { + // Start with the major, minor, and patch versions. + version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch) + + // Append pre-release version if there is one. The hyphen called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the pre-release string. The pre-release version + // is not appended if it contains invalid characters. + preRelease := normalizeVerString(appPreRelease) + if preRelease != "" { + version = fmt.Sprintf("%s-%s", version, preRelease) + } + + // Append build metadata if there is any. The plus called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the build metadata string. The build metadata + // string is not appended if it contains invalid characters. + build := normalizeVerString(appBuild) + if build != "" { + version = fmt.Sprintf("%s+%s", version, build) + } + + return version +} + +// normalizeVerString returns the passed string stripped of all characters which +// are not valid according to the semantic versioning guidelines for pre-release +// version and build metadata strings. In particular they MUST only contain +// characters in semanticAlphabet. +func normalizeVerString(str string) string { + var result bytes.Buffer + for _, r := range str { + if strings.ContainsRune(semanticAlphabet, r) { + // Ignoring the error here since it can only fail if + // the the system is out of memory and there are much + // bigger issues at that point. + _, _ = result.WriteRune(r) + } + } + return result.String() +} diff --git a/config.go b/config.go index 27500be5..15758a7d 100644 --- a/config.go +++ b/config.go @@ -32,7 +32,6 @@ import ( _ "github.com/lbryio/lbcd/database/ffldb" "github.com/lbryio/lbcd/mempool" "github.com/lbryio/lbcd/peer" - "github.com/lbryio/lbcd/version" "github.com/lbryio/lbcd/wire" btcutil "github.com/lbryio/lbcutil" ) @@ -66,9 +65,8 @@ const ( defaultMaxOrphanTxSize = 100000 defaultSigCacheMaxSize = 100000 sampleConfigFilename = "sample-lbcd.conf" - defaultTxIndex = true + defaultTxIndex = false defaultAddrIndex = false - defaultUpnp = true ) var ( @@ -117,7 +115,6 @@ type config struct { ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"` CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"` - MemProfile string `long:"memprofile" description:"Write memory profile to the specified file"` DataDir string `short:"b" long:"datadir" description:"Directory to store data"` DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"` DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify =,=,... to set the log level for individual subsystems -- Use show to list available subsystems"` @@ -177,7 +174,7 @@ type config struct { TrickleInterval time.Duration `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"` TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"` UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` - Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"` + NoUpnp bool `long:"noupnp" description:"Don't use UPnP to map our listening port outside of NAT"` ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"` lookup func(string) ([]net.IP, error) @@ -409,10 +406,10 @@ func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *fl // line options. // // The configuration proceeds as follows: -// 1. Start with a default config with sane settings -// 2. Pre-parse the command line to check for an alternative config file -// 3. Load configuration file overwriting defaults with any specified options -// 4. Parse CLI options and overwrite/add any specified options +// 1) Start with a default config with sane settings +// 2) Pre-parse the command line to check for an alternative config file +// 3) Load configuration file overwriting defaults with any specified options +// 4) Parse CLI options and overwrite/add any specified options // // The above results in lbcd functioning properly without any config settings // while still allowing the user to override settings with config files and @@ -446,7 +443,6 @@ func loadConfig() (*config, []string, error) { Generate: defaultGenerate, TxIndex: defaultTxIndex, AddrIndex: defaultAddrIndex, - Upnp: defaultUpnp, } // Service options which are only added on Windows. @@ -471,7 +467,7 @@ func loadConfig() (*config, []string, error) { appName = strings.TrimSuffix(appName, filepath.Ext(appName)) usageMessage := fmt.Sprintf("Use %s -h to show usage", appName) if preCfg.ShowVersion { - fmt.Println(appName, "version", version.Full()) + fmt.Println(appName, "version", version()) os.Exit(0) } @@ -977,8 +973,13 @@ func loadConfig() (*config, []string, error) { // Only allow TLS to be disabled if the RPC is bound to localhost // addresses. if !cfg.DisableRPC && cfg.DisableTLS { + allowedTLSListeners := map[string]struct{}{ + "localhost": {}, + "127.0.0.1": {}, + "::1": {}, + } for _, addr := range cfg.RPCListeners { - _, _, err := net.SplitHostPort(addr) + host, _, err := net.SplitHostPort(addr) if err != nil { str := "%s: RPC listen interface '%s' is " + "invalid: %v" @@ -987,6 +988,15 @@ func loadConfig() (*config, []string, error) { fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err } + if _, ok := allowedTLSListeners[host]; !ok { + str := "%s: the --notls option may not be used " + + "when binding RPC to non localhost " + + "addresses: %s" + err := fmt.Errorf(str, funcName, addr) + fmt.Fprintln(os.Stderr, err) + fmt.Fprintln(os.Stderr, usageMessage) + return nil, nil, err + } } } diff --git a/config_test.go b/config_test.go index ad09ffb5..15953b15 100644 --- a/config_test.go +++ b/config_test.go @@ -20,6 +20,7 @@ var ( // parameters which are command-line only. These fields are copied line-by-line // from "config" struct in "config.go", and the field names, types, and tags must // match for the test to work. +// type configCmdLineOnly struct { ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"` diff --git a/connmgr/doc.go b/connmgr/doc.go index d101c434..acb90c31 100644 --- a/connmgr/doc.go +++ b/connmgr/doc.go @@ -5,7 +5,7 @@ /* Package connmgr implements a generic Bitcoin network connection manager. -# Connection Manager Overview +Connection Manager Overview Connection Manager handles all the general connection concerns such as maintaining a set number of outbound connections, sourcing peers, banning, diff --git a/contrib/showminer.sh b/contrib/showminer.sh deleted file mode 100755 index 9ee52624..00000000 --- a/contrib/showminer.sh +++ /dev/null @@ -1,42 +0,0 @@ -#! /bin/bash - -read -r -d '' help << EOM -$0 - helper script for displaying miner of a mined block. - -Options: - - -h Display this message. - - --height Specify blockheight. - --hash Specify blockhash. -EOM - -while getopts ":h-:" optchar; do - case "${optchar}" in - -) - case "${OPTARG}" in - hash) - blockhash="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 )) - ;; - height) - blockheight="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 )) - blockhash=$(lbcctl getblockhash ${blockheight}) - ;; - *) echo "Unknown long option --${OPTARG}" >&2; exit -2 ;; - esac - ;; - h) printf "${help}\n\n"; exit 2;; - *) echo "Unknown option -${OPTARG}" >&2; exit -2;; - esac -done - - -block=$(lbcctl getblock $blockhash) -blockheight=$(lbcctl getblock $blockhash | jq -r .height) - -coinbase_txid=$(echo ${block} | jq -r '.tx[0]') -coinbase_raw=$(lbcctl getrawtransaction ${coinbase_txid} 1) -coinbase=$(echo ${coinbase_raw} | jq '.vin[0].coinbase') -miner=$(echo ${coinbase} | grep -o '2f.*2f' | xxd -r -p | strings) - -echo ${blockheight}: ${blockhash}: ${miner} diff --git a/contrib/snapshot.sh b/contrib/snapshot.sh deleted file mode 100755 index 9b885514..00000000 --- a/contrib/snapshot.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -read -r -d '' help << EOM -snapshot.sh - helper script for generating snapshot from lbcd's app dir. - -The default output name "lbcd_snapshot___.tar.zst" - -To extract the snapshot (data/mainter/): - - zstd -d lbcd_snapshot___.tar.zst | tar xf - -C - -Default appdir of lbcd on different OSes: - - Darwin) "\${HOME}/Library/Application Support/Lbcd" - Linux) "\${HOME}/.lbcd" - Windows) "%%LOCALAPPDATA%%/lbcd" - -Options: - - -h Display this message. - -d Specify APPDIR to copy the snapshot from. - - -o Specify the output filename of snapshot. - -b Specify the best block height of the snapshot. (ignored if -o is specified) - -l Specify git tag of the running lbcd. (ignored if -o is specified) - -t Specify the date when the snapshot is generated. (ignored if -o is specified) -EOM - -while getopts o:d:b:l:t:h flag -do - case "${flag}" in - h) printf "${help}\n\n"; exit 0;; - d) appdir=${OPTARG};; - - o) snapshot=${OPTARG};; - b) height=${OPTARG};; - l) lbcd_ver=${OPTARG};; - t) date=${OPTARG};; - esac -done - -if [ -z "$appdir" ]; then - case $(uname) in - Darwin) appdir="${HOME}/Library/Application Support/Lbcd" ;; - Linux) appdir="${HOME}/.lbcd" ;; - Windows) appdir="%LOCALAPPDATA%/lbcd" ;; - esac -fi - - -if [ -z ${snapshot} ]; then - git_repo=$(git rev-parse --show-toplevel) - [ -z "${height}" ] && height=$(go run ${git_repo}/claimtrie/cmd block best --showhash=false) - [ -z "${lbcd_ver}" ] && lbcd_ver=$(git describe --tags) - [ -z "${date}" ] && date=$(date +"%Y-%m-%d") - snapshot="lbcd_snapshot_${height}_${lbcd_ver}_${date}.tar.zst" -fi - - -echo "Generating $snapshot ..." - -tar c -C "${appdir}" data/mainnet | zstd -9 --no-progress -o "${snapshot}" - diff --git a/database/doc.go b/database/doc.go index 80a2669d..49720671 100644 --- a/database/doc.go +++ b/database/doc.go @@ -5,7 +5,7 @@ /* Package database provides a block and metadata storage database. -# Overview +Overview As of Feb 2016, there are over 400,000 blocks in the Bitcoin block chain and and over 112 million transactions (which turns out to be over 60GB of data). @@ -18,15 +18,15 @@ storage, and strict checksums in key areas to ensure data integrity. A quick overview of the features database provides are as follows: - - Key/value metadata store - - Bitcoin block storage - - Efficient retrieval of block headers and regions (transactions, scripts, etc) - - Read-only and read-write transactions with both manual and managed modes - - Nested buckets - - Supports registration of backend databases - - Comprehensive test coverage + - Key/value metadata store + - Bitcoin block storage + - Efficient retrieval of block headers and regions (transactions, scripts, etc) + - Read-only and read-write transactions with both manual and managed modes + - Nested buckets + - Supports registration of backend databases + - Comprehensive test coverage -# Database +Database The main entry point is the DB interface. It exposes functionality for transactional-based access and storage of metadata and block data. It is @@ -43,14 +43,14 @@ The Begin function provides an unmanaged transaction while the View and Update functions provide a managed transaction. These are described in more detail below. -# Transactions +Transactions The Tx interface provides facilities for rolling back or committing changes that took place while the transaction was active. It also provides the root metadata bucket under which all keys, values, and nested buckets are stored. A transaction can either be read-only or read-write and managed or unmanaged. -# Managed versus Unmanaged Transactions +Managed versus Unmanaged Transactions A managed transaction is one where the caller provides a function to execute within the context of the transaction and the commit or rollback is handled @@ -63,7 +63,7 @@ call Commit or Rollback when they are finished with it. Leaving transactions open for long periods of time can have several adverse effects, so it is recommended that managed transactions are used instead. -# Buckets +Buckets The Bucket interface provides the ability to manipulate key/value pairs and nested buckets as well as iterate through them. @@ -73,7 +73,7 @@ CreateBucket, CreateBucketIfNotExists, and DeleteBucket functions work with buckets. The ForEach function allows the caller to provide a function to be called with each key/value pair and nested bucket in the current bucket. -# Metadata Bucket +Metadata Bucket As discussed above, all of the functions which are used to manipulate key/value pairs and nested buckets exist on the Bucket interface. The root metadata @@ -81,7 +81,7 @@ bucket is the upper-most bucket in which data is stored and is created at the same time as the database. Use the Metadata function on the Tx interface to retrieve it. -# Nested Buckets +Nested Buckets The CreateBucket and CreateBucketIfNotExists functions on the Bucket interface provide the ability to create an arbitrary number of nested buckets. It is diff --git a/database/ffldb/blockio.go b/database/ffldb/blockio.go index a0abfe72..2ed4eccf 100644 --- a/database/ffldb/blockio.go +++ b/database/ffldb/blockio.go @@ -622,8 +622,8 @@ func (s *blockStore) syncBlocks() error { // were partially written. // // There are effectively two scenarios to consider here: -// 1. Transient write failures from which recovery is possible -// 2. More permanent failures such as hard disk death and/or removal +// 1) Transient write failures from which recovery is possible +// 2) More permanent failures such as hard disk death and/or removal // // In either case, the write cursor will be repositioned to the old block file // offset regardless of any other errors that occur while attempting to undo diff --git a/database/ffldb/doc.go b/database/ffldb/doc.go index e9f42d5e..cca5ebc5 100644 --- a/database/ffldb/doc.go +++ b/database/ffldb/doc.go @@ -10,7 +10,7 @@ This driver is the recommended driver for use with lbcd. It makes use leveldb for the metadata, flat files for block storage, and checksums in key areas to ensure data integrity. -# Usage +Usage This package is a driver to the database package and provides the database type of "ffldb". The parameters the Open and Create functions take are the diff --git a/database/internal/treap/treapiter.go b/database/internal/treap/treapiter.go index ae7ed853..d6981aaf 100644 --- a/database/internal/treap/treapiter.go +++ b/database/internal/treap/treapiter.go @@ -318,14 +318,13 @@ func (iter *Iterator) ForceReseek() { // unexpected keys and/or values. // // For example: -// -// iter := t.Iterator(nil, nil) -// for iter.Next() { -// if someCondition { -// t.Delete(iter.Key()) -// iter.ForceReseek() -// } -// } +// iter := t.Iterator(nil, nil) +// for iter.Next() { +// if someCondition { +// t.Delete(iter.Key()) +// iter.ForceReseek() +// } +// } func (t *Mutable) Iterator(startKey, limitKey []byte) *Iterator { iter := &Iterator{ t: t, diff --git a/doc.go b/doc.go index cbfa6b6b..ee4a9405 100644 --- a/doc.go +++ b/doc.go @@ -18,144 +18,143 @@ on Windows. The -C (--configfile) flag, as shown below, can be used to override this location. Usage: - - lbcd [OPTIONS] + lbcd [OPTIONS] Application Options: - - --addcheckpoint= Add a custom checkpoint. Format: - ':' - -a, --addpeer= Add a peer to connect with at startup - --addrindex Maintain a full address-based transaction index - which makes the searchrawtransactions RPC - available - --banduration= How long to ban misbehaving peers. Valid time - units are {s, m, h}. Minimum 1 second (default: - 24h0m0s) - --banthreshold= Maximum allowed ban score before disconnecting - and banning misbehaving peers. (default: 100) - --blockmaxsize= Maximum block size in bytes to be used when - creating a block (default: 750000) - --blockminsize= Mininum block size in bytes to be used when - creating a block - --blockmaxweight= Maximum block weight to be used when creating a - block (default: 3000000) - --blockminweight= Mininum block weight to be used when creating a - block - --blockprioritysize= Size in bytes for high-priority/low-fee - transactions when creating a block (default: - 50000) - --blocksonly Do not accept transactions from remote peers. - -C, --configfile= Path to configuration file - --connect= Connect only to the specified peers at startup - --cpuprofile= Write CPU profile to the specified file - -b, --datadir= Directory to store data - --dbtype= Database backend to use for the Block Chain - (default: ffldb) - -d, --debuglevel= Logging level for all subsystems {trace, debug, - info, warn, error, critical} -- You may also - specify - =,=,... to - set the log level for individual subsystems -- - Use show to list available subsystems (default: - info) - --dropaddrindex Deletes the address-based transaction index from - the database on start up and then exits. - --dropcfindex Deletes the index used for committed filtering - (CF) support from the database on start up and - then exits. - --droptxindex Deletes the hash-based transaction index from the - database on start up and then exits. - --externalip= Add an ip to the list of local addresses we claim - to listen on to peers - --generate Generate (mine) bitcoins using the CPU - --limitfreerelay= Limit relay of transactions with no transaction - fee to the given amount in thousands of bytes per - minute (default: 15) - --listen= Add an interface/port to listen for connections - (default all interfaces port: 9246, testnet: - 19246, regtest: 29246, signet: 39246) - --logdir= Directory to log output - --maxorphantx= Max number of orphan transactions to keep in - memory (default: 100) - --maxpeers= Max number of inbound and outbound peers - (default: 125) - --memprofile= Write memory profile to the specified file - --miningaddr= Add the specified payment address to the list of - addresses to use for generated blocks -- At least - one address is required if the generate option is - set - --minrelaytxfee= The minimum transaction fee in BTC/kB to be - considered a non-zero fee. (default: 1e-05) - --nobanning Disable banning of misbehaving peers - --nocfilters Disable committed filtering (CF) support - --nocheckpoints Disable built-in checkpoints. Don't do this - unless you know what you're doing. - --nodnsseed Disable DNS seeding for peers - --nolisten Disable listening for incoming connections -- - NOTE: Listening is automatically disabled if the - --connect or --proxy options are used without - also specifying listen interfaces via --listen - --noonion Disable connecting to tor hidden services - --nopeerbloomfilters Disable bloom filtering support - --norelaypriority Do not require free or low-fee transactions to - have high priority for relaying - --norpc Disable built-in RPC server -- NOTE: The RPC - server is disabled by default if no - rpcuser/rpcpass or rpclimituser/rpclimitpass is - specified - --notls Disable TLS for the RPC server - --onion= Connect to tor hidden services via SOCKS5 proxy - (eg. 127.0.0.1:9050) - --onionpass= Password for onion proxy server - --onionuser= Username for onion proxy server - --profile= Enable HTTP profiling on given port -- NOTE port - must be between 1024 and 65536 - --proxy= Connect via SOCKS5 proxy (eg. 127.0.0.1:9050) - --proxypass= Password for proxy server - --proxyuser= Username for proxy server - --regtest Use the regression test network - --rejectnonstd Reject non-standard transactions regardless of - the default settings for the active network. - --relaynonstd Relay non-standard transactions regardless of the - default settings for the active network. - --rpccert= File containing the certificate file - --rpckey= File containing the certificate key - --rpclimitpass= Password for limited RPC connections - --rpclimituser= Username for limited RPC connections - --rpclisten= Add an interface/port to listen for RPC - connections (default port: 9245, testnet: 19245, regtest: 29245) - --rpcmaxclients= Max number of RPC clients for standard - connections (default: 10) - --rpcmaxconcurrentreqs= Max number of concurrent RPC requests that may be - processed concurrently (default: 20) - --rpcmaxwebsockets= Max number of RPC websocket connections (default: - 25) - --rpcquirks Mirror some JSON-RPC quirks of Bitcoin Core -- - NOTE: Discouraged unless interoperability issues - need to be worked around - -P, --rpcpass= Password for RPC connections - -u, --rpcuser= Username for RPC connections - --sigcachemaxsize= The maximum number of entries in the signature - verification cache (default: 100000) - --simnet Use the simulation test network - --testnet Use the test network - --torisolation Enable Tor stream isolation by randomizing user - credentials for each connection. - --trickleinterval= Minimum time between attempts to send new - inventory to a connected peer (default: 10s) - --txindex Maintain a full hash-based transaction index - which makes all transactions available via the - getrawtransaction RPC - --uacomment= Comment to add to the user agent -- See BIP 14 - for more information. - --upnp Use UPnP to map our listening port outside of NAT - -V, --version Display version information and exit - --whitelist= Add an IP network or IP that will not be banned. - (eg. 192.168.1.0/24 or ::1) + --addcheckpoint= Add a custom checkpoint. Format: + ':' + -a, --addpeer= Add a peer to connect with at startup + --addrindex Maintain a full address-based transaction index + which makes the searchrawtransactions RPC + available + --banduration= How long to ban misbehaving peers. Valid time + units are {s, m, h}. Minimum 1 second (default: + 24h0m0s) + --banthreshold= Maximum allowed ban score before disconnecting + and banning misbehaving peers. (default: 100) + --blockmaxsize= Maximum block size in bytes to be used when + creating a block (default: 750000) + --blockminsize= Mininum block size in bytes to be used when + creating a block + --blockmaxweight= Maximum block weight to be used when creating a + block (default: 3000000) + --blockminweight= Mininum block weight to be used when creating a + block + --blockprioritysize= Size in bytes for high-priority/low-fee + transactions when creating a block (default: + 50000) + --blocksonly Do not accept transactions from remote peers. + -C, --configfile= Path to configuration file + --connect= Connect only to the specified peers at startup + --cpuprofile= Write CPU profile to the specified file + -b, --datadir= Directory to store data + --dbtype= Database backend to use for the Block Chain + (default: ffldb) + -d, --debuglevel= Logging level for all subsystems {trace, debug, + info, warn, error, critical} -- You may also + specify + =,=,... to + set the log level for individual subsystems -- + Use show to list available subsystems (default: + info) + --dropaddrindex Deletes the address-based transaction index from + the database on start up and then exits. + --dropcfindex Deletes the index used for committed filtering + (CF) support from the database on start up and + then exits. + --droptxindex Deletes the hash-based transaction index from the + database on start up and then exits. + --externalip= Add an ip to the list of local addresses we claim + to listen on to peers + --generate Generate (mine) bitcoins using the CPU + --limitfreerelay= Limit relay of transactions with no transaction + fee to the given amount in thousands of bytes per + minute (default: 15) + --listen= Add an interface/port to listen for connections + (default all interfaces port: 9246, testnet: + 19246, regtest: 29246, signet: 39246) + --logdir= Directory to log output + --maxorphantx= Max number of orphan transactions to keep in + memory (default: 100) + --maxpeers= Max number of inbound and outbound peers + (default: 125) + --miningaddr= Add the specified payment address to the list of + addresses to use for generated blocks -- At least + one address is required if the generate option is + set + --minrelaytxfee= The minimum transaction fee in BTC/kB to be + considered a non-zero fee. (default: 1e-05) + --nobanning Disable banning of misbehaving peers + --nocfilters Disable committed filtering (CF) support + --nocheckpoints Disable built-in checkpoints. Don't do this + unless you know what you're doing. + --nodnsseed Disable DNS seeding for peers + --nolisten Disable listening for incoming connections -- + NOTE: Listening is automatically disabled if the + --connect or --proxy options are used without + also specifying listen interfaces via --listen + --noonion Disable connecting to tor hidden services + --nopeerbloomfilters Disable bloom filtering support + --norelaypriority Do not require free or low-fee transactions to + have high priority for relaying + --norpc Disable built-in RPC server -- NOTE: The RPC + server is disabled by default if no + rpcuser/rpcpass or rpclimituser/rpclimitpass is + specified + --notls Disable TLS for the RPC server -- NOTE: This is + only allowed if the RPC server is bound to + localhost + --onion= Connect to tor hidden services via SOCKS5 proxy + (eg. 127.0.0.1:9050) + --onionpass= Password for onion proxy server + --onionuser= Username for onion proxy server + --profile= Enable HTTP profiling on given port -- NOTE port + must be between 1024 and 65536 + --proxy= Connect via SOCKS5 proxy (eg. 127.0.0.1:9050) + --proxypass= Password for proxy server + --proxyuser= Username for proxy server + --regtest Use the regression test network + --rejectnonstd Reject non-standard transactions regardless of + the default settings for the active network. + --relaynonstd Relay non-standard transactions regardless of the + default settings for the active network. + --rpccert= File containing the certificate file + --rpckey= File containing the certificate key + --rpclimitpass= Password for limited RPC connections + --rpclimituser= Username for limited RPC connections + --rpclisten= Add an interface/port to listen for RPC + connections (default port: 9245, testnet: 19245, regtest: 29245) + --rpcmaxclients= Max number of RPC clients for standard + connections (default: 10) + --rpcmaxconcurrentreqs= Max number of concurrent RPC requests that may be + processed concurrently (default: 20) + --rpcmaxwebsockets= Max number of RPC websocket connections (default: + 25) + --rpcquirks Mirror some JSON-RPC quirks of Bitcoin Core -- + NOTE: Discouraged unless interoperability issues + need to be worked around + -P, --rpcpass= Password for RPC connections + -u, --rpcuser= Username for RPC connections + --sigcachemaxsize= The maximum number of entries in the signature + verification cache (default: 100000) + --simnet Use the simulation test network + --testnet Use the test network + --torisolation Enable Tor stream isolation by randomizing user + credentials for each connection. + --trickleinterval= Minimum time between attempts to send new + inventory to a connected peer (default: 10s) + --txindex Maintain a full hash-based transaction index + which makes all transactions available via the + getrawtransaction RPC + --uacomment= Comment to add to the user agent -- See BIP 14 + for more information. + --upnp Use UPnP to map our listening port outside of NAT + -V, --version Display version information and exit + --whitelist= Add an IP network or IP that will not be banned. + (eg. 192.168.1.0/24 or ::1) Help Options: + -h, --help Show this help message - -h, --help Show this help message */ package main diff --git a/fees/doc.go b/fees/doc.go index 627337b6..77419317 100644 --- a/fees/doc.go +++ b/fees/doc.go @@ -7,11 +7,11 @@ Package fees provides decred-specific methods for tracking and estimating fee rates for new transactions to be mined into the network. Fee rate estimation has two main goals: - - Ensuring transactions are mined within a target _confirmation range_ - (expressed in blocks); - - Attempting to minimize fees while maintaining be above restriction. +- Ensuring transactions are mined within a target _confirmation range_ + (expressed in blocks); +- Attempting to minimize fees while maintaining be above restriction. -# Preliminaries +Preliminaries There are two main regimes against which fee estimation needs to be evaluated according to how full blocks being mined are (and consequently how important fee @@ -39,7 +39,7 @@ The current approach to implement this estimation is based on bitcoin core's algorithm. References [1] and [2] provide a high level description of how it works there. Actual code is linked in references [3] and [4]. -# Outline of the Algorithm +Outline of the Algorithm The algorithm is currently based in fee estimation as used in v0.14 of bitcoin core (which is also the basis for the v0.15+ method). A more comprehensive @@ -54,31 +54,31 @@ The basic algorithm is as follows (as executed by a single full node): Stats building stage: - - For each transaction observed entering mempool, record the block at which it - was first seen - - For each mined transaction which was previously observed to enter the mempool, - record how long (in blocks) it took to be mined and its fee rate - - Group mined transactions into fee rate _buckets_ and _confirmation ranges_, - creating a table of how many transactions were mined at each confirmation - range and fee rate bucket and their total committed fee - - Whenever a new block is mined, decay older transactions to account for a - dynamic fee environment +- For each transaction observed entering mempool, record the block at which it + was first seen +- For each mined transaction which was previously observed to enter the mempool, + record how long (in blocks) it took to be mined and its fee rate +- Group mined transactions into fee rate _buckets_ and _confirmation ranges_, + creating a table of how many transactions were mined at each confirmation + range and fee rate bucket and their total committed fee +- Whenever a new block is mined, decay older transactions to account for a + dynamic fee environment Estimation stage: - - Input a target confirmation range (how many blocks to wait for the tx to be - mined) - - Starting at the highest fee bucket, look for buckets where the chance of - confirmation within the desired confirmation window is > 95% - - Average all such buckets to get the estimated fee rate +- Input a target confirmation range (how many blocks to wait for the tx to be + mined) +- Starting at the highest fee bucket, look for buckets where the chance of + confirmation within the desired confirmation window is > 95% +- Average all such buckets to get the estimated fee rate -# Simulation +Simulation Development of the estimator was originally performed and simulated using the code in [5]. Simulation of the current code can be performed by using the dcrfeesim tool available in [6]. -# Acknowledgements +Acknowledgements Thanks to @davecgh for providing the initial review of the results and the original developers of the bitcoin core code (the brunt of which seems to have diff --git a/go.mod b/go.mod index 77fd4cce..129c3f44 100644 --- a/go.mod +++ b/go.mod @@ -1,56 +1,54 @@ module github.com/lbryio/lbcd -go 1.19 +go 1.17 require ( github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 github.com/btcsuite/winsvc v1.0.0 - github.com/cockroachdb/errors v1.9.0 - github.com/cockroachdb/pebble v0.0.0-20220523221036-bb2c1501ac23 + github.com/cockroachdb/errors v1.8.6 + github.com/cockroachdb/pebble v0.0.0-20211124004043-0dc90bc41e62 github.com/davecgh/go-spew v1.1.1 - github.com/decred/dcrd/lru v1.1.1 - github.com/felixge/fgprof v0.9.2 - github.com/jessevdk/go-flags v1.5.0 + github.com/decred/dcrd/lru v1.0.0 + github.com/felixge/fgprof v0.9.1 + github.com/jessevdk/go-flags v1.4.0 github.com/jrick/logrotate v1.0.0 - github.com/lbryio/lbcutil v1.0.202 + github.com/lbryio/lbcutil v1.0.202-rc3 github.com/pkg/errors v0.9.1 - github.com/shirou/gopsutil/v3 v3.22.4 + github.com/shirou/gopsutil/v3 v3.22.1 github.com/spf13/cobra v1.1.3 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/vmihailenco/msgpack/v5 v5.3.2 - golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 + golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b ) require ( - github.com/DataDog/zstd v1.5.2 // indirect + github.com/DataDog/zstd v1.5.0 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/aead/siphash v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect github.com/cockroachdb/redact v1.1.3 // indirect - github.com/codahale/hdrhistogram v0.9.0 // indirect - github.com/getsentry/sentry-go v0.13.0 // indirect + github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/pprof v0.0.0-20220520215854-d04f2422c8a1 // indirect + github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/kkdai/bstream v1.0.0 // indirect - github.com/klauspost/compress v1.15.4 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lufia/plan9stats v0.0.0-20220517141722-cf486979b281 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect - github.com/rogpeppe/go-internal v1.8.1 // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/tklauser/go-sysconf v0.3.10 // indirect - github.com/tklauser/numcpus v0.5.0 // indirect + github.com/tklauser/go-sysconf v0.3.9 // indirect + github.com/tklauser/numcpus v0.3.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect - golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/exp v0.0.0-20211123021643-48cbe7f80d7c // indirect + golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 29fa50be..bc353fc7 100644 --- a/go.sum +++ b/go.sum @@ -11,43 +11,69 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= +github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -55,29 +81,29 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= -github.com/cockroachdb/datadriven v1.0.1-0.20211007161720-b558070c3be0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= -github.com/cockroachdb/datadriven v1.0.1-0.20220214170620-9913f5bc19b7/go.mod h1:hi0MtSY3AYDQNDi83kDkMH5/yqM/CsIrsOITkSoH7KI= github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/errors v1.8.8/go.mod h1:z6VnEL3hZ/2ONZEvG7S5Ym0bU2AqPcEKnIiA1wbsSu0= -github.com/cockroachdb/errors v1.9.0 h1:B48dYem5SlAY7iU8AKsgedb4gH6mo+bDkbtLIvM/a88= -github.com/cockroachdb/errors v1.9.0/go.mod h1:vaNcEYYqbIqB5JhKBhFV9CneUqeuEbB2OYJBK4GBNYQ= +github.com/cockroachdb/errors v1.8.6 h1:Am9evxl/po3RzpokemQvq7S7Cd0mxv24xy0B/trlQF4= +github.com/cockroachdb/errors v1.8.6/go.mod h1:hOm5fabihW+xEyY1kuypGwqT+Vt7rafg04ytBtIpeIQ= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f h1:6jduT9Hfc0njg5jJ1DdKCFPdMBrp/mdZfCpa5h+WM74= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20220523221036-bb2c1501ac23 h1:/Pvbuwd61qRxNCIpSIWbx7Oqy1tinfErdetF91DU9gQ= -github.com/cockroachdb/pebble v0.0.0-20220523221036-bb2c1501ac23/go.mod h1:buxOO9GBtOcq1DiXDpIPYrmxY020K2A8lOrwno5FetU= +github.com/cockroachdb/pebble v0.0.0-20210525181856-e45797baeb78/go.mod h1:1XpB4cLQcF189RAcWi4gUc110zJgtOfT7SVNGY8sOe0= +github.com/cockroachdb/pebble v0.0.0-20211124004043-0dc90bc41e62 h1:MPucjIPsIzjSY4RLiyhjX00sHQVNXbzzTpfYHfj0cQw= +github.com/cockroachdb/pebble v0.0.0-20211124004043-0dc90bc41e62/go.mod h1:buxOO9GBtOcq1DiXDpIPYrmxY020K2A8lOrwno5FetU= github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/redact v1.1.1/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codahale/hdrhistogram v0.9.0 h1:9GjrtRI+mLEFPtTfR/AZhcxp+Ii8NZYWq5104FbZQY0= -github.com/codahale/hdrhistogram v0.9.0/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -85,22 +111,33 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/lru v1.1.1 h1:kWFDaW0OWx6AD6Ki342c+JPmHbiVdE6rK81pT3fuo/Y= -github.com/decred/dcrd/lru v1.1.1/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -110,16 +147,15 @@ github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHj github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/fgprof v0.9.2 h1:tAMHtWMyl6E0BimjVbFt7fieU6FpjttsZN7j0wT5blc= -github.com/felixge/fgprof v0.9.2/go.mod h1:+VNi+ZXtHIQ6wIw6bUT8nXQRefQflWECoFyRealT5sg= +github.com/felixge/fgprof v0.9.1 h1:E6FUJ2Mlv043ipLOCFqo8+cHo9MhQ203E2cdEK/isEs= +github.com/felixge/fgprof v0.9.1/go.mod h1:7/HK6JFtFaARhIljgP2IV8rJLIoHDoOYoUphsnGvqxE= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= -github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo= -github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -130,16 +166,24 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -148,9 +192,10 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -167,6 +212,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -178,32 +225,39 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20220520215854-d04f2422c8a1 h1:K4bn56FHdjFCfjSo3wWaD6rJL8r9yvmmncJNMhdkKrw= -github.com/google/pprof v0.0.0-20220520215854-d04f2422c8a1/go.mod h1:gSuNB+gJaOiQKLEZ+q+PK9Mq3SOzhRcw2GsGS/FhYDk= +github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040 h1:i7RUpu0EybzQyQvPT7J3MmODs4+gPcHsD/pqW0uIYVo= +github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -224,25 +278,28 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= @@ -251,30 +308,26 @@ github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0t github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.4 h1:1kn4/7MepF/CHmYub99/nNX8az0IJjfSOU/jbnTVfqQ= -github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -282,30 +335,30 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/lbryio/lbcutil v1.0.202 h1:L0aRMs2bdCUAicD8Xe4NmUEvevDDea3qkIpCSACnftI= -github.com/lbryio/lbcutil v1.0.202/go.mod h1:LGPtVBBzh4cFXfLFb8ginlFcbA2QwumLNFd0yk/as2o= +github.com/lbryio/lbcd v0.22.100-beta/go.mod h1:u8SaFX4xdGMMR5xasBGfgApC8pvD4rnK2OujZnrq5gs= +github.com/lbryio/lbcd v0.22.100-beta-rc5/go.mod h1:9PbFSlHYX7WlnDQwcTxHVf1W35VAnRsattCSyKOO55g= +github.com/lbryio/lbcutil v1.0.201/go.mod h1:gDHc/b+Rdz3J7+VB8e5/Bl9roVf8Q5/8FQCyuK9dXD0= +github.com/lbryio/lbcutil v1.0.202-rc3 h1:J7zYnIj3iN/ndPYKqMKBukLaLM1GhCEaiaMOYIMdUCU= +github.com/lbryio/lbcutil v1.0.202-rc3/go.mod h1:LGPtVBBzh4cFXfLFb8ginlFcbA2QwumLNFd0yk/as2o= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20220517141722-cf486979b281 h1:aczX6NMOtt6L4YT0fQvKkDK6LZEtdOso9sUH89V1+P0= -github.com/lufia/plan9stats v0.0.0-20220517141722-cf486979b281/go.mod h1:lc+czkgO/8F7puNki5jk8QyujbfK1LOT7Wl0ON2hxyk= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -323,25 +376,47 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -349,55 +424,79 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI= -github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil/v3 v3.22.4 h1:srAQaiX6jX/cYL6q29aE0m8lOskT9CurZ9N61YR3yoI= -github.com/shirou/gopsutil/v3 v3.22.4/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.21.7 h1:PnTqQamUjwEDSgn+nBGu0qSDV/CfvyiR/gwTH3i7HTU= +github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4= +github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w= +github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -405,27 +504,29 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A= -github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo= +github.com/tklauser/go-sysconf v0.3.7 h1:HT7h4+536gjqeq1ZIJPgOl1rg1XFatQGVZWp7Py53eg= +github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4= +github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.2.3 h1:nQ0QYpiritP6ViFhrKYsiv6VVxOpum2Gks5GhnJbS/8= +github.com/tklauser/numcpus v0.2.3/go.mod h1:vpEPS/JC+oZGGQ/My/vJnNsvMDQL6PwOqt8dsCw5j+E= +github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vmihailenco/msgpack/v5 v5.3.2 h1:MsXyN2rqdM8NM0lLiIpTn610e8Zcoj8ZuHxsMOi9qhI= github.com/vmihailenco/msgpack/v5 v5.3.2/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= @@ -443,14 +544,35 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -459,20 +581,23 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 h1:SLP7Q4Di66FONjDJbCYrCRrh97focO6sLogHO7/g8F0= -golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b h1:QAqMVf3pSa6eeTsuklijukjXBlj7Es2QQplab+/RbQ4= +golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf h1:oXVg4h2qJDd9htKxb5SCpFBHLipW6hXmL3qpUixS2jw= -golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys= +golang.org/x/exp v0.0.0-20211123021643-48cbe7f80d7c h1:hp+QRBz/P/780ndA1Rv/UpvsR6AsVmOMGYitxgZ1PPA= +golang.org/x/exp v0.0.0-20211123021643-48cbe7f80d7c/go.mod h1:b9TAUYHmRtqA6klRHApnXMnj+OyLce4yF5cZCUbk2ps= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -485,13 +610,18 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -500,6 +630,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -507,17 +638,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -537,45 +671,49 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211123173158-ef496fb156ab h1:rfJ1bsoJQQIAoAxTxB7bme+vHrNkRw8CqfsYh9w54cw= +golang.org/x/sys v0.0.0-20211123173158-ef496fb156ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -585,10 +723,12 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -608,24 +748,32 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -635,6 +783,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -642,11 +791,17 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= @@ -666,16 +821,18 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -683,13 +840,16 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/integration/bip0009_test.go b/integration/bip0009_test.go index 333da952..e22fdaba 100644 --- a/integration/bip0009_test.go +++ b/integration/bip0009_test.go @@ -282,20 +282,19 @@ func testBIP0009(t *testing.T, forkKey string, deploymentID uint32) { // - Assert the chain height is 0 and the state is ThresholdDefined // - Generate 1 fewer blocks than needed to reach the first state transition // - Assert chain height is expected and state is still ThresholdDefined -// // - Generate 1 more block to reach the first state transition // - Assert chain height is expected and state moved to ThresholdStarted -// - Generate enough blocks to reach the next state transition window, but only -// signal support in 1 fewer than the required number to achieve -// ThresholdLockedIn +// - Generate enough blocks to reach the next state transition window, but only +// signal support in 1 fewer than the required number to achieve +// ThresholdLockedIn // - Assert chain height is expected and state is still ThresholdStarted -// - Generate enough blocks to reach the next state transition window with only -// the exact number of blocks required to achieve locked in status signalling -// support. +// - Generate enough blocks to reach the next state transition window with only +// the exact number of blocks required to achieve locked in status signalling +// support. // - Assert chain height is expected and state moved to ThresholdLockedIn -// - Generate 1 fewer blocks than needed to reach the next state transition +// - Generate 1 fewer blocks than needed to reach the next state transition // - Assert chain height is expected and state is still ThresholdLockedIn -// - Generate 1 more block to reach the next state transition +// - Generate 1 more block to reach the next state transition // - Assert chain height is expected and state moved to ThresholdActive func TestBIP0009(t *testing.T) { t.Parallel() @@ -310,14 +309,11 @@ func TestBIP0009(t *testing.T) { // Overview: // - Generate block 1 // - Assert bit is NOT set (ThresholdDefined) -// // - Generate enough blocks to reach first state transition // - Assert bit is NOT set for block prior to state transition // - Assert bit is set for block at state transition (ThresholdStarted) -// // - Generate enough blocks to reach second state transition // - Assert bit is set for block at state transition (ThresholdLockedIn) -// // - Generate enough blocks to reach third state transition // - Assert bit is set for block prior to state transition (ThresholdLockedIn) // - Assert bit is NOT set for block at state transition (ThresholdActive) diff --git a/integration/csv_fork_test.go b/integration/csv_fork_test.go index 298a2367..ac8512e0 100644 --- a/integration/csv_fork_test.go +++ b/integration/csv_fork_test.go @@ -95,22 +95,17 @@ func makeTestOutput(r *rpctest.Harness, t *testing.T, // them. // // Overview: +// - Pre soft-fork: +// - Transactions with non-final lock-times from the PoV of MTP should be +// rejected from the mempool. +// - Transactions within non-final MTP based lock-times should be accepted +// in valid blocks. // -// - Pre soft-fork: -// -// - Transactions with non-final lock-times from the PoV of MTP should be -// rejected from the mempool. -// -// - Transactions within non-final MTP based lock-times should be accepted -// in valid blocks. -// -// - Post soft-fork: -// -// - Transactions with non-final lock-times from the PoV of MTP should be -// rejected from the mempool and when found within otherwise valid blocks. -// -// - Transactions with final lock-times from the PoV of MTP should be -// accepted to the mempool and mined in future block. +// - Post soft-fork: +// - Transactions with non-final lock-times from the PoV of MTP should be +// rejected from the mempool and when found within otherwise valid blocks. +// - Transactions with final lock-times from the PoV of MTP should be +// accepted to the mempool and mined in future block. func TestBIP0113Activation(t *testing.T) { t.Parallel() @@ -396,13 +391,13 @@ func assertTxInBlock(r *rpctest.Harness, t *testing.T, blockHash *chainhash.Hash // 112 and BIP 68 rule-set after the activation of the CSV-package soft-fork. // // Overview: -// - Pre soft-fork: -// - A transaction spending a CSV output validly should be rejected from the -// mempool, but accepted in a valid generated block including the -// transaction. -// - Post soft-fork: -// - See the cases exercised within the table driven tests towards the end -// of this test. +// - Pre soft-fork: +// - A transaction spending a CSV output validly should be rejected from the +// mempool, but accepted in a valid generated block including the +// transaction. +// - Post soft-fork: +// - See the cases exercised within the table driven tests towards the end +// of this test. func TestBIP0068AndBIP0112Activation(t *testing.T) { t.Parallel() diff --git a/integration/rpcserver_test.go b/integration/rpcserver_test.go index 5f59b594..2ed6b408 100644 --- a/integration/rpcserver_test.go +++ b/integration/rpcserver_test.go @@ -13,17 +13,12 @@ import ( "fmt" "os" "runtime/debug" - "sort" "testing" - "time" "github.com/lbryio/lbcd/chaincfg" "github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/lbryio/lbcd/integration/rpctest" "github.com/lbryio/lbcd/rpcclient" - "github.com/lbryio/lbcd/txscript" - "github.com/lbryio/lbcd/wire" - "github.com/lbryio/lbcutil" ) func testGetBestBlock(r *rpctest.Harness, t *testing.T) { @@ -138,278 +133,13 @@ func testBulkClient(r *rpctest.Harness, t *testing.T) { t.Fatalf("expected hash %s to be in generated hash list", blockHash) } } -} -func testGetBlockStats(r *rpctest.Harness, t *testing.T) { - t.Parallel() - - baseFeeRate := int64(10) - txValue := int64(50000000) - txQuantity := 10 - txs := make([]*lbcutil.Tx, txQuantity) - fees := make([]int64, txQuantity) - sizes := make([]int64, txQuantity) - feeRates := make([]int64, txQuantity) - var outputCount int - - // Generate test sample. - for i := 0; i < txQuantity; i++ { - address, err := r.NewAddress() - if err != nil { - t.Fatalf("Unable to generate address: %v", err) - } - - pkScript, err := txscript.PayToAddrScript(address) - if err != nil { - t.Fatalf("Unable to generate PKScript: %v", err) - } - - // This feerate is not the actual feerate. See comment below. - feeRate := baseFeeRate * int64(i) - - tx, err := r.CreateTransaction([]*wire.TxOut{wire.NewTxOut(txValue, pkScript)}, lbcutil.Amount(feeRate), true) - if err != nil { - t.Fatalf("Unable to generate segwit transaction: %v", err) - } - - txs[i] = lbcutil.NewTx(tx) - sizes[i] = int64(tx.SerializeSize()) - - // memWallet.fundTx makes some assumptions when calculating fees. - // For instance, it assumes the signature script has exactly 108 bytes - // and it does not account for the size of the change output. - // This needs to be taken into account when getting the true feerate. - scriptSigOffset := 108 - len(tx.TxIn[0].SignatureScript) - changeOutputSize := tx.TxOut[len(tx.TxOut)-1].SerializeSize() - fees[i] = (sizes[i] + int64(scriptSigOffset) - int64(changeOutputSize)) * feeRate - feeRates[i] = fees[i] / sizes[i] - - outputCount += len(tx.TxOut) - } - - stats := func(slice []int64) (int64, int64, int64, int64, int64) { - var total, average, min, max, median int64 - min = slice[0] - length := len(slice) - for _, item := range slice { - if min > item { - min = item - } - if max < item { - max = item - } - total += item - } - average = total / int64(length) - sort.Slice(slice, func(i, j int) bool { return slice[i] < slice[j] }) - if length == 0 { - median = 0 - } else if length%2 == 0 { - median = (slice[length/2-1] + slice[length/2]) / 2 - } else { - median = slice[length/2] - } - return total, average, min, max, median - } - - totalFee, avgFee, minFee, maxFee, medianFee := stats(fees) - totalSize, avgSize, minSize, maxSize, medianSize := stats(sizes) - _, avgFeeRate, minFeeRate, maxFeeRate, _ := stats(feeRates) - - tests := []struct { - name string - txs []*lbcutil.Tx - stats []string - expectedResults map[string]interface{} - }{ - { - name: "empty block", - txs: []*lbcutil.Tx{}, - stats: []string{}, - expectedResults: map[string]interface{}{ - "avgfee": int64(0), - "avgfeerate": int64(0), - "avgtxsize": int64(0), - "feerate_percentiles": []int64{0, 0, 0, 0, 0}, - "ins": int64(0), - "maxfee": int64(0), - "maxfeerate": int64(0), - "maxtxsize": int64(0), - "medianfee": int64(0), - "mediantxsize": int64(0), - "minfee": int64(0), - "mintxsize": int64(0), - "outs": int64(1), - "swtotal_size": int64(0), - "swtotal_weight": int64(0), - "swtxs": int64(0), - "total_out": int64(0), - "total_size": int64(0), - "total_weight": int64(0), - "txs": int64(1), - "utxo_increase": int64(1), - }, - }, - { - name: "block with 10 transactions + coinbase", - txs: txs, - stats: []string{"avgfee", "avgfeerate", "avgtxsize", "feerate_percentiles", - "ins", "maxfee", "maxfeerate", "maxtxsize", "medianfee", "mediantxsize", - "minfee", "minfeerate", "mintxsize", "outs", "subsidy", "swtxs", - "total_size", "total_weight", "totalfee", "txs", "utxo_increase"}, - expectedResults: map[string]interface{}{ - "avgfee": avgFee, - "avgfeerate": avgFeeRate, - "avgtxsize": avgSize, - "feerate_percentiles": []int64{feeRates[0], feeRates[2], - feeRates[4], feeRates[7], feeRates[8]}, - "ins": int64(txQuantity), - "maxfee": maxFee, - "maxfeerate": maxFeeRate, - "maxtxsize": maxSize, - "medianfee": medianFee, - "mediantxsize": medianSize, - "minfee": minFee, - "minfeerate": minFeeRate, - "mintxsize": minSize, - "outs": int64(outputCount + 1), // Coinbase output also counts. - "subsidy": int64(100000000), - "swtotal_weight": nil, // This stat was not selected, so it should be nil. - "swtxs": int64(0), - "total_size": totalSize, - "total_weight": totalSize * 4, - "totalfee": totalFee, - "txs": int64(txQuantity + 1), // Coinbase transaction also counts. - "utxo_increase": int64(outputCount + 1 - txQuantity), - "utxo_size_inc": nil, - }, - }, - } - for _, test := range tests { - // Submit a new block with the provided transactions. - block, err := r.GenerateAndSubmitBlock(test.txs, -1, time.Time{}) - if err != nil { - t.Fatalf("Unable to generate block: %v from test %s", err, test.name) - } - - blockStats, err := r.GetBlockStats(block.Hash(), &test.stats) - if err != nil { - t.Fatalf("Call to `getblockstats` on test %s failed: %v", test.name, err) - } - - if blockStats.Height != (*int64)(nil) && *blockStats.Height != int64(block.Height()) { - t.Fatalf("Unexpected result in test %s, stat: %v, expected: %v, got: %v", test.name, "height", block.Height(), *blockStats.Height) - } - - for stat, value := range test.expectedResults { - var result interface{} - switch stat { - case "avgfee": - result = blockStats.AverageFee - case "avgfeerate": - result = blockStats.AverageFeeRate - case "avgtxsize": - result = blockStats.AverageTxSize - case "feerate_percentiles": - result = blockStats.FeeratePercentiles - case "blockhash": - result = blockStats.Hash - case "height": - result = blockStats.Height - case "ins": - result = blockStats.Ins - case "maxfee": - result = blockStats.MaxFee - case "maxfeerate": - result = blockStats.MaxFeeRate - case "maxtxsize": - result = blockStats.MaxTxSize - case "medianfee": - result = blockStats.MedianFee - case "mediantime": - result = blockStats.MedianTime - case "mediantxsize": - result = blockStats.MedianTxSize - case "minfee": - result = blockStats.MinFee - case "minfeerate": - result = blockStats.MinFeeRate - case "mintxsize": - result = blockStats.MinTxSize - case "outs": - result = blockStats.Outs - case "swtotal_size": - result = blockStats.SegWitTotalSize - case "swtotal_weight": - result = blockStats.SegWitTotalWeight - case "swtxs": - result = blockStats.SegWitTxs - case "subsidy": - result = blockStats.Subsidy - case "time": - result = blockStats.Time - case "total_out": - result = blockStats.TotalOut - case "total_size": - result = blockStats.TotalSize - case "total_weight": - result = blockStats.TotalWeight - case "totalfee": - result = blockStats.TotalFee - case "txs": - result = blockStats.Txs - case "utxo_increase": - result = blockStats.UTXOIncrease - case "utxo_size_inc": - result = blockStats.UTXOSizeIncrease - } - - var equality bool - - // Check for nil equality. - if value == nil && result == (*int64)(nil) { - equality = true - break - } else if result == nil || value == nil { - equality = false - } - - var resultValue interface{} - switch v := value.(type) { - case int64: - resultValue = *result.(*int64) - equality = v == resultValue - case string: - resultValue = *result.(*string) - equality = v == resultValue - case []int64: - resultValue = *result.(*[]int64) - resultSlice := resultValue.([]int64) - equality = true - for i, item := range resultSlice { - if item != v[i] { - equality = false - break - } - } - } - if !equality { - if result != nil { - t.Fatalf("Unexpected result in test %s, stat: %v, expected: %v, got: %v", test.name, stat, value, resultValue) - } else { - t.Fatalf("Unexpected result in test %s, stat: %v, expected: %v, got: %v", test.name, stat, value, "") - } - } - - } - } } var rpcTestCases = []rpctest.HarnessTestCase{ testGetBestBlock, testGetBlockCount, testGetBlockHash, - testGetBlockStats, testBulkClient, } @@ -421,8 +151,7 @@ func TestMain(m *testing.M) { // In order to properly test scenarios on as if we were on mainnet, // ensure that non-standard transactions aren't accepted into the // mempool or relayed. - // Enable transaction index to be able to fully test GetBlockStats - btcdCfg := []string{"--rejectnonstd", "--txindex"} + btcdCfg := []string{"--rejectnonstd"} primaryHarness, err = rpctest.New( &chaincfg.SimNetParams, nil, btcdCfg, "", ) diff --git a/integration/rpctest/rpc_harness.go b/integration/rpctest/rpc_harness.go index 4bd72f9c..17603aa7 100644 --- a/integration/rpctest/rpc_harness.go +++ b/integration/rpctest/rpc_harness.go @@ -16,7 +16,6 @@ import ( "testing" "time" - "github.com/lbryio/lbcd/btcjson" "github.com/lbryio/lbcd/chaincfg" "github.com/lbryio/lbcd/chaincfg/chainhash" "github.com/lbryio/lbcd/rpcclient" @@ -513,18 +512,6 @@ func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs( return newBlock, nil } -// GetBlockStats returns block statistics. First argument specifies height or -// hash of the target block. Second argument allows to select certain stats to -// return. If second argument is empty, all stats are returned. -func (h *Harness) GetBlockStats(hashOrHeight interface{}, stats *[]string) ( - *btcjson.GetBlockStatsResult, error) { - - h.Lock() - defer h.Unlock() - - return h.Client.GetBlockStats(hashOrHeight, stats) -} - // generateListeningAddresses returns two strings representing listening // addresses designated for the current rpc test. If there haven't been any // test instances created, the default ports are used. Otherwise, in order to diff --git a/lbcd.go b/lbcd.go index 3a7860b1..e47efdb8 100644 --- a/lbcd.go +++ b/lbcd.go @@ -19,7 +19,6 @@ import ( "github.com/lbryio/lbcd/claimtrie/param" "github.com/lbryio/lbcd/database" "github.com/lbryio/lbcd/limits" - "github.com/lbryio/lbcd/version" "github.com/felixge/fgprof" ) @@ -65,7 +64,7 @@ func btcdMain(serverChan chan<- *server) error { defer btcdLog.Info("Shutdown complete") // Show version at startup. - btcdLog.Infof("Version %s", version.Full()) + btcdLog.Infof("Version %s", version()) // Enable http profiling server if requested. if cfg.Profile != "" { @@ -92,25 +91,6 @@ func btcdMain(serverChan chan<- *server) error { defer pprof.StopCPUProfile() } - // Write memory profile if requested. - if cfg.MemProfile != "" { - f, err := os.Create(cfg.MemProfile + ".heap") - if err != nil { - btcdLog.Errorf("Unable to create mem profile: %v", err) - return err - } - defer f.Close() - defer pprof.Lookup("heap").WriteTo(f, 0) - - f, err = os.Create(cfg.MemProfile + ".allocs") - if err != nil { - btcdLog.Errorf("Unable to create mem profile: %v", err) - return err - } - defer f.Close() - defer pprof.Lookup("allocs").WriteTo(f, 0) - } - // Perform upgrades to btcd as new versions require it. if err := doUpgrades(); err != nil { btcdLog.Errorf("%v", err) @@ -300,9 +280,7 @@ func main() { // limits the garbage collector from excessively overallocating during // bursts. This value was arrived at with the help of profiling live // usage. - if _, ok := os.LookupEnv("GOGC"); !ok { - debug.SetGCPercent(10) - } + debug.SetGCPercent(10) // Up some limits. if err := limits.SetLimits(); err != nil { diff --git a/mempool/doc.go b/mempool/doc.go index 1bd7c5a9..3adad018 100644 --- a/mempool/doc.go +++ b/mempool/doc.go @@ -31,40 +31,40 @@ proceed. Typically, this will involve things such as relaying the transactions to other peers on the network and notifying the mining process that new transactions are available. -# Feature Overview +Feature Overview The following is a quick overview of the major features. It is not intended to be an exhaustive list. - - Maintain a pool of fully validated transactions - - Reject non-fully-spent duplicate transactions - - Reject coinbase transactions - - Reject double spends (both from the chain and other transactions in pool) - - Reject invalid transactions according to the network consensus rules - - Full script execution and validation with signature cache support - - Individual transaction query support - - Orphan transaction support (transactions that spend from unknown outputs) - - Configurable limits (see transaction acceptance policy) - - Automatic addition of orphan transactions that are no longer orphans as new - transactions are added to the pool - - Individual orphan transaction query support - - Configurable transaction acceptance policy - - Option to accept or reject standard transactions - - Option to accept or reject transactions based on priority calculations - - Rate limiting of low-fee and free transactions - - Non-zero fee threshold - - Max signature operations per transaction - - Max orphan transaction size - - Max number of orphan transactions allowed - - Additional metadata tracking for each transaction - - Timestamp when the transaction was added to the pool - - Most recent block height when the transaction was added to the pool - - The fee the transaction pays - - The starting priority for the transaction - - Manual control of transaction removal - - Recursive removal of all dependent transactions + - Maintain a pool of fully validated transactions + - Reject non-fully-spent duplicate transactions + - Reject coinbase transactions + - Reject double spends (both from the chain and other transactions in pool) + - Reject invalid transactions according to the network consensus rules + - Full script execution and validation with signature cache support + - Individual transaction query support + - Orphan transaction support (transactions that spend from unknown outputs) + - Configurable limits (see transaction acceptance policy) + - Automatic addition of orphan transactions that are no longer orphans as new + transactions are added to the pool + - Individual orphan transaction query support + - Configurable transaction acceptance policy + - Option to accept or reject standard transactions + - Option to accept or reject transactions based on priority calculations + - Rate limiting of low-fee and free transactions + - Non-zero fee threshold + - Max signature operations per transaction + - Max orphan transaction size + - Max number of orphan transactions allowed + - Additional metadata tracking for each transaction + - Timestamp when the transaction was added to the pool + - Most recent block height when the transaction was added to the pool + - The fee the transaction pays + - The starting priority for the transaction + - Manual control of transaction removal + - Recursive removal of all dependent transactions -# Errors +Errors Errors returned by this package are either the raw errors provided by underlying calls or of type mempool.RuleError. Since there are two classes of rules diff --git a/mempool/estimatefee.go b/mempool/estimatefee.go index 719c42e2..bb1d5770 100644 --- a/mempool/estimatefee.go +++ b/mempool/estimatefee.go @@ -275,7 +275,7 @@ func (ef *FeeEstimator) RegisterBlock(block *btcutil.Block) error { // This shouldn't happen but check just in case to avoid // an out-of-bounds array index later. - if blocksToConfirm >= estimateFeeDepth { + if blocksToConfirm >= estimateFeeDepth || blocksToConfirm < 0 { continue } diff --git a/mempool/mempool.go b/mempool/mempool.go index 4ef5a018..45cf602b 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -8,7 +8,6 @@ import ( "container/list" "fmt" "math" - "reflect" "sync" "sync/atomic" "time" @@ -157,15 +156,6 @@ type Policy struct { RejectReplacement bool } -// aggregateInfo tracks aggregated serialized size, memory usage, and fees -// for TxDesc in the mempool. -type aggregateInfo struct { - totalCount int64 - totalBytes int64 - totalMem int64 - totalFee int64 -} - // TxDesc is a descriptor containing a transaction in the mempool along with // additional metadata. type TxDesc struct { @@ -176,20 +166,6 @@ type TxDesc struct { StartingPriority float64 } -func (txD *TxDesc) incr(info *aggregateInfo) { - info.totalCount += 1 - info.totalBytes += int64(txD.Tx.MsgTx().SerializeSize()) - info.totalMem += int64(dynamicMemUsage(reflect.ValueOf(txD))) - info.totalFee += txD.Fee -} - -func (txD *TxDesc) decr(info *aggregateInfo) { - info.totalCount -= 1 - info.totalBytes -= int64(txD.Tx.MsgTx().SerializeSize()) - info.totalMem -= int64(dynamicMemUsage(reflect.ValueOf(txD))) - info.totalFee -= txD.Fee -} - // orphanTx is normal transaction that references an ancestor transaction // that is not yet available. It also contains additional information related // to it such as an expiration time to help prevent caching the orphan forever. @@ -199,18 +175,6 @@ type orphanTx struct { expiration time.Time } -func (otx *orphanTx) incr(info *aggregateInfo) { - info.totalCount += 1 - info.totalBytes += int64(otx.tx.MsgTx().SerializeSize()) - info.totalMem += int64(dynamicMemUsage(reflect.ValueOf(otx))) -} - -func (otx *orphanTx) decr(info *aggregateInfo) { - info.totalCount -= 1 - info.totalBytes -= int64(otx.tx.MsgTx().SerializeSize()) - info.totalMem -= int64(dynamicMemUsage(reflect.ValueOf(otx))) -} - // TxPool is used as a source of transactions that need to be mined into blocks // and relayed to other peers. It is safe for concurrent access from multiple // peers. @@ -232,12 +196,6 @@ type TxPool struct { // the scan will only run when an orphan is added to the pool as opposed // to on an unconditional timer. nextExpireScan time.Time - - // stats are aggregated over pool, orphans, etc. - stats aggregateInfo - - // unbroadcast is a set of transactions yet to be broadcast. - unbroadcast map[chainhash.Hash]bool } // Ensure the TxPool type implements the mining.TxSource interface. @@ -282,9 +240,6 @@ func (mp *TxPool) removeOrphan(tx *btcutil.Tx, removeRedeemers bool) { // Remove the transaction from the orphan pool. delete(mp.orphans, *txHash) - - // Update stats. - otx.decr(&mp.stats) } // RemoveOrphan removes the passed orphan transaction from the orphan pool and @@ -381,12 +336,11 @@ func (mp *TxPool) addOrphan(tx *btcutil.Tx, tag Tag) { // orphan if space is still needed. mp.limitNumOrphans() - otx := &orphanTx{ + mp.orphans[*tx.Hash()] = &orphanTx{ tx: tx, tag: tag, expiration: time.Now().Add(orphanTTL), } - mp.orphans[*tx.Hash()] = otx for _, txIn := range tx.MsgTx().TxIn { if _, exists := mp.orphansByPrev[txIn.PreviousOutPoint]; !exists { mp.orphansByPrev[txIn.PreviousOutPoint] = @@ -395,9 +349,6 @@ func (mp *TxPool) addOrphan(tx *btcutil.Tx, tag Tag) { mp.orphansByPrev[txIn.PreviousOutPoint][*tx.Hash()] = tx } - // Update stats. - otx.incr(&mp.stats) - log.Debugf("Stored orphan transaction %v (total: %d)", tx.Hash(), len(mp.orphans)) } @@ -547,9 +498,6 @@ func (mp *TxPool) removeTransaction(tx *btcutil.Tx, removeRedeemers bool) { } delete(mp.pool, *txHash) - // Update stats. - txDesc.decr(&mp.stats) - // Inform associated fee estimator that the transaction has been removed // from the mempool if mp.cfg.RemoveTxFromFeeEstimation != nil { @@ -631,9 +579,6 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil mp.cfg.AddTxToFeeEstimation(txD.Tx.Hash(), txD.Fee, size) } - // Update stats. - txD.incr(&mp.stats) - return txD } @@ -1558,38 +1503,6 @@ func (mp *TxPool) MiningDescs() []*mining.TxDesc { return descs } -func (mp *TxPool) AddUnbroadcastTx(hash *chainhash.Hash) { - mp.mtx.Lock() - mp.unbroadcast[*hash] = true - mp.mtx.Unlock() -} - -func (mp *TxPool) RemoveUnbroadcastTx(hash *chainhash.Hash) { - mp.mtx.Lock() - delete(mp.unbroadcast, *hash) - mp.mtx.Unlock() -} - -func (mp *TxPool) MempoolInfo() *btcjson.GetMempoolInfoResult { - mp.mtx.RLock() - policy := mp.cfg.Policy - stats := mp.stats - unbroadcastCount := int64(len(mp.unbroadcast)) - mp.mtx.RUnlock() - - ret := &btcjson.GetMempoolInfoResult{ - Size: stats.totalCount, - Usage: stats.totalMem, - Bytes: stats.totalBytes, - TotalFee: btcutil.Amount(stats.totalFee).ToBTC(), - MemPoolMinFee: btcutil.Amount(calcMinRequiredTxRelayFee(1000, policy.MinRelayTxFee)).ToBTC(), - MinRelayTxFee: policy.MinRelayTxFee.ToBTC(), - UnbroadcastCount: unbroadcastCount, - } - - return ret -} - // RawMempoolVerbose returns all the entries in the mempool as a fully // populated btcjson result. // @@ -1663,6 +1576,5 @@ func New(cfg *Config) *TxPool { orphansByPrev: make(map[wire.OutPoint]map[chainhash.Hash]*btcutil.Tx), nextExpireScan: time.Now().Add(orphanExpireScanInterval), outpoints: make(map[wire.OutPoint]*btcutil.Tx), - unbroadcast: make(map[chainhash.Hash]bool), } } diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index 1b343cd8..17d2d452 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -21,12 +21,6 @@ import ( btcutil "github.com/lbryio/lbcutil" ) -func init() { - // Toggle assert & debug messages when running tests. - dynamicMemUsageAssert = true - dynamicMemUsageDebug = false -} - // fakeChain is used by the pool harness to provide generated test utxos and // a current faked chain height to the pool callbacks. This, in turn, allows // transactions to appear as though they are spending completely valid utxos. diff --git a/mempool/memusage.go b/mempool/memusage.go deleted file mode 100644 index c4030a08..00000000 --- a/mempool/memusage.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package mempool - -import ( - "fmt" - "reflect" -) - -var ( - dynamicMemUsageAssert = false - dynamicMemUsageDebug = false - dynamicMemUsageMaxDepth = 10 -) - -func dynamicMemUsage(v reflect.Value) uintptr { - return dynamicMemUsageCrawl(v, 0) -} - -func dynamicMemUsageCrawl(v reflect.Value, depth int) uintptr { - t := v.Type() - bytes := t.Size() - if dynamicMemUsageDebug { - println("[", depth, "]", t.Kind().String(), "(", t.String(), ") ->", t.Size()) - } - - if depth >= dynamicMemUsageMaxDepth { - if dynamicMemUsageAssert { - panic("crawl reached maximum depth") - } - return bytes - } - - // For complex types, we need to peek inside slices/arrays/structs and chase pointers. - switch t.Kind() { - case reflect.Pointer, reflect.Interface: - if !v.IsNil() { - bytes += dynamicMemUsageCrawl(v.Elem(), depth+1) - } - case reflect.Array, reflect.Slice: - for j := 0; j < v.Len(); j++ { - vi := v.Index(j) - k := vi.Type().Kind() - if dynamicMemUsageDebug { - println("[", depth, "] index:", j, "kind:", k.String()) - } - elemBytes := uintptr(0) - if t.Kind() == reflect.Array { - if (k == reflect.Pointer || k == reflect.Interface) && !vi.IsNil() { - elemBytes += dynamicMemUsageCrawl(vi.Elem(), depth+1) - } - } else { // slice - elemBytes += dynamicMemUsageCrawl(vi, depth+1) - } - if k == reflect.Uint8 { - // short circuit for byte slice/array - bytes += elemBytes * uintptr(v.Len()) - if dynamicMemUsageDebug { - println("...", v.Len(), "elements") - } - break - } - bytes += elemBytes - } - case reflect.Struct: - for _, f := range reflect.VisibleFields(t) { - vf := v.FieldByIndex(f.Index) - k := vf.Type().Kind() - if dynamicMemUsageDebug { - println("[", depth, "] field:", f.Name, "kind:", k.String()) - } - if (k == reflect.Pointer || k == reflect.Interface) && !vf.IsNil() { - bytes += dynamicMemUsageCrawl(vf.Elem(), depth+1) - } else if k == reflect.Array || k == reflect.Slice { - bytes -= vf.Type().Size() - bytes += dynamicMemUsageCrawl(vf, depth+1) - } - } - case reflect.Uint8: - default: - if dynamicMemUsageAssert { - panic(fmt.Sprintf("unsupported kind: %v", t.Kind())) - } - } - - return bytes -} diff --git a/mempool/policy.go b/mempool/policy.go index aa391c5d..e91ce260 100644 --- a/mempool/policy.go +++ b/mempool/policy.go @@ -249,7 +249,7 @@ func GetDustThreshold(txOut *wire.TxOut) int64 { totalSize += 107 } - return int64(totalSize) + return 3 * int64(totalSize) } // IsDust returns whether or not the passed transaction output amount is @@ -264,7 +264,7 @@ func IsDust(txOut *wire.TxOut, minRelayTxFee btcutil.Amount) bool { } // The output is considered dust if the cost to the network to spend the - // coins is more than the minimum free transaction relay fee. + // coins is more than 1/3 of the minimum free transaction relay fee. // minFreeTxRelayFee is in Satoshi/KB, so multiply by 1000 to // convert to bytes. // @@ -273,7 +273,7 @@ func IsDust(txOut *wire.TxOut, minRelayTxFee btcutil.Amount) bool { // fee of 1000, this equates to values less than 546 satoshi being // considered dust. // - // The following is equivalent to (value/totalSize) * 1000 + // The following is equivalent to (value/totalSize) * (1/3) * 1000 // without needing to do floating point math. if txOut.Value > dustCap { return false diff --git a/mempool/policy_test.go b/mempool/policy_test.go index aed2c4d7..5e4d4ff0 100644 --- a/mempool/policy_test.go +++ b/mempool/policy_test.go @@ -233,14 +233,14 @@ func TestDust(t *testing.T) { true, }, { - "38 byte public key script with value 194", - wire.TxOut{Value: 194, PkScript: pkScript}, + "38 byte public key script with value 584", + wire.TxOut{Value: 584, PkScript: pkScript}, 1000, true, }, { - "38 byte public key script with value 195", - wire.TxOut{Value: 195, PkScript: pkScript}, + "38 byte public key script with value 585", + wire.TxOut{Value: 585, PkScript: pkScript}, 1000, false, }, diff --git a/mining/mining.go b/mining/mining.go index 61e4a1d1..4f3ac9e5 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -420,26 +420,26 @@ func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params, // // Given the above, a block generated by this function is of the following form: // -// ----------------------------------- -- -- -// | Coinbase Transaction | | | -// |-----------------------------------| | | -// | | | | ----- policy.BlockPrioritySize -// | High-priority Transactions | | | -// | | | | -// |-----------------------------------| | -- -// | | | -// | | | -// | | |--- policy.BlockMaxSize -// | Transactions prioritized by fee | | -// | until <= policy.TxMinFreeFee | | -// | | | -// | | | -// | | | -// |-----------------------------------| | -// | Low-fee/Non high-priority (free) | | -// | transactions (while block size | | -// | <= policy.BlockMinSize) | | -// ----------------------------------- -- +// ----------------------------------- -- -- +// | Coinbase Transaction | | | +// |-----------------------------------| | | +// | | | | ----- policy.BlockPrioritySize +// | High-priority Transactions | | | +// | | | | +// |-----------------------------------| | -- +// | | | +// | | | +// | | |--- policy.BlockMaxSize +// | Transactions prioritized by fee | | +// | until <= policy.TxMinFreeFee | | +// | | | +// | | | +// | | | +// |-----------------------------------| | +// | Low-fee/Non high-priority (free) | | +// | transactions (while block size | | +// | <= policy.BlockMinSize) | | +// ----------------------------------- -- func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*BlockTemplate, error) { // Extend the most recently known best block. best := g.chain.BestSnapshot() diff --git a/netsync/blocklogger.go b/netsync/blocklogger.go index b7a394ec..34a549a1 100644 --- a/netsync/blocklogger.go +++ b/netsync/blocklogger.go @@ -27,9 +27,8 @@ type blockProgressLogger struct { // newBlockProgressLogger returns a new block progress logger. // The progress message is templated as follows: -// -// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} -// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) +// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod} +// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp}) func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger { return &blockProgressLogger{ lastBlockLogTime: time.Now(), diff --git a/netsync/manager.go b/netsync/manager.go index 169cec8f..72fce625 100644 --- a/netsync/manager.go +++ b/netsync/manager.go @@ -903,7 +903,7 @@ func (sm *SyncManager) fetchHeaderBlocks() { numRequested++ } sm.startHeader = e.Next() - if numRequested >= wire.MaxInvPerMsg/99 { + if numRequested >= wire.MaxInvPerMsg { break } } @@ -1294,9 +1294,16 @@ func (sm *SyncManager) handleInvMsg(imsg *invMsg) { break } } + + e := wire.BaseEncoding + // we think that the iv.Type set above is sufficient. If not: + // if peer.IsWitnessEnabled() { + // e = wire.WitnessEncoding + //} + state.requestQueue = requestQueue if len(gdmsg.InvList) > 0 { - peer.QueueMessage(gdmsg, nil) + peer.QueueMessageWithEncoding(gdmsg, nil, e) } } diff --git a/peer/doc.go b/peer/doc.go index 1a12609c..1bb8cf32 100644 --- a/peer/doc.go +++ b/peer/doc.go @@ -6,7 +6,7 @@ Package peer provides a common base for creating and managing Bitcoin network peers. -# Overview +Overview This package builds upon the wire package, which provides the fundamental primitives necessary to speak the bitcoin wire protocol, in order to simplify @@ -16,41 +16,41 @@ Payment Verification (SPV) nodes, proxies, etc. A quick overview of the major features peer provides are as follows: - - Provides a basic concurrent safe bitcoin peer for handling bitcoin - communications via the peer-to-peer protocol - - Full duplex reading and writing of bitcoin protocol messages - - Automatic handling of the initial handshake process including protocol - version negotiation - - Asynchronous message queuing of outbound messages with optional channel for - notification when the message is actually sent - - Flexible peer configuration - - Caller is responsible for creating outgoing connections and listening for - incoming connections so they have flexibility to establish connections as - they see fit (proxies, etc) - - User agent name and version - - Bitcoin network - - Service support signalling (full nodes, bloom filters, etc) - - Maximum supported protocol version - - Ability to register callbacks for handling bitcoin protocol messages - - Inventory message batching and send trickling with known inventory detection - and avoidance - - Automatic periodic keep-alive pinging and pong responses - - Random nonce generation and self connection detection - - Proper handling of bloom filter related commands when the caller does not - specify the related flag to signal support - - Disconnects the peer when the protocol version is high enough - - Does not invoke the related callbacks for older protocol versions - - Snapshottable peer statistics such as the total number of bytes read and - written, the remote address, user agent, and negotiated protocol version - - Helper functions pushing addresses, getblocks, getheaders, and reject - messages - - These could all be sent manually via the standard message output function, - but the helpers provide additional nice functionality such as duplicate - filtering and address randomization - - Ability to wait for shutdown/disconnect - - Comprehensive test coverage + - Provides a basic concurrent safe bitcoin peer for handling bitcoin + communications via the peer-to-peer protocol + - Full duplex reading and writing of bitcoin protocol messages + - Automatic handling of the initial handshake process including protocol + version negotiation + - Asynchronous message queuing of outbound messages with optional channel for + notification when the message is actually sent + - Flexible peer configuration + - Caller is responsible for creating outgoing connections and listening for + incoming connections so they have flexibility to establish connections as + they see fit (proxies, etc) + - User agent name and version + - Bitcoin network + - Service support signalling (full nodes, bloom filters, etc) + - Maximum supported protocol version + - Ability to register callbacks for handling bitcoin protocol messages + - Inventory message batching and send trickling with known inventory detection + and avoidance + - Automatic periodic keep-alive pinging and pong responses + - Random nonce generation and self connection detection + - Proper handling of bloom filter related commands when the caller does not + specify the related flag to signal support + - Disconnects the peer when the protocol version is high enough + - Does not invoke the related callbacks for older protocol versions + - Snapshottable peer statistics such as the total number of bytes read and + written, the remote address, user agent, and negotiated protocol version + - Helper functions pushing addresses, getblocks, getheaders, and reject + messages + - These could all be sent manually via the standard message output function, + but the helpers provide additional nice functionality such as duplicate + filtering and address randomization + - Ability to wait for shutdown/disconnect + - Comprehensive test coverage -# Peer Configuration +Peer Configuration All peer configuration is handled with the Config struct. This allows the caller to specify things such as the user agent name and version, the bitcoin @@ -58,7 +58,7 @@ network to use, which services it supports, and callbacks to invoke when bitcoin messages are received. See the documentation for each field of the Config struct for more details. -# Inbound and Outbound Peers +Inbound and Outbound Peers A peer can either be inbound or outbound. The caller is responsible for establishing the connection to remote peers and listening for incoming peers. @@ -73,7 +73,7 @@ Disconnect to disconnect from the peer and clean up all resources. WaitForDisconnect can be used to block until peer disconnection and resource cleanup has completed. -# Callbacks +Callbacks In order to do anything useful with a peer, it is necessary to react to bitcoin messages. This is accomplished by creating an instance of the MessageListeners @@ -92,7 +92,7 @@ It is often useful to use closures which encapsulate state when specifying the callback handlers. This provides a clean method for accessing that state when callbacks are invoked. -# Queuing Messages and Inventory +Queuing Messages and Inventory The QueueMessage function provides the fundamental means to send messages to the remote peer. As the name implies, this employs a non-blocking queue. A done @@ -106,7 +106,7 @@ QueueInventory function. It employs batching and trickling along with intelligent known remote peer inventory detection and avoidance through the use of a most-recently used algorithm. -# Message Sending Helper Functions +Message Sending Helper Functions In addition to the bare QueueMessage function previously described, the PushAddrMsg, PushGetBlocksMsg, PushGetHeadersMsg, and PushRejectMsg functions @@ -128,13 +128,13 @@ appropriate reject message based on the provided parameters as well as optionally provides a flag to cause it to block until the message is actually sent. -# Peer Statistics +Peer Statistics A snapshot of the current peer statistics can be obtained with the StatsSnapshot function. This includes statistics such as the total number of bytes read and written, the remote address, user agent, and negotiated protocol version. -# Logging +Logging This package provides extensive logging capabilities through the UseLogger function which allows a btclog.Logger to be specified. For example, logging at @@ -142,7 +142,7 @@ the debug level provides summaries of every message sent and received, and logging at the trace level provides full dumps of parsed messages as well as the raw message bytes using a format similar to hexdump -C. -# Bitcoin Improvement Proposals +Bitcoin Improvement Proposals This package supports all BIPS supported by the wire package. (https://pkg.go.dev/github.com/lbryio/lbcd/wire#hdr-Bitcoin_Improvement_Proposals) diff --git a/peer/peer.go b/peer/peer.go index 6fe622f5..ffedc6dc 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -2096,10 +2096,10 @@ func (p *Peer) writeLocalVersionMsg() error { // peer. The events should occur in the following order, otherwise an error is // returned: // -// 1. Remote peer sends their version. -// 2. We send our version. -// 3. We send our verack. -// 4. Remote peer sends their verack. +// 1. Remote peer sends their version. +// 2. We send our version. +// 3. We send our verack. +// 4. Remote peer sends their verack. func (p *Peer) negotiateInboundProtocol() error { if err := p.readRemoteVersionMsg(); err != nil { return err @@ -2121,10 +2121,10 @@ func (p *Peer) negotiateInboundProtocol() error { // peer. The events should occur in the following order, otherwise an error is // returned: // -// 1. We send our version. -// 2. Remote peer sends their version. -// 3. Remote peer sends their verack. -// 4. We send our verack. +// 1. We send our version. +// 2. Remote peer sends their version. +// 3. Remote peer sends their verack. +// 4. We send our verack. func (p *Peer) negotiateOutboundProtocol() error { if err := p.writeLocalVersionMsg(); err != nil { return err diff --git a/rpcadapters.go b/rpcadapters.go index d6f809fc..2a1af72f 100644 --- a/rpcadapters.go +++ b/rpcadapters.go @@ -6,7 +6,6 @@ package main import ( "sync/atomic" - "time" "github.com/lbryio/lbcd/blockchain" "github.com/lbryio/lbcd/chaincfg/chainhash" @@ -182,57 +181,6 @@ func (cm *rpcConnManager) ConnectedPeers() []rpcserverPeer { return peers } -// BannedPeers returns a map consisting of all banned host with banned period. -// -// This function is safe for concurrent access and is part of the -// rpcserverConnManager interface implementation. -func (cm *rpcConnManager) BannedPeers() map[string]bannedPeriod { - replyChan := make(chan map[string]bannedPeriod) - cm.server.query <- listBannedPeersMsg{reply: replyChan} - return <-replyChan -} - -// SetBan removes the peer associated with the provided address from the -// list of persistent peers. -// -// This function is safe for concurrent access and is part of the -// rpcserverConnManager interface implementation. -func (cm *rpcConnManager) SetBan(addr string, since, until time.Time) error { - replyChan := make(chan error) - cm.server.query <- setBanMsg{ - addr: addr, - since: since, - until: until, - reply: replyChan, - } - return <-replyChan -} - -// RemoveBan removes a host from banned list. -// -// This function is safe for concurrent access and is part of the -// rpcserverConnManager interface implementation. -func (cm *rpcConnManager) RemoveBan(addr string) error { - replyChan := make(chan error) - cm.server.query <- removeBanMsg{ - addr: addr, - reply: replyChan, - } - return <-replyChan -} - -// ClearBanned removes all banned host with banned period. -// -// This function is safe for concurrent access and is part of the -// rpcserverConnManager interface implementation. -func (cm *rpcConnManager) ClearBanned() error { - replyChan := make(chan error) - cm.server.query <- clearBannedMsg{ - reply: replyChan, - } - return <-replyChan -} - // PersistentPeers returns an array consisting of all the added persistent // peers. // diff --git a/rpcclient/doc.go b/rpcclient/doc.go index 7a02dded..d82a40a1 100644 --- a/rpcclient/doc.go +++ b/rpcclient/doc.go @@ -5,7 +5,7 @@ /* Package rpcclient implements a websocket-enabled Bitcoin JSON-RPC client. -# Overview +Overview This client provides a robust and easy to use client for interfacing with a Bitcoin RPC server that uses a btcd/bitcoin core compatible Bitcoin JSON-RPC @@ -24,7 +24,7 @@ btcd or btcwallet by default. However, configuration options are provided to fall back to HTTP POST and disable TLS to support talking with inferior bitcoin core style RPC servers. -# Websockets vs HTTP POST +Websockets vs HTTP POST In HTTP POST-based JSON-RPC, every request creates a new HTTP connection, issues the call, waits for the response, and closes the connection. This adds @@ -40,7 +40,7 @@ can be invoked without having to go through a connect/disconnect cycle for every call. In addition, the websocket interface provides other nice features such as the ability to register for asynchronous notifications of various events. -# Synchronous vs Asynchronous API +Synchronous vs Asynchronous API The client provides both a synchronous (blocking) and asynchronous API. @@ -57,7 +57,7 @@ the Receive method on the returned instance will either return the result immediately if it has already arrived, or block until it has. This is useful since it provides the caller with greater control over concurrency. -# Notifications +Notifications The first important part of notifications is to realize that they will only work when connected via websockets. This should intuitively make sense @@ -67,7 +67,7 @@ All notifications provided by btcd require registration to opt-in. For example, if you want to be notified when funds are received by a set of addresses, you register the addresses via the NotifyReceived (or NotifyReceivedAsync) function. -# Notification Handlers +Notification Handlers Notifications are exposed by the client through the use of callback handlers which are setup via a NotificationHandlers instance that is specified by the @@ -83,7 +83,7 @@ will cause a deadlock as more server responses won't be read until the callback returns, but the callback would be waiting for a response. Thus, any additional RPCs must be issued an a completely decoupled manner. -# Automatic Reconnection +Automatic Reconnection By default, when running in websockets mode, this client will automatically keep trying to reconnect to the RPC server should the connection be lost. There @@ -116,7 +116,7 @@ chain services will be available. Depending on your application, you might only need chain-related RPCs. In contrast, btcwallet provides pass through treatment for chain-related RPCs, so it supports them in addition to wallet-related RPCs. -# Errors +Errors There are 3 categories of errors that will be returned throughout this package: @@ -144,35 +144,35 @@ The third category of errors, that is errors returned by the server, can be detected by type asserting the error in a *btcjson.RPCError. For example, to detect if a command is unimplemented by the remote RPC server: - amount, err := client.GetBalance("") - if err != nil { - if jerr, ok := err.(*btcjson.RPCError); ok { - switch jerr.Code { - case btcjson.ErrRPCUnimplemented: - // Handle not implemented error + amount, err := client.GetBalance("") + if err != nil { + if jerr, ok := err.(*btcjson.RPCError); ok { + switch jerr.Code { + case btcjson.ErrRPCUnimplemented: + // Handle not implemented error - // Handle other specific errors you care about - } - } + // Handle other specific errors you care about + } + } - // Log or otherwise handle the error knowing it was not one returned - // from the remote RPC server. - } + // Log or otherwise handle the error knowing it was not one returned + // from the remote RPC server. + } -# Example Usage +Example Usage The following full-blown client examples are in the examples directory: - - bitcoincorehttp - Connects to a bitcoin core RPC server using HTTP POST mode with TLS disabled - and gets the current block count - - btcdwebsockets - Connects to a btcd RPC server using TLS-secured websockets, registers for - block connected and block disconnected notifications, and gets the current - block count - - btcwalletwebsockets - Connects to a btcwallet RPC server using TLS-secured websockets, registers - for notifications about changes to account balances, and gets a list of - unspent transaction outputs (utxos) the wallet can sign + - bitcoincorehttp + Connects to a bitcoin core RPC server using HTTP POST mode with TLS disabled + and gets the current block count + - btcdwebsockets + Connects to a btcd RPC server using TLS-secured websockets, registers for + block connected and block disconnected notifications, and gets the current + block count + - btcwalletwebsockets + Connects to a btcwallet RPC server using TLS-secured websockets, registers + for notifications about changes to account balances, and gets a list of + unspent transaction outputs (utxos) the wallet can sign */ package rpcclient diff --git a/rpcclient/examples/lbcdblocknotify/README.md b/rpcclient/examples/lbcdblocknotify/README.md index ea1fc777..45ab3b29 100644 --- a/rpcclient/examples/lbcdblocknotify/README.md +++ b/rpcclient/examples/lbcdblocknotify/README.md @@ -1,21 +1,15 @@ -# lbcdbloknotify +# lbcd Websockets Example -This bridge program subscribes to lbcd's notifications over websockets using the rpcclient package. -Users can specify supported actions upon receiving this notifications. +This example shows how to use the rpcclient package to connect to a btcd RPC +server using TLS-secured websockets, register for block connected and block +disconnected notifications, and get the current block count. -## Building(or Running) the Program +## Running the Example -Clone the lbcd package: +The first step is to clone the lbcd package: ```bash $ git clone github.com/lbryio/lbcd -$ cd lbcd/rpcclient/examples - -# build the program -$ go build . - -# or directly run it (build implicitly behind the scene) -$ go run . ``` Display available options: @@ -35,31 +29,18 @@ $ go run . -h Stratum server (default "lbrypool.net:3334") -stratumpass string Stratum server password (default "password") - -quiet - Do not print periodic logs ``` -Running the program: +Start the program: ```bash -# Send stratum mining.update_block mesage upon receving block connected notifiations. -$ go run . -rpcuser -rpcpass --notls -stratum -stratumpass +$ go run . -stratumpass -rpcuser -rpcpass -2022/01/10 23:16:21 Current block count: 1093112 +2022/01/10 23:16:21 NotifyBlocks: Registration Complete +2022/01/10 23:16:21 Block count: 1093112 ... - -# Execute a custome command (with blockhash) upon receving block connected notifiations. -$ go run . -rpcuser -rpcpass --notls -run "echo %s" ``` -## Notes - -* Stratum TCP connection is persisted with auto-reconnect. (retry backoff increases from 1s to 60s maximum) - -* Stratum update_block jobs on previous notifications are canceled when a new notification arrives. - Usually, the jobs are so short and completed immediately. However, if the Stratum connection is broken, this - prevents the bridge from accumulating stale jobs. - ## License This example is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/rpcclient/examples/lbcdblocknotify/adapter.go b/rpcclient/examples/lbcdblocknotify/adapter.go deleted file mode 100644 index b12b0d90..00000000 --- a/rpcclient/examples/lbcdblocknotify/adapter.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "github.com/lbryio/lbcd/wire" - "github.com/lbryio/lbcutil" -) - -type eventBlockConected struct { - height int32 - header *wire.BlockHeader - txns []*lbcutil.Tx -} - -type adapter struct { - *bridge -} - -func (a *adapter) onFilteredBlockConnected(height int32, header *wire.BlockHeader, txns []*lbcutil.Tx) { - a.eventCh <- &eventBlockConected{height, header, txns} -} diff --git a/rpcclient/examples/lbcdblocknotify/bridge.go b/rpcclient/examples/lbcdblocknotify/bridge.go deleted file mode 100644 index db5e8cc0..00000000 --- a/rpcclient/examples/lbcdblocknotify/bridge.go +++ /dev/null @@ -1,172 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "log" - "net" - "os" - "os/exec" - "strings" - "sync" - "syscall" - "time" -) - -type bridge struct { - ctx context.Context - - prevJobContext context.Context - prevJobCancel context.CancelFunc - - eventCh chan interface{} - errorc chan error - wg sync.WaitGroup - - stratum *stratumClient - - customCmd string -} - -func newBridge(stratumServer, stratumPass, coinid string) *bridge { - - s := &bridge{ - ctx: context.Background(), - eventCh: make(chan interface{}), - errorc: make(chan error), - } - - if len(stratumServer) > 0 { - s.stratum = newStratumClient(stratumServer, stratumPass, coinid) - } - - return s -} - -func (b *bridge) start() { - - if b.stratum != nil { - backoff := time.Second - for { - err := b.stratum.dial() - if err == nil { - break - } - log.Printf("WARN: stratum.dial() error: %s, retry in %s", err, backoff) - time.Sleep(backoff) - if backoff < 60*time.Second { - backoff += time.Second - } - } - } - - for e := range b.eventCh { - switch e := e.(type) { - case *eventBlockConected: - b.handleFilteredBlockConnected(e) - default: - b.errorc <- fmt.Errorf("unknown event type: %T", e) - return - } - } -} - -func (b *bridge) handleFilteredBlockConnected(e *eventBlockConected) { - - if !*quiet { - log.Printf("Block connected: %s (%d) %v", e.header.BlockHash(), e.height, e.header.Timestamp) - } - - hash := e.header.BlockHash().String() - height := e.height - - // Cancel jobs on previous block. It's safe if they are already done. - if b.prevJobContext != nil { - select { - case <-b.prevJobContext.Done(): - log.Printf("prev one canceled") - default: - b.prevJobCancel() - } - } - - // Wait until all previous jobs are done or canceled. - b.wg.Wait() - - // Create and save cancelable subcontext for new jobs. - ctx, cancel := context.WithCancel(b.ctx) - b.prevJobContext, b.prevJobCancel = ctx, cancel - - if len(b.customCmd) > 0 { - go b.execCustomCommand(ctx, hash, height) - } - - // Send stratum update block message - if b.stratum != nil { - go b.stratumUpdateBlock(ctx, hash, height) - } -} - -func (s *bridge) stratumUpdateBlock(ctx context.Context, hash string, height int32) { - s.wg.Add(1) - defer s.wg.Done() - - backoff := time.Second - retry := func(err error) { - if backoff < 60*time.Second { - backoff += time.Second - } - log.Printf("WARN: stratum.send() on block %d error: %s", height, err) - time.Sleep(backoff) - s.stratum.dial() - } - - msg := stratumUpdateBlockMsg(*stratumPass, *coinid, hash) - - for { - switch err := s.stratum.send(ctx, msg); { - case err == nil: - return - case errors.Is(err, context.Canceled): - log.Printf("INFO: stratum.send() on block %d: %s.", height, err) - return - case errors.Is(err, syscall.EPIPE): - errClose := s.stratum.conn.Close() - if errClose != nil { - log.Printf("WARN: stratum.conn.Close() on block %d: %s.", height, errClose) - } - retry(err) - case errors.Is(err, net.ErrClosed): - retry(err) - default: - retry(err) - } - } - -} - -func (s *bridge) execCustomCommand(ctx context.Context, hash string, height int32) { - s.wg.Add(1) - defer s.wg.Done() - - cmd := strings.ReplaceAll(s.customCmd, "%s", hash) - err := doExecCustomCommand(ctx, cmd) - if err != nil { - log.Printf("ERROR: execCustomCommand on block %s(%d): %s", hash, height, err) - } -} - -func doExecCustomCommand(ctx context.Context, cmd string) error { - strs := strings.Split(cmd, " ") - path, err := exec.LookPath(strs[0]) - if errors.Is(err, exec.ErrDot) { - err = nil - } - if err != nil { - return err - } - c := exec.CommandContext(ctx, path, strs[1:]...) - c.Stdout = os.Stdout - return c.Run() -} diff --git a/rpcclient/examples/lbcdblocknotify/lbcdclient.go b/rpcclient/examples/lbcdblocknotify/lbcdclient.go deleted file mode 100644 index 91580fd8..00000000 --- a/rpcclient/examples/lbcdblocknotify/lbcdclient.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "io/ioutil" - "log" - "path/filepath" - - "github.com/lbryio/lbcd/rpcclient" -) - -func newLbcdClient(server, user, pass string, notls bool, adpt adapter) *rpcclient.Client { - - ntfnHandlers := rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: adpt.onFilteredBlockConnected, - } - - // Config lbcd RPC client with websockets. - connCfg := &rpcclient.ConnConfig{ - Host: server, - Endpoint: "ws", - User: user, - Pass: pass, - DisableTLS: true, - } - - if !notls { - cert, err := ioutil.ReadFile(filepath.Join(lbcdHomeDir, "rpc.cert")) - if err != nil { - log.Fatalf("can't read lbcd certificate: %s", err) - } - connCfg.Certificates = cert - connCfg.DisableTLS = false - } - - client, err := rpcclient.New(connCfg, &ntfnHandlers) - if err != nil { - log.Fatalf("can't create rpc client: %s", err) - } - - // Register for block connect and disconnect notifications. - if err = client.NotifyBlocks(); err != nil { - log.Fatalf("can't register block notification: %s", err) - } - - // Get the current block count. - blockCount, err := client.GetBlockCount() - if err != nil { - log.Fatalf("can't get block count: %s", err) - } - log.Printf("Current block count: %d", blockCount) - - return client -} diff --git a/rpcclient/examples/lbcdblocknotify/main.go b/rpcclient/examples/lbcdblocknotify/main.go index 27cdf329..431331ee 100644 --- a/rpcclient/examples/lbcdblocknotify/main.go +++ b/rpcclient/examples/lbcdblocknotify/main.go @@ -1,63 +1,103 @@ +// Copyright (c) 2014-2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + package main import ( "flag" + "fmt" + "io/ioutil" "log" - "os/exec" + "net" "path/filepath" - "strings" + "github.com/lbryio/lbcd/rpcclient" + "github.com/lbryio/lbcd/wire" "github.com/lbryio/lbcutil" ) -var ( - lbcdHomeDir = lbcutil.AppDataDir("lbcd", false) - defaultCert = filepath.Join(lbcdHomeDir, "rpc.cert") -) -var ( - coinid = flag.String("coinid", "1425", "Coin ID") - stratumServer = flag.String("stratum", "", "Stratum server") - stratumPass = flag.String("stratumpass", "", "Stratum server password") - rpcserver = flag.String("rpcserver", "localhost:9245", "LBCD RPC server") - rpcuser = flag.String("rpcuser", "rpcuser", "LBCD RPC username") - rpcpass = flag.String("rpcpass", "rpcpass", "LBCD RPC password") - rpccert = flag.String("rpccert", defaultCert, "LBCD RPC certificate") - notls = flag.Bool("notls", false, "Connect to LBCD with TLS disabled") - run = flag.String("run", "", "Run custom shell command") - quiet = flag.Bool("quiet", false, "Do not print logs") -) +func send(stratum, stratumPass, coinid, blockHash string) error { + addr, err := net.ResolveTCPAddr("tcp", stratum) + if err != nil { + return fmt.Errorf("can't resolve addr: %w", err) + } + + conn, err := net.DialTCP("tcp", nil, addr) + if err != nil { + return fmt.Errorf("can't dial tcp: %w", err) + } + defer conn.Close() + + msg := fmt.Sprintf(`{"id":1,"method":"mining.update_block","params":[%q,%q,%q]}`, + stratumPass, coinid, blockHash) + + _, err = conn.Write([]byte(msg)) + if err != nil { + return fmt.Errorf("can't write message: %w", err) + } + + return nil +} func main() { + var ( + coinid = flag.String("coinid", "1425", "Coin ID") + stratum = flag.String("stratum", "lbrypool.net:3334", "Stratum server") + stratumPass = flag.String("stratumpass", "password", "Stratum server password") + rpcserver = flag.String("rpcserver", "localhost:9245", "LBCD RPC server") + rpcuser = flag.String("rpcuser", "rpcuser", "LBCD RPC username") + rpcpass = flag.String("rpcpass", "rpcpass", "LBCD RPC password") + notls = flag.Bool("notls", false, "Connect to LBCD with TLS disabled") + ) + flag.Parse() - // Setup notification handler - b := newBridge(*stratumServer, *stratumPass, *coinid) + ntfnHandlers := rpcclient.NotificationHandlers{ + OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txns []*lbcutil.Tx) { - if len(*run) > 0 { - // Check if ccommand exists. - strs := strings.Split(*run, " ") - cmd := strs[0] - _, err := exec.LookPath(cmd) - if err != nil { - log.Fatalf("ERROR: %s not found: %s", cmd, err) - } - b.customCmd = *run + blockHash := header.BlockHash().String() + + log.Printf("Block connected: %v (%d) %v", blockHash, height, header.Timestamp) + + if err := send(*stratum, *stratumPass, *coinid, blockHash); err != nil { + log.Printf("ERROR: failed to notify stratum: %s", err) + } + }, } - // Start the eventt handler. - go b.start() + // Connect to local lbcd RPC server using websockets. + lbcdHomeDir := lbcutil.AppDataDir("lbcd", false) + certs, err := ioutil.ReadFile(filepath.Join(lbcdHomeDir, "rpc.cert")) + if err != nil { + log.Fatalf("can't read lbcd certificate: %s", err) + } + connCfg := &rpcclient.ConnConfig{ + Host: *rpcserver, + Endpoint: "ws", + User: *rpcuser, + Pass: *rpcpass, + Certificates: certs, + DisableTLS: *notls, + } + client, err := rpcclient.New(connCfg, &ntfnHandlers) + if err != nil { + log.Fatalf("can't create rpc client: %s", err) + } - // Adaptater receives lbcd notifications, and emit events. - adpt := adapter{b} + // Register for block connect and disconnect notifications. + if err = client.NotifyBlocks(); err != nil { + log.Fatalf("can't register block notification: %s", err) + } + log.Printf("NotifyBlocks: Registration Complete") - client := newLbcdClient(*rpcserver, *rpcuser, *rpcpass, *notls, adpt) - - go func() { - err := <-b.errorc - log.Fatalf("ERROR: %s", err) - client.Shutdown() - }() + // Get the current block count. + blockCount, err := client.GetBlockCount() + if err != nil { + log.Fatalf("can't get block count: %s", err) + } + log.Printf("Block count: %d", blockCount) // Wait until the client either shuts down gracefully (or the user // terminates the process with Ctrl+C). diff --git a/rpcclient/examples/lbcdblocknotify/stratumclient.go b/rpcclient/examples/lbcdblocknotify/stratumclient.go deleted file mode 100644 index 449135ce..00000000 --- a/rpcclient/examples/lbcdblocknotify/stratumclient.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "context" - "fmt" - "net" -) - -type stratumClient struct { - server string - passwd string - coinid string - conn *net.TCPConn -} - -func newStratumClient(server, passwd, coinid string) *stratumClient { - - return &stratumClient{ - server: server, - } -} - -func (c *stratumClient) dial() error { - - addr, err := net.ResolveTCPAddr("tcp", c.server) - if err != nil { - return fmt.Errorf("resolve tcp addr: %w", err) - } - - conn, err := net.DialTCP("tcp", nil, addr) - if err != nil { - return fmt.Errorf("dial tcp: %w", err) - } - c.conn = conn - - return nil -} - -func (c *stratumClient) send(ctx context.Context, msg string) error { - - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - - _, err := c.conn.Write([]byte(msg)) - - return err -} - -func stratumUpdateBlockMsg(stratumPass, coinid, blockHash string) string { - - return fmt.Sprintf(`{"id":1,"method":"mining.update_block","params":[%q,%s,%q]}`, - stratumPass, coinid, blockHash) -} diff --git a/rpcclient/extensions.go b/rpcclient/extensions.go index c21101c3..da44e91f 100644 --- a/rpcclient/extensions.go +++ b/rpcclient/extensions.go @@ -56,8 +56,7 @@ func (c *Client) DebugLevelAsync(levelSpec string) FutureDebugLevelResult { // specification. // // The levelspec can be either a debug level or of the form: -// -// =,=,... +// =,=,... // // Additionally, the special keyword 'show' can be used to get a list of the // available subsystems. diff --git a/rpcclient/infrastructure.go b/rpcclient/infrastructure.go index 87fe9ec9..9923cbd1 100644 --- a/rpcclient/infrastructure.go +++ b/rpcclient/infrastructure.go @@ -774,8 +774,7 @@ func (c *Client) handleSendPostMessage(jReq *jsonRequest) { tries := 10 for i := 0; tries == 0 || i < tries; i++ { bodyReader := bytes.NewReader(jReq.marshalledJSON) - var httpReq *http.Request - httpReq, err = http.NewRequest("POST", url, bodyReader) + httpReq, err := http.NewRequest("POST", url, bodyReader) if err != nil { jReq.responseChan <- &Response{result: nil, err: err} return @@ -787,8 +786,7 @@ func (c *Client) handleSendPostMessage(jReq *jsonRequest) { } // Configure basic access authorization. - var user, pass string - user, pass, err = c.config.getAuth() + user, pass, err := c.config.getAuth() if err != nil { jReq.responseChan <- &Response{result: nil, err: err} return @@ -1194,9 +1192,6 @@ type ConnConfig struct { // the wire in cleartext. DisableTLS bool - // SkipVerify instruct the client to skip verifying TLS certificate. - SkipVerify bool - // Certificates are the bytes for a PEM-encoded certificate chain used // for the TLS connection. It has no effect if the DisableTLS parameter // is true. @@ -1300,8 +1295,7 @@ func newHTTPClient(config *ConnConfig) (*http.Client, error) { pool := x509.NewCertPool() pool.AppendCertsFromPEM(config.Certificates) tlsConfig = &tls.Config{ - RootCAs: pool, - InsecureSkipVerify: config.SkipVerify, + RootCAs: pool, } } } @@ -1324,8 +1318,7 @@ func dial(config *ConnConfig) (*websocket.Conn, error) { var scheme = "ws" if !config.DisableTLS { tlsConfig = &tls.Config{ - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: config.SkipVerify, + MinVersion: tls.VersionTLS12, } if len(config.Certificates) > 0 { pool := x509.NewCertPool() diff --git a/rpcclient/net.go b/rpcclient/net.go index 385875df..2d268235 100644 --- a/rpcclient/net.go +++ b/rpcclient/net.go @@ -355,75 +355,6 @@ func (c *Client) GetPeerInfo() ([]btcjson.GetPeerInfoResult, error) { return c.GetPeerInfoAsync().Receive() } -// FutureListBannedResult is a future promise to deliver the result of a -// ListBannedAsync RPC invocation (or an applicable error). -type FutureListBannedResult chan *Response - -// Receive waits for the Response promised by the future and returns data about -// each connected network peer. -func (r FutureListBannedResult) Receive() ([]btcjson.ListBannedResult, error) { - res, err := ReceiveFuture(r) - if err != nil { - return nil, err - } - - // Unmarshal result as an array of ListBanned result objects. - var bannedPeers []btcjson.ListBannedResult - err = json.Unmarshal(res, &bannedPeers) - if err != nil { - return nil, err - } - - return bannedPeers, nil -} - -// SetBanCommand enumerates the available commands that the SetBanCommand function -// accepts. -type SetBanCommand string - -// Constants used to indicate the command for the SetBanCommand function. -const ( - // SBAdd indicates the specified host should be added as a banned - // peer. - SBAdd SetBanCommand = "add" - - // SBRemove indicates the specified peer should be removed. - SBRemove SetBanCommand = "remove" -) - -// String returns the SetBanCommand in human-readable form. -func (cmd SetBanCommand) String() string { - return string(cmd) -} - -// FutureSetBanResult is a future promise to deliver the result of an -// SetBanAsync RPC invocation (or an applicable error). -type FutureSetBanResult chan *Response - -// Receive waits for the Response promised by the future and returns an error if -// any occurred when performing the specified command. -func (r FutureSetBanResult) Receive() error { - _, err := ReceiveFuture(r) - return err -} - -// SetBanAsync returns an instance of a type that can be used to get the result -// of the RPC at some future time by invoking the Receive function on the -// returned instance. -func (c *Client) SetBanAsync(addr string, command string, banTime *int, - absolute *bool) FutureSetBanResult { - cmd := btcjson.NewSetBanCmd(addr, btcjson.SetBanSubCmd(command), banTime, - absolute) - return c.SendCmd(cmd) -} - -// SetBan attempts to perform the passed command on the passed persistent peer. -// For example, it can be used to add or a remove a banned peer. -func (c *Client) SetBan(addr string, command string, banTime *int, - absolute *bool) error { - return c.SetBanAsync(addr, command, banTime, absolute).Receive() -} - // FutureGetNetTotalsResult is a future promise to deliver the result of a // GetNetTotalsAsync RPC invocation (or an applicable error). type FutureGetNetTotalsResult chan *Response diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index 6d14d228..e4402f1d 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -291,18 +291,13 @@ func (r FutureCreateRawTransactionResult) Receive() (*wire.MsgTx, error) { // // See CreateRawTransaction for the blocking version and more details. func (c *Client) CreateRawTransactionAsync(inputs []btcjson.TransactionInput, - outputs map[btcutil.Address]interface{}, lockTime *int64) FutureCreateRawTransactionResult { + amounts map[btcutil.Address]btcutil.Amount, lockTime *int64) FutureCreateRawTransactionResult { - convertedData := make(map[string]interface{}, len(outputs)) - for key, value := range outputs { - switch val := value.(type) { - case btcutil.Amount: - convertedData[key.String()] = val.ToBTC() - case string: - convertedData[key.String()] = val - } + convertedAmts := make(map[string]float64, len(amounts)) + for addr, amount := range amounts { + convertedAmts[addr.String()] = amount.ToBTC() } - cmd := btcjson.NewCreateRawTransactionCmd(inputs, convertedData, lockTime) + cmd := btcjson.NewCreateRawTransactionCmd(inputs, convertedAmts, lockTime) return c.SendCmd(cmd) } @@ -310,9 +305,9 @@ func (c *Client) CreateRawTransactionAsync(inputs []btcjson.TransactionInput, // and sending to the provided addresses. If the inputs are either nil or an // empty slice, it is interpreted as an empty slice. func (c *Client) CreateRawTransaction(inputs []btcjson.TransactionInput, - outputs map[btcutil.Address]interface{}, lockTime *int64) (*wire.MsgTx, error) { + amounts map[btcutil.Address]btcutil.Amount, lockTime *int64) (*wire.MsgTx, error) { - return c.CreateRawTransactionAsync(inputs, outputs, lockTime).Receive() + return c.CreateRawTransactionAsync(inputs, amounts, lockTime).Receive() } // FutureSendRawTransactionResult is a future promise to deliver the result diff --git a/rpcclient/wallet.go b/rpcclient/wallet.go index 10da4439..784f0688 100644 --- a/rpcclient/wallet.go +++ b/rpcclient/wallet.go @@ -536,10 +536,9 @@ func (r FutureSendToAddressResult) Receive() (*chainhash.Hash, error) { // returned instance. // // See SendToAddress for the blocking version and more details. -func (c *Client) SendToAddressAsync(address btcutil.Address, amount btcutil.Amount, - addrType *string) FutureSendToAddressResult { +func (c *Client) SendToAddressAsync(address btcutil.Address, amount btcutil.Amount) FutureSendToAddressResult { addr := address.EncodeAddress() - cmd := btcjson.NewSendToAddressCmd(addr, amount.ToBTC(), addrType, nil, nil) + cmd := btcjson.NewSendToAddressCmd(addr, amount.ToBTC(), nil, nil) return c.SendCmd(cmd) } @@ -551,9 +550,8 @@ func (c *Client) SendToAddressAsync(address btcutil.Address, amount btcutil.Amou // // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. -func (c *Client) SendToAddress(address btcutil.Address, amount btcutil.Amount, - addrType *string) (*chainhash.Hash, error) { - return c.SendToAddressAsync(address, amount, addrType).Receive() +func (c *Client) SendToAddress(address btcutil.Address, amount btcutil.Amount) (*chainhash.Hash, error) { + return c.SendToAddressAsync(address, amount).Receive() } // SendToAddressCommentAsync returns an instance of a type that can be used to @@ -562,12 +560,12 @@ func (c *Client) SendToAddress(address btcutil.Address, amount btcutil.Amount, // // See SendToAddressComment for the blocking version and more details. func (c *Client) SendToAddressCommentAsync(address btcutil.Address, - amount btcutil.Amount, addrType *string, comment string, + amount btcutil.Amount, comment, commentTo string) FutureSendToAddressResult { addr := address.EncodeAddress() - cmd := btcjson.NewSendToAddressCmd(addr, amount.ToBTC(), addrType, - &comment, &commentTo) + cmd := btcjson.NewSendToAddressCmd(addr, amount.ToBTC(), &comment, + &commentTo) return c.SendCmd(cmd) } @@ -583,10 +581,9 @@ func (c *Client) SendToAddressCommentAsync(address btcutil.Address, // // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. -func (c *Client) SendToAddressComment(address btcutil.Address, amount btcutil.Amount, - addrType *string, comment, commentTo string) (*chainhash.Hash, error) { - return c.SendToAddressCommentAsync(address, amount, addrType, - comment, commentTo).Receive() +func (c *Client) SendToAddressComment(address btcutil.Address, amount btcutil.Amount, comment, commentTo string) (*chainhash.Hash, error) { + return c.SendToAddressCommentAsync(address, amount, comment, + commentTo).Receive() } // FutureSendFromResult is a future promise to deliver the result of a @@ -618,11 +615,10 @@ func (r FutureSendFromResult) Receive() (*chainhash.Hash, error) { // returned instance. // // See SendFrom for the blocking version and more details. -func (c *Client) SendFromAsync(fromAccount string, toAddress btcutil.Address, - amount btcutil.Amount, addrType *string) FutureSendFromResult { +func (c *Client) SendFromAsync(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount) FutureSendFromResult { addr := toAddress.EncodeAddress() cmd := btcjson.NewSendFromCmd(fromAccount, addr, amount.ToBTC(), nil, - addrType, nil, nil) + nil, nil) return c.SendCmd(cmd) } @@ -634,8 +630,8 @@ func (c *Client) SendFromAsync(fromAccount string, toAddress btcutil.Address, // // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. -func (c *Client) SendFrom(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount, addrType *string) (*chainhash.Hash, error) { - return c.SendFromAsync(fromAccount, toAddress, amount, addrType).Receive() +func (c *Client) SendFrom(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount) (*chainhash.Hash, error) { + return c.SendFromAsync(fromAccount, toAddress, amount).Receive() } // SendFromMinConfAsync returns an instance of a type that can be used to get @@ -643,12 +639,10 @@ func (c *Client) SendFrom(fromAccount string, toAddress btcutil.Address, amount // the returned instance. // // See SendFromMinConf for the blocking version and more details. -func (c *Client) SendFromMinConfAsync(fromAccount string, - toAddress btcutil.Address, amount btcutil.Amount, - minConfirms int, addrType *string) FutureSendFromResult { +func (c *Client) SendFromMinConfAsync(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount, minConfirms int) FutureSendFromResult { addr := toAddress.EncodeAddress() cmd := btcjson.NewSendFromCmd(fromAccount, addr, amount.ToBTC(), - &minConfirms, addrType, nil, nil) + &minConfirms, nil, nil) return c.SendCmd(cmd) } @@ -661,10 +655,9 @@ func (c *Client) SendFromMinConfAsync(fromAccount string, // // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. -func (c *Client) SendFromMinConf(fromAccount string, toAddress btcutil.Address, - amount btcutil.Amount, minConfirms int, addrType *string) (*chainhash.Hash, error) { +func (c *Client) SendFromMinConf(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount, minConfirms int) (*chainhash.Hash, error) { return c.SendFromMinConfAsync(fromAccount, toAddress, amount, - minConfirms, addrType).Receive() + minConfirms).Receive() } // SendFromCommentAsync returns an instance of a type that can be used to get @@ -674,11 +667,11 @@ func (c *Client) SendFromMinConf(fromAccount string, toAddress btcutil.Address, // See SendFromComment for the blocking version and more details. func (c *Client) SendFromCommentAsync(fromAccount string, toAddress btcutil.Address, amount btcutil.Amount, minConfirms int, - addrType *string, comment, commentTo string) FutureSendFromResult { + comment, commentTo string) FutureSendFromResult { addr := toAddress.EncodeAddress() cmd := btcjson.NewSendFromCmd(fromAccount, addr, amount.ToBTC(), - &minConfirms, addrType, &comment, &commentTo) + &minConfirms, &comment, &commentTo) return c.SendCmd(cmd) } @@ -694,11 +687,11 @@ func (c *Client) SendFromCommentAsync(fromAccount string, // NOTE: This function requires to the wallet to be unlocked. See the // WalletPassphrase function for more details. func (c *Client) SendFromComment(fromAccount string, toAddress btcutil.Address, - amount btcutil.Amount, minConfirms int, addrType *string, + amount btcutil.Amount, minConfirms int, comment, commentTo string) (*chainhash.Hash, error) { return c.SendFromCommentAsync(fromAccount, toAddress, amount, - minConfirms, addrType, comment, commentTo).Receive() + minConfirms, comment, commentTo).Receive() } // FutureSendManyResult is a future promise to deliver the result of a @@ -735,7 +728,7 @@ func (c *Client) SendManyAsync(fromAccount string, amounts map[btcutil.Address]b for addr, amount := range amounts { convertedAmounts[addr.EncodeAddress()] = amount.ToBTC() } - cmd := btcjson.NewSendManyCmd(fromAccount, convertedAmounts, nil, nil, nil) + cmd := btcjson.NewSendManyCmd(fromAccount, convertedAmounts, nil, nil) return c.SendCmd(cmd) } @@ -758,14 +751,14 @@ func (c *Client) SendMany(fromAccount string, amounts map[btcutil.Address]btcuti // See SendManyMinConf for the blocking version and more details. func (c *Client) SendManyMinConfAsync(fromAccount string, amounts map[btcutil.Address]btcutil.Amount, - minConfirms int, addrType *string) FutureSendManyResult { + minConfirms int) FutureSendManyResult { convertedAmounts := make(map[string]float64, len(amounts)) for addr, amount := range amounts { convertedAmounts[addr.EncodeAddress()] = amount.ToBTC() } cmd := btcjson.NewSendManyCmd(fromAccount, convertedAmounts, - &minConfirms, nil, addrType) + &minConfirms, nil) return c.SendCmd(cmd) } @@ -780,10 +773,9 @@ func (c *Client) SendManyMinConfAsync(fromAccount string, // WalletPassphrase function for more details. func (c *Client) SendManyMinConf(fromAccount string, amounts map[btcutil.Address]btcutil.Amount, - minConfirms int, addrType *string) (*chainhash.Hash, error) { + minConfirms int) (*chainhash.Hash, error) { - return c.SendManyMinConfAsync(fromAccount, amounts, minConfirms, - addrType).Receive() + return c.SendManyMinConfAsync(fromAccount, amounts, minConfirms).Receive() } // SendManyCommentAsync returns an instance of a type that can be used to get @@ -793,14 +785,14 @@ func (c *Client) SendManyMinConf(fromAccount string, // See SendManyComment for the blocking version and more details. func (c *Client) SendManyCommentAsync(fromAccount string, amounts map[btcutil.Address]btcutil.Amount, minConfirms int, - addrType *string, comment string) FutureSendManyResult { + comment string) FutureSendManyResult { convertedAmounts := make(map[string]float64, len(amounts)) for addr, amount := range amounts { convertedAmounts[addr.EncodeAddress()] = amount.ToBTC() } cmd := btcjson.NewSendManyCmd(fromAccount, convertedAmounts, - &minConfirms, &comment, addrType) + &minConfirms, &comment) return c.SendCmd(cmd) } @@ -816,10 +808,10 @@ func (c *Client) SendManyCommentAsync(fromAccount string, // WalletPassphrase function for more details. func (c *Client) SendManyComment(fromAccount string, amounts map[btcutil.Address]btcutil.Amount, minConfirms int, - addrType *string, comment string) (*chainhash.Hash, error) { + comment string) (*chainhash.Hash, error) { return c.SendManyCommentAsync(fromAccount, amounts, minConfirms, - addrType, comment).Receive() + comment).Receive() } // ************************* @@ -1024,10 +1016,10 @@ func (c *Client) CreateWalletAsync(name string, opts ...CreateWalletOpt) FutureC // // Optional parameters can be specified using functional-options pattern. The // following functions are available: -// - WithCreateWalletDisablePrivateKeys -// - WithCreateWalletBlank -// - WithCreateWalletPassphrase -// - WithCreateWalletAvoidReuse +// * WithCreateWalletDisablePrivateKeys +// * WithCreateWalletBlank +// * WithCreateWalletPassphrase +// * WithCreateWalletAvoidReuse func (c *Client) CreateWallet(name string, opts ...CreateWalletOpt) (*btcjson.CreateWalletResult, error) { return c.CreateWalletAsync(name, opts...).Receive() } @@ -1143,8 +1135,8 @@ func (r FutureGetRawChangeAddressResult) Receive() (btcutil.Address, error) { // function on the returned instance. // // See GetRawChangeAddress for the blocking version and more details. -func (c *Client) GetRawChangeAddressAsync(account *string) FutureGetRawChangeAddressResult { - cmd := btcjson.NewGetRawChangeAddressCmd(account) +func (c *Client) GetRawChangeAddressAsync(account string) FutureGetRawChangeAddressResult { + cmd := btcjson.NewGetRawChangeAddressCmd(&account) result := FutureGetRawChangeAddressResult{ network: c.chainParams, responseChannel: c.SendCmd(cmd), @@ -1155,7 +1147,7 @@ func (c *Client) GetRawChangeAddressAsync(account *string) FutureGetRawChangeAdd // GetRawChangeAddress returns a new address for receiving change that will be // associated with the provided account. Note that this is only for raw // transactions and NOT for normal use. -func (c *Client) GetRawChangeAddress(account *string) (btcutil.Address, error) { +func (c *Client) GetRawChangeAddress(account string) (btcutil.Address, error) { return c.GetRawChangeAddressAsync(account).Receive() } @@ -1234,7 +1226,7 @@ func (r FutureGetAccountAddressResult) Receive() (btcutil.Address, error) { // the returned instance. // // See GetAccountAddress for the blocking version and more details. -func (c *Client) GetAccountAddressAsync(account *string) FutureGetAccountAddressResult { +func (c *Client) GetAccountAddressAsync(account string) FutureGetAccountAddressResult { cmd := btcjson.NewGetAccountAddressCmd(account) result := FutureGetAccountAddressResult{ network: c.chainParams, @@ -1245,7 +1237,7 @@ func (c *Client) GetAccountAddressAsync(account *string) FutureGetAccountAddress // GetAccountAddress returns the current Bitcoin address for receiving payments // to the specified account. -func (c *Client) GetAccountAddress(account *string) (btcutil.Address, error) { +func (c *Client) GetAccountAddress(account string) (btcutil.Address, error) { return c.GetAccountAddressAsync(account).Receive() } @@ -1287,6 +1279,33 @@ func (c *Client) GetAccount(address btcutil.Address) (string, error) { return c.GetAccountAsync(address).Receive() } +// FutureSetAccountResult is a future promise to deliver the result of a +// SetAccountAsync RPC invocation (or an applicable error). +type FutureSetAccountResult chan *Response + +// Receive waits for the Response promised by the future and returns the result +// of setting the account to be associated with the passed address. +func (r FutureSetAccountResult) Receive() error { + _, err := ReceiveFuture(r) + return err +} + +// SetAccountAsync returns an instance of a type that can be used to get the +// result of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See SetAccount for the blocking version and more details. +func (c *Client) SetAccountAsync(address btcutil.Address, account string) FutureSetAccountResult { + addr := address.EncodeAddress() + cmd := btcjson.NewSetAccountCmd(addr, account) + return c.SendCmd(cmd) +} + +// SetAccount sets the account associated with the passed address. +func (c *Client) SetAccount(address btcutil.Address, account string) error { + return c.SetAccountAsync(address, account).Receive() +} + // FutureGetAddressesByAccountResult is a future promise to deliver the result // of a GetAddressesByAccountAsync RPC invocation (or an applicable error). type FutureGetAddressesByAccountResult struct { @@ -1325,7 +1344,7 @@ func (r FutureGetAddressesByAccountResult) Receive() ([]btcutil.Address, error) // function on the returned instance. // // See GetAddressesByAccount for the blocking version and more details. -func (c *Client) GetAddressesByAccountAsync(account *string) FutureGetAddressesByAccountResult { +func (c *Client) GetAddressesByAccountAsync(account string) FutureGetAddressesByAccountResult { cmd := btcjson.NewGetAddressesByAccountCmd(account) result := FutureGetAddressesByAccountResult{ network: c.chainParams, @@ -1336,7 +1355,7 @@ func (c *Client) GetAddressesByAccountAsync(account *string) FutureGetAddressesB // GetAddressesByAccount returns the list of addresses associated with the // passed account. -func (c *Client) GetAddressesByAccount(account *string) ([]btcutil.Address, error) { +func (c *Client) GetAddressesByAccount(account string) ([]btcutil.Address, error) { return c.GetAddressesByAccountAsync(account).Receive() } @@ -1363,6 +1382,74 @@ func (r FutureMoveResult) Receive() (bool, error) { return moveResult, nil } +// MoveAsync returns an instance of a type that can be used to get the result of +// the RPC at some future time by invoking the Receive function on the returned +// instance. +// +// See Move for the blocking version and more details. +func (c *Client) MoveAsync(fromAccount, toAccount string, amount btcutil.Amount) FutureMoveResult { + cmd := btcjson.NewMoveCmd(fromAccount, toAccount, amount.ToBTC(), nil, + nil) + return c.SendCmd(cmd) +} + +// Move moves specified amount from one account in your wallet to another. Only +// funds with the default number of minimum confirmations will be used. +// +// See MoveMinConf and MoveComment for different options. +func (c *Client) Move(fromAccount, toAccount string, amount btcutil.Amount) (bool, error) { + return c.MoveAsync(fromAccount, toAccount, amount).Receive() +} + +// MoveMinConfAsync returns an instance of a type that can be used to get the +// result of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See MoveMinConf for the blocking version and more details. +func (c *Client) MoveMinConfAsync(fromAccount, toAccount string, + amount btcutil.Amount, minConfirms int) FutureMoveResult { + + cmd := btcjson.NewMoveCmd(fromAccount, toAccount, amount.ToBTC(), + &minConfirms, nil) + return c.SendCmd(cmd) +} + +// MoveMinConf moves specified amount from one account in your wallet to +// another. Only funds with the passed number of minimum confirmations will be +// used. +// +// See Move to use the default number of minimum confirmations and MoveComment +// for additional options. +func (c *Client) MoveMinConf(fromAccount, toAccount string, amount btcutil.Amount, minConf int) (bool, error) { + return c.MoveMinConfAsync(fromAccount, toAccount, amount, minConf).Receive() +} + +// MoveCommentAsync returns an instance of a type that can be used to get the +// result of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See MoveComment for the blocking version and more details. +func (c *Client) MoveCommentAsync(fromAccount, toAccount string, + amount btcutil.Amount, minConfirms int, comment string) FutureMoveResult { + + cmd := btcjson.NewMoveCmd(fromAccount, toAccount, amount.ToBTC(), + &minConfirms, &comment) + return c.SendCmd(cmd) +} + +// MoveComment moves specified amount from one account in your wallet to +// another and stores the provided comment in the wallet. The comment +// parameter is only available in the wallet. Only funds with the passed number +// of minimum confirmations will be used. +// +// See Move and MoveMinConf to use defaults. +func (c *Client) MoveComment(fromAccount, toAccount string, amount btcutil.Amount, + minConf int, comment string) (bool, error) { + + return c.MoveCommentAsync(fromAccount, toAccount, amount, minConf, + comment).Receive() +} + // FutureRenameAccountResult is a future promise to deliver the result of a // RenameAccountAsync RPC invocation (or an applicable error). type FutureRenameAccountResult chan *Response @@ -1717,7 +1804,7 @@ func (r FutureGetReceivedByAccountResult) Receive() (btcutil.Amount, error) { // function on the returned instance. // // See GetReceivedByAccount for the blocking version and more details. -func (c *Client) GetReceivedByAccountAsync(account *string) FutureGetReceivedByAccountResult { +func (c *Client) GetReceivedByAccountAsync(account string) FutureGetReceivedByAccountResult { cmd := btcjson.NewGetReceivedByAccountCmd(account, nil) return c.SendCmd(cmd) } @@ -1727,7 +1814,7 @@ func (c *Client) GetReceivedByAccountAsync(account *string) FutureGetReceivedByA // // See GetReceivedByAccountMinConf to override the minimum number of // confirmations. -func (c *Client) GetReceivedByAccount(account *string) (btcutil.Amount, error) { +func (c *Client) GetReceivedByAccount(account string) (btcutil.Amount, error) { return c.GetReceivedByAccountAsync(account).Receive() } @@ -1736,8 +1823,8 @@ func (c *Client) GetReceivedByAccount(account *string) (btcutil.Amount, error) { // function on the returned instance. // // See GetReceivedByAccountMinConf for the blocking version and more details. -func (c *Client) GetReceivedByAccountMinConfAsync(account *string, minConfirms *int) FutureGetReceivedByAccountResult { - cmd := btcjson.NewGetReceivedByAccountCmd(account, minConfirms) +func (c *Client) GetReceivedByAccountMinConfAsync(account string, minConfirms int) FutureGetReceivedByAccountResult { + cmd := btcjson.NewGetReceivedByAccountCmd(account, &minConfirms) return c.SendCmd(cmd) } @@ -1746,7 +1833,7 @@ func (c *Client) GetReceivedByAccountMinConfAsync(account *string, minConfirms * // confirmations. // // See GetReceivedByAccount to use the default minimum number of confirmations. -func (c *Client) GetReceivedByAccountMinConf(account *string, minConfirms *int) (btcutil.Amount, error) { +func (c *Client) GetReceivedByAccountMinConf(account string, minConfirms int) (btcutil.Amount, error) { return c.GetReceivedByAccountMinConfAsync(account, minConfirms).Receive() } @@ -2035,44 +2122,6 @@ func (c *Client) ListReceivedByAddressIncludeEmpty(minConfirms int, includeEmpty includeEmpty).Receive() } -// FutureRescanBlockchainResult is a future promise to deliver the error result of a -// RescanBlockchainAsync RPC invocation. -type FutureRescanBlockchainResult chan *Response - -// Receive waits for the Response promised by the future and returns the result -// of locking or unlocking the unspent output(s). -func (r FutureRescanBlockchainResult) Receive() (*btcjson.RescanBlockchainResult, error) { - res, err := ReceiveFuture(r) - if err != nil { - return nil, err - } - - // Unmarshal as an array of listreceivedbyaddress result objects. - var received btcjson.RescanBlockchainResult - err = json.Unmarshal(res, &received) - if err != nil { - return nil, err - } - - return &received, nil -} - -// RescanBlockchainAsync returns an instance of a type that can be used to get the -// result of the RPC at some future time by invoking the Receive function on the -// returned instance. -// -// See RescanBlockchain for the blocking version and more details. -func (c *Client) RescanBlockchainAsync(startHeight *int32, stopHeight *int32) FutureRescanBlockchainResult { - cmd := btcjson.NewRescanBlockchainCmd(startHeight, stopHeight) - return c.SendCmd(cmd) -} - -// RescanBlockchain rescans the local blockchain for wallet related -// transactions from the startHeight to the the inclusive stopHeight. -func (c *Client) RescanBlockchain(startHeight *int32, stopHeight *int32) (*btcjson.RescanBlockchainResult, error) { - return c.RescanBlockchainAsync(startHeight, stopHeight).Receive() -} - // ************************ // Wallet Locking Functions // ************************ diff --git a/rpcserver.go b/rpcserver.go index 359f8f2c..0724a757 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -21,7 +21,6 @@ import ( "net" "net/http" "os" - "sort" "strconv" "strings" "sync" @@ -43,7 +42,6 @@ import ( "github.com/lbryio/lbcd/mining/cpuminer" "github.com/lbryio/lbcd/peer" "github.com/lbryio/lbcd/txscript" - "github.com/lbryio/lbcd/version" "github.com/lbryio/lbcd/wire" btcutil "github.com/lbryio/lbcutil" ) @@ -135,7 +133,6 @@ type commandHandler func(*rpcServer, interface{}, <-chan struct{}) (interface{}, var rpcHandlers map[string]commandHandler var rpcHandlersBeforeInit = map[string]commandHandler{ "addnode": handleAddNode, - "clearbanned": handleClearBanned, "createrawtransaction": handleCreateRawTransaction, "debuglevel": handleDebugLevel, "decoderawtransaction": handleDecodeRawTransaction, @@ -152,11 +149,10 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getblockcount": handleGetBlockCount, "getblockhash": handleGetBlockHash, "getblockheader": handleGetBlockHeader, - "getblockstats": handleGetBlockStats, + "getchaintips": handleGetChainTips, "getblocktemplate": handleGetBlockTemplate, "getcfilter": handleGetCFilter, "getcfilterheader": handleGetCFilterHeader, - "getchaintips": handleGetChainTips, "getconnectioncount": handleGetConnectionCount, "getcurrentnet": handleGetCurrentNet, "getdifficulty": handleGetDifficulty, @@ -164,8 +160,8 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "gethashespersec": handleGetHashesPerSec, "getheaders": handleGetHeaders, "getinfo": handleGetInfo, - "getmempoolentry": handleGetMempoolEntry, "getmempoolinfo": handleGetMempoolInfo, + "getmempoolentry": handleGetMempoolEntry, "getmininginfo": handleGetMiningInfo, "getnettotals": handleGetNetTotals, "getnetworkhashps": handleGetNetworkHashPS, @@ -177,13 +173,11 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "gettxout": handleGetTxOut, "help": handleHelp, "invalidateblock": handleInvalidateBlock, - "listbanned": handleListBanned, "node": handleNode, "ping": handlePing, "reconsiderblock": handleReconsiderBlock, "searchrawtransactions": handleSearchRawTransactions, "sendrawtransaction": handleSendRawTransaction, - "setban": handleSetBan, "setgenerate": handleSetGenerate, "signmessagewithprivkey": handleSignMessageWithPrivKey, "stop": handleStop, @@ -230,10 +224,11 @@ var rpcAskWallet = map[string]struct{}{ "listtransactions": {}, "listunspent": {}, "lockunspent": {}, - "rescanblockchain": {}, + "move": {}, "sendfrom": {}, "sendmany": {}, "sendtoaddress": {}, + "setaccount": {}, "settxfee": {}, "signmessage": {}, "signrawtransaction": {}, @@ -329,15 +324,6 @@ func rpcDecodeHexError(gotHex string) *btcjson.RPCError { gotHex)) } -// rpcInvalidAddressOrKey is a convenience function for returning a nicely -// formatted RPC error which indicates the address or key is invalid. -func rpcInvalidAddressOrKeyError(addr string, msg string) *btcjson.RPCError { - return &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidAddressOrKey, - Message: msg, - } -} - // rpcNoTxInfoError is a convenience function for returning a nicely formatted // RPC error which indicates there is no information available for the provided // transaction hash. @@ -413,21 +399,6 @@ func handleAddNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in return nil, nil } -// handleClearBanned handles clearbanned commands. -func handleClearBanned(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - - err := s.cfg.ConnMgr.ClearBanned() - if err != nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidParameter, - Message: err.Error(), - } - } - - // no data returned unless an error. - return nil, nil -} - // handleNode handles node commands. func handleNode(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.NodeCmd) @@ -579,92 +550,59 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan // Add all transaction outputs to the transaction after performing // some validity checks. params := s.cfg.ChainParams - - // Ensure amount is in the valid range for monetary amounts. - // Decode the provided address. - // Ensure the address is one of the supported types and that - // the network encoded with the address matches the network the - // server is currently on. - // Create a new script which pays to the provided address. - // Convert the amount to satoshi. - handleAmountFn := func(amount float64, encodedAddr string) (*wire.TxOut, - error) { - - if amount <= 0 || - amount*btcutil.SatoshiPerBitcoin > btcutil.MaxSatoshi { + for encodedAddr, amount := range c.Amounts { + // Ensure amount is in the valid range for monetary amounts. + if amount <= 0 || amount*btcutil.SatoshiPerBitcoin > btcutil.MaxSatoshi { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCType, - Message: "invalid amount", + Message: "Invalid amount", } } + // Decode the provided address. addr, err := btcutil.DecodeAddress(encodedAddr, params) if err != nil { - return nil, rpcInvalidAddressOrKeyError(encodedAddr, - "invalid address or key") + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidAddressOrKey, + Message: "Invalid address or key: " + err.Error(), + } } + // Ensure the address is one of the supported types and that + // the network encoded with the address matches the network the + // server is currently on. switch addr.(type) { case *btcutil.AddressPubKeyHash: case *btcutil.AddressScriptHash: default: - return nil, rpcInvalidAddressOrKeyError(addr.String(), - "invalid address or key") + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidAddressOrKey, + Message: "Invalid address or key: " + addr.String(), + } } if !addr.IsForNet(params) { - return nil, rpcInvalidAddressOrKeyError(addr.String(), - "wrong network") + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidAddressOrKey, + Message: "Invalid address: " + encodedAddr + + " is for the wrong network", + } } + // Create a new script which pays to the provided address. pkScript, err := txscript.PayToAddrScript(addr) if err != nil { - context := "failed to generate pay-to-address script" + context := "Failed to generate pay-to-address script" return nil, internalRPCError(err.Error(), context) } + // Convert the amount to satoshi. satoshi, err := btcutil.NewAmount(amount) if err != nil { - context := "failed to convert amount" + context := "Failed to convert amount" return nil, internalRPCError(err.Error(), context) } - return wire.NewTxOut(int64(satoshi), pkScript), nil - } - - handleDataFn := func(key string, value string) (*wire.TxOut, error) { - if key != "data" { - context := "output key must be an address or \"data\"" - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidParameter, - Message: context, - } - } - var data []byte - data, err := hex.DecodeString(value) - if err != nil { - return nil, rpcDecodeHexError(value) - } - return wire.NewTxOut(0, data), nil - } - - for key, value := range c.Outputs { - var err error - var txOut *wire.TxOut - switch value := value.(type) { - case float64: - txOut, err = handleAmountFn(value, key) - case string: - txOut, err = handleDataFn(key, value) - default: - context := "output value must be a string or float" - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCType, - Message: context, - } - } - if err != nil { - return nil, err - } + txOut := wire.NewTxOut(int64(satoshi), pkScript) mtx.AddTxOut(txOut) } @@ -1255,7 +1193,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCBlockNotFound, - Message: "Block not found: " + err.Error(), + Message: "Block not found", } } // If verbosity is 0, return the serialized block as a hex encoded string. @@ -1272,23 +1210,31 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i return nil, internalRPCError(err.Error(), context) } - params := s.cfg.ChainParams - blockHeader := &blk.MsgBlock().Header - - // Get further details (height, confirmations, nexthash, mediantime, etc.) from chain. - attrs, best, err := s.cfg.Chain.BlockAttributesByHash(hash, &blockHeader.PrevBlock) + // Get the block height from chain. + blockHeight, err := s.cfg.Chain.BlockHeightByHash(hash) if err != nil { - context := "Failed to obtain block details" + context := "Failed to obtain block height" return nil, internalRPCError(err.Error(), context) } + blk.SetHeight(blockHeight) + best := s.cfg.Chain.BestSnapshot() - var prevHashString string - if attrs.PrevHash != nil { - prevHashString = attrs.PrevHash.String() - } + // Get next block hash unless there are none. var nextHashString string - if attrs.NextHash != nil { - nextHashString = attrs.NextHash.String() + if blockHeight < best.Height { + nextHash, err := s.cfg.Chain.BlockHashByHeight(blockHeight + 1) + if err != nil { + context := "No next block" + return nil, internalRPCError(err.Error(), context) + } + nextHashString = nextHash.String() + } + + params := s.cfg.ChainParams + blockHeader := &blk.MsgBlock().Header + var prevHashString string + if blockHeight > 0 { + prevHashString = blockHeader.PrevBlock.String() } base := btcjson.GetBlockVerboseResultBase{ @@ -1299,15 +1245,13 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i PreviousHash: prevHashString, Nonce: blockHeader.Nonce, Time: blockHeader.Timestamp.Unix(), - MedianTime: attrs.MedianTime.Unix(), - Confirmations: int64(attrs.Confirmations), - Height: int64(attrs.Height), + Confirmations: int64(1 + best.Height - blockHeight), + Height: int64(blockHeight), Size: int32(len(blkBytes)), StrippedSize: int32(blk.MsgBlock().SerializeSizeStripped()), Weight: int32(blockchain.GetBlockWeight(blk)), Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: getDifficultyRatio(blockHeader.Bits, params), - ChainWork: attrs.ChainWork.Text(16), NextHash: nextHashString, ClaimTrie: blockHeader.ClaimTrie.String(), } @@ -1332,7 +1276,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i for i, tx := range txns { rawTxn, err := createTxRawResult(params, tx.MsgTx(), tx.Hash().String(), blockHeader, hash.String(), - attrs.Height, best.Height) + blockHeight, best.Height) if err != nil { return nil, err } @@ -1580,405 +1524,6 @@ func handleGetChainTips(s *rpcServer, cmd interface{}, closeChan <-chan struct{} return results, nil } -// handleGetBlockStats implements the getblockstats command. -func handleGetBlockStats(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - c := cmd.(*btcjson.GetBlockStatsCmd) - - // Check whether a block height or hash was provided. - blockHeight, ok := c.HashOrHeight.Value.(int) - var hash *chainhash.Hash - var err error - if ok { - // Block height was provided. - hash, err = s.cfg.Chain.BlockHashByHeight(int32(blockHeight)) - if err != nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCOutOfRange, - Message: "Block number out of range", - } - } - } else { - // Block hash was provided. - hashString := c.HashOrHeight.Value.(string) - hash, err = chainhash.NewHashFromStr(hashString) - if err != nil { - return nil, rpcDecodeHexError(hashString) - } - - // Get the block height from chain. - blockHeightByHash, err := s.cfg.Chain.BlockHeightByHash(hash) - if err != nil { - context := "Failed to obtain block height" - return nil, internalRPCError(err.Error(), context) - } - blockHeight = int(blockHeightByHash) - } - - // Load block bytes from the database. - var blkBytes []byte - err = s.cfg.DB.View(func(dbTx database.Tx) error { - var err error - blkBytes, err = dbTx.FetchBlock(hash) - return err - }) - if err != nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCBlockNotFound, - Message: "Block not found", - } - } - - // Deserialize the block. - blk, err := btcutil.NewBlockFromBytes(blkBytes) - if err != nil { - context := "Failed to deserialize block" - return nil, internalRPCError(err.Error(), context) - } - - var selectedStats []string - if c.Stats != nil { - selectedStats = *c.Stats - } - - // Create a set of selected stats to facilitate queries. - statsSet := make(map[string]bool) - for _, value := range selectedStats { - statsSet[value] = true - } - - // Return all stats if an empty array was provided. - allStats := len(selectedStats) == 0 - calcFees := statsSet["avgfee"] || statsSet["avgfeerate"] || statsSet["maxfee"] || statsSet["maxfeerate"] || - statsSet["medianfee"] || statsSet["totalfee"] || statsSet["feerate_percentiles"] - - if calcFees && s.cfg.TxIndex == nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCNoTxInfo, - Message: "The transaction index must be " + - "enabled to obtain fee statistics " + - "(specify --txindex)", - } - } - - txs := blk.Transactions() - txCount := len(txs) - var inputCount, outputCount int - var totalOutputValue int64 - - // Create a map of transaction statistics. - txStats := make([]map[string]interface{}, txCount) - for i, tx := range txs { - size := tx.MsgTx().SerializeSize() - witnessSize := size - tx.MsgTx().SerializeSizeStripped() - weight := int64(tx.MsgTx().SerializeSizeStripped()*4 + witnessSize) - - var fee, feeRate int64 - if (calcFees || allStats) && s.cfg.TxIndex != nil && !blockchain.IsCoinBaseTx(tx.MsgTx()) { - fee, err = calculateFee(tx, s.cfg.TxIndex, s.cfg.DB) - if err != nil { - context := "Failed to calculate fees" - return nil, internalRPCError(err.Error(), context) - } - if weight != 0 { - feeRate = fee * 4 / weight - } - } - segwit := tx.HasWitness() - txStats[i] = map[string]interface{}{"tx": tx, "fee": fee, "size": int64(size), - "feeRate": feeRate, "weight": weight, "segwit": segwit} - inputCount += len(tx.MsgTx().TxIn) - outputCount += len(tx.MsgTx().TxOut) - - // Coinbase is excluded from the total output. - if !blockchain.IsCoinBase(tx) { - for _, txOut := range tx.MsgTx().TxOut { - totalOutputValue += txOut.Value - } - } - } - - var totalFees, minFee, maxFee, minFeeRate, maxFeeRate, segwitCount, - segwitWeight, totalWeight, totalSize, minSize, maxSize, segwitSize int64 - if txCount > 1 { - minFee = txStats[1]["fee"].(int64) - minFeeRate = txStats[1]["feeRate"].(int64) - } - for i := 0; i < len(txStats); i++ { - var fee, feeRate int64 - tx := txStats[i]["tx"].(*btcutil.Tx) - if !blockchain.IsCoinBaseTx(tx.MsgTx()) { - // Fee statistics. - fee = txStats[i]["fee"].(int64) - feeRate = txStats[i]["feeRate"].(int64) - if minFee > fee { - minFee = fee - } - if maxFee < fee { - maxFee = fee - } - if minFeeRate > feeRate { - minFeeRate = feeRate - } - if maxFeeRate < feeRate { - maxFeeRate = feeRate - } - totalFees += txStats[i]["fee"].(int64) - - // Segwit statistics. - if txStats[i]["segwit"].(bool) { - segwitCount++ - segwitSize += txStats[i]["size"].(int64) - segwitWeight += txStats[i]["weight"].(int64) - } - - // Size statistics. - size := txStats[i]["size"].(int64) - if minSize == 0 { - minSize = size - } - if maxSize < size { - maxSize = size - } else if minSize > size { - minSize = size - } - totalSize += txStats[i]["size"].(int64) - - totalWeight += txStats[i]["weight"].(int64) - } - } - - var avgFee, avgFeeRate, avgSize int64 - if txCount > 1 { - avgFee = totalFees / int64(txCount-1) - } - if totalWeight != 0 { - avgFeeRate = totalFees * 4 / totalWeight - } - if txCount > 1 { - avgSize = totalSize / int64(txCount-1) - } - - subsidy := blockchain.CalcBlockSubsidy(int32(blockHeight), s.cfg.ChainParams) - - medianStat := func(stat string) int64 { - size := len(txStats) - 1 - if size == 0 { - return 0 - } - statArray := make([]int64, size) - // Start with the second element to ignore entry associated with coinbase. - for i, stats := range txStats[1:] { - statArray[i] = stats[stat].(int64) - } - sort.Slice(statArray, func(i, j int) bool { - return statArray[i] < statArray[j] - }) - if size%2 == 0 { - return (statArray[size/2-1] + statArray[size/2]) / 2 - } - return statArray[size/2] - } - - var medianFee int64 - if totalFees > 0 { - medianFee = medianStat("fee") - } else { - medianFee = 0 - } - medianSize := medianStat("size") - - // Calculate feerate percentiles. - var feeratePercentiles []int64 - if allStats || calcFees { - - // Sort by feerate. - sort.Slice(txStats, func(i, j int) bool { - return txStats[i]["feeRate"].(int64) < txStats[j]["feeRate"].(int64) - }) - totalWeight := float64(totalWeight) - - // Find 10th, 25th, 50th, 75th and 90th percentile weight units. - weights := []float64{ - totalWeight / 10, totalWeight / 4, totalWeight / 2, - (totalWeight * 3) / 4, (totalWeight * 9) / 10} - var cumulativeWeight int64 - feeratePercentiles = make([]int64, len(weights)) - nextPercentileIndex := 0 - for i := 0; i < len(txStats); i++ { - cumulativeWeight += txStats[i]["weight"].(int64) - for nextPercentileIndex < len(weights) && float64(cumulativeWeight) >= weights[nextPercentileIndex] { - feeratePercentiles[nextPercentileIndex] = txStats[i]["feeRate"].(int64) - nextPercentileIndex++ - } - } - - // Fill any remaining percentiles with the last value. - for i := nextPercentileIndex; i < len(weights); i++ { - feeratePercentiles[i] = txStats[len(txStats)-1]["feeRate"].(int64) - } - } - - var blockHash string - if allStats || statsSet["blockhash"] { - blockHash = blk.Hash().String() - } - - medianTime, err := medianBlockTime(blk.Hash(), s.cfg.Chain) - if err != nil { - context := "Failed to obtain block median time" - return nil, internalRPCError(err.Error(), context) - } - - resultMap := map[string]int64{ - "avgfee": avgFee, - "avgfeerate": avgFeeRate, - "avgtxsize": avgSize, - "height": int64(blockHeight), - "ins": int64(inputCount - 1), // Coinbase input is not included. - "maxfee": maxFee, - "maxfeerate": maxFeeRate, - "maxtxsize": maxSize, - "medianfee": medianFee, - "mediantime": medianTime.Unix(), - "mediantxsize": medianSize, - "minfee": minFee, - "minfeerate": minFeeRate, - "mintxsize": minSize, - "outs": int64(outputCount), - "swtotal_size": segwitSize, - "swtotal_weight": segwitWeight, - "swtxs": segwitCount, - "subsidy": subsidy, - "time": blk.MsgBlock().Header.Timestamp.Unix(), - "total_out": totalOutputValue, - "total_size": totalSize, - "total_weight": totalWeight, - "totalfee": totalFees, - "txs": int64(len(txs)), - "utxo_increase": int64(outputCount - (inputCount - 1)), - } - - // This function determines whether a statistic goes into the - // final result, except for blockhash and feerate_percentiles - // which are handled separately. - resultFilter := func(stat string) *int64 { - if allStats && s.cfg.TxIndex == nil { - // There are no fee statistics to send. - excludedStats := []string{"avgfee", "avgfeerate", "maxfee", "maxfeerate", "medianfee", "minfee", "minfeerate"} - for _, excluded := range excludedStats { - if stat == excluded { - return nil - } - } - } - if allStats || statsSet[stat] { - if value, ok := resultMap[stat]; ok { - return &value - } - } - return nil - } - - result := &btcjson.GetBlockStatsResult{ - AverageFee: resultFilter("avgfee"), - AverageFeeRate: resultFilter("avgfeerate"), - AverageTxSize: resultFilter("avgtxsize"), - FeeratePercentiles: &feeratePercentiles, - Hash: &blockHash, - Height: resultFilter("height"), - Ins: resultFilter("ins"), - MaxFee: resultFilter("maxfee"), - MaxFeeRate: resultFilter("maxfeerate"), - MaxTxSize: resultFilter("maxtxsize"), - MedianFee: resultFilter("medianfee"), - MedianTime: resultFilter("mediantime"), - MedianTxSize: resultFilter("mediantxsize"), - MinFee: resultFilter("minfee"), - MinFeeRate: resultFilter("minfeerate"), - MinTxSize: resultFilter("mintxsize"), - Outs: resultFilter("outs"), - SegWitTotalSize: resultFilter("swtotal_size"), - SegWitTotalWeight: resultFilter("swtotal_weight"), - SegWitTxs: resultFilter("swtxs"), - Subsidy: resultFilter("subsidy"), - Time: resultFilter("time"), - TotalOut: resultFilter("total_out"), - TotalSize: resultFilter("total_size"), - TotalWeight: resultFilter("total_weight"), - TotalFee: resultFilter("totalfee"), - Txs: resultFilter("txs"), - UTXOIncrease: resultFilter("utxo_increase"), - UTXOSizeIncrease: resultFilter("utxo_size_inc"), - } - return result, nil -} - -// calculateFee returns the fee of a transaction. -func calculateFee(tx *btcutil.Tx, txIndex *indexers.TxIndex, db database.DB) (int64, error) { - var inValue, outValue int64 - for _, input := range tx.MsgTx().TxIn { - prevTxHash := input.PreviousOutPoint.Hash - // Look up the location of the previous transaction in the index. - blockRegion, err := txIndex.TxBlockRegion(&prevTxHash) - if err != nil { - context := "Failed to retrieve transaction location" - return 0, internalRPCError(err.Error(), context) - } - if blockRegion == nil { - return 0, rpcNoTxInfoError(&prevTxHash) - } - - // Load the raw transaction bytes from the database. - var txBytes []byte - err = db.View(func(dbTx database.Tx) error { - var err error - txBytes, err = dbTx.FetchBlockRegion(blockRegion) - return err - }) - if err != nil { - return 0, rpcNoTxInfoError(&prevTxHash) - } - - var msgTx wire.MsgTx - err = msgTx.Deserialize(bytes.NewReader(txBytes)) - if err != nil { - context := "Failed to deserialize transaction" - return 0, internalRPCError(err.Error(), context) - } - prevOutValue := msgTx.TxOut[input.PreviousOutPoint.Index].Value - inValue += prevOutValue - } - for _, output := range tx.MsgTx().TxOut { - outValue += output.Value - } - fee := inValue - outValue - return fee, nil -} - -// medianBlockTime returns the median time of a block and its 10 previous blocks -// as per BIP113. -func medianBlockTime(blockHash *chainhash.Hash, chain *blockchain.BlockChain) (*time.Time, error) { - blockTimes := make([]time.Time, 0) - currentHash := blockHash - for i := 0; i < 11; i++ { - header, err := chain.HeaderByHash(currentHash) - if err != nil { - return nil, err - } - blockTimes = append(blockTimes, header.Timestamp) - genesisPrevBlock, _ := chainhash.NewHashFromStr("0000000000000000000000000000000000000000000000000000000000000000") - if header.PrevBlock.IsEqual(genesisPrevBlock) { - // This is the genesis block so there's no need to iterate further. - break - } - currentHash = &header.PrevBlock - } - sort.Slice(blockTimes, func(i, j int) bool { - return blockTimes[i].Before(blockTimes[j]) - }) - return &blockTimes[len(blockTimes)/2], nil -} - // encodeTemplateID encodes the passed details into an ID that can be used to // uniquely identify a block template. func encodeTemplateID(prevHash *chainhash.Hash, lastGenerated time.Time) string { @@ -2362,12 +1907,11 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld if template.WitnessCommitment != nil { reply.DefaultWitnessCommitment = hex.EncodeToString(template.WitnessCommitment) reply.Rules = append(reply.Rules, "!segwit") - } else { - reply.Rules = append(reply.Rules, "segwit") } if useCoinbaseValue { reply.CoinbaseAux = gbtCoinbaseAux + reply.CoinbaseValue = &msgBlock.Transactions[0].TxOut[0].Value } else { // Ensure the template has a valid payment address associated // with it when a full coinbase is requested. @@ -2400,9 +1944,6 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld reply.CoinbaseTxn = &resultTx } - // Return coinbasevalue anyway as lbrycrd and bitcoind do. - reply.CoinbaseValue = &msgBlock.Transactions[0].TxOut[0].Value - return &reply, nil } @@ -2910,7 +2451,7 @@ func handleGetHeaders(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) func handleGetInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { best := s.cfg.Chain.BestSnapshot() ret := &btcjson.InfoChainResult{ - Version: version.Numeric(), + Version: int32(1000000*appMajor + 10000*appMinor + 100*appPatch), ProtocolVersion: int32(maxProtocolVersion), Blocks: best.Height, TimeOffset: int64(s.cfg.TimeSource.Offset().Seconds()), @@ -2926,7 +2467,19 @@ func handleGetInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in // handleGetMempoolInfo implements the getmempoolinfo command. func handleGetMempoolInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - return s.cfg.TxMemPool.MempoolInfo(), nil + mempoolTxns := s.cfg.TxMemPool.TxDescs() + + var numBytes int64 + for _, txD := range mempoolTxns { + numBytes += int64(txD.Tx.MsgTx().SerializeSize()) + } + + ret := &btcjson.GetMempoolInfoResult{ + Size: int64(len(mempoolTxns)), + Bytes: numBytes, + } + + return ret, nil } // handleGetMempoolEntry implements the getmempoolentry command. @@ -3197,7 +2750,7 @@ func handleGetNetworkInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct reply := &btcjson.GetNetworkInfoResult{ ProtocolVersion: int32(wire.ProtocolVersion), - Version: version.Numeric(), + Version: versionNumeric(), Connections: s.cfg.ConnMgr.ConnectedCount(), IncrementalFee: cfg.MinRelayTxFee, LocalAddresses: localAddrs, @@ -3610,24 +3163,6 @@ func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter return help, nil } -// handleListBanned handles the listbanned command. -func handleListBanned(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - banned := s.cfg.ConnMgr.BannedPeers() - reply := make([]*btcjson.ListBannedResult, 0, len(banned)) - for address, period := range banned { - since, until := period.since, period.until - r := btcjson.ListBannedResult{ - Address: address, - BanCreated: since.Unix(), - BannedUntil: until.Unix(), - BanDuration: int64(until.Sub(since).Seconds()), - TimeRemaining: int64(time.Until(until).Seconds()), - } - reply = append(reply, &r) - } - return reply, nil -} - // handlePing implements the ping command. func handlePing(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { // Ask server to ping \o_ @@ -4224,66 +3759,12 @@ func handleSendRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan st // Keep track of all the sendrawtransaction request txns so that they // can be rebroadcast if they don't make their way into a block. txD := acceptedTxs[0] - s.cfg.TxMemPool.AddUnbroadcastTx(txD.Tx.Hash()) iv := wire.NewInvVect(wire.InvTypeTx, txD.Tx.Hash()) s.cfg.ConnMgr.AddRebroadcastInventory(iv, txD) return tx.Hash().String(), nil } -// handleSetBan handles the setban command. -func handleSetBan(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - c := cmd.(*btcjson.SetBanCmd) - - addr := net.ParseIP(c.Addr) - if addr == nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidParameter, - Message: "invalid addr for setban", - } - } - - since := time.Now() - until := since.Add(time.Second * time.Duration(*c.BanTime)) - if *c.BanTime == 0 { - until = since.Add(defaultBanDuration) - } - if *c.Absolute { - until = time.Unix(int64(*c.BanTime), 0) - } - - var err error - switch c.SubCmd { - case "add": - err = s.cfg.ConnMgr.SetBan(addr.String(), since, until) - addr := addr.String() - peers := s.cfg.ConnMgr.ConnectedPeers() - for _, peer := range peers { - p := peer.ToPeer() - if p.NA().IP.String() == addr { - p.Disconnect() - } - } - case "remove": - err = s.cfg.ConnMgr.RemoveBan(addr.String()) - default: - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidParameter, - Message: "invalid subcommand for setban", - } - } - - if err != nil { - return nil, &btcjson.RPCError{ - Code: btcjson.ErrRPCInvalidParameter, - Message: err.Error(), - } - } - - // no data returned unless an error. - return nil, nil -} - // handleSetGenerate implements the setgenerate command. func handleSetGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.SetGenerateCmd) @@ -5341,18 +4822,6 @@ type rpcserverConnManager interface { // ConnectedPeers returns an array consisting of all connected peers. ConnectedPeers() []rpcserverPeer - // BannedPeers returns an array consisting of all Banned peers. - BannedPeers() map[string]bannedPeriod - - // SetBan add the addr to the ban list. - SetBan(addr string, since time.Time, until time.Time) error - - // RemoveBan remove the subnet from the ban list. - RemoveBan(subnet string) error - - // ClearBanned removes all banned IPs. - ClearBanned() error - // PersistentPeers returns an array consisting of all the persistent // peers. PersistentPeers() []rpcserverPeer diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 06dbba53..4cfde4d3 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -49,16 +49,13 @@ var helpDescsEnUS = map[string]string{ "The transaction inputs are not signed in the created transaction.\n" + "The signrawtransaction RPC command provided by wallet must be used to sign the resulting transaction.", "createrawtransaction-inputs": "The inputs to the transaction", - "createrawtransaction-outputs": "JSON object with the destination addresses as keys and amounts as values", - "createrawtransaction-outputs--key": "address or \"data\"", - "createrawtransaction-outputs--value": "value in BTC as floating point number or hex-encoded data for \"data\"", - "createrawtransaction-outputs--desc": "The destination address as the key and the amount in LBC as the value", + "createrawtransaction-amounts": "JSON object with the destination addresses as keys and amounts as values", + "createrawtransaction-amounts--key": "address", + "createrawtransaction-amounts--value": "n.nnn", + "createrawtransaction-amounts--desc": "The destination address as the key and the amount in LBC as the value", "createrawtransaction-locktime": "Locktime value; a non-zero value will also locktime-activate the inputs", "createrawtransaction--result0": "Hex-encoded bytes of the serialized transaction", - // ClearBannedCmd help. - "clearbanned--synopsis": "Clear all banned IPs.", - // ScriptSig help. "scriptsig-asm": "Disassembly of the script", "scriptsig-hex": "Hex-encoded bytes of the script", @@ -200,43 +197,6 @@ var helpDescsEnUS = map[string]string{ "getblockchaininforesult-softforks": "The status of the super-majority soft-forks", "getblockchaininforesult-unifiedsoftforks": "The status of the super-majority soft-forks used by bitcoind on or after v0.19.0", - // GetBlockStatsCmd help. - "getblockstats--synopsis": "Returns statistics about a block given its hash or height. --txindex must be enabled for fee and feerate statistics.", - "getblockstats-hashorheight": "The hash or height of the block", - "hashorheight-value": "The hash or height of the block", - "getblockstats-stats": "Selected statistics", - - // GetBlockStatsResult help. - "getblockstatsresult-avgfee": "The average fee in the block", - "getblockstatsresult-avgfeerate": "The average feerate in the block (in satoshis per virtual byte)", - "getblockstatsresult-avgtxsize": "The average transaction size in the block", - "getblockstatsresult-blockhash": "The block hash", - "getblockstatsresult-feerate_percentiles": "Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)", - "getblockstatsresult-height": "The block height", - "getblockstatsresult-ins": "The number of inputs (excluding coinbase)", - "getblockstatsresult-maxfee": "Maxium fee in the block", - "getblockstatsresult-maxfeerate": "Maximum feerate in the block (in satoshis per virtual byte)", - "getblockstatsresult-maxtxsize": "Maximum transaction size", - "getblockstatsresult-medianfee": "Truncated median fee", - "getblockstatsresult-mediantime": "The median time from the block and its previous 10 blocks (BIP113)", - "getblockstatsresult-mediantxsize": "Truncated median transaction size", - "getblockstatsresult-minfee": "Minimum fee in the block", - "getblockstatsresult-minfeerate": "Minimum feerate in the block (in satoshis per virtual byte)", - "getblockstatsresult-mintxsize": "Minimum transaction size", - "getblockstatsresult-outs": "The number of outputs", - "getblockstatsresult-subsidy": "The block subsidy", - "getblockstatsresult-swtotal_size": "Total size of all segwit transactions in the block (excluding coinbase)", - "getblockstatsresult-swtotal_weight": "Total weight of all segwit transactions in the block (excluding coinbase)", - "getblockstatsresult-swtxs": "The number of segwit transactions in the block (excluding coinbase)", - "getblockstatsresult-time": "The block time", - "getblockstatsresult-total_out": "Total amount in all outputs (excluding coinbase)", - "getblockstatsresult-total_size": "Total size of all transactions (excluding coinbase)", - "getblockstatsresult-total_weight": "Total weight of all transactions (excluding coinbase)", - "getblockstatsresult-totalfee": "The total of fees", - "getblockstatsresult-txs": "The number of transactions (excluding coinbase)", - "getblockstatsresult-utxo_increase": "The increase/decrease in the number of unspent outputs", - "getblockstatsresult-utxo_size_inc": "The increase/decrease in size for the utxo index", - // SoftForkDescription help. "softforkdescription-reject": "The current activation status of the softfork", "softforkdescription-version": "The block version that signals enforcement of this softfork", @@ -300,11 +260,9 @@ var helpDescsEnUS = map[string]string{ "getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)", "getblockverboseresult-nTx": "The number of transactions (aka, count of TX)", "getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", - "getblockverboseresult-mediantime": "The median block time in seconds since 1 Jan 1970 GMT", "getblockverboseresult-nonce": "The block nonce", "getblockverboseresult-bits": "The bits which represent the block difficulty", "getblockverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", - "getblockverboseresult-chainwork": "Expected number of hashes required to produce the chain up to this block (in hex)", "getblockverboseresult-previousblockhash": "The hash of the previous block", "getblockverboseresult-nextblockhash": "The hash of the next block (only if there is one)", "getblockverboseresult-strippedsize": "The size of the block without witness data", @@ -495,13 +453,8 @@ var helpDescsEnUS = map[string]string{ "getmempoolinfo--synopsis": "Returns memory pool information", // GetMempoolInfoResult help. - "getmempoolinforesult-bytes": "Size in bytes of the mempool", - "getmempoolinforesult-size": "Number of transactions in the mempool", - "getmempoolinforesult-usage": "Total memory usage for the mempool", - "getmempoolinforesult-total_fee": "Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction", - "getmempoolinforesult-mempoolminfee": "Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee", - "getmempoolinforesult-minrelaytxfee": "Current minimum relay fee for transactions", - "getmempoolinforesult-unbroadcastcount": "Current number of transactions that haven't passed initial broadcast yet", + "getmempoolinforesult-bytes": "Size in bytes of the mempool", + "getmempoolinforesult-size": "Number of transactions in the mempool", // GetMiningInfoResult help. "getmininginforesult-blocks": "Height of the latest best block", @@ -676,16 +629,6 @@ var helpDescsEnUS = map[string]string{ "ping--synopsis": "Queues a ping to be sent to each connected peer.\n" + "Ping times are provided by getpeerinfo via the pingtime and pingwait fields.", - // ListBannedCmd help. - "listbanned--synopsis": "List all banned IPs.", - - // ListBannedResult help. - "listbannedresult-address": "The IP of the banned node.", - "listbannedresult-ban_created": "The UNIX epoch time the ban was created.", - "listbannedresult-banned_until": "The UNIX epoch time the ban expires.", - "listbannedresult-ban_duration": "The duration of the ban, in seconds.", - "listbannedresult-time_remaining": "The time remaining on the ban, in seconds", - // ReconsiderBlockCmd "reconsiderblock--synopsis": "Reconsider a block for validation.", "reconsiderblock-blockhash": "Hash of the block you want to reconsider", @@ -714,13 +657,6 @@ var helpDescsEnUS = map[string]string{ "sendrawtransaction--result0": "The hash of the transaction", "allowhighfeesormaxfeerate-value": "Either the boolean value for the allowhighfees parameter in bitcoind < v0.19.0 or the numerical value for the maxfeerate field in bitcoind v0.19.0 and later", - // SetBanCmd help. - "setban--synopsis": "Add or remove an IP from the banned list. (Currently, subnet is not supported.)", - "setban-addr": "The IP to ban. (Currently, subnet is not supported.)", - "setban-subcmd": "'add' to add an IP to the list, 'remove' to remove an IP from the list", - "setban-bantime": "Time in seconds the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)", - "setban-absolute": "If set, the bantime must be an absolute timestamp expressed in UNIX epoch time; default to false.", - // SetGenerateCmd help. "setgenerate--synopsis": "Set the server to generate coins (mine) or not.", "setgenerate-generate": "Use true to enable generation, false to disable it", @@ -937,7 +873,6 @@ var helpDescsEnUS = map[string]string{ // pointer to the type (or nil to indicate no return value). var rpcResultTypes = map[string][]interface{}{ "addnode": nil, - "clearbanned": nil, "createrawtransaction": {(*string)(nil)}, "debuglevel": {(*string)(nil), (*string)(nil)}, "decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)}, @@ -950,12 +885,11 @@ var rpcResultTypes = map[string][]interface{}{ "getbestblock": {(*btcjson.GetBestBlockResult)(nil)}, "getbestblockhash": {(*string)(nil)}, "getblock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)}, - "getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)}, "getblockcount": {(*int64)(nil)}, "getblockhash": {(*string)(nil)}, "getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)}, - "getblockstats": {(*btcjson.GetBlockStatsResult)(nil)}, "getblocktemplate": {(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil}, + "getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)}, "getcfilter": {(*string)(nil)}, "getcfilterheader": {(*string)(nil)}, "getchaintips": {(*[]btcjson.GetChainTipsResult)(nil)}, @@ -977,15 +911,13 @@ var rpcResultTypes = map[string][]interface{}{ "getrawmempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)}, "getrawtransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)}, "gettxout": {(*btcjson.GetTxOutResult)(nil)}, + "node": nil, "help": {(*string)(nil), (*string)(nil)}, "invalidateblock": nil, - "listbanned": {(*[]btcjson.ListBannedResult)(nil)}, - "node": nil, "ping": nil, "reconsiderblock": nil, "searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)}, "sendrawtransaction": {(*string)(nil)}, - "setban": nil, "setgenerate": nil, "signmessagewithprivkey": {(*string)(nil)}, "stop": {(*string)(nil)}, diff --git a/sample-lbcd.conf b/sample-lbcd.conf index f2c0b8c7..57da5b87 100644 --- a/sample-lbcd.conf +++ b/sample-lbcd.conf @@ -49,7 +49,7 @@ ; Do NOT use Universal Plug and Play (UPnP) to automatically open the listen port ; and obtain the external IP address from supported devices. NOTE: This option ; will have no effect if exernal IP addresses are specified. -; upnp=1 +; noupnp=0 ; Specify the external IP addresses your node is listening on. One address per ; line. lbcd will not contact 3rd-party sites to obtain external ip addresses. @@ -297,7 +297,7 @@ ; Build and maintain a full hash-based transaction index which makes all ; transactions available via the getrawtransaction RPC. -; txindex=1 + txindex=1 ; Build and maintain a full address-based transaction index which makes the ; searchrawtransactions RPC available. @@ -376,9 +376,6 @@ ; Write CPU profile to the specified file. ; cpuprofile= -; Write memory profile to the specified file. -; memprofile= - ; The port used to listen for HTTP profile requests. The profile server will ; be disabled if this option is not specified. The profile information can be ; accessed at http://localhost:/debug/pprof once running. diff --git a/server.go b/server.go index e7ccb3f1..a9a9193a 100644 --- a/server.go +++ b/server.go @@ -39,7 +39,6 @@ import ( "github.com/lbryio/lbcd/netsync" "github.com/lbryio/lbcd/peer" "github.com/lbryio/lbcd/txscript" - "github.com/lbryio/lbcd/version" "github.com/lbryio/lbcd/wire" "github.com/lbryio/lbcutil" btcutil "github.com/lbryio/lbcutil" @@ -72,7 +71,7 @@ var ( // userAgentVersion is the user agent version and is used to help // identify ourselves to other bitcoin peers. - userAgentVersion = version.Full() + userAgentVersion = fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch) ) // zeroHash is the zero value hash (all zeros). It is defined as a convenience. @@ -156,18 +155,13 @@ type updatePeerHeightsMsg struct { originPeer *peer.Peer } -type bannedPeriod struct { - since time.Time - until time.Time -} - // peerState maintains state of inbound, persistent, outbound peers as well // as banned peers and outbound groups. type peerState struct { inboundPeers map[int32]*serverPeer outboundPeers map[int32]*serverPeer persistentPeers map[int32]*serverPeer - banned map[string]bannedPeriod + banned map[string]time.Time outboundGroups map[string]int } @@ -704,11 +698,6 @@ func (sp *serverPeer) OnGetData(_ *peer.Peer, msg *wire.MsgGetData) { if i == len(msg.InvList)-1 && c != nil { <-c } - } else if iv.Type == wire.InvTypeWitnessTx || iv.Type == wire.InvTypeTx { - // We interpret fulfilling a GETDATA for a transaction as a - // successful initial broadcast and remove it from our - // unbroadcast set. - sp.server.txMemPool.RemoveUnbroadcastTx(&iv.Hash) } numAdded++ waitChan = c @@ -1661,10 +1650,10 @@ func (s *server) handleAddPeerMsg(state *peerState, sp *serverPeer) bool { sp.Disconnect() return false } - if ban, ok := state.banned[host]; ok { - if time.Now().Before(ban.until) { - srvrLog.Infof("Peer %s is banned for another %v - disconnecting", - host, time.Until(ban.until)) + if banEnd, ok := state.banned[host]; ok { + if time.Now().Before(banEnd) { + srvrLog.Debugf("Peer %s is banned for another %v - disconnecting", + host, time.Until(banEnd)) sp.Disconnect() return false } @@ -1786,12 +1775,7 @@ func (s *server) handleBanPeerMsg(state *peerState, sp *serverPeer) { direction := directionString(sp.Inbound()) srvrLog.Infof("Banned peer %s (%s) for %v", host, direction, cfg.BanDuration) - - since := time.Now() - state.banned[host] = bannedPeriod{ - since: since, - until: since.Add(cfg.BanDuration), - } + state.banned[host] = time.Now().Add(cfg.BanDuration) } // handleRelayInvMsg deals with relaying inventory to peers that are not already @@ -1886,25 +1870,6 @@ type getPeersMsg struct { reply chan []*serverPeer } -type listBannedPeersMsg struct { - reply chan map[string]bannedPeriod -} - -type setBanMsg struct { - addr string - since time.Time - until time.Time - reply chan error -} - -type removeBanMsg struct { - addr string - reply chan error -} - -type clearBannedMsg struct { - reply chan error -} type getOutboundGroup struct { key string reply chan int @@ -1953,29 +1918,6 @@ func (s *server) handleQuery(state *peerState, querymsg interface{}) { }) msg.reply <- peers - case listBannedPeersMsg: - banned := map[string]bannedPeriod{} - for host, ban := range state.banned { - banned[host] = ban - } - msg.reply <- banned - - case setBanMsg: - ban := bannedPeriod{ - since: msg.since, - until: msg.until, - } - state.banned[msg.addr] = ban - msg.reply <- nil - - case removeBanMsg: - delete(state.banned, msg.addr) - msg.reply <- nil - - case clearBannedMsg: - state.banned = map[string]bannedPeriod{} - msg.reply <- nil - case connectNodeMsg: // TODO: duplicate oneshots? // Limit max number of total peers. @@ -2213,7 +2155,7 @@ func (s *server) peerHandler() { inboundPeers: make(map[int32]*serverPeer), persistentPeers: make(map[int32]*serverPeer), outboundPeers: make(map[int32]*serverPeer), - banned: make(map[string]bannedPeriod), + banned: make(map[string]time.Time), outboundGroups: make(map[string]int), } @@ -3081,7 +3023,7 @@ func initListeners(amgr *addrmgr.AddrManager, listenAddrs []string, services wir } } } else { - if cfg.Upnp && !cfg.RegressionTest && !cfg.SimNet { + if !cfg.NoUpnp && !cfg.RegressionTest && !cfg.SimNet { var err error nat, err = Discover() if err != nil { diff --git a/service_windows.go b/service_windows.go index 448720b7..378c9204 100644 --- a/service_windows.go +++ b/service_windows.go @@ -10,8 +10,6 @@ import ( "path/filepath" "time" - "github.com/lbryio/lbcd/version" - "github.com/btcsuite/winsvc/eventlog" "github.com/btcsuite/winsvc/mgr" "github.com/btcsuite/winsvc/svc" @@ -38,7 +36,7 @@ var elog *eventlog.Log // been started to the Windows event log. func logServiceStartOfDay(srvr *server) { var message string - message += fmt.Sprintf("Version %s\n", version.Full()) + message += fmt.Sprintf("Version %s\n", version()) message += fmt.Sprintf("Configuration directory: %s\n", defaultHomeDir) message += fmt.Sprintf("Configuration file: %s\n", cfg.ConfigFile) message += fmt.Sprintf("Data directory: %s\n", cfg.DataDir) diff --git a/txscript/claimscript.go b/txscript/claimscript.go index 694cc970..1737ff60 100644 --- a/txscript/claimscript.go +++ b/txscript/claimscript.go @@ -33,9 +33,6 @@ const ( // ErrInvalidClaimUpdateScript is returned a claim update script does not conform to the format. ErrInvalidClaimUpdateScript - - // ErrInvalidClaimName is returned when the claim name is invalid. - ErrInvalidClaimName ) func claimScriptError(c ErrorCode, desc string) Error { @@ -101,15 +98,11 @@ func ExtractClaimScript(script []byte) (*ClaimScript, error) { if !tokenizer.Next() || tokenizer.Opcode() != OP_2DROP || !tokenizer.Next() || tokenizer.Opcode() != OP_DROP { - return nil, claimScriptError(ErrInvalidClaimNameScript, "expect OP_2DROP OP_DROP") - } - - cs.Size = int(tokenizer.ByteIndex()) - if cs.Size > MaxClaimScriptSize { - str := fmt.Sprintf("script size %d exceeds limit %d", cs.Size, MaxClaimScriptSize) + str := fmt.Sprintf("expect OP_2DROP OP_DROP") return nil, claimScriptError(ErrInvalidClaimNameScript, str) } + cs.Size = int(tokenizer.ByteIndex()) return &cs, nil case OP_SUPPORTCLAIM: @@ -135,7 +128,8 @@ func ExtractClaimScript(script []byte) (*ClaimScript, error) { case tokenizer.Opcode() == OP_2DROP: // Case 1: OP_SUPPORTCLAIM OP_2DROP OP_DROP if !tokenizer.Next() || tokenizer.Opcode() != OP_DROP { - return nil, claimScriptError(ErrInvalidClaimSupportScript, "expect OP_2DROP OP_DROP") + str := fmt.Sprintf("expect OP_2DROP OP_DROP") + return nil, claimScriptError(ErrInvalidClaimSupportScript, str) } case len(tokenizer.Data()) != 0: @@ -144,21 +138,19 @@ func ExtractClaimScript(script []byte) (*ClaimScript, error) { cs.Value = tokenizer.Data() if !tokenizer.Next() || tokenizer.Opcode() != OP_2DROP || !tokenizer.Next() || tokenizer.Opcode() != OP_2DROP { - return nil, claimScriptError(ErrInvalidClaimSupportScript, "expect OP_2DROP OP_2DROP") + str := fmt.Sprintf("expect OP_2DROP OP_2DROP") + return nil, claimScriptError(ErrInvalidClaimSupportScript, str) } default: - return nil, claimScriptError(ErrInvalidClaimSupportScript, "expect OP_2DROP OP_DROP") - } - - cs.Size = int(tokenizer.ByteIndex()) - if cs.Size > MaxClaimScriptSize { - str := fmt.Sprintf("script size %d exceeds limit %d", cs.Size, MaxClaimScriptSize) + str := fmt.Sprintf("expect OP_2DROP OP_DROP") return nil, claimScriptError(ErrInvalidClaimSupportScript, str) } + cs.Size = int(tokenizer.ByteIndex()) return &cs, nil case OP_UPDATECLAIM: + // OP_UPDATECLAIM OP_2DROP OP_2DROP if !tokenizer.Next() || len(tokenizer.Data()) > MaxClaimNameSize { str := fmt.Sprintf("name size %d exceeds limit %d", len(tokenizer.data), MaxClaimNameSize) @@ -185,11 +177,6 @@ func ExtractClaimScript(script []byte) (*ClaimScript, error) { } cs.Size = int(tokenizer.ByteIndex()) - if cs.Size > MaxClaimScriptSize { - str := fmt.Sprintf("script size %d exceeds limit %d", cs.Size, MaxClaimScriptSize) - return nil, claimScriptError(ErrInvalidClaimUpdateScript, str) - } - return &cs, nil default: @@ -206,7 +193,7 @@ func StripClaimScriptPrefix(script []byte) []byte { return script[cs.Size:] } -const illegalChars = "=&#:$%?/;\\\b\n\t\r\x00" +const illegalChars = "=&#:*$%?/;\\\b\n\t\r\x00" func AllClaimsAreSane(script []byte, enforceSoftFork bool) error { cs, err := ExtractClaimScript(script) @@ -218,11 +205,10 @@ func AllClaimsAreSane(script []byte, enforceSoftFork bool) error { } if enforceSoftFork { if !utf8.Valid(cs.Name) { - return claimScriptError(ErrInvalidClaimName, "claim name is not valid UTF-8") + return fmt.Errorf("claim name is not valid UTF-8") } if bytes.ContainsAny(cs.Name, illegalChars) { - str := fmt.Sprintf("claim name has illegal chars; it should not contain any of these: %s", illegalChars) - return claimScriptError(ErrInvalidClaimName, str) + return fmt.Errorf("claim name has illegal chars; it should not contain any of these: %s", illegalChars) } } diff --git a/txscript/doc.go b/txscript/doc.go index 179cb227..7da52161 100644 --- a/txscript/doc.go +++ b/txscript/doc.go @@ -12,7 +12,7 @@ overview to provide information on how to use the package. This package provides data structures and functions to parse and execute bitcoin transaction scripts. -# Script Overview +Script Overview Bitcoin transaction scripts are written in a stack-base, FORTH-like language. @@ -30,7 +30,7 @@ is used to prove the the spender is authorized to perform the transaction. One benefit of using a scripting language is added flexibility in specifying what conditions must be met in order to spend bitcoins. -# Errors +Errors Errors returned by this package are of type txscript.Error. This allows the caller to programmatically determine the specific error by examining the diff --git a/txscript/error.go b/txscript/error.go index e0a1fc2e..f42b893e 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -427,10 +427,10 @@ func (e ErrorCode) String() string { // Error identifies a script-related error. It is used to indicate three // classes of errors: -// 1. Script execution failures due to violating one of the many requirements -// imposed by the script engine or evaluating to false -// 2. Improper API usage by callers -// 3. Internal consistency check failures +// 1) Script execution failures due to violating one of the many requirements +// imposed by the script engine or evaluating to false +// 2) Improper API usage by callers +// 3) Internal consistency check failures // // The caller can use type assertions on the returned errors to access the // ErrorCode field to ascertain the specific reason for the error. As an diff --git a/txscript/scriptbuilder.go b/txscript/scriptbuilder.go index 49dff6b4..7984dd96 100644 --- a/txscript/scriptbuilder.go +++ b/txscript/scriptbuilder.go @@ -37,17 +37,16 @@ func (e ErrScriptNotCanonical) Error() string { // For example, the following would build a 2-of-3 multisig script for usage in // a pay-to-script-hash (although in this situation MultiSigScript() would be a // better choice to generate the script): -// -// builder := txscript.NewScriptBuilder() -// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2) -// builder.AddData(pubKey3).AddOp(txscript.OP_3) -// builder.AddOp(txscript.OP_CHECKMULTISIG) -// script, err := builder.Script() -// if err != nil { -// // Handle the error. -// return -// } -// fmt.Printf("Final multi-sig script: %x\n", script) +// builder := txscript.NewScriptBuilder() +// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2) +// builder.AddData(pubKey3).AddOp(txscript.OP_3) +// builder.AddOp(txscript.OP_CHECKMULTISIG) +// script, err := builder.Script() +// if err != nil { +// // Handle the error. +// return +// } +// fmt.Printf("Final multi-sig script: %x\n", script) type ScriptBuilder struct { script []byte err error diff --git a/txscript/scriptnum.go b/txscript/scriptnum.go index e75bdeaa..81f26361 100644 --- a/txscript/scriptnum.go +++ b/txscript/scriptnum.go @@ -89,19 +89,18 @@ func checkMinimalDataEncoding(v []byte) error { // Bytes returns the number serialized as a little endian with a sign bit. // // Example encodings: -// -// 127 -> [0x7f] -// -127 -> [0xff] -// 128 -> [0x80 0x00] -// -128 -> [0x80 0x80] -// 129 -> [0x81 0x00] -// -129 -> [0x81 0x80] -// 256 -> [0x00 0x01] -// -256 -> [0x00 0x81] -// 32767 -> [0xff 0x7f] -// -32767 -> [0xff 0xff] -// 32768 -> [0x00 0x80 0x00] -// -32768 -> [0x00 0x80 0x80] +// 127 -> [0x7f] +// -127 -> [0xff] +// 128 -> [0x80 0x00] +// -128 -> [0x80 0x80] +// 129 -> [0x81 0x00] +// -129 -> [0x81 0x80] +// 256 -> [0x00 0x01] +// -256 -> [0x00 0x81] +// 32767 -> [0xff 0x7f] +// -32767 -> [0xff 0xff] +// 32768 -> [0x00 0x80 0x00] +// -32768 -> [0x00 0x80 0x80] func (n scriptNum) Bytes() []byte { // Zero encodes as an empty byte slice. if n == 0 { diff --git a/version.go b/version.go new file mode 100644 index 00000000..852e3ae8 --- /dev/null +++ b/version.go @@ -0,0 +1,77 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "strings" +) + +// semanticAlphabet +const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + +// These constants define the application version and follow the semantic +// versioning 2.0.0 spec (http://semver.org/). +const ( + appMajor uint = 0 + appMinor uint = 22 + appPatch uint = 200 + + // appPreRelease MUST only contain characters from semanticAlphabet + // per the semantic versioning spec. + appPreRelease = "beta" +) + +// appBuild is defined as a variable so it can be overridden during the build +// process with '-ldflags "-X main.appBuild foo' if needed. It MUST only +// contain characters from semanticAlphabet per the semantic versioning spec. +var appBuild string + +// version returns the application version as a properly formed string per the +// semantic versioning 2.0.0 spec (http://semver.org/). +func version() string { + // Start with the major, minor, and patch versions. + version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch) + + // Append pre-release version if there is one. The hyphen called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the pre-release string. The pre-release version + // is not appended if it contains invalid characters. + preRelease := normalizeVerString(appPreRelease) + if preRelease != "" { + version = fmt.Sprintf("%s-%s", version, preRelease) + } + + // Append build metadata if there is any. The plus called for + // by the semantic versioning spec is automatically appended and should + // not be contained in the build metadata string. The build metadata + // string is not appended if it contains invalid characters. + build := normalizeVerString(appBuild) + if build != "" { + version = fmt.Sprintf("%s+%s", version, build) + } + + return version +} + +// Numeric returns the application version as an integer. +func versionNumeric() int32 { + return int32(2 ^ appMajor*3 ^ appMinor*5 ^ appPatch) +} + +// normalizeVerString returns the passed string stripped of all characters which +// are not valid according to the semantic versioning guidelines for pre-release +// version and build metadata strings. In particular they MUST only contain +// characters in semanticAlphabet. +func normalizeVerString(str string) string { + var result bytes.Buffer + for _, r := range str { + if strings.ContainsRune(semanticAlphabet, r) { + result.WriteRune(r) + } + } + return result.String() +} diff --git a/version/version.go b/version/version.go deleted file mode 100644 index af3965ea..00000000 --- a/version/version.go +++ /dev/null @@ -1,267 +0,0 @@ -package version - -import ( - "fmt" - "runtime/debug" - "strconv" - "strings" -) - -var appTag = "v0.0.0-local.0" - -// Full returns full version string conforming to semantic versioning 2.0.0 -// spec (http://semver.org/). -// -// Major.Minor.Patch-Prerelease+Buildmeta -// -// Prerelease must be either empty or in the form of Phase.Revision. The Phase -// must be local, dev, alpha, beta, or rc. -// Buildmeta is full length of 40-digit git commit ID with "-dirty" appended -// refelecting uncommited chanegs. -// -// This function relies injected git version tag in the form of: -// -// vMajor.Minor.Patch-Prerelease -// -// The injection can be done with go build flags for example: -// -// go build -ldflags "-X github.com/lbryio/lbcd/version.appTag=v1.2.3-beta.45" -// -// Without explicitly injected tag, a default one - "v0.0.0-local.0" is used -// indicating a local development build. - -// The version is encoded into a int32 numeric form, which imposes valid ranges -// on each component: -// -// Major: 0 - 41 -// Minor: 0 - 99 -// Patch: 0 - 999 -// -// Prerelease: Phase.Revision -// Phase: [ local | dev | alpha | beta | rc | ] -// Revision: 0 - 99 -// -// Buildmeta: CommitID or CommitID-dirty -// -// Examples: -// -// 1.2.3-beta.45+950b68348261e0b4ff288d216269b8ad2a384411 -// 2.6.4-alpha.3+92d00aaee19d1709ae64b36682ae9897ef91a2ca-dirty - -func Full() string { - return parsed.full() -} - -// Numeric returns numeric form of full version (excluding meta) in a 32-bit decimal number. -// See Full() for more details. -func Numeric() int32 { - numeric := parsed.major*100000000 + - parsed.minor*1000000 + - parsed.patch*1000 + - parsed.phase.numeric()*100 + - parsed.revision - - return int32(numeric) -} - -func init() { - - version, prerelease, err := parseTag(appTag) - if err != nil { - panic(fmt.Errorf("parse tag: %s; %w", appTag, err)) - } - - major, minor, patch, err := parseVersion(version) - if err != nil { - panic(fmt.Errorf("parse version: %s; %w", version, err)) - } - - phase, revision, err := parsePrerelease(prerelease) - if err != nil { - panic(fmt.Errorf("parse prerelease: %s; %w", prerelease, err)) - } - - info, ok := debug.ReadBuildInfo() - if !ok { - panic(fmt.Errorf("binary must be built with Go 1.18+ with module support")) - } - - var commit string - var modified bool - for _, s := range info.Settings { - if s.Key == "vcs.revision" { - commit = s.Value - } - if s.Key == "vcs.modified" && s.Value == "true" { - modified = true - } - } - - parsed = parsedVersion{ - version: version, - major: major, - minor: minor, - patch: patch, - - prerelease: prerelease, - phase: phase, - revision: revision, - - commit: commit, - modified: modified, - } -} - -var parsed parsedVersion - -type parsedVersion struct { - version string - // Semantic Version - major int - minor int - patch int - - // Prerelease - prerelease string - phase releasePhase - revision int - - // Build Metadata - commit string - modified bool -} - -func (v parsedVersion) buildmeta() string { - if !v.modified { - return v.commit - } - return v.commit + "-dirty" -} - -func (v parsedVersion) full() string { - if len(v.prerelease) > 0 { - return fmt.Sprintf("%s-%s+%s", v.version, v.prerelease, v.buildmeta()) - } - return fmt.Sprintf("%s+%s", v.version, v.buildmeta()) -} - -func parseTag(tag string) (version string, prerelease string, err error) { - - if len(tag) == 0 || tag[0] != 'v' { - return "", "", fmt.Errorf("tag must be prefixed with v; %s", tag) - } - - tag = tag[1:] - - if !strings.Contains(tag, "-") { - return tag, "", nil - } - - strs := strings.Split(tag, "-") - - if len(strs) != 2 { - return "", "", fmt.Errorf("tag must be in the form of Version.Revision; %s", tag) - } - - version = strs[0] - prerelease = strs[1] - - return version, prerelease, nil -} - -func parseVersion(ver string) (major int, minor int, patch int, err error) { - - strs := strings.Split(ver, ".") - - if len(strs) != 3 { - return major, minor, patch, fmt.Errorf("invalid format; must be in the form of Major.Minor.Patch") - } - - major, err = strconv.Atoi(strs[0]) - if err != nil { - return major, minor, patch, fmt.Errorf("invalid major: %s", strs[0]) - } - if major < 0 || major > 41 { - return major, minor, patch, fmt.Errorf("major must between 0 - 41; got %d", major) - } - - minor, err = strconv.Atoi(strs[1]) - if err != nil { - return major, minor, patch, fmt.Errorf("invalid minor: %s", strs[1]) - } - if minor < 0 || minor > 99 { - return major, minor, patch, fmt.Errorf("minor must between 0 - 99; got %d", minor) - } - - patch, err = strconv.Atoi(strs[2]) - if err != nil { - return major, minor, patch, fmt.Errorf("invalid patch: %s", strs[2]) - } - if patch < 0 || patch > 999 { - return major, minor, patch, fmt.Errorf("patch must between 0 - 999; got %d", patch) - } - - return major, minor, patch, nil -} - -func parsePrerelease(pre string) (phase releasePhase, revision int, err error) { - - phase = Unkown - - if pre == "" { - return GA, 0, nil - } - - strs := strings.Split(pre, ".") - if len(strs) != 2 { - return phase, revision, fmt.Errorf("prerelease must be in the form of Phase.Revision; got: %s", pre) - } - - phase = releasePhase(strs[0]) - if phase.numeric() == -1 { - return phase, revision, fmt.Errorf("phase must be local, dev, alpha, beta, or rc; got: %s", strs[0]) - } - - revision, err = strconv.Atoi(strs[1]) - if err != nil { - return phase, revision, fmt.Errorf("invalid revision: %s", strs[0]) - } - if revision < 0 || revision > 99 { - return phase, revision, fmt.Errorf("revision must between 0 - 999; got %d", revision) - } - - return phase, revision, nil -} - -type releasePhase string - -const ( - Unkown releasePhase = "unkown" - Local releasePhase = "local" - Dev releasePhase = "dev" - Alpha releasePhase = "alpha" - Beta releasePhase = "beta" - RC releasePhase = "rc" - GA releasePhase = "" -) - -func (p releasePhase) numeric() int { - - switch p { - case Local: - return 0 - case Dev: - return 1 - case Alpha: - return 2 - case Beta: - return 3 - case RC: - return 4 - case GA: - return 5 - } - - // Unknown phase - return -1 -} diff --git a/wire/doc.go b/wire/doc.go index 5e03ff20..b8b8c56f 100644 --- a/wire/doc.go +++ b/wire/doc.go @@ -14,7 +14,7 @@ supported bitcoin messages to and from the wire. This package does not deal with the specifics of message handling such as what to do when a message is received. This provides the caller with a high level of flexibility. -# Bitcoin Message Overview +Bitcoin Message Overview The bitcoin protocol consists of exchanging messages between peers. Each message is preceded by a header which identifies information about it such as @@ -30,7 +30,7 @@ messages, all of the details of marshalling and unmarshalling to and from the wire using bitcoin encoding are handled so the caller doesn't have to concern themselves with the specifics. -# Message Interaction +Message Interaction The following provides a quick summary of how the bitcoin messages are intended to interact with one another. As stated above, these interactions are not @@ -62,13 +62,13 @@ interactions in no particular order. in BIP0031. The BIP0031Version constant can be used to detect a recent enough protocol version for this purpose (version > BIP0031Version). -# Common Parameters +Common Parameters There are several common parameters that arise when using this package to read and write bitcoin messages. The following sections provide a quick overview of these parameters so the next sections can build on them. -# Protocol Version +Protocol Version The protocol version should be negotiated with the remote peer at a higher level than this package via the version (MsgVersion) message exchange, however, @@ -77,7 +77,7 @@ latest protocol version this package supports and is typically the value to use for all outbound connections before a potentially lower protocol version is negotiated. -# Bitcoin Network +Bitcoin Network The bitcoin network is a magic number which is used to identify the start of a message and which bitcoin network the message applies to. This package provides @@ -88,7 +88,7 @@ the following constants: wire.TestNet3 (Test network version 3) wire.SimNet (Simulation test network) -# Determining Message Type +Determining Message Type As discussed in the bitcoin message overview section, this package reads and writes bitcoin messages using a generic interface named Message. In @@ -106,7 +106,7 @@ switch or type assertion. An example of a type switch follows: fmt.Printf("Number of tx in block: %v", msg.Header.TxnCount) } -# Reading Messages +Reading Messages In order to unmarshall bitcoin messages from the wire, use the ReadMessage function. It accepts any io.Reader, but typically this will be a net.Conn to @@ -121,7 +121,7 @@ a remote node running a bitcoin peer. Example syntax is: // Log and handle the error } -# Writing Messages +Writing Messages In order to marshall bitcoin messages to the wire, use the WriteMessage function. It accepts any io.Writer, but typically this will be a net.Conn to @@ -139,7 +139,7 @@ from a remote peer is: // Log and handle the error } -# Errors +Errors Errors returned by this package are either the raw errors provided by underlying calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and @@ -147,7 +147,7 @@ io.ErrShortWrite, or of type wire.MessageError. This allows the caller to differentiate between general IO errors and malformed messages through type assertions. -# Bitcoin Improvement Proposals +Bitcoin Improvement Proposals This package includes spec changes outlined by the following BIPs: diff --git a/wire/msgtx.go b/wire/msgtx.go index a60f7a82..34bdeaed 100644 --- a/wire/msgtx.go +++ b/wire/msgtx.go @@ -114,18 +114,16 @@ const ( // transaction from one that would require a different parsing logic. // // Position of FLAG in a bitcoin tx message: -// -// ┌─────────┬────────────────────┬─────────────┬─────┐ -// │ VERSION │ FLAG │ TX-IN-COUNT │ ... │ -// │ 4 bytes │ 2 bytes (optional) │ varint │ │ -// └─────────┴────────────────────┴─────────────┴─────┘ +// ┌─────────┬────────────────────┬─────────────┬─────┐ +// │ VERSION │ FLAG │ TX-IN-COUNT │ ... │ +// │ 4 bytes │ 2 bytes (optional) │ varint │ │ +// └─────────┴────────────────────┴─────────────┴─────┘ // // Zooming into the FLAG field: -// -// ┌── FLAG ─────────────┬────────┐ -// │ TxFlagMarker (0x00) │ TxFlag │ -// │ 1 byte │ 1 byte │ -// └─────────────────────┴────────┘ +// ┌── FLAG ─────────────┬────────┐ +// │ TxFlagMarker (0x00) │ TxFlag │ +// │ 1 byte │ 1 byte │ +// └─────────────────────┴────────┘ const TxFlagMarker = 0x00 // TxFlag is the second byte of the FLAG field in a bitcoin tx message.