Compare commits

..

3 commits

Author SHA1 Message Date
Patrick O'Grady
46da44d520
Attempt aggressive caching 2020-10-27 22:41:51 -07:00
Patrick O'Grady
311eb6988c
Use rwmutex 2020-10-27 22:20:54 -07:00
Patrick O'Grady
863313103a
In-memory coin cache during sync, first pass 2020-10-27 22:09:30 -07:00
58 changed files with 781 additions and 1082 deletions

View file

@ -16,9 +16,9 @@ version: 2.1
executors:
default:
docker:
- image: circleci/golang:1.15
- image: circleci/golang:1.13
user: root # go directory is owned by root
working_directory: /go/src/github.com/lbryio/rosetta-lbry
working_directory: /go/src/github.com/coinbase/rosetta-bitcoin
environment:
- GO111MODULE: "on"
@ -50,7 +50,7 @@ jobs:
name: default
steps:
- *fast-checkout
- run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.32.2
- run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
- run: make lint
check-license:
executor:
@ -69,7 +69,7 @@ jobs:
name: default
steps:
- *fast-checkout
- run: make coverage
- run: make coverage
salus:
machine: true
steps:

View file

@ -1,3 +1,3 @@
rosetta-lbry
lbry-data
rosetta-bitcoin
bitcoin-data
cli-data

4
.gitignore vendored
View file

@ -1,3 +1,3 @@
rosetta-lbry
lbry-data
rosetta-bitcoin
bitcoin-data
cli-data

View file

@ -10,11 +10,11 @@ from further participation in this project, or potentially all Coinbase projects
## Bug Reports
- Ensure your issue [has not already been reported][1]. It may already be fixed!
- Include the steps you carried out to produce the problem.
- Include the behavior you observed along with the behavior you expected, and
* Ensure your issue [has not already been reported][1]. It may already be fixed!
* Include the steps you carried out to produce the problem.
* Include the behavior you observed along with the behavior you expected, and
why you expected it.
- Include any relevant stack traces or debugging output.
* Include any relevant stack traces or debugging output.
## Feature Requests
@ -27,18 +27,18 @@ The best way to see a feature added, however, is to submit a pull request.
## Pull Requests
- Before creating your pull request, it's usually worth asking if the code
* Before creating your pull request, it's usually worth asking if the code
you're planning on writing will actually be considered for merging. You can
do this by [opening an issue][1] and asking. It may also help give the
maintainers context for when the time comes to review your code.
- Ensure your [commit messages are well-written][2]. This can double as your
* Ensure your [commit messages are well-written][2]. This can double as your
pull request message, so it pays to take the time to write a clear message.
- Add tests for your feature. You should be able to look at other tests for
* Add tests for your feature. You should be able to look at other tests for
examples. If you're unsure, don't hesitate to [open an issue][1] and ask!
- Submit your pull request!
* Submit your pull request!
## Support Requests
@ -48,6 +48,6 @@ be locked to prevent further discussion.
All support requests must be made via [our support team][3].
[1]: https://github.com/lbryio/rosetta-bitcoin/issues
[1]: https://github.com/coinbase/rosetta-bitcoin/issues
[2]: https://chris.beams.io/posts/git-commit/#seven-rules
[3]: https://support.coinbase.com/customer/en/portal/articles/2288496-how-can-i-contact-coinbase-support-

View file

@ -12,47 +12,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Build LBRYCrdd
FROM ubuntu:18.04 as lbrycrdd-builder
ENV LANG C.UTF-8
# Build bitcoind
FROM ubuntu:18.04 as bitcoind-builder
RUN mkdir -p /app \
&& chown -R nobody:nogroup /app
WORKDIR /app
# Source: https://github.com/lbryio/lbrycrd/blob/v19_master/packaging/docker-for-gcc/Dockerfile
RUN set -xe; \
apt-get update; \
apt-get install --no-install-recommends -y build-essential libtool autotools-dev automake pkg-config git wget apt-utils \
librsvg2-bin cmake libcap-dev libz-dev libbz2-dev python-setuptools python3-setuptools xz-utils ccache \
bsdmainutils curl ca-certificates; \
rm -rf /var/lib/apt/lists/*; \
/usr/sbin/update-ccache-symlinks;
# Source: https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md#ubuntu--debian
RUN apt-get update && apt-get install -y make gcc g++ autoconf autotools-dev bsdmainutils build-essential git libboost-all-dev \
libcurl4-openssl-dev libdb++-dev libevent-dev libssl-dev libtool pkg-config python python-pip libzmq3-dev wget
# VERSION: LBRYcrd 0.19.1.3
RUN git clone https://github.com/lbryio/lbrycrd \
&& cd lbrycrd \
&& git checkout v0.19.1.3
# VERSION: Bitcoin Core 0.20.1
RUN git clone https://github.com/bitcoin/bitcoin \
&& cd bitcoin \
&& git checkout 7ff64311bee570874c4f0dfa18f518552188df08
ENV CXXFLAGS "${CXXFLAGS:--frecord-gcc-switches}"
RUN cd lbrycrd \
&& cd depends \
&& make -j$(getconf _NPROCESSORS_ONLN) HOST=x86_64-pc-linux-gnu NO_QT=1 V=1
ENV DEPS_DIR /app/lbrycrd/depends/x86_64-pc-linux-gnu
RUN echo $DEPS_DIR
ENV CONFIG_SITE ${DEPS_DIR}/share/config.site
RUN echo $CONFIG_SITE
RUN cd lbrycrd \
RUN cd bitcoin \
&& ./autogen.sh \
&& ./configure --enable-static --with-pic --disable-shared --enable-glibc-back-compat --disable-tests --without-miniupnpc --without-gui --with-incompatible-bdb --disable-hardening --disable-zmq --disable-bench --disable-wallet \
&& make -j$(getconf _NPROCESSORS_ONLN)
&& ./configure --enable-glibc-back-compat --disable-tests --without-miniupnpc --without-gui --with-incompatible-bdb --disable-hardening --disable-zmq --disable-bench --disable-wallet \
&& make
RUN mv lbrycrd/src/lbrycrdd /app/lbrycrdd \
&& rm -rf lbrycrd
RUN mv bitcoin/src/bitcoind /app/bitcoind \
&& rm -rf bitcoin
# Build Rosetta Server Components
FROM ubuntu:18.04 as rosetta-builder
@ -62,8 +44,8 @@ RUN mkdir -p /app \
WORKDIR /app
RUN apt-get update && apt-get install -y curl make gcc g++
ENV GOLANG_VERSION 1.15.5
ENV GOLANG_DOWNLOAD_SHA256 9a58494e8da722c3aef248c9227b0e9c528c7318309827780f16220998180a0d
ENV GOLANG_VERSION 1.15.2
ENV GOLANG_DOWNLOAD_SHA256 b49fda1ca29a1946d6bb2a5a6982cf07ccd2aba849289508ee0f9918f6bb4552
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
@ -76,19 +58,13 @@ ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
# Use native remote build context to build in any directory
COPY . src
## Cleanup
RUN cd src \
&& rm go.sum \
&& go mod edit -replace github.com/golang/lint=golang.org/x/lint@latest \
&& go clean -modcache
COPY . src
RUN cd src \
&& go build \
&& cd .. \
&& mv src/rosetta-lbry /app/rosetta-lbry \
&& mv src/rosetta-bitcoin /app/rosetta-bitcoin \
&& mv src/assets/* /app \
&& rm -rf src
&& rm -rf src
## Build Final Image
FROM ubuntu:18.04
@ -104,8 +80,8 @@ RUN mkdir -p /app \
WORKDIR /app
# Copy binary from lbrycrdd-builder
COPY --from=lbrycrdd-builder /app/lbrycrdd /app/lbrycrdd
# Copy binary from bitcoind-builder
COPY --from=bitcoind-builder /app/bitcoind /app/bitcoind
# Copy binary from rosetta-builder
COPY --from=rosetta-builder /app/* /app/
@ -113,4 +89,4 @@ COPY --from=rosetta-builder /app/* /app/
# Set permissions for everything added to /app
RUN chmod -R 755 /app/*
CMD ["/app/rosetta-lbry"]
CMD ["/app/rosetta-bitcoin"]

View file

@ -9,7 +9,7 @@ GOLINES_CMD=go run github.com/segmentio/golines
GOLINT_CMD=go run golang.org/x/lint/golint
GOVERALLS_CMD=go run github.com/mattn/goveralls
GOIMPORTS_CMD=go run golang.org/x/tools/cmd/goimports
GO_PACKAGES=./services/... ./indexer/... ./lbry/... ./configuration/...
GO_PACKAGES=./services/... ./indexer/... ./bitcoin/... ./configuration/...
GO_FOLDERS=$(shell echo ${GO_PACKAGES} | sed -e "s/\.\///g" | sed -e "s/\/\.\.\.//g")
TEST_SCRIPT=go test ${GO_PACKAGES}
LINT_SETTINGS=golint,misspell,gocyclo,gocritic,whitespace,goconst,gocognit,bodyclose,unconvert,lll,unparam
@ -20,27 +20,27 @@ deps:
go get ./...
build:
docker build -t rosetta-lbry:latest https://github.com/lbryio/rosetta-lbry.git
docker build -t rosetta-bitcoin:latest https://github.com/coinbase/rosetta-bitcoin.git
build-local:
docker build -t rosetta-lbry:latest .
docker build -t rosetta-bitcoin:latest .
build-release:
# make sure to always set version with vX.X.X
docker build -t rosetta-lbry:$(version) .;
docker save rosetta-lbry:$(version) | gzip > rosetta-lbry-$(version).tar.gz;
docker build -t rosetta-bitcoin:$(version) .;
docker save rosetta-bitcoin:$(version) | gzip > rosetta-bitcoin-$(version).tar.gz;
run-mainnet-online:
docker run -d --rm --ulimit "nofile=${NOFILE}:${NOFILE}" -v "${PWD}/lbry-data:/data" -e "MODE=ONLINE" -e "NETWORK=MAINNET" -e "PORT=8080" -p 8080:8080 -p 9246:9246 rosetta-lbry:latest
docker run -d --rm --ulimit "nofile=${NOFILE}:${NOFILE}" -v "${PWD}/bitcoin-data:/data" -e "MODE=ONLINE" -e "NETWORK=MAINNET" -e "PORT=8080" -p 8080:8080 -p 8333:8333 rosetta-bitcoin:latest
run-mainnet-offline:
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=MAINNET" -e "PORT=8081" -p 8081:8081 rosetta-lbry:latest
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=MAINNET" -e "PORT=8081" -p 8081:8081 rosetta-bitcoin:latest
run-testnet-online:
docker run -d --rm --ulimit "nofile=${NOFILE}:${NOFILE}" -v "${PWD}/lbry-data:/data" -e "MODE=ONLINE" -e "NETWORK=TESTNET" -e "PORT=8080" -p 8080:8080 -p 19246:19246 rosetta-lbry:latest
docker run -d --rm --ulimit "nofile=${NOFILE}:${NOFILE}" -v "${PWD}/bitcoin-data:/data" -e "MODE=ONLINE" -e "NETWORK=TESTNET" -e "PORT=8080" -p 8080:8080 -p 18333:18333 rosetta-bitcoin:latest
run-testnet-offline:
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=TESTNET" -e "PORT=8081" -p 8081:8081 rosetta-lbry:latest
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=TESTNET" -e "PORT=8081" -p 8081:8081 rosetta-bitcoin:latest
train:
./zstd-train.sh $(network) transaction $(data-directory)
@ -71,7 +71,7 @@ check-format:
test:
${TEST_SCRIPT}
coverage:
coverage:
if [ "${COVERALLS_TOKEN}" ]; then ${TEST_SCRIPT} -coverprofile=c.out -covermode=count; ${GOVERALLS_CMD} -coverprofile=c.out -repotoken ${COVERALLS_TOKEN}; fi
coverage-local:

View file

@ -7,11 +7,11 @@
Rosetta Bitcoin
</h3>
<p align="center">
<a href="https://circleci.com/gh/lbryio/rosetta-bitcoin/tree/master"><img src="https://circleci.com/gh/lbryio/rosetta-bitcoin/tree/master.svg?style=shield" /></a>
<a href="https://coveralls.io/github/lbryio/rosetta-bitcoin"><img src="https://coveralls.io/repos/github/lbryio/rosetta-bitcoin/badge.svg" /></a>
<a href="https://goreportcard.com/report/github.com/lbryio/rosetta-bitcoin"><img src="https://goreportcard.com/badge/github.com/lbryio/rosetta-bitcoin" /></a>
<a href="https://github.com/lbryio/rosetta-bitcoin/blob/master/LICENSE.txt"><img src="https://img.shields.io/github/license/lbryio/rosetta-bitcoin.svg" /></a>
<a href="https://pkg.go.dev/github.com/lbryio/rosetta-bitcoin?tab=overview"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=shield" /></a>
<a href="https://circleci.com/gh/coinbase/rosetta-bitcoin/tree/master"><img src="https://circleci.com/gh/coinbase/rosetta-bitcoin/tree/master.svg?style=shield" /></a>
<a href="https://coveralls.io/github/coinbase/rosetta-bitcoin"><img src="https://coveralls.io/repos/github/coinbase/rosetta-bitcoin/badge.svg" /></a>
<a href="https://goreportcard.com/report/github.com/coinbase/rosetta-bitcoin"><img src="https://goreportcard.com/badge/github.com/coinbase/rosetta-bitcoin" /></a>
<a href="https://github.com/coinbase/rosetta-bitcoin/blob/master/LICENSE.txt"><img src="https://img.shields.io/github/license/coinbase/rosetta-bitcoin.svg" /></a>
<a href="https://pkg.go.dev/github.com/coinbase/rosetta-bitcoin?tab=overview"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=shield" /></a>
</p>
<p align="center"><b>
@ -20,19 +20,16 @@ USE AT YOUR OWN RISK! COINBASE ASSUMES NO RESPONSIBILITY NOR LIABILITY IF THERE
</b></p>
## Overview
`rosetta-bitcoin` provides a reference implementation of the Rosetta API for
Bitcoin in Golang. If you haven't heard of the Rosetta API, you can find more
information [here](https://rosetta-api.org).
## Features
- Rosetta API implementation (both Data API and Construction API)
- UTXO cache for all accounts (accessible using `/account/balance`)
- Stateless, offline, curve-based transaction construction from any SegWit-Bech32 Address
* Rosetta API implementation (both Data API and Construction API)
* UTXO cache for all accounts (accessible using `/account/balance`)
* Stateless, offline, curve-based transaction construction from any SegWit-Bech32 Address
## Usage
As specified in the [Rosetta API Principles](https://www.rosetta-api.org/docs/automated_deployment.html),
all Rosetta implementations must be deployable via Docker and support running via either an
[`online` or `offline` mode](https://www.rosetta-api.org/docs/node_deployment.html#multiple-modes).
@ -41,77 +38,59 @@ all Rosetta implementations must be deployable via Docker and support running vi
DOCKER [HERE](https://www.docker.com/get-started).**
### Install
Running the following commands will create a Docker image called `rosetta-bitcoin:latest`.
#### From GitHub
To download the pre-built Docker image from the latest release, run:
```text
curl -sSfL https://raw.githubusercontent.com/lbryio/rosetta-bitcoin/master/install.sh | sh -s
curl -sSfL https://raw.githubusercontent.com/coinbase/rosetta-bitcoin/master/install.sh | sh -s
```
_Do not try to install rosetta-bitcoin using GitHub Packages!_
#### From Source
After cloning this repository, run:
```text
make build-local
```
### Run
Running the following commands will start a Docker container in
[detached mode](https://docs.docker.com/engine/reference/run/#detached--d) with
a data directory at `<working directory>/bitcoin-data` and the Rosetta API accessible
at port `8080`.
#### Mainnet:Online
```text
docker run -d --rm --ulimit "nofile=100000:100000" -v "$(pwd)/bitcoin-data:/data" -e "MODE=ONLINE" -e "NETWORK=MAINNET" -e "PORT=8080" -p 8080:8080 -p 8333:8333 rosetta-bitcoin:latest
```
_If you cloned the repository, you can run `make run-mainnet-online`._
#### Mainnet:Offline
```text
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=MAINNET" -e "PORT=8081" -p 8081:8081 rosetta-bitcoin:latest
```
_If you cloned the repository, you can run `make run-mainnet-offline`._
#### Testnet:Online
```text
docker run -d --rm --ulimit "nofile=100000:100000" -v "$(pwd)/bitcoin-data:/data" -e "MODE=ONLINE" -e "NETWORK=TESTNET" -e "PORT=8080" -p 8080:8080 -p 18333:18333 rosetta-bitcoin:latest
```
_If you cloned the repository, you can run `make run-testnet-online`._
#### Testnet:Offline
```text
docker run -d --rm -e "MODE=OFFLINE" -e "NETWORK=TESTNET" -e "PORT=8081" -p 8081:8081 rosetta-bitcoin:latest
```
_If you cloned the repository, you can run `make run-testnet-offline`._
## System Requirements
`rosetta-bitcoin` has been tested on an [AWS c5.2xlarge instance](https://aws.amazon.com/ec2/instance-types/c5).
This instance type has 8 vCPU and 16 GB of RAM.
### Network Settings
To increase the load `rosetta-bitcoin` can handle, it is recommended to tune your OS
settings to allow for more connections. On a linux-based OS, you can run the following
commands ([source](http://www.tweaked.io/guide/kernel)):
```text
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.core.rmem_max=16777216
@ -120,7 +99,6 @@ sysctl -w net.ipv4.tcp_max_syn_backlog=10000
sysctl -w net.core.somaxconn=10000
sysctl -p (when done)
```
_We have not tested `rosetta-bitcoin` with `net.ipv4.tcp_tw_recycle` and do not recommend
enabling it._
@ -128,7 +106,6 @@ You should also modify your open file settings to `100000`. This can be done on
with the command: `ulimit -n 100000`.
### Memory-Mapped Files
`rosetta-bitcoin` uses [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file) to
persist data in the `indexer`. As a result, you **must** run `rosetta-bitcoin` on a 64-bit
architecture (the virtual address space easily exceeds 100s of GBs).
@ -137,12 +114,10 @@ If you receive a kernel OOM, you may need to increase the allocated size of swap
on your OS. There is a great tutorial for how to do this on Linux [here](https://linuxize.com/post/create-a-linux-swap-file/).
## Architecture
`rosetta-bitcoin` uses the `syncer`, `storage`, `parser`, and `server` package
from [`rosetta-sdk-go`](https://github.com/coinbase/rosetta-sdk-go) instead
of a new Bitcoin-specific implementation of packages of similar functionality. Below
you can find a high-level overview of how everything fits together:
```text
+------------------------------------------------------------------+
| |
@ -182,20 +157,17 @@ you can find a high-level overview of how everything fits together:
```
### Optimizations
- Automatically prune bitcoind while indexing blocks
- Reduce sync time with concurrent block indexing
- Use [Zstandard compression](https://github.com/facebook/zstd) to reduce the size of data stored on disk
without needing to write a manual byte-level encoding
* Automatically prune bitcoind while indexing blocks
* Reduce sync time with concurrent block indexing
* Use [Zstandard compression](https://github.com/facebook/zstd) to reduce the size of data stored on disk
without needing to write a manual byte-level encoding
#### Concurrent Block Syncing
To speed up indexing, `rosetta-bitcoin` uses concurrent block processing
with a "wait free" design (using channels instead of sleeps to signal
which threads are unblocked). This allows `rosetta-bitcoin` to fetch
multiple inputs from disk while it waits for inputs that appeared
in recently processed blocks to save to disk.
```text
+----------+
| bitcoind |
@ -233,35 +205,30 @@ in recently processed blocks to save to disk.
```
## Testing with rosetta-cli
To validate `rosetta-bitcoin`, [install `rosetta-cli`](https://github.com/lbryio/rosetta-cli#install)
To validate `rosetta-bitcoin`, [install `rosetta-cli`](https://github.com/coinbase/rosetta-cli#install)
and run one of the following commands:
- `rosetta-cli check:data --configuration-file rosetta-cli-conf/testnet/config.json`
- `rosetta-cli check:construction --configuration-file rosetta-cli-conf/testnet/config.json`
- `rosetta-cli check:data --configuration-file rosetta-cli-conf/mainnet/config.json`
* `rosetta-cli check:data --configuration-file rosetta-cli-conf/testnet/config.json`
* `rosetta-cli check:construction --configuration-file rosetta-cli-conf/testnet/config.json`
* `rosetta-cli check:data --configuration-file rosetta-cli-conf/mainnet/config.json`
## Future Work
- Publish benchamrks for sync speed, storage usage, and load testing
- [Rosetta API `/mempool/transaction`](https://www.rosetta-api.org/docs/MempoolApi.html#mempooltransaction) implementation
- Add CI test using `rosetta-cli` to run on each PR (likely on a regtest network)
- Add performance mode to use unlimited RAM (implementation currently optimized to use <= 16 GB of RAM)
- Support Multi-Sig Sends
* Publish benchamrks for sync speed, storage usage, and load testing
* [Rosetta API `/mempool/transaction`](https://www.rosetta-api.org/docs/MempoolApi.html#mempooltransaction) implementation
* Add CI test using `rosetta-cli` to run on each PR (likely on a regtest network)
* Add performance mode to use unlimited RAM (implementation currently optimized to use <= 16 GB of RAM)
* Support Multi-Sig Sends
_Please reach out on our [community](https://community.rosetta-api.org) if you want to tackle anything on this list!_
## Development
- `make deps` to install dependencies
- `make test` to run tests
- `make lint` to lint the source code
- `make salus` to check for security concerns
- `make build-local` to build a Docker image from the local context
- `make coverage-local` to generate a coverage report
* `make deps` to install dependencies
* `make test` to run tests
* `make lint` to lint the source code
* `make salus` to check for security concerns
* `make build-local` to build a Docker image from the local context
* `make coverage-local` to generate a coverage report
## License
This project is available open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
© 2020 Coinbase

View file

@ -0,0 +1,26 @@
##
## bitcoin.conf configuration file. Lines beginning with # are comments.
##
# DO NOT USE THIS CONFIGURATION FILE IF YOU PLAN TO EXPOSE
# BITCOIND'S RPC PORT PUBLICALLY (THESE INSECURE CREDENTIALS
# COULD LEAD TO AN ATTACK). ROSETTA-BITCOIN USES THE RPC PORT
# FOR INDEXING AND TRANSACTION BROADCAST BUT NEVER PROVIDES THE
# CALLER ACCESS TO BITCOIND'S RPC PORT.
datadir=/data/bitcoind
bind=0.0.0.0
rpcbind=0.0.0.0
bantime=15
rpcallowip=0.0.0.0/0
rpcthreads=16
rpcworkqueue=1000
disablewallet=1
txindex=0
port=8333
rpcport=8332
rpcuser=rosetta
rpcpassword=rosetta
# allow manual pruning
prune=1

View file

@ -1,14 +1,14 @@
##
## lbry.conf configuration file. Lines beginning with # are comments.
## bitcoin.conf configuration file. Lines beginning with # are comments.
##
# DO NOT USE THIS CONFIGURATION FILE IF YOU PLAN TO EXPOSE
# LBRYCRDD'S RPC PORT PUBLICALLY (THESE INSECURE CREDENTIALS
# COULD LEAD TO AN ATTACK). ROSETTA-LBRY USES THE RPC PORT
# BITCOIND'S RPC PORT PUBLICALLY (THESE INSECURE CREDENTIALS
# COULD LEAD TO AN ATTACK). ROSETTA-BITCOIN USES THE RPC PORT
# FOR INDEXING AND TRANSACTION BROADCAST BUT NEVER PROVIDES THE
# CALLER ACCESS TO LBRYCRDD'S RPC PORT.
# CALLER ACCESS TO BITCOIND'S RPC PORT.
datadir=/data/lbrycrdd
datadir=/data/bitcoind
bantime=15
rpcallowip=0.0.0.0/0
rpcthreads=16
@ -23,7 +23,7 @@ prune=1
testnet=1
[test]
port=19246
port=18333
bind=0.0.0.0
rpcport=19245
rpcport=18332
rpcbind=0.0.0.0

17
assets/bitcoin.json Normal file
View file

@ -0,0 +1,17 @@
{
"network": {
"blockchain": "Bitcoin",
"network": "Mainnet"
},
"online_url": "http://localhost:8080",
"data_directory": "",
"http_timeout": 10,
"sync_concurrency": 8,
"transaction_concurrency": 16,
"tip_delay": 300,
"disable_memory_limit": false,
"log_configuration": false,
"data": {
"historical_balance_disabled": true
}
}

View file

@ -1,27 +0,0 @@
##
## lbry.conf configuration file. Lines beginning with # are comments.
##
# DO NOT USE THIS CONFIGURATION FILE IF YOU PLAN TO EXPOSE
# LBRYCRDD'S RPC PORT PUBLICALLY (THESE INSECURE CREDENTIALS
# COULD LEAD TO AN ATTACK). ROSETTA-LBRY USES THE RPC PORT
# FOR INDEXING AND TRANSACTION BROADCAST BUT NEVER PROVIDES THE
# CALLER ACCESS TO LBRYCRDD'S RPC PORT.
datadir=/data/lbrycrdd
bind=0.0.0.0
rpcbind=0.0.0.0
bantime=15
rpcallowip=0.0.0.0/0
rpcthreads=30
disablewallet=1
txindex=0
port=9246
rpcport=9245
rpcuser=rosetta
rpcpassword=rosetta
rpcworkqueue=3000
dbcache=3000
# allow manual pruning
prune=1

View file

@ -1,17 +0,0 @@
{
"network": {
"blockchain": "lbry",
"network": "Mainnet"
},
"online_url": "http://localhost:8080",
"data_directory": "",
"http_timeout": 10,
"sync_concurrency": 8,
"transaction_concurrency": 16,
"tip_delay": 300,
"disable_memory_limit": false,
"log_configuration": false,
"data": {
"historical_balance_disabled": true
}
}

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package lbry
package bitcoin
import (
"bytes"
@ -26,16 +26,17 @@ import (
"strconv"
"time"
lbryUtils "github.com/lbryio/rosetta-lbry/utils"
bitcoinUtils "github.com/coinbase/rosetta-bitcoin/utils"
"github.com/btcsuite/btcutil"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/coinbase/rosetta-sdk-go/utils"
)
const (
// genesisBlockIndex is the height of the block we consider to be the
// genesis block of the lbry blockchain for polling
// genesis block of the bitcoin blockchain for polling
genesisBlockIndex = 0
// requestID is the JSON-RPC request ID we use for making requests.
@ -56,28 +57,28 @@ const (
type requestMethod string
const (
// https://lbry.org/en/developer-reference#getblock
// https://bitcoin.org/en/developer-reference#getblock
requestMethodGetBlock requestMethod = "getblock"
// https://lbry.org/en/developer-reference#getblockhash
// https://bitcoin.org/en/developer-reference#getblockhash
requestMethodGetBlockHash requestMethod = "getblockhash"
// https://lbry.org/en/developer-reference#getblockchaininfo
// https://bitcoin.org/en/developer-reference#getblockchaininfo
requestMethodGetBlockchainInfo requestMethod = "getblockchaininfo"
// https://developer.lbry.org/reference/rpc/getpeerinfo.html
// https://developer.bitcoin.org/reference/rpc/getpeerinfo.html
requestMethodGetPeerInfo requestMethod = "getpeerinfo"
// https://developer.lbry.org/reference/rpc/pruneblockchain.html
// https://developer.bitcoin.org/reference/rpc/pruneblockchain.html
requestMethodPruneBlockchain requestMethod = "pruneblockchain"
// https://developer.lbry.org/reference/rpc/sendrawtransaction.html
// https://developer.bitcoin.org/reference/rpc/sendrawtransaction.html
requestMethodSendRawTransaction requestMethod = "sendrawtransaction"
// https://developer.lbry.org/reference/rpc/estimatesmartfee.html
// https://developer.bitcoin.org/reference/rpc/estimatesmartfee.html
requestMethodEstimateSmartFee requestMethod = "estimatesmartfee"
// https://developer.lbry.org/reference/rpc/getrawmempool.html
// https://developer.bitcoin.org/reference/rpc/getrawmempool.html
requestMethodRawMempool requestMethod = "getrawmempool"
// blockNotFoundErrCode is the RPC error code when a block cannot be found
@ -89,11 +90,11 @@ const (
dialTimeout = 5 * time.Second
// timeMultiplier is used to multiply the time
// returned in lbry blocks to be milliseconds.
// returned in Bitcoin blocks to be milliseconds.
timeMultiplier = 1000
// rpc credentials are fixed in rosetta-lbry
// because we never expose access to the raw lbrycrdd
// rpc credentials are fixed in rosetta-bitcoin
// because we never expose access to the raw bitcoind
// endpoints (that could be used perform an attack, like
// changing our peers).
rpcUsername = "rosetta"
@ -109,10 +110,10 @@ var (
ErrJSONRPCError = errors.New("JSON-RPC error")
)
// Client is used to fetch blocks from lbrycrdd and
// to parse lbry block data into Rosetta types.
// Client is used to fetch blocks from bitcoind and
// to parse Bitcoin block data into Rosetta types.
//
// We opted not to use existing lbry RPC libraries
// We opted not to use existing Bitcoin RPC libraries
// because they don't allow providing context
// in each request.
type Client struct {
@ -130,7 +131,7 @@ func LocalhostURL(rpcPort int) string {
return fmt.Sprintf("http://localhost:%d", rpcPort)
}
// NewClient creates a new lbry client.
// NewClient creates a new Bitcoin client.
func NewClient(
baseURL string,
genesisBlockIdentifier *types.BlockIdentifier,
@ -161,7 +162,7 @@ func newHTTPClient(timeout time.Duration) *http.Client {
}
// NetworkStatus returns the *types.NetworkStatusResponse for
// lbrycrdd.
// bitcoind.
func (b *Client) NetworkStatus(ctx context.Context) (*types.NetworkStatusResponse, error) {
rawBlock, err := b.getBlock(ctx, nil)
if err != nil {
@ -240,12 +241,12 @@ func (b *Client) GetRawBlock(
return block, coins, nil
}
// ParseBlock returns a parsed lbry block given a raw lbry
// ParseBlock returns a parsed bitcoin block given a raw bitcoin
// block and a map of transactions containing inputs.
func (b *Client) ParseBlock(
ctx context.Context,
block *Block,
coins map[string]*types.AccountCoin,
coins map[string]*storage.AccountCoin,
) (*types.Block, error) {
rblock, err := b.parseBlockData(block)
if err != nil {
@ -263,7 +264,7 @@ func (b *Client) ParseBlock(
}
// SendRawTransaction submits a serialized transaction
// to lbrycrdd.
// to bitcoind.
func (b *Client) SendRawTransaction(
ctx context.Context,
serializedTx string,
@ -300,14 +301,14 @@ func (b *Client) SuggestedFeeRate(
}
// PruneBlockchain prunes up to the provided height.
// https://lbrycore.org/en/doc/0.20.0/rpc/blockchain/pruneblockchain
// https://bitcoincore.org/en/doc/0.20.0/rpc/blockchain/pruneblockchain
func (b *Client) PruneBlockchain(
ctx context.Context,
height int64,
) (int64, error) {
// Parameters:
// 1. Height
// https://developer.lbry.org/reference/rpc/pruneblockchain.html#argument-1-height
// https://developer.bitcoin.org/reference/rpc/pruneblockchain.html#argument-1-height
params := []interface{}{height}
response := &pruneBlockchainResponse{}
@ -361,7 +362,7 @@ func (b *Client) getBlock(
// Parameters:
// 1. Block hash (string, required)
// 2. Verbosity (integer, optional, default=1)
// https://lbry.org/en/developer-reference#getblock
// https://bitcoin.org/en/developer-reference#getblock
params := []interface{}{hash, blockVerbosity}
response := &blockResponse{}
@ -447,14 +448,14 @@ func (b *Client) parseBlockData(block *Block) (*types.Block, error) {
// getHashFromIndex performs the `getblockhash` JSON-RPC request for the specified
// block index, and returns the hash.
// https://lbry.org/en/developer-reference#getblockhash
// https://bitcoin.org/en/developer-reference#getblockhash
func (b *Client) getHashFromIndex(
ctx context.Context,
index int64,
) (string, error) {
// Parameters:
// 1. Block height (numeric, required)
// https://lbry.org/en/developer-reference#getblockhash
// https://bitcoin.org/en/developer-reference#getblockhash
params := []interface{}{index}
response := &blockHashResponse{}
@ -471,9 +472,9 @@ func (b *Client) getHashFromIndex(
// skipTransactionOperations is used to skip operations on transactions that
// contain duplicate UTXOs (which are no longer possible after BIP-30). This
// function mirrors the behavior of a similar commit in lbry-core.
// function mirrors the behavior of a similar commit in bitcoin-core.
//
// Source: https://github.com/lbry/lbry/commit/ab91bf39b7c11e9c86bb2043c24f0f377f1cf514
// Source: https://github.com/bitcoin/bitcoin/commit/ab91bf39b7c11e9c86bb2043c24f0f377f1cf514
func skipTransactionOperations(blockNumber int64, blockHash string, transactionHash string) bool {
if blockNumber == 91842 && blockHash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec" &&
transactionHash == "d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599" {
@ -492,9 +493,9 @@ func skipTransactionOperations(blockNumber int64, blockHash string, transactionH
func (b *Client) parseTransactions(
ctx context.Context,
block *Block,
coins map[string]*types.AccountCoin,
coins map[string]*storage.AccountCoin,
) ([]*types.Transaction, error) {
logger := lbryUtils.ExtractLogger(ctx, "client")
logger := bitcoinUtils.ExtractLogger(ctx, "client")
if block == nil {
return nil, errors.New("error parsing nil block")
@ -515,8 +516,9 @@ func (b *Client) parseTransactions(
"block hash", block.Hash,
"transaction hash", transaction.Hash,
)
for _, op := range txOps {
op.Status = types.String(SkippedStatus)
op.Status = SkippedStatus
}
}
@ -546,7 +548,7 @@ func (b *Client) parseTransactions(
continue
}
coins[op.CoinChange.CoinIdentifier.Identifier] = &types.AccountCoin{
coins[op.CoinChange.CoinIdentifier.Identifier] = &storage.AccountCoin{
Coin: &types.Coin{
CoinIdentifier: op.CoinChange.CoinIdentifier,
Amount: op.Amount,
@ -564,12 +566,12 @@ func (b *Client) parseTransactions(
func (b *Client) parseTxOperations(
tx *Transaction,
txIndex int,
coins map[string]*types.AccountCoin,
coins map[string]*storage.AccountCoin,
) ([]*types.Operation, error) {
txOps := []*types.Operation{}
for networkIndex, input := range tx.Inputs {
if lbryIsCoinbaseInput(input, txIndex, networkIndex) {
if bitcoinIsCoinbaseInput(input, txIndex, networkIndex) {
txOp, err := b.coinbaseTxOperation(input, int64(len(txOps)), int64(networkIndex))
if err != nil {
return nil, err
@ -579,7 +581,7 @@ func (b *Client) parseTxOperations(
break
}
// Fetch the *types.AccountCoin the input is associated with
// Fetch the *storage.AccountCoin the input is associated with
accountCoin, ok := coins[CoinIdentifier(input.TxHash, input.Vout)]
if !ok {
return nil, fmt.Errorf(
@ -627,7 +629,7 @@ func (b *Client) parseTxOperations(
}
// parseOutputTransactionOperation returns the types.Operation for the specified
// `lbryOutput` transaction output.
// `bitcoinOutput` transaction output.
func (b *Client) parseOutputTransactionOperation(
output *Output,
txHash string,
@ -656,7 +658,7 @@ func (b *Client) parseOutputTransactionOperation(
CoinAction: types.CoinCreated,
}
// If we are unable to parse the output account (i.e. lbrycrdd
// If we are unable to parse the output account (i.e. bitcoind
// returns a blank/nonstandard ScriptPubKey), we create an address as the
// concatenation of the tx hash and index.
//
@ -679,7 +681,7 @@ func (b *Client) parseOutputTransactionOperation(
NetworkIndex: &networkIndex,
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: account,
Amount: &types.Amount{
Value: strconv.FormatInt(int64(amount), 10),
@ -698,17 +700,17 @@ func (b *Client) getInputTxHash(
txIndex int,
inputIndex int,
) (string, int64, bool) {
if lbryIsCoinbaseInput(input, txIndex, inputIndex) {
if bitcoinIsCoinbaseInput(input, txIndex, inputIndex) {
return "", -1, false
}
return input.TxHash, input.Vout, true
}
// lbryIsCoinbaseInput returns whether the specified input is
// bitcoinIsCoinbaseInput returns whether the specified input is
// the coinbase input. The coinbase input is always the first input in the first
// transaction, and does not contain a previous transaction hash.
func lbryIsCoinbaseInput(input *Input, txIndex int, inputIndex int) bool {
func bitcoinIsCoinbaseInput(input *Input, txIndex int, inputIndex int) bool {
return txIndex == 0 && inputIndex == 0 && input.TxHash == "" && input.Coinbase != ""
}
@ -718,7 +720,7 @@ func (b *Client) parseInputTransactionOperation(
input *Input,
index int64,
networkIndex int64,
accountCoin *types.AccountCoin,
accountCoin *storage.AccountCoin,
) (*types.Operation, error) {
metadata, err := input.Metadata()
if err != nil {
@ -736,7 +738,7 @@ func (b *Client) parseInputTransactionOperation(
NetworkIndex: &networkIndex,
},
Type: InputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: accountCoin.Account,
Amount: &types.Amount{
Value: newValue,
@ -767,7 +769,7 @@ func (b *Client) parseAmount(amount float64) (uint64, error) {
return uint64(atomicAmount), nil
}
// parseOutputAccount parses a lbryScriptPubKey and returns an account
// parseOutputAccount parses a bitcoinScriptPubKey and returns an account
// identifier. The account identifier's address corresponds to the first
// address encoded in the script.
func (b *Client) parseOutputAccount(
@ -798,12 +800,12 @@ func (b *Client) coinbaseTxOperation(
NetworkIndex: &networkIndex,
},
Type: CoinbaseOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Metadata: metadata,
}, nil
}
// post makes a HTTP request to a lbry node
// post makes a HTTP request to a Bitcoin node
func (b *Client) post(
ctx context.Context,
method requestMethod,

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package lbry
package bitcoin
import (
"context"
@ -24,6 +24,7 @@ import (
"net/http/httptest"
"testing"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"
)
@ -707,14 +708,14 @@ func mustMarshalMap(v interface{}) map[string]interface{} {
func TestParseBlock(t *testing.T) {
tests := map[string]struct {
block *Block
coins map[string]*types.AccountCoin
coins map[string]*storage.AccountCoin
expectedBlock *types.Block
expectedError error
}{
"no fetched transactions": {
block: block1000,
coins: map[string]*types.AccountCoin{},
coins: map[string]*storage.AccountCoin{},
expectedBlock: &types.Block{
BlockIdentifier: blockIdentifier1000,
ParentBlockIdentifier: &types.BlockIdentifier{
@ -734,7 +735,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: CoinbaseOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Metadata: mustMarshalMap(&OperationMetadata{
Coinbase: "04ffff001d02fd04",
Sequence: 4294967295,
@ -746,7 +747,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac", // nolint
},
@ -787,7 +788,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "mmtKKnjqTPdkBnBMbNt5Yu2SCwpMaEshEL", // nolint
},
@ -819,7 +820,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(1),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "4852fe372ff7534c16713b3146bbc1e86379c70bea4d5c02fb1fa0112980a081:1",
},
@ -864,7 +865,7 @@ func TestParseBlock(t *testing.T) {
},
"block 100000": {
block: block100000,
coins: map[string]*types.AccountCoin{
coins: map[string]*storage.AccountCoin{
"87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03:0": {
Account: &types.AccountIdentifier{
Address: "1BNwxHGaFbeUBitpjy2AsKpJ29Ybxntqvb",
@ -927,7 +928,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: CoinbaseOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Metadata: mustMarshalMap(&OperationMetadata{
Coinbase: "044c86041b020602",
Sequence: 4294967295,
@ -939,7 +940,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "34qkc2iac6RsyxZVfyE2S5U5WcRsbg2dpK",
},
@ -971,7 +972,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(1),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "6a24aa21a9ed10109f4b82aa3ed7ec9d02a2a90246478b3308c8b85daf62fe501d58d05727a4",
},
@ -1006,7 +1007,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: InputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Amount: &types.Amount{
Value: "-5000000000",
Currency: MainnetCurrency,
@ -1034,7 +1035,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "1JqDybm2nWTENrHvMyafbSXXtTk5Uv5QAn",
},
@ -1066,7 +1067,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(1),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "1EYTGtG4LnFfiMvjJdsU7GMGCQvsRSjYhx",
},
@ -1111,7 +1112,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: InputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Amount: &types.Amount{
Value: "-3467607",
Currency: MainnetCurrency,
@ -1143,7 +1144,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(1),
},
Type: InputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Amount: &types.Amount{
Value: "0",
Currency: MainnetCurrency,
@ -1171,7 +1172,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(2),
},
Type: InputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Amount: &types.Amount{
Value: "-556000000",
Currency: MainnetCurrency,
@ -1199,7 +1200,7 @@ func TestParseBlock(t *testing.T) {
NetworkIndex: int64Pointer(0),
},
Type: OutputOpType,
Status: types.String(SuccessStatus),
Status: SuccessStatus,
Account: &types.AccountIdentifier{
Address: "76a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac",
},
@ -1250,7 +1251,7 @@ func TestParseBlock(t *testing.T) {
},
"missing transactions": {
block: block100000,
coins: map[string]*types.AccountCoin{},
coins: map[string]*storage.AccountCoin{},
expectedError: errors.New("error finding previous tx"),
},
}

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package lbry
package bitcoin
import (
"bufio"
@ -23,14 +23,14 @@ import (
"os/exec"
"strings"
"github.com/lbryio/rosetta-lbry/utils"
"github.com/coinbase/rosetta-bitcoin/utils"
"golang.org/x/sync/errgroup"
)
const (
lbrycrddLogger = "lbrycrdd"
lbrycrddStdErrLogger = "lbrycrdd stderr"
bitcoindLogger = "bitcoind"
bitcoindStdErrLogger = "bitcoind stderr"
)
func logPipe(ctx context.Context, pipe io.ReadCloser, identifier string) error {
@ -43,7 +43,7 @@ func logPipe(ctx context.Context, pipe io.ReadCloser, identifier string) error {
return err
}
message := strings.ReplaceAll(str, "\n", "")
message := strings.Replace(str, "\n", "", -1)
messages := strings.SplitAfterN(message, " ", 2)
// Trim the timestamp from the log if it exists
@ -51,8 +51,8 @@ func logPipe(ctx context.Context, pipe io.ReadCloser, identifier string) error {
message = messages[1]
}
// Print debug log if from lbrycrddLogger
if identifier == lbrycrddLogger {
// Print debug log if from bitcoindLogger
if identifier == bitcoindLogger {
logger.Debugw(message)
continue
}
@ -61,12 +61,12 @@ func logPipe(ctx context.Context, pipe io.ReadCloser, identifier string) error {
}
}
// Startlbrycrdd starts a lbrycrdd daemon in another goroutine
// StartBitcoind starts a bitcoind daemon in another goroutine
// and logs the results to the console.
func Startlbrycrdd(ctx context.Context, configPath string, g *errgroup.Group) error {
logger := utils.ExtractLogger(ctx, "lbrycrdd")
func StartBitcoind(ctx context.Context, configPath string, g *errgroup.Group) error {
logger := utils.ExtractLogger(ctx, "bitcoind")
cmd := exec.Command(
"/app/lbrycrdd",
"/app/bitcoind",
fmt.Sprintf("--conf=%s", configPath),
) // #nosec G204
@ -81,21 +81,21 @@ func Startlbrycrdd(ctx context.Context, configPath string, g *errgroup.Group) er
}
g.Go(func() error {
return logPipe(ctx, stdout, lbrycrddLogger)
return logPipe(ctx, stdout, bitcoindLogger)
})
g.Go(func() error {
return logPipe(ctx, stderr, lbrycrddStdErrLogger)
return logPipe(ctx, stderr, bitcoindStdErrLogger)
})
if err := cmd.Start(); err != nil {
return fmt.Errorf("%w: unable to start lbrycrdd", err)
return fmt.Errorf("%w: unable to start bitcoind", err)
}
g.Go(func() error {
<-ctx.Done()
logger.Warnw("sending interrupt to lbrycrdd")
logger.Warnw("sending interrupt to bitcoind")
return cmd.Process.Signal(os.Interrupt)
})

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package lbry
package bitcoin
import (
"fmt"
@ -23,8 +23,8 @@ import (
)
const (
// Blockchain is lbry.
Blockchain string = "lbry"
// Blockchain is Bitcoin.
Blockchain string = "Bitcoin"
// MainnetNetwork is the value of the network
// in MainnetNetworkIdentifier.
@ -38,9 +38,9 @@ const (
// used in Currency.
Decimals = 8
// SatoshisInlbry is the number of
// Satoshis in 1 LBC (10^8).
SatoshisInlbry = 100000000
// SatoshisInBitcoin is the number of
// Satoshis in 1 BTC (10^8).
SatoshisInBitcoin = 100000000
// InputOpType is used to describe
// INPUT.
@ -55,7 +55,7 @@ const (
CoinbaseOpType = "COINBASE"
// SuccessStatus is the status of all
// lbry operations because anything
// Bitcoin operations because anything
// on-chain is considered successful.
SuccessStatus = "SUCCESS"
@ -66,17 +66,17 @@ const (
SkippedStatus = "SKIPPED"
// TransactionHashLength is the length
// of any transaction hash in lbry.
// of any transaction hash in Bitcoin.
TransactionHashLength = 64
// NullData is returned by lbrycrdd
// NullData is returned by bitcoind
// as the ScriptPubKey.Type for OP_RETURN
// locking scripts.
NullData = "nulldata"
)
// Fee estimate constants
// Source: https://lbryops.org/en/tools/calc-size/
// Source: https://bitcoinops.org/en/tools/calc-size/
const (
MinFeeRate = float64(0.00001) // nolint:gomnd
TransactionOverhead = 12 // 4 version, 2 segwit flag, 1 vin, 1 vout, 4 lock time
@ -88,21 +88,21 @@ const (
var (
// MainnetGenesisBlockIdentifier is the genesis block for mainnet.
MainnetGenesisBlockIdentifier = &types.BlockIdentifier{
Hash: "9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463",
Hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
}
// MainnetParams are the params for mainnet.
MainnetParams = &LbryMainnetParams
MainnetParams = &chaincfg.MainNetParams
// MainnetCurrency is the *types.Currency for mainnet.
MainnetCurrency = &types.Currency{
Symbol: "LBC",
Symbol: "BTC",
Decimals: Decimals,
}
// TestnetGenesisBlockIdentifier is the genesis block for testnet.
TestnetGenesisBlockIdentifier = &types.BlockIdentifier{
Hash: "9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463",
Hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
}
// TestnetParams are the params for testnet.
@ -110,7 +110,7 @@ var (
// TestnetCurrency is the *types.Currency for testnet.
TestnetCurrency = &types.Currency{
Symbol: "tLBC",
Symbol: "tBTC",
Decimals: Decimals,
}
@ -135,7 +135,7 @@ var (
)
// ScriptPubKey is a script placed on the output operations
// of a lbry transaction that must be satisfied to spend
// of a Bitcoin transaction that must be satisfied to spend
// the output.
type ScriptPubKey struct {
ASM string `json:"asm"`
@ -146,14 +146,14 @@ type ScriptPubKey struct {
}
// ScriptSig is a script on the input operations of a
// lbry transaction that satisfies the ScriptPubKey
// Bitcoin transaction that satisfies the ScriptPubKey
// on an output being spent.
type ScriptSig struct {
ASM string `json:"asm"`
Hex string `json:"hex"`
}
// BlockchainInfo is information about the lbry network.
// BlockchainInfo is information about the Bitcoin network.
// This struct only contains the information necessary for
// this implementation.
type BlockchainInfo struct {
@ -176,7 +176,7 @@ type PeerInfo struct {
SyncedHeaders int64 `json:"synced_headers"`
}
// Block is a raw lbry block (with verbosity == 2).
// Block is a raw Bitcoin block (with verbosity == 2).
type Block struct {
Hash string `json:"hash"`
Height int64 `json:"height"`
@ -223,7 +223,7 @@ type BlockMetadata struct {
Difficulty float64 `json:"difficulty,omitempty"`
}
// Transaction is a raw lbry transaction.
// Transaction is a raw Bitcoin transaction.
type Transaction struct {
Hex string `json:"hex"`
Hash string `json:"txid"`
@ -260,7 +260,7 @@ type TransactionMetadata struct {
Weight int64 `json:"weight,omitempty"`
}
// Input is a raw input in a lbry transaction.
// Input is a raw input in a Bitcoin transaction.
type Input struct {
TxHash string `json:"txid"`
Vout int64 `json:"vout"`
@ -284,7 +284,7 @@ func (i Input) Metadata() (map[string]interface{}, error) {
return types.MarshalMap(m)
}
// Output is a raw output in a lbry transaction.
// Output is a raw output in a Bitcoin transaction.
type Output struct {
Value float64 `json:"value"`
Index int64 `json:"n"`
@ -301,7 +301,7 @@ func (o Output) Metadata() (map[string]interface{}, error) {
}
// OperationMetadata is a collection of useful
// metadata from lbry inputs and outputs.
// metadata from Bitcoin inputs and outputs.
type OperationMetadata struct {
// Coinbase Metadata
Coinbase string `json:"coinbase,omitempty"`
@ -499,7 +499,7 @@ func (r rawMempoolResponse) Err() error {
// CoinIdentifier converts a tx hash and vout into
// the canonical CoinIdentifier.Identifier used in
// rosetta-lbry.
// rosetta-bitcoin.
func CoinIdentifier(hash string, vout int64) string {
return fmt.Sprintf("%s:%d", hash, vout)
}

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package lbry
package bitcoin
import (
"fmt"

View file

@ -22,10 +22,10 @@ import (
"strconv"
"time"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/btcsuite/btcd/chaincfg"
"github.com/coinbase/rosetta-sdk-go/storage/encoder"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
)
@ -42,34 +42,34 @@ const (
// to make outbound connections.
Offline Mode = "OFFLINE"
// Mainnet is the lbry Mainnet.
// Mainnet is the Bitcoin Mainnet.
Mainnet string = "MAINNET"
// Testnet is lbry Testnet3.
// Testnet is Bitcoin Testnet3.
Testnet string = "TESTNET"
// mainnetConfigPath is the path of the lbry
// mainnetConfigPath is the path of the Bitcoin
// configuration file for mainnet.
mainnetConfigPath = "/app/lbry-mainnet.conf"
mainnetConfigPath = "/app/bitcoin-mainnet.conf"
// testnetConfigPath is the path of the lbry
// testnetConfigPath is the path of the Bitcoin
// configuration file for testnet.
testnetConfigPath = "/app/lbry-testnet.conf"
testnetConfigPath = "/app/bitcoin-testnet.conf"
// Zstandard compression dictionaries
transactionNamespace = "transaction"
testnetTransactionDictionary = "/app/testnet-transaction.zstd"
mainnetTransactionDictionary = "/app/mainnet-transaction.zstd"
mainnetRPCPort = 9245
testnetRPCPort = 19245
mainnetRPCPort = 8332
testnetRPCPort = 18332
// min prune depth is 288:
// https://github.com/lbry/lbry/blob/ad2952d17a2af419a04256b10b53c7377f826a27/src/validation.h#L84
// https://github.com/bitcoin/bitcoin/blob/ad2952d17a2af419a04256b10b53c7377f826a27/src/validation.h#L84
pruneDepth = int64(10000) //nolint
// min prune height (on mainnet):
// https://github.com/lbry/lbry/blob/62d137ac3b701aae36c1aa3aa93a83fd6357fde6/src/chainparams.cpp#L102
// https://github.com/bitcoin/bitcoin/blob/62d137ac3b701aae36c1aa3aa93a83fd6357fde6/src/chainparams.cpp#L102
minPruneHeight = int64(100000) //nolint
// attempt to prune once an hour
@ -79,8 +79,8 @@ const (
// persistent data.
DataDirectory = "/data"
LBRYcrdPath = "LBRYcrd"
indexerPath = "indexer"
bitcoindPath = "bitcoind"
indexerPath = "indexer"
// allFilePermissions specifies anyone can do anything
// to the file.
@ -120,8 +120,8 @@ type Configuration struct {
ConfigPath string
Pruning *PruningConfiguration
IndexerPath string
LBRYcrdPath string
Compressors []*encoder.CompressorEntry
BitcoindPath string
Compressors []*storage.CompressorEntry
}
// LoadConfiguration attempts to create a new Configuration
@ -143,9 +143,9 @@ func LoadConfiguration(baseDirectory string) (*Configuration, error) {
return nil, fmt.Errorf("%w: unable to create indexer path", err)
}
config.LBRYcrdPath = path.Join(baseDirectory, LBRYcrdPath)
if err := ensurePathExists(config.LBRYcrdPath); err != nil {
return nil, fmt.Errorf("%w: unable to create LBRYcrd path", err)
config.BitcoindPath = path.Join(baseDirectory, bitcoindPath)
if err := ensurePathExists(config.BitcoindPath); err != nil {
return nil, fmt.Errorf("%w: unable to create bitcoind path", err)
}
case Offline:
config.Mode = Offline
@ -159,15 +159,15 @@ func LoadConfiguration(baseDirectory string) (*Configuration, error) {
switch networkValue {
case Mainnet:
config.Network = &types.NetworkIdentifier{
Blockchain: lbry.Blockchain,
Network: lbry.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
Network: bitcoin.MainnetNetwork,
}
config.GenesisBlockIdentifier = lbry.MainnetGenesisBlockIdentifier
config.Params = lbry.MainnetParams
config.Currency = lbry.MainnetCurrency
config.GenesisBlockIdentifier = bitcoin.MainnetGenesisBlockIdentifier
config.Params = bitcoin.MainnetParams
config.Currency = bitcoin.MainnetCurrency
config.ConfigPath = mainnetConfigPath
config.RPCPort = mainnetRPCPort
config.Compressors = []*encoder.CompressorEntry{
config.Compressors = []*storage.CompressorEntry{
{
Namespace: transactionNamespace,
DictionaryPath: mainnetTransactionDictionary,
@ -175,15 +175,15 @@ func LoadConfiguration(baseDirectory string) (*Configuration, error) {
}
case Testnet:
config.Network = &types.NetworkIdentifier{
Blockchain: lbry.Blockchain,
Network: lbry.TestnetNetwork,
Blockchain: bitcoin.Blockchain,
Network: bitcoin.TestnetNetwork,
}
config.GenesisBlockIdentifier = lbry.TestnetGenesisBlockIdentifier
config.Params = lbry.TestnetParams
config.Currency = lbry.TestnetCurrency
config.GenesisBlockIdentifier = bitcoin.TestnetGenesisBlockIdentifier
config.Params = bitcoin.TestnetParams
config.Currency = bitcoin.TestnetCurrency
config.ConfigPath = testnetConfigPath
config.RPCPort = testnetRPCPort
config.Compressors = []*encoder.CompressorEntry{
config.Compressors = []*storage.CompressorEntry{
{
Namespace: transactionNamespace,
DictionaryPath: testnetTransactionDictionary,

View file

@ -20,9 +20,9 @@ import (
"path"
"testing"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-sdk-go/storage/encoder"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/coinbase/rosetta-sdk-go/utils"
"github.com/stretchr/testify/assert"
@ -56,12 +56,12 @@ func TestLoadConfiguration(t *testing.T) {
cfg: &Configuration{
Mode: Online,
Network: &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
},
Params: lbry.MainnetParams,
Currency: lbry.MainnetCurrency,
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
Params: bitcoin.MainnetParams,
Currency: bitcoin.MainnetCurrency,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
Port: 1000,
RPCPort: mainnetRPCPort,
ConfigPath: mainnetConfigPath,
@ -70,7 +70,7 @@ func TestLoadConfiguration(t *testing.T) {
Depth: pruneDepth,
MinHeight: minPruneHeight,
},
Compressors: []*encoder.CompressorEntry{
Compressors: []*storage.CompressorEntry{
{
Namespace: transactionNamespace,
DictionaryPath: mainnetTransactionDictionary,
@ -85,12 +85,12 @@ func TestLoadConfiguration(t *testing.T) {
cfg: &Configuration{
Mode: Online,
Network: &types.NetworkIdentifier{
Network: lbry.TestnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.TestnetNetwork,
Blockchain: bitcoin.Blockchain,
},
Params: lbry.TestnetParams,
Currency: lbry.TestnetCurrency,
GenesisBlockIdentifier: lbry.TestnetGenesisBlockIdentifier,
Params: bitcoin.TestnetParams,
Currency: bitcoin.TestnetCurrency,
GenesisBlockIdentifier: bitcoin.TestnetGenesisBlockIdentifier,
Port: 1000,
RPCPort: testnetRPCPort,
ConfigPath: testnetConfigPath,
@ -99,7 +99,7 @@ func TestLoadConfiguration(t *testing.T) {
Depth: pruneDepth,
MinHeight: minPruneHeight,
},
Compressors: []*encoder.CompressorEntry{
Compressors: []*storage.CompressorEntry{
{
Namespace: transactionNamespace,
DictionaryPath: testnetTransactionDictionary,
@ -143,7 +143,7 @@ func TestLoadConfiguration(t *testing.T) {
assert.Contains(t, err.Error(), test.err.Error())
} else {
test.cfg.IndexerPath = path.Join(newDir, "indexer")
test.cfg.lbrycrddPath = path.Join(newDir, "lbrycrdd")
test.cfg.BitcoindPath = path.Join(newDir, "bitcoind")
assert.Equal(t, test.cfg, cfg)
assert.NoError(t, err)
}

24
go.mod
View file

@ -1,32 +1,16 @@
module github.com/lbryio/rosetta-lbry
module github.com/coinbase/rosetta-bitcoin
go 1.13
require (
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a // indirect
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4 // indirect
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 // indirect
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 // indirect
github.com/alexkohler/nakedret v1.0.0 // indirect
github.com/btcsuite/btcd v0.21.0-beta
github.com/btcsuite/btcutil v1.0.2
github.com/coinbase/rosetta-sdk-go v0.6.3
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f
github.com/dgraph-io/badger/v2 v2.2007.2
github.com/golang/lint v0.0.0-20200302205851-738671d3881b // indirect
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/jgautheron/goconst v0.0.0-20201117150253-ccae5bf973f3 // indirect
github.com/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0 // indirect
github.com/mdempsky/unconvert v0.0.0-20200228143138-95ecdbfc0b5f // indirect
github.com/mibk/dupl v1.0.0 // indirect
github.com/opennota/check v0.0.0-20180911053232-0c771f5545ff // indirect
github.com/stretchr/testify v1.6.1
github.com/stripe/safesql v0.2.0 // indirect
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9 // indirect
github.com/walle/lll v1.0.1 // indirect
go.uber.org/zap v1.16.0
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/tools v0.0.0-20200904185747-39188db58858 // indirect
honnef.co/go/tools v0.0.1-2020.1.5 // indirect
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 // indirect
)

95
go.sum
View file

@ -1,10 +1,4 @@
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a h1:wFEQiK85fRsEVF0CRrPAos5LoAryUsIX1kPW/WrIqFw=
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a/go.mod h1:Sk40JNJmh0koZukOjJfaBNLZazbZthFfHnLHIcZNS6A=
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4 h1:bf5qocEKjrY58JO2GwywfLsb1199lIVs7qHkiplwHy0=
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4/go.mod h1:4o1i5aXtIF5tJFt3UD1knCVmWOXg7fLYdHVu6jeNcnM=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as=
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
@ -19,7 +13,6 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
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/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
@ -30,30 +23,21 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6 h1:1d9pzdbkth4D9AX6ndKSl7of3UTV0RYl3z64U2dXMGo=
github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 h1:YI/8G3uLbYyowJeOPVL6BMKe2wbL54h0FdEKmncU6lU=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214/go.mod h1:Ef5UOtJdJ5rVFObdOVsrNgKV/Wf4I+daTCSk8GTrHIk=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alexflint/go-arg v0.0.0-20160306200701-e71d6514f40a/go.mod h1:PHxo6ZWOLVMZZgWSAqBynb/KhIqoGO6WKwOVX7rM9dg=
github.com/alexkohler/nakedret v1.0.0 h1:S/bzOFhZHYUJp6qPmdXdFHS5nlWGFmLmoc8QOydvotE=
github.com/alexkohler/nakedret v1.0.0/go.mod h1:tfDQbtPt67HhBK/6P0yNktIX7peCxfOp0jO9007DrLE=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
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-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
@ -77,8 +61,8 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coinbase/rosetta-sdk-go v0.6.3 h1:PPj14tPJ7SFc8sY/hlwK8zddT7PKwWU2wicxyerDxlg=
github.com/coinbase/rosetta-sdk-go v0.6.3/go.mod h1:MvQfsL2KlJ5786OdDviRIJE3agui2YcvS1CaQPDl1Yo=
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f h1:aWkN9dKMkMMpZKX5QycpePxH176Fj2fNNC7jESfLZw0=
github.com/coinbase/rosetta-sdk-go v0.5.8-0.20201027222031-dd9e29377d5f/go.mod h1:l5aNeyeZKBkmWbVdkdLpWdToQ6hTwI7cZ1OU9cMbljY=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
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=
@ -112,11 +96,11 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
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=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.9.24 h1:6AK+ORt3EMDO+FTjzXy/AQwHMbu52J2nYHIjyQX9azQ=
github.com/ethereum/go-ethereum v1.9.24/go.mod h1:JIfVb6esrqALTExdz9hRYvrP0xBDf6wCncIu1hNwHpM=
github.com/ethereum/go-ethereum v1.9.23 h1:SIKhg/z4Q7AbvqcxuPYvMxf36che/Rq/Pp0IdYEkbtw=
github.com/ethereum/go-ethereum v1.9.23/go.mod h1:JIfVb6esrqALTExdz9hRYvrP0xBDf6wCncIu1hNwHpM=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -130,11 +114,8 @@ github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dT
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20200302205851-738671d3881b h1:BOvdkG2qv61G8DSvnEEgkjT/+tkEyHPPUfz0uGXXELY=
github.com/golang/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -162,11 +143,9 @@ github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
@ -182,16 +161,12 @@ github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jgautheron/goconst v0.0.0-20201117150253-ccae5bf973f3 h1:7nkB9fLPMwtn/R6qfPcHileL/x9ydlhw8XyDrLI1ZXg=
github.com/jgautheron/goconst v0.0.0-20201117150253-ccae5bf973f3/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
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/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
@ -201,37 +176,33 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77 h1:6xiz3+ZczT3M4+I+JLpcPGG1bQKm8067HktB17EDWEE=
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0 h1:+6XJvFZBYbNv/nSekNWFZyaGNMXcPnZ4n/HHoCXn+Ms=
github.com/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0/go.mod h1:3UB4iTzhLciyWcrrvXSkrtCIU+IJ5GCfEmnleHRsxL4=
github.com/mdempsky/unconvert v0.0.0-20200228143138-95ecdbfc0b5f h1:Kc3s6QFyh9DLgInXpWKuG+8I7R7lXbnP7mcoOVIt6KY=
github.com/mdempsky/unconvert v0.0.0-20200228143138-95ecdbfc0b5f/go.mod h1:AmCV4WB3cDMZqgPk+OUQKumliiQS4ZYsBt3AXekyuAU=
github.com/mibk/dupl v1.0.0 h1:aZc3jqrF9n0tUHwHt/+jsRxA8cRgA0Gdl56M7W7PoqE=
github.com/mibk/dupl v1.0.0/go.mod h1:pCr4pNxxIbFGvtyCOi0c7LVjmV6duhKWV+ex5vh38ME=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/neilotoole/errgroup v0.1.5 h1:DxEGoIfFm5ooGicidR+okiHjoOaGRKFaSxDPVZuuu2I=
github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@ -245,8 +216,6 @@ github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5
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/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opennota/check v0.0.0-20180911053232-0c771f5545ff h1:lRHufowVGvUvxGsPveAZOpSa/9T5Gpxg6d7UbHCA9MQ=
github.com/opennota/check v0.0.0-20180911053232-0c771f5545ff/go.mod h1:tydB+MZxWpY8M/NRu7jQhND/mXuLAPsKcSV6JkzofsA=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@ -265,19 +234,15 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
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/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/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=
@ -294,37 +259,26 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stripe/safesql v0.2.0 h1:xiefmCDd8c35PVSGrL2FhBiaKxviXnGziBDOpOejeBE=
github.com/stripe/safesql v0.2.0/go.mod h1:q7b2n0JmzM1mVGfcYpanfVb2j23cXZeWFxcILPn3JV4=
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws=
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI=
github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.1.2 h1:NC5okI+tQ8OG/oyzchvwXXxRxCV/FVdhODbPKkQ25jQ=
github.com/tidwall/sjson v1.1.2/go.mod h1:SEzaDwxiPzKzNfUEO4HbYF/m4UCSJDsGgNqsS1LvdoY=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9 h1:vY5WqiEon0ZSTGM3ayVVi+twaHKHDFUVloaQ/wug9/c=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vmihailenco/msgpack/v5 v5.1.0 h1:+od5YbEXxW95SPlW6beocmt8nOtlh83zqat5Ip9Hwdc=
github.com/vmihailenco/msgpack/v5 v5.1.0/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.8 h1:R2L6zPq1pWFumpeIxAJoeiov5GxyEZUq9NyS8eus/6s=
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.8/go.mod h1:HVxBVPUK/+fZMonk4bi1islLa8V3cfnBug0+4dykPzo=
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/walle/lll v1.0.1 h1:lbK8008fOXbQNYt8daBGUrjvElvlwlE7D7N/9dLP5IQ=
github.com/walle/lll v1.0.1/go.mod h1:lYxcXzoPhiAHR9eaq+Yv7RYg1nIipLloBCIfPUzfaWQ=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
@ -332,7 +286,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
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.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
@ -340,7 +293,6 @@ 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-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -359,7 +311,6 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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=
@ -370,7 +321,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b h1:GgiSbuUyC0BlbUmHQBgFqu32eiRR/CEYdjOjOd4zE6Y=
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 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -382,7 +332,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
@ -391,20 +340,18 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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=
@ -412,6 +359,7 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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=
@ -422,7 +370,6 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -444,12 +391,8 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa h1:5E4dL8+NgFOgjwbTKz+OOEGGhP+ectTmF842l6KjupQ=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200904185747-39188db58858 h1:xLt+iB5ksWcZVxqc+g9K41ZHy+6MKWfXCDsjSThnsPA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201030204249-4fc0492b8eca h1:KWfVIHfTHZf4IQhrLjrbG+kLyoSym7yYp0WgqtOVH9s=
golang.org/x/tools v0.0.0-20201030204249-4fc0492b8eca/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@ -505,7 +448,3 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k=
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 h1:kAREL6MPwpsk1/PQPFD3Eg7WAQR5mPTWZJaBiG5LDbY=
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc=

View file

@ -18,12 +18,11 @@ import (
"context"
"github.com/coinbase/rosetta-sdk-go/parser"
"github.com/coinbase/rosetta-sdk-go/storage/database"
"github.com/coinbase/rosetta-sdk-go/storage/modules"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
)
var _ modules.BalanceStorageHandler = (*BalanceStorageHandler)(nil)
var _ storage.BalanceStorageHandler = (*BalanceStorageHandler)(nil)
// BalanceStorageHandler implements storage.BalanceStorageHandler.
type BalanceStorageHandler struct{}
@ -45,21 +44,3 @@ func (h *BalanceStorageHandler) BlockRemoved(
) error {
return nil
}
// AccountsReconciled updates the total accounts reconciled by count.
func (h *BalanceStorageHandler) AccountsReconciled(
ctx context.Context,
dbTx database.Transaction,
count int,
) error {
return nil
}
// AccountsSeen updates the total accounts seen by count.
func (h *BalanceStorageHandler) AccountsSeen(
ctx context.Context,
dbTx database.Transaction,
count int,
) error {
return nil
}

View file

@ -16,21 +16,14 @@ package indexer
import (
"context"
"errors"
"math/big"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/parser"
"github.com/coinbase/rosetta-sdk-go/storage/database"
"github.com/coinbase/rosetta-sdk-go/storage/modules"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
)
var _ modules.BalanceStorageHelper = (*BalanceStorageHelper)(nil)
var (
errNotImplemented = errors.New("not implemented")
)
var _ storage.BalanceStorageHelper = (*BalanceStorageHelper)(nil)
// BalanceStorageHelper implements storage.BalanceStorageHelper.
type BalanceStorageHelper struct {
@ -67,19 +60,3 @@ func (h *BalanceStorageHelper) ExemptFunc() parser.ExemptOperation {
return false
}
}
// AccountsReconciled returns the total accounts reconciled by count.
func (h *BalanceStorageHelper) AccountsReconciled(
ctx context.Context,
dbTx database.Transaction,
) (*big.Int, error) {
return nil, errNotImplemented
}
// AccountsSeen returns the total accounts seen by count.
func (h *BalanceStorageHelper) AccountsSeen(
ctx context.Context,
dbTx database.Transaction,
) (*big.Int, error) {
return nil, errNotImplemented
}

View file

@ -17,23 +17,22 @@ package indexer
import (
"context"
"github.com/coinbase/rosetta-sdk-go/storage/database"
"github.com/coinbase/rosetta-sdk-go/storage/modules"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
)
var _ modules.CoinStorageHelper = (*CoinStorageHelper)(nil)
var _ storage.CoinStorageHelper = (*CoinStorageHelper)(nil)
// CoinStorageHelper implements storage.CoinStorageHelper.
type CoinStorageHelper struct {
b *modules.BlockStorage
b *storage.BlockStorage
}
// CurrentBlockIdentifier returns the current head block identifier
// and is used to comply with the CoinStorageHelper interface.
func (h *CoinStorageHelper) CurrentBlockIdentifier(
ctx context.Context,
transaction database.Transaction,
transaction storage.DatabaseTransaction,
) (*types.BlockIdentifier, error) {
return h.b.GetHeadBlockIdentifierTransactional(ctx, transaction)
}

View file

@ -18,17 +18,16 @@ import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/lbryio/rosetta-lbry/services"
"github.com/lbryio/rosetta-lbry/utils"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-bitcoin/services"
"github.com/coinbase/rosetta-bitcoin/utils"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/storage/database"
storageErrs "github.com/coinbase/rosetta-sdk-go/storage/errors"
"github.com/coinbase/rosetta-sdk-go/storage/modules"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/syncer"
"github.com/coinbase/rosetta-sdk-go/types"
sdkUtils "github.com/coinbase/rosetta-sdk-go/utils"
@ -54,7 +53,7 @@ const (
// estimate for pre-fetching blocks. In other words,
// this is the estimated memory overhead for each
// block fetched by the indexer.
sizeMultiplier = 5
sizeMultiplier = 15
// zeroValue is 0 as a string
zeroValue = "0"
@ -68,11 +67,11 @@ var (
type Client interface {
NetworkStatus(context.Context) (*types.NetworkStatusResponse, error)
PruneBlockchain(context.Context, int64) (int64, error)
GetRawBlock(context.Context, *types.PartialBlockIdentifier) (*lbry.Block, []string, error)
GetRawBlock(context.Context, *types.PartialBlockIdentifier) (*bitcoin.Block, []string, error)
ParseBlock(
context.Context,
*lbry.Block,
map[string]*types.AccountCoin,
*bitcoin.Block,
map[string]*storage.AccountCoin,
) (*types.Block, error)
}
@ -90,13 +89,15 @@ type Indexer struct {
client Client
asserter *asserter.Asserter
database database.Database
blockStorage *modules.BlockStorage
balanceStorage *modules.BalanceStorage
coinStorage *modules.CoinStorage
workers []modules.BlockWorker
database storage.Database
blockStorage *storage.BlockStorage
balanceStorage *storage.BalanceStorage
coinStorage *storage.CoinStorage
workers []storage.BlockWorker
waiter *waitTable
waiter *waitTable
coinMapMutex sync.RWMutex
coinMap map[string]*storage.AccountCoin
}
// CloseDatabase closes a storage.Database. This should be called
@ -127,11 +128,11 @@ func defaultBadgerOptions(
opts.ValueLogLoadingMode = options.MemoryMap
// Use an extended table size for larger commits.
opts.MaxTableSize = database.DefaultMaxTableSize
opts.MaxTableSize = storage.DefaultMaxTableSize
// Smaller value log sizes means smaller contiguous memory allocations
// and less RAM usage on cleanup.
opts.ValueLogFileSize = database.DefaultLogValueSize
opts.ValueLogFileSize = storage.DefaultLogValueSize
// To allow writes at a faster speed, we create a new memtable as soon as
// an existing memtable is filled up. This option determines how many
@ -166,11 +167,11 @@ func Initialize(
config *configuration.Configuration,
client Client,
) (*Indexer, error) {
localStore, err := database.NewBadgerDatabase(
localStore, err := storage.NewBadgerStorage(
ctx,
config.IndexerPath,
database.WithCompressorEntries(config.Compressors),
database.WithCustomSettings(defaultBadgerOptions(
storage.WithCompressorEntries(config.Compressors),
storage.WithCustomSettings(defaultBadgerOptions(
config.IndexerPath,
)),
)
@ -178,12 +179,12 @@ func Initialize(
return nil, fmt.Errorf("%w: unable to initialize storage", err)
}
blockStorage := modules.NewBlockStorage(localStore)
blockStorage := storage.NewBlockStorage(localStore)
asserter, err := asserter.NewClientWithOptions(
config.Network,
config.GenesisBlockIdentifier,
lbry.OperationTypes,
lbry.OperationStatuses,
bitcoin.OperationTypes,
bitcoin.OperationStatuses,
services.Errors,
nil,
)
@ -200,28 +201,31 @@ func Initialize(
blockStorage: blockStorage,
waiter: newWaitTable(),
asserter: asserter,
// TODO: only enable during fast catchup (i.e. far behind chain)
// Delete oldest entries whenever some size: https://stackoverflow.com/questions/60829460/is-there-a-way-to-delete-first-element-from-map
coinMap: map[string]*storage.AccountCoin{},
}
coinStorage := modules.NewCoinStorage(
coinStorage := storage.NewCoinStorage(
localStore,
&CoinStorageHelper{blockStorage},
asserter,
)
i.coinStorage = coinStorage
balanceStorage := modules.NewBalanceStorage(localStore)
balanceStorage := storage.NewBalanceStorage(localStore)
balanceStorage.Initialize(
&BalanceStorageHelper{asserter},
&BalanceStorageHandler{},
)
i.balanceStorage = balanceStorage
i.workers = []modules.BlockWorker{coinStorage, balanceStorage}
i.workers = []storage.BlockWorker{coinStorage, balanceStorage}
return i, nil
}
// waitForNode returns once lbrycrdd is ready to serve
// waitForNode returns once bitcoind is ready to serve
// block queries.
func (i *Indexer) waitForNode(ctx context.Context) error {
logger := utils.ExtractLogger(ctx, "indexer")
@ -231,15 +235,15 @@ func (i *Indexer) waitForNode(ctx context.Context) error {
return nil
}
logger.Infow("waiting for lbrycrdd...")
logger.Infow("waiting for bitcoind...")
if err := sdkUtils.ContextSleep(ctx, nodeWaitSleep); err != nil {
return err
}
}
}
// Sync attempts to index lbry blocks using
// the lbry.Client until stopped.
// Sync attempts to index Bitcoin blocks using
// the bitcoin.Client until stopped.
func (i *Indexer) Sync(ctx context.Context) error {
if err := i.waitForNode(ctx); err != nil {
return fmt.Errorf("%w: failed to wait for node", err)
@ -257,7 +261,7 @@ func (i *Indexer) Sync(ctx context.Context) error {
// If previously processed blocks exist in storage, they are fetched.
// Otherwise, none are provided to the cache (the syncer will not attempt
// a reorg if the cache is empty).
pastBlocks := i.blockStorage.CreateBlockCache(ctx, syncer.DefaultPastBlockLimit)
pastBlocks := i.blockStorage.CreateBlockCache(ctx)
syncer := syncer.New(
i.network,
@ -272,7 +276,7 @@ func (i *Indexer) Sync(ctx context.Context) error {
return syncer.Sync(ctx, startIndex, indexPlaceholder)
}
// Prune attempts to prune blocks in lbrycrdd every
// Prune attempts to prune blocks in bitcoind every
// pruneFrequency.
func (i *Indexer) Prune(ctx context.Context) error {
logger := utils.ExtractLogger(ctx, "pruner")
@ -291,25 +295,25 @@ func (i *Indexer) Prune(ctx context.Context) error {
continue
}
// Must meet pruning conditions in lbry core
// Must meet pruning conditions in bitcoin core
// Source:
// https://github.com/lbry/lbry/blob/a63a26f042134fa80356860c109edb25ac567552/src/rpc/blockchain.cpp#L953-L960
// https://github.com/bitcoin/bitcoin/blob/a63a26f042134fa80356860c109edb25ac567552/src/rpc/blockchain.cpp#L953-L960
pruneHeight := head.Index - i.pruningConfig.Depth
if pruneHeight <= i.pruningConfig.MinHeight {
logger.Infow("waiting to prune", "min prune height", i.pruningConfig.MinHeight)
continue
}
logger.Infow("attempting to prune lbrycrdd", "prune height", pruneHeight)
logger.Infow("attempting to prune bitcoind", "prune height", pruneHeight)
prunedHeight, err := i.client.PruneBlockchain(ctx, pruneHeight)
if err != nil {
logger.Warnw(
"unable to prune lbrycrdd",
"unable to prune bitcoind",
"prune height", pruneHeight,
"error", err,
)
} else {
logger.Infow("pruned lbrycrdd", "prune height", prunedHeight)
logger.Infow("pruned bitcoind", "prune height", prunedHeight)
}
}
}
@ -319,6 +323,30 @@ func (i *Indexer) Prune(ctx context.Context) error {
func (i *Indexer) BlockAdded(ctx context.Context, block *types.Block) error {
logger := utils.ExtractLogger(ctx, "indexer")
// Update cache
i.coinMapMutex.Lock()
for _, transaction := range block.Transactions {
for _, op := range transaction.Operations {
if op.CoinChange == nil || op.Amount == nil {
continue
}
if op.CoinChange.CoinAction == types.CoinSpent {
delete(i.coinMap, op.CoinChange.CoinIdentifier.Identifier)
continue
}
i.coinMap[op.CoinChange.CoinIdentifier.Identifier] = &storage.AccountCoin{
Account: op.Account,
Coin: &types.Coin{
CoinIdentifier: op.CoinChange.CoinIdentifier,
Amount: op.Amount,
},
}
}
}
i.coinMapMutex.Unlock()
err := i.blockStorage.AddBlock(ctx, block)
if err != nil {
return fmt.Errorf(
@ -418,20 +446,36 @@ func (i *Indexer) NetworkStatus(
return i.client.NetworkStatus(ctx)
}
func (i *Indexer) getCoin(
ctx context.Context,
dbTx storage.DatabaseTransaction,
coinIdentifier *types.CoinIdentifier,
) (*types.Coin, *types.AccountIdentifier, error) {
i.coinMapMutex.RLock()
m, ok := i.coinMap[coinIdentifier.Identifier]
i.coinMapMutex.RUnlock()
if ok {
return m.Coin, m.Account, nil
}
// THis is SUPER dangerous (won't survive restart)
return nil, nil, storage.ErrCoinNotFound
}
func (i *Indexer) findCoin(
ctx context.Context,
btcBlock *lbry.Block,
btcBlock *bitcoin.Block,
coinIdentifier string,
) (*types.Coin, *types.AccountIdentifier, error) {
for ctx.Err() == nil {
databaseTransaction := i.database.ReadTransaction(ctx)
databaseTransaction := i.database.NewDatabaseTransaction(ctx, false)
defer databaseTransaction.Discard(ctx)
coinHeadBlock, err := i.blockStorage.GetHeadBlockIdentifierTransactional(
ctx,
databaseTransaction,
)
if errors.Is(err, storageErrs.ErrHeadBlockNotFound) {
if errors.Is(err, storage.ErrHeadBlockNotFound) {
if err := sdkUtils.ContextSleep(ctx, missingTransactionDelay); err != nil {
return nil, nil, err
}
@ -446,7 +490,7 @@ func (i *Indexer) findCoin(
}
// Attempt to find coin
coin, owner, err := i.coinStorage.GetCoinTransactional(
coin, owner, err := i.getCoin(
ctx,
databaseTransaction,
&types.CoinIdentifier{
@ -457,7 +501,7 @@ func (i *Indexer) findCoin(
return coin, owner, nil
}
if !errors.Is(err, storageErrs.ErrCoinNotFound) {
if !errors.Is(err, storage.ErrCoinNotFound) {
return nil, nil, fmt.Errorf("%w: unable to lookup coin %s", err, coinIdentifier)
}
@ -482,7 +526,7 @@ func (i *Indexer) findCoin(
// Put Transaction in WaitTable if doesn't already exist (could be
// multiple listeners)
transactionHash := lbry.TransactionHash(coinIdentifier)
transactionHash := bitcoin.TransactionHash(coinIdentifier)
val, ok := i.waiter.Get(transactionHash, false)
if !ok {
val = &waitTableEntry{
@ -505,10 +549,10 @@ func (i *Indexer) findCoin(
func (i *Indexer) checkHeaderMatch(
ctx context.Context,
btcBlock *lbry.Block,
btcBlock *bitcoin.Block,
) error {
headBlock, err := i.blockStorage.GetHeadBlockIdentifier(ctx)
if err != nil && !errors.Is(err, storageErrs.ErrHeadBlockNotFound) {
if err != nil && !errors.Is(err, storage.ErrHeadBlockNotFound) {
return fmt.Errorf("%w: unable to lookup head block", err)
}
@ -525,14 +569,14 @@ func (i *Indexer) checkHeaderMatch(
func (i *Indexer) findCoins(
ctx context.Context,
btcBlock *lbry.Block,
btcBlock *bitcoin.Block,
coins []string,
) (map[string]*types.AccountCoin, error) {
) (map[string]*storage.AccountCoin, error) {
if err := i.checkHeaderMatch(ctx, btcBlock); err != nil {
return nil, fmt.Errorf("%w: check header match failed", err)
}
coinMap := map[string]*types.AccountCoin{}
coinMap := map[string]*storage.AccountCoin{}
remainingCoins := []string{}
for _, coinIdentifier := range coins {
coin, owner, err := i.findCoin(
@ -541,7 +585,7 @@ func (i *Indexer) findCoins(
coinIdentifier,
)
if err == nil {
coinMap[coinIdentifier] = &types.AccountCoin{
coinMap[coinIdentifier] = &storage.AccountCoin{
Account: owner,
Coin: coin,
}
@ -564,7 +608,7 @@ func (i *Indexer) findCoins(
shouldAbort := false
for _, coinIdentifier := range remainingCoins {
// Wait on Channel
txHash := lbry.TransactionHash(coinIdentifier)
txHash := bitcoin.TransactionHash(coinIdentifier)
entry, ok := i.waiter.Get(txHash, true)
if !ok {
return nil, fmt.Errorf("transaction %s not in waiter", txHash)
@ -626,7 +670,7 @@ func (i *Indexer) Block(
blockIdentifier *types.PartialBlockIdentifier,
) (*types.Block, error) {
// get raw block
var btcBlock *lbry.Block
var btcBlock *bitcoin.Block
var coins []string
var err error
@ -674,14 +718,14 @@ func (i *Indexer) Block(
func (i *Indexer) GetScriptPubKeys(
ctx context.Context,
coins []*types.Coin,
) ([]*lbry.ScriptPubKey, error) {
databaseTransaction := i.database.ReadTransaction(ctx)
) ([]*bitcoin.ScriptPubKey, error) {
databaseTransaction := i.database.NewDatabaseTransaction(ctx, false)
defer databaseTransaction.Discard(ctx)
scripts := make([]*lbry.ScriptPubKey, len(coins))
scripts := make([]*bitcoin.ScriptPubKey, len(coins))
for j, coin := range coins {
coinIdentifier := coin.CoinIdentifier
transactionHash, networkIndex, err := lbry.ParseCoinIdentifier(coinIdentifier)
transactionHash, networkIndex, err := bitcoin.ParseCoinIdentifier(coinIdentifier)
if err != nil {
return nil, fmt.Errorf("%w: unable to parse coin identifier", err)
}
@ -700,7 +744,7 @@ func (i *Indexer) GetScriptPubKeys(
}
for _, op := range transaction.Operations {
if op.Type != lbry.OutputOpType {
if op.Type != bitcoin.OutputOpType {
continue
}
@ -708,7 +752,7 @@ func (i *Indexer) GetScriptPubKeys(
continue
}
var opMetadata lbry.OperationMetadata
var opMetadata bitcoin.OperationMetadata
if err := types.UnmarshalMap(op.Metadata, &opMetadata); err != nil {
return nil, fmt.Errorf(
"%w: unable to unmarshal operation metadata %+v",
@ -788,7 +832,7 @@ func (i *Indexer) GetBalance(
currency *types.Currency,
blockIdentifier *types.PartialBlockIdentifier,
) (*types.Amount, *types.BlockIdentifier, error) {
dbTx := i.database.ReadTransaction(ctx)
dbTx := i.database.NewDatabaseTransaction(ctx, false)
defer dbTx.Discard(ctx)
blockResponse, err := i.blockStorage.GetBlockLazyTransactional(
@ -807,7 +851,7 @@ func (i *Indexer) GetBalance(
currency,
blockResponse.Block.BlockIdentifier.Index,
)
if errors.Is(err, storageErrs.ErrAccountMissing) {
if errors.Is(err, storage.ErrAccountMissing) {
return &types.Amount{
Value: zeroValue,
Currency: currency,

View file

@ -23,10 +23,11 @@ import (
"testing"
"time"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
mocks "github.com/lbryio/rosetta-lbry/mocks/indexer"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/indexer"
"github.com/coinbase/rosetta-sdk-go/storage"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/coinbase/rosetta-sdk-go/utils"
"github.com/stretchr/testify/assert"
@ -59,10 +60,10 @@ func TestIndexer_Pruning(t *testing.T) {
minHeight := int64(200)
cfg := &configuration.Configuration{
Network: &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
Pruning: &configuration.PruningConfiguration{
Frequency: 50 * time.Millisecond,
Depth: pruneDepth,
@ -74,7 +75,7 @@ func TestIndexer_Pruning(t *testing.T) {
i, err := Initialize(ctx, cancel, cfg, mockClient)
assert.NoError(t, err)
// Waiting for lbrycrdd...
// Waiting for bitcoind...
mockClient.On("NetworkStatus", ctx).Return(nil, errors.New("not ready")).Once()
mockClient.On("NetworkStatus", ctx).Return(&types.NetworkStatusResponse{}, nil).Once()
@ -83,7 +84,7 @@ func TestIndexer_Pruning(t *testing.T) {
CurrentBlockIdentifier: &types.BlockIdentifier{
Index: 1000,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
}, nil)
// Timeout on first request
@ -131,7 +132,7 @@ func TestIndexer_Pruning(t *testing.T) {
parentIdentifier.Hash = getBlockHash(0)
}
block := &lbry.Block{
block := &bitcoin.Block{
Hash: identifier.Hash,
Height: identifier.Index,
PreviousBlockHash: parentIdentifier.Hash,
@ -156,7 +157,7 @@ func TestIndexer_Pruning(t *testing.T) {
"ParseBlock",
mock.Anything,
block,
map[string]*types.AccountCoin{},
map[string]*storage.AccountCoin{},
).Return(
blockReturn,
nil,
@ -166,7 +167,7 @@ func TestIndexer_Pruning(t *testing.T) {
"ParseBlock",
mock.Anything,
block,
map[string]*types.AccountCoin{},
map[string]*storage.AccountCoin{},
).Return(
blockReturn,
nil,
@ -224,10 +225,10 @@ func TestIndexer_Transactions(t *testing.T) {
mockClient := &mocks.Client{}
cfg := &configuration.Configuration{
Network: &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
IndexerPath: newDir,
}
@ -239,13 +240,13 @@ func TestIndexer_Transactions(t *testing.T) {
CurrentBlockIdentifier: &types.BlockIdentifier{
Index: 1000,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
}, nil)
// Add blocks
waitForCheck := make(chan struct{})
type coinBankEntry struct {
Script *lbry.ScriptPubKey
Script *bitcoin.ScriptPubKey
Coin *types.Coin
Account *types.AccountIdentifier
}
@ -270,7 +271,7 @@ func TestIndexer_Transactions(t *testing.T) {
rawHash := fmt.Sprintf("block %d transaction %d", i, j)
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(rawHash)))
coinIdentifier := fmt.Sprintf("%s:%d", hash, index0)
scriptPubKey := &lbry.ScriptPubKey{
scriptPubKey := &bitcoin.ScriptPubKey{
ASM: coinIdentifier,
}
marshal, err := types.MarshalMap(scriptPubKey)
@ -285,14 +286,14 @@ func TestIndexer_Transactions(t *testing.T) {
Index: 0,
NetworkIndex: &index0,
},
Status: types.String(bitcoin.SuccessStatus),
Status: bitcoin.SuccessStatus,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: rawHash,
},
Amount: &types.Amount{
Value: fmt.Sprintf("%d", rand.Intn(1000)),
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
CoinChange: &types.CoinChange{
CoinAction: types.CoinCreated,
@ -322,7 +323,7 @@ func TestIndexer_Transactions(t *testing.T) {
transactions = append(transactions, tx)
}
block := &lbry.Block{
block := &bitcoin.Block{
Hash: identifier.Hash,
Height: identifier.Index,
PreviousBlockHash: parentIdentifier.Hash,
@ -355,9 +356,9 @@ func TestIndexer_Transactions(t *testing.T) {
Transactions: transactions,
}
coinMap := map[string]*types.AccountCoin{}
coinMap := map[string]*storage.AccountCoin{}
for _, coinIdentifier := range requiredCoins {
coinMap[coinIdentifier] = &types.AccountCoin{
coinMap[coinIdentifier] = &storage.AccountCoin{
Account: coinBank[coinIdentifier].Account,
Coin: coinBank[coinIdentifier].Coin,
}
@ -401,13 +402,13 @@ func TestIndexer_Transactions(t *testing.T) {
if currBlock.BlockIdentifier.Index == 1000 {
// Ensure ScriptPubKeys are accessible.
allCoins := []*types.Coin{}
expectedPubKeys := []*lbry.ScriptPubKey{}
expectedPubKeys := []*bitcoin.ScriptPubKey{}
for k, v := range coinBank {
allCoins = append(allCoins, &types.Coin{
CoinIdentifier: &types.CoinIdentifier{Identifier: k},
Amount: &types.Amount{
Value: fmt.Sprintf("-%s", v.Coin.Amount.Value),
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
})
expectedPubKeys = append(expectedPubKeys, v.Script)
@ -442,10 +443,10 @@ func TestIndexer_Reorg(t *testing.T) {
mockClient := &mocks.Client{}
cfg := &configuration.Configuration{
Network: &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
IndexerPath: newDir,
}
@ -457,13 +458,13 @@ func TestIndexer_Reorg(t *testing.T) {
CurrentBlockIdentifier: &types.BlockIdentifier{
Index: 1000,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
}, nil)
// Add blocks
waitForCheck := make(chan struct{})
type coinBankEntry struct {
Script *lbry.ScriptPubKey
Script *bitcoin.ScriptPubKey
Coin *types.Coin
Account *types.AccountIdentifier
}
@ -489,7 +490,7 @@ func TestIndexer_Reorg(t *testing.T) {
rawHash := fmt.Sprintf("block %d transaction %d", i, j)
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(rawHash)))
coinIdentifier := fmt.Sprintf("%s:%d", hash, index0)
scriptPubKey := &lbry.ScriptPubKey{
scriptPubKey := &bitcoin.ScriptPubKey{
ASM: coinIdentifier,
}
marshal, err := types.MarshalMap(scriptPubKey)
@ -504,14 +505,14 @@ func TestIndexer_Reorg(t *testing.T) {
Index: 0,
NetworkIndex: &index0,
},
Status: types.String(bitcoin.SuccessStatus),
Status: bitcoin.SuccessStatus,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: rawHash,
},
Amount: &types.Amount{
Value: fmt.Sprintf("%d", rand.Intn(1000)),
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
CoinChange: &types.CoinChange{
CoinAction: types.CoinCreated,
@ -540,7 +541,7 @@ func TestIndexer_Reorg(t *testing.T) {
transactions = append(transactions, tx)
}
block := &lbry.Block{
block := &bitcoin.Block{
Hash: identifier.Hash,
Height: identifier.Index,
PreviousBlockHash: parentIdentifier.Hash,
@ -601,9 +602,9 @@ func TestIndexer_Reorg(t *testing.T) {
Transactions: transactions,
}
coinMap := map[string]*types.AccountCoin{}
coinMap := map[string]*storage.AccountCoin{}
for _, coinIdentifier := range requiredCoins {
coinMap[coinIdentifier] = &types.AccountCoin{
coinMap[coinIdentifier] = &storage.AccountCoin{
Account: coinBank[coinIdentifier].Account,
Coin: coinBank[coinIdentifier].Coin,
}
@ -684,10 +685,10 @@ func TestIndexer_HeaderReorg(t *testing.T) {
mockClient := &mocks.Client{}
cfg := &configuration.Configuration{
Network: &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
IndexerPath: newDir,
}
@ -699,7 +700,7 @@ func TestIndexer_HeaderReorg(t *testing.T) {
CurrentBlockIdentifier: &types.BlockIdentifier{
Index: 1000,
},
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
}, nil)
// Add blocks
@ -719,7 +720,7 @@ func TestIndexer_HeaderReorg(t *testing.T) {
}
transactions := []*types.Transaction{}
block := &lbry.Block{
block := &bitcoin.Block{
Hash: identifier.Hash,
Height: identifier.Index,
PreviousBlockHash: parentIdentifier.Hash,
@ -746,7 +747,7 @@ func TestIndexer_HeaderReorg(t *testing.T) {
mock.Anything,
&types.PartialBlockIdentifier{Index: &identifier.Index},
).Return(
&lbry.Block{
&bitcoin.Block{
Hash: identifier.Hash,
Height: identifier.Index,
PreviousBlockHash: "blah",
@ -773,7 +774,7 @@ func TestIndexer_HeaderReorg(t *testing.T) {
Transactions: transactions,
}
coinMap := map[string]*types.AccountCoin{}
coinMap := map[string]*storage.AccountCoin{}
if i == 400 {
mockClient.On(
"ParseBlock",

View file

@ -20,7 +20,7 @@ set -e
usage() {
this=$1
cat <<EOF
$this: download pre-compiled Docker images for lbryio/rosetta-lbry
$this: download pre-compiled Docker images for coinbase/rosetta-bitcoin
Usage: $this [-d]
-d turns on debug logging
@ -44,8 +44,8 @@ execute() {
log_info "downloading image into ${tmpdir}"
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}" "" "1"
docker load --input "${tmpdir}/${TARBALL}"
docker tag "rosetta-lbry:${TAG}" "rosetta-lbry:latest"
log_info "loaded rosetta-lbry:${TAG} and tagged as rosetta-lbry:latest"
docker tag "rosetta-bitcoin:${TAG}" "rosetta-bitcoin:latest"
log_info "loaded rosetta-bitcoin:${TAG} and tagged as rosetta-bitcoin:latest"
rm -rf "${tmpdir}"
log_info "removed temporary directory ${tmpdir}"
}
@ -196,10 +196,10 @@ End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
BINARY=rosetta-lbry
BINARY=rosetta-bitcoin
FORMAT=tar.gz
OWNER=coinbase
REPO="rosetta-lbry"
REPO="rosetta-bitcoin"
PREFIX="$OWNER/$REPO"
# use in logging routines

View file

@ -1,172 +0,0 @@
package lbry
import (
"math/big"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)
func init() {
if err := chaincfg.Register(&LbryMainnetParams); err != nil {
panic(err)
}
if err := chaincfg.Register(&LbryTestnetParams); err != nil {
panic(err)
}
}
var (
bigOne = big.NewInt(1)
mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne)
)
const (
// DeploymentTestDummy ...
DeploymentTestDummy = iota
// DeploymentCSV ...
DeploymentCSV
// DeploymentSegwit ...
DeploymentSegwit
// DefinedDeployments ...
DefinedDeployments
)
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
// the main network, regression test network, and test network (version 3).
var genesisCoinbaseTx = wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0xffffffff,
},
SignatureScript: []byte{
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x17,
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x12a05f200,
PkScript: []byte{ // ToDo
0x76, 0xa9, 0x14, 0x34, 0x59, 0x91, 0xdb, 0xf5,
0x7b, 0xfb, 0x01, 0x4b, 0x87, 0x00, 0x6a, 0xcd,
0xfa, 0xfb, 0xfc, 0x5f, 0xe8, 0x29, 0x2f, 0x88,
0xac,
},
},
},
LockTime: 0,
}
// https://github.com/lbryio/lbrycrd/blob/master/src/chainparams.cpp#L19
var genesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0xcc, 0x59, 0xe5, 0x9f, 0xf9, 0x7a, 0xc0, 0x92,
0xb5, 0x5e, 0x42, 0x3a, 0xa5, 0x49, 0x51, 0x51,
0xed, 0x6f, 0xb8, 0x05, 0x70, 0xa5, 0xbb, 0x78,
0xcd, 0x5b, 0xd1, 0xc3, 0x82, 0x1c, 0x21, 0xb8,
})
var genesisBlock = wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
MerkleRoot: genesisMerkleRoot, // b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc
Timestamp: time.Unix(1446058291, 0), // Wednesday, October 28, 2015 6:51:31 PM GMT
Bits: 0x1f00ffff,
Nonce: 1287,
},
Transactions: []*wire.MsgTx{&genesisCoinbaseTx},
}
var genesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x63, 0xf4, 0x34, 0x6a, 0x4d, 0xb3, 0x4f, 0xdf,
0xce, 0x29, 0xa7, 0x0f, 0x5e, 0x8d, 0x11, 0xf0,
0x65, 0xf6, 0xb9, 0x16, 0x02, 0xb7, 0x03, 0x6c,
0x7f, 0x22, 0xf3, 0xa0, 0x3b, 0x28, 0x89, 0x9c,
})
func newHashFromStr(hexStr string) *chainhash.Hash {
hash, err := chainhash.NewHashFromStr(hexStr)
if err != nil {
panic(err)
}
return hash
}
// MainNetParams returns the chain configuration for mainnet
var LbryMainnetParams = chaincfg.Params{
Name: "mainnet",
Net: 0xfae4aaf1,
DefaultPort: "9246",
// Chain parameters
GenesisBlock: &genesisBlock,
GenesisHash: &genesisHash,
// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "lbc",
// Address encoding magics
PubKeyHashAddrID: 85,
ScriptHashAddrID: 122,
PrivateKeyID: 28,
WitnessPubKeyHashAddrID: 0x06, // starts with p2
WitnessScriptHashAddrID: 0x0A, // starts with 7Xh
BIP0034Height: 1,
BIP0065Height: 200000,
BIP0066Height: 200000,
// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv
HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub
// BIP44 coin type used in the hierarchical deterministic path for
// address generation.
HDCoinType: 0x8c,
}
// TestnetParams returns the chain configuration for testnet
var LbryTestnetParams = chaincfg.Params{
Name: "testnet",
Net: 0xfae4aae1,
DefaultPort: "19246",
// Chain parameters
GenesisBlock: &genesisBlock,
GenesisHash: &genesisHash,
// Human-readable part for Bech32 encoded segwit addresses, as defined in
// BIP 173.
Bech32HRPSegwit: "tlbc", // always bc for main net
// Address encoding magics
PubKeyHashAddrID: 111,
ScriptHashAddrID: 196,
PrivateKeyID: 239,
WitnessPubKeyHashAddrID: 0x06, // starts with p2
WitnessScriptHashAddrID: 0x0A, // starts with 7Xh
BIP0034Height: 1,
BIP0065Height: 200000,
BIP0066Height: 200000,
// BIP32 hierarchical deterministic extended key magics
HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with xprv
HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with xpub
// BIP44 coin type used in the hierarchical deterministic path for
// address generation.
HDCoinType: 0x8c,
}

27
main.go
View file

@ -24,11 +24,11 @@ import (
"syscall"
"time"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/indexer"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/lbryio/rosetta-lbry/services"
"github.com/lbryio/rosetta-lbry/utils"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-bitcoin/indexer"
"github.com/coinbase/rosetta-bitcoin/services"
"github.com/coinbase/rosetta-bitcoin/utils"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/server"
@ -79,15 +79,15 @@ func startOnlineDependencies(
cancel context.CancelFunc,
cfg *configuration.Configuration,
g *errgroup.Group,
) (*lbry.Client, *indexer.Indexer, error) {
client := lbry.NewClient(
lbry.LocalhostURL(cfg.RPCPort),
) (*bitcoin.Client, *indexer.Indexer, error) {
client := bitcoin.NewClient(
bitcoin.LocalhostURL(cfg.RPCPort),
cfg.GenesisBlockIdentifier,
cfg.Currency,
)
g.Go(func() error {
return lbry.Startlbrycrdd(ctx, cfg.ConfigPath, g)
return bitcoin.StartBitcoind(ctx, cfg.ConfigPath, g)
})
i, err := indexer.Initialize(
@ -142,7 +142,7 @@ func main() {
})
var i *indexer.Indexer
var client *lbry.Client
var client *bitcoin.Client
if cfg.Mode == configuration.Online {
client, i, err = startOnlineDependencies(ctx, cancel, cfg, g)
if err != nil {
@ -153,11 +153,10 @@ func main() {
// The asserter automatically rejects incorrectly formatted
// requests.
asserter, err := asserter.NewServer(
lbry.OperationTypes,
bitcoin.OperationTypes,
services.HistoricalBalanceLookup,
[]*types.NetworkIdentifier{cfg.Network},
nil,
services.MempoolCoins,
)
if err != nil {
logger.Fatalw("unable to create new server asserter", "error", err)
@ -197,10 +196,10 @@ func main() {
}
if signalReceived {
logger.Fatalw("rosetta-lbry halted")
logger.Fatalw("rosetta-bitcoin halted")
}
if err != nil {
logger.Fatalw("rosetta-lbry sync failed", "error", err)
logger.Fatalw("rosetta-bitcoin sync failed", "error", err)
}
}

View file

@ -5,10 +5,12 @@ package indexer
import (
context "context"
lbry "github.com/lbryio/rosetta-lbry/lbry"
bitcoin "github.com/coinbase/rosetta-bitcoin/bitcoin"
mock "github.com/stretchr/testify/mock"
storage "github.com/coinbase/rosetta-sdk-go/storage"
types "github.com/coinbase/rosetta-sdk-go/types"
)
@ -18,15 +20,15 @@ type Client struct {
}
// GetRawBlock provides a mock function with given fields: _a0, _a1
func (_m *Client) GetRawBlock(_a0 context.Context, _a1 *types.PartialBlockIdentifier) (*lbry.Block, []string, error) {
func (_m *Client) GetRawBlock(_a0 context.Context, _a1 *types.PartialBlockIdentifier) (*bitcoin.Block, []string, error) {
ret := _m.Called(_a0, _a1)
var r0 *lbry.Block
if rf, ok := ret.Get(0).(func(context.Context, *types.PartialBlockIdentifier) *lbry.Block); ok {
var r0 *bitcoin.Block
if rf, ok := ret.Get(0).(func(context.Context, *types.PartialBlockIdentifier) *bitcoin.Block); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*lbry.Block)
r0 = ret.Get(0).(*bitcoin.Block)
}
}
@ -73,11 +75,11 @@ func (_m *Client) NetworkStatus(_a0 context.Context) (*types.NetworkStatusRespon
}
// ParseBlock provides a mock function with given fields: _a0, _a1, _a2
func (_m *Client) ParseBlock(_a0 context.Context, _a1 *bitcoin.Block, _a2 map[string]*types.AccountCoin) (*types.Block, error) {
func (_m *Client) ParseBlock(_a0 context.Context, _a1 *bitcoin.Block, _a2 map[string]*storage.AccountCoin) (*types.Block, error) {
ret := _m.Called(_a0, _a1, _a2)
var r0 *types.Block
if rf, ok := ret.Get(0).(func(context.Context, *bitcoin.Block, map[string]*types.AccountCoin) *types.Block); ok {
if rf, ok := ret.Get(0).(func(context.Context, *bitcoin.Block, map[string]*storage.AccountCoin) *types.Block); ok {
r0 = rf(_a0, _a1, _a2)
} else {
if ret.Get(0) != nil {
@ -86,7 +88,7 @@ func (_m *Client) ParseBlock(_a0 context.Context, _a1 *bitcoin.Block, _a2 map[st
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *bitcoin.Block, map[string]*types.AccountCoin) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, *bitcoin.Block, map[string]*storage.AccountCoin) error); ok {
r1 = rf(_a0, _a1, _a2)
} else {
r1 = ret.Error(1)

View file

@ -5,7 +5,7 @@ package services
import (
context "context"
lbry "github.com/lbryio/rosetta-lbry/lbry"
bitcoin "github.com/coinbase/rosetta-bitcoin/bitcoin"
mock "github.com/stretchr/testify/mock"
@ -128,15 +128,15 @@ func (_m *Indexer) GetCoins(_a0 context.Context, _a1 *types.AccountIdentifier) (
}
// GetScriptPubKeys provides a mock function with given fields: _a0, _a1
func (_m *Indexer) GetScriptPubKeys(_a0 context.Context, _a1 []*types.Coin) ([]*lbry.ScriptPubKey, error) {
func (_m *Indexer) GetScriptPubKeys(_a0 context.Context, _a1 []*types.Coin) ([]*bitcoin.ScriptPubKey, error) {
ret := _m.Called(_a0, _a1)
var r0 []*lbry.ScriptPubKey
if rf, ok := ret.Get(0).(func(context.Context, []*types.Coin) []*lbry.ScriptPubKey); ok {
var r0 []*bitcoin.ScriptPubKey
if rf, ok := ret.Get(0).(func(context.Context, []*types.Coin) []*bitcoin.ScriptPubKey); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*lbry.ScriptPubKey)
r0 = ret.Get(0).([]*bitcoin.ScriptPubKey)
}
}

View file

@ -1,22 +1,40 @@
{
"network": {
"blockchain": "lbry",
"network": "Mainnet"
},
"data_directory": "cli-data",
"http_timeout": 300,
"max_retries": 5,
"max_online_connections": 1000,
"tip_delay": 1800,
"compression_disabled": true,
"memory_limit_disabled": true,
"data": {
"initial_balance_fetch_disabled": true,
"end_conditions": {
"reconciliation_coverage": {
"coverage": 0.95,
"from_tip": true
}
"network": {
"blockchain": "Bitcoin",
"network": "Mainnet"
},
"data_directory": "cli-data",
"http_timeout": 300,
"max_retries": 5,
"retry_elapsed_time": 0,
"max_online_connections": 1000,
"max_sync_concurrency": 0,
"tip_delay": 1800,
"log_configuration": false,
"compression_disabled": true,
"memory_limit_disabled": true,
"data": {
"active_reconciliation_concurrency": 0,
"inactive_reconciliation_concurrency": 0,
"inactive_reconciliation_frequency": 0,
"log_blocks": false,
"log_transactions": false,
"log_balance_changes": false,
"log_reconciliations": false,
"ignore_reconciliation_error": false,
"exempt_accounts": "",
"bootstrap_balances": "",
"interesting_accounts": "",
"reconciliation_disabled": false,
"inactive_discrepency_search_disabled": false,
"balance_tracking_disabled": false,
"coin_tracking_disabled": false,
"end_conditions": {
"reconciliation_coverage": {
"coverage": 0.95,
"from_tip": true
}
}
},
"results_output_file": ""
}
}

View file

@ -1,6 +1,6 @@
request_funds(1){
find_account{
currency = {"symbol":"tLBC", "decimals":8};
currency = {"symbol":"tBTC", "decimals":8};
random_account = find_balance({
"minimum_balance":{
"value": "0",
@ -27,7 +27,7 @@ request_funds(1){
create_account(1){
create{
network = {"network":"Testnet3", "blockchain":"LBRY"};
network = {"network":"Testnet3", "blockchain":"Bitcoin"};
key = generate_key({"curve_type": "secp256k1"});
account = derive({
"network_identifier": {{network}},
@ -44,8 +44,8 @@ create_account(1){
transfer(10){
transfer_dry_run{
transfer_dry_run.network = {"network":"Testnet3", "blockchain":"LBRY"};
currency = {"symbol":"tLBC", "decimals":8};
transfer_dry_run.network = {"network":"Testnet3", "blockchain":"Bitcoin"};
currency = {"symbol":"tBTC", "decimals":8};
// We set the max_fee_amount to know how much buffer we should
// leave for fee payment when selecting a sender account.
@ -165,10 +165,10 @@ transfer(10){
return_funds(10){
transfer_dry_run{
transfer_dry_run.network = {"network":"Testnet3", "blockchain":"LBRY"};
currency = {"symbol":"tLBC", "decimals":8};
transfer_dry_run.network = {"network":"Testnet3", "blockchain":"Bitcoin"};
currency = {"symbol":"tBTC", "decimals":8};
// We look for a sender that is able to pay the
// We look for a sender that is able to pay the
// max_fee_amount + min_utxo size (reserved_amount is max_fee_amount + min_utxo size).
max_fee_amount = "1200";
reserved_amount = "1800";

View file

@ -1,29 +1,55 @@
{
"network": {
"blockchain": "lbry",
"network": "Testnet3"
},
"data_directory": "cli-data",
"http_timeout": 300,
"max_retries": 5,
"max_online_connections": 1000,
"tip_delay": 1800,
"memory_limit_disabled": true,
"compression_disabled": true,
"construction": {
"constructor_dsl_file": "lbry.ros",
"end_conditions": {
"create_account": 10,
"transfer": 10
}
},
"data": {
"initial_balance_fetch_disabled": true,
"end_conditions": {
"reconciliation_coverage": {
"coverage": 0.95,
"from_tip": true
}
}
"network": {
"blockchain": "Bitcoin",
"network": "Testnet3"
},
"data_directory": "cli-data",
"http_timeout": 300,
"max_retries": 5,
"retry_elapsed_time": 0,
"max_online_connections": 1000,
"max_sync_concurrency": 0,
"tip_delay": 1800,
"log_configuration": false,
"compression_disabled": true,
"memory_limit_disabled": true,
"construction": {
"max_offline_connections": 0,
"stale_depth": 0,
"broadcast_limit": 0,
"ignore_broadcast_failures": false,
"clear_broadcasts": false,
"broadcast_behind_tip": false,
"block_broadcast_limit": 0,
"rebroadcast_all": false,
"constructor_dsl_file": "bitcoin.ros",
"end_conditions": {
"create_account": 10,
"transfer": 10
}
},
"data": {
"active_reconciliation_concurrency": 0,
"inactive_reconciliation_concurrency": 0,
"inactive_reconciliation_frequency": 0,
"log_blocks": false,
"log_transactions": false,
"log_balance_changes": false,
"log_reconciliations": false,
"ignore_reconciliation_error": false,
"exempt_accounts": "",
"bootstrap_balances": "",
"interesting_accounts": "",
"reconciliation_disabled": false,
"inactive_discrepency_search_disabled": false,
"balance_tracking_disabled": false,
"coin_tracking_disabled": false,
"end_conditions": {
"reconciliation_coverage": {
"coverage": 0.95,
"from_tip": true
}
},
"results_output_file": ""
}
}

View file

@ -17,7 +17,7 @@ package services
import (
"context"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
@ -49,7 +49,34 @@ func (s *AccountAPIService) AccountBalance(
return nil, wrapErr(ErrUnavailableOffline, nil)
}
// TODO: filter balances by request currencies
// If we are fetching the current balance,
// return all coins for an address and calculate
// the balance from those coins.
if request.BlockIdentifier == nil {
coins, block, err := s.i.GetCoins(ctx, request.AccountIdentifier)
if err != nil {
return nil, wrapErr(ErrUnableToGetCoins, err)
}
balance := "0"
for _, coin := range coins {
balance, err = types.AddValues(balance, coin.Amount.Value)
if err != nil {
return nil, wrapErr(ErrUnableToParseIntermediateResult, err)
}
}
return &types.AccountBalanceResponse{
BlockIdentifier: block,
Coins: coins,
Balances: []*types.Amount{
{
Value: balance,
Currency: s.config.Currency,
},
},
}, nil
}
// If we are fetching a historical balance,
// use balance storage and don't return coins.
@ -70,31 +97,3 @@ func (s *AccountAPIService) AccountBalance(
},
}, nil
}
// AccountCoins implements /account/coins.
func (s *AccountAPIService) AccountCoins(
ctx context.Context,
request *types.AccountCoinsRequest,
) (*types.AccountCoinsResponse, *types.Error) {
if s.config.Mode != configuration.Online {
return nil, wrapErr(ErrUnavailableOffline, nil)
}
// TODO: filter coins by request currencies
// TODO: support include_mempool query
// https://github.com/coinbase/rosetta-sdk-go-bitcoin/issues/36#issuecomment-724992022
// Once mempoolcoins are supported also change the bool service/types.go:MempoolCoins to true
coins, block, err := s.i.GetCoins(ctx, request.AccountIdentifier)
if err != nil {
return nil, wrapErr(ErrUnableToGetCoins, err)
}
result := &types.AccountCoinsResponse{
BlockIdentifier: block,
Coins: coins,
}
return result, nil
}

View file

@ -18,9 +18,9 @@ import (
"context"
"testing"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
mocks "github.com/lbryio/rosetta-lbry/mocks/services"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/services"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"
@ -38,103 +38,13 @@ func TestAccountBalance_Offline(t *testing.T) {
assert.Nil(t, bal)
assert.Equal(t, ErrUnavailableOffline.Code, err.Code)
coins, err := servicer.AccountCoins(ctx, &types.AccountCoinsRequest{})
assert.Nil(t, coins)
assert.Equal(t, ErrUnavailableOffline.Code, err.Code)
mockIndexer.AssertExpectations(t)
}
func TestAccountBalance_Online_Current(t *testing.T) {
cfg := &configuration.Configuration{
Mode: configuration.Online,
Currency: lbry.MainnetCurrency,
}
mockIndexer := &mocks.Indexer{}
servicer := NewAccountAPIService(cfg, mockIndexer)
ctx := context.Background()
account := &types.AccountIdentifier{
Address: "hello",
}
block := &types.BlockIdentifier{
Index: 1000,
Hash: "block 1000",
}
amount := &types.Amount{
Value: "25",
Currency: lbry.MainnetCurrency,
}
mockIndexer.On(
"GetBalance",
ctx,
account,
bitcoin.MainnetCurrency,
(*types.PartialBlockIdentifier)(nil),
).Return(amount, block, nil).Once()
bal, err := servicer.AccountBalance(ctx, &types.AccountBalanceRequest{
AccountIdentifier: account,
})
assert.Nil(t, err)
assert.Equal(t, &types.AccountBalanceResponse{
BlockIdentifier: block,
Balances: []*types.Amount{
amount,
},
}, bal)
mockIndexer.AssertExpectations(t)
}
func TestAccountBalance_Online_Historical(t *testing.T) {
cfg := &configuration.Configuration{
Mode: configuration.Online,
Currency: lbry.MainnetCurrency,
}
mockIndexer := &mocks.Indexer{}
servicer := NewAccountAPIService(cfg, mockIndexer)
ctx := context.Background()
account := &types.AccountIdentifier{
Address: "hello",
}
block := &types.BlockIdentifier{
Index: 1000,
Hash: "block 1000",
}
partialBlock := &types.PartialBlockIdentifier{
Index: &block.Index,
}
amount := &types.Amount{
Value: "25",
Currency: lbry.MainnetCurrency,
}
mockIndexer.On(
"GetBalance",
ctx,
account,
lbry.MainnetCurrency,
partialBlock,
).Return(amount, block, nil).Once()
bal, err := servicer.AccountBalance(ctx, &types.AccountBalanceRequest{
AccountIdentifier: account,
BlockIdentifier: partialBlock,
})
assert.Nil(t, err)
assert.Equal(t, &types.AccountBalanceResponse{
BlockIdentifier: block,
Balances: []*types.Amount{
amount,
},
}, bal)
mockIndexer.AssertExpectations(t)
}
func TestAccountCoins_Online(t *testing.T) {
cfg := &configuration.Configuration{
Mode: configuration.Online,
Currency: lbry.MainnetCurrency,
Currency: bitcoin.MainnetCurrency,
}
mockIndexer := &mocks.Indexer{}
servicer := NewAccountAPIService(cfg, mockIndexer)
@ -176,14 +86,65 @@ func TestAccountCoins_Online(t *testing.T) {
}
mockIndexer.On("GetCoins", ctx, account).Return(coins, block, nil).Once()
bal, err := servicer.AccountCoins(ctx, &types.AccountCoinsRequest{
bal, err := servicer.AccountBalance(ctx, &types.AccountBalanceRequest{
AccountIdentifier: account,
})
assert.Nil(t, err)
assert.Equal(t, &types.AccountCoinsResponse{
assert.Equal(t, &types.AccountBalanceResponse{
BlockIdentifier: block,
Coins: coins,
Balances: []*types.Amount{
{
Value: "25",
Currency: bitcoin.MainnetCurrency,
},
},
}, bal)
mockIndexer.AssertExpectations(t)
}
func TestAccountBalance_Online_Historical(t *testing.T) {
cfg := &configuration.Configuration{
Mode: configuration.Online,
Currency: bitcoin.MainnetCurrency,
}
mockIndexer := &mocks.Indexer{}
servicer := NewAccountAPIService(cfg, mockIndexer)
ctx := context.Background()
account := &types.AccountIdentifier{
Address: "hello",
}
block := &types.BlockIdentifier{
Index: 1000,
Hash: "block 1000",
}
partialBlock := &types.PartialBlockIdentifier{
Index: &block.Index,
}
amount := &types.Amount{
Value: "25",
Currency: bitcoin.MainnetCurrency,
}
mockIndexer.On(
"GetBalance",
ctx,
account,
bitcoin.MainnetCurrency,
partialBlock,
).Return(amount, block, nil).Once()
bal, err := servicer.AccountBalance(ctx, &types.AccountBalanceRequest{
AccountIdentifier: account,
BlockIdentifier: partialBlock,
})
assert.Nil(t, err)
assert.Equal(t, &types.AccountBalanceResponse{
BlockIdentifier: block,
Balances: []*types.Amount{
amount,
},
}, bal)
mockIndexer.AssertExpectations(t)

View file

@ -17,7 +17,7 @@ package services
import (
"context"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"

View file

@ -19,8 +19,8 @@ import (
"fmt"
"testing"
"github.com/lbryio/rosetta-lbry/configuration"
mocks "github.com/lbryio/rosetta-lbry/mocks/services"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/services"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"

View file

@ -24,8 +24,8 @@ import (
"math/big"
"strconv"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
@ -37,7 +37,7 @@ import (
)
const (
// bytesInKB is the number of bytes in a KB. In lbry, this is
// bytesInKB is the number of bytes in a KB. In Bitcoin, this is
// considered to be 1000.
bytesInKb = float64(1000) // nolint:gomnd
@ -88,22 +88,22 @@ func (s *ConstructionAPIService) ConstructionDerive(
// estimateSize returns the estimated size of a transaction in vBytes.
func (s *ConstructionAPIService) estimateSize(operations []*types.Operation) float64 {
size := lbry.TransactionOverhead
size := bitcoin.TransactionOverhead
for _, operation := range operations {
switch operation.Type {
case lbry.InputOpType:
size += lbry.InputSize
case lbry.OutputOpType:
size += lbry.OutputOverhead
case bitcoin.InputOpType:
size += bitcoin.InputSize
case bitcoin.OutputOpType:
size += bitcoin.OutputOverhead
addr, err := btcutil.DecodeAddress(operation.Account.Address, s.config.Params)
if err != nil {
size += lbry.P2PKHScriptPubkeySize
size += bitcoin.P2PKHScriptPubkeySize
continue
}
script, err := txscript.PayToAddrScript(addr)
if err != nil {
size += lbry.P2PKHScriptPubkeySize
size += bitcoin.P2PKHScriptPubkeySize
continue
}
@ -123,7 +123,7 @@ func (s *ConstructionAPIService) ConstructionPreprocess(
descriptions := &parser.Descriptions{
OperationDescriptions: []*parser.OperationDescription{
{
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
@ -192,12 +192,12 @@ func (s *ConstructionAPIService) ConstructionMetadata(
if options.FeeMultiplier != nil {
feePerKB *= *options.FeeMultiplier
}
if feePerKB < lbry.MinFeeRate {
feePerKB = lbry.MinFeeRate
if feePerKB < bitcoin.MinFeeRate {
feePerKB = bitcoin.MinFeeRate
}
// Calculated the estimated fee in Satoshis
satoshisPerB := (feePerKB * float64(lbry.SatoshisInlbry)) / bytesInKb
satoshisPerB := (feePerKB * float64(bitcoin.SatoshisInBitcoin)) / bytesInKb
estimatedFee := satoshisPerB * options.EstimatedSize
suggestedFee := &types.Amount{
Value: fmt.Sprintf("%d", int64(estimatedFee)),
@ -228,7 +228,7 @@ func (s *ConstructionAPIService) ConstructionPayloads(
descriptions := &parser.Descriptions{
OperationDescriptions: []*parser.OperationDescription{
{
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
@ -241,7 +241,7 @@ func (s *ConstructionAPIService) ConstructionPayloads(
CoinAction: types.CoinSpent,
},
{
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &parser.AccountDescription{
Exists: true,
},
@ -267,7 +267,7 @@ func (s *ConstructionAPIService) ConstructionPayloads(
return nil, wrapErr(ErrUnclearIntent, errors.New("CoinChange cannot be nil"))
}
transactionHash, index, err := lbry.ParseCoinIdentifier(input.CoinChange.CoinIdentifier)
transactionHash, index, err := bitcoin.ParseCoinIdentifier(input.CoinChange.CoinIdentifier)
if err != nil {
return nil, wrapErr(ErrInvalidCoin, err)
}
@ -324,7 +324,7 @@ func (s *ConstructionAPIService) ConstructionPayloads(
return nil, wrapErr(ErrUnableToDecodeScriptPubKey, err)
}
class, _, err := lbry.ParseSingleAddress(s.config.Params, script)
class, _, err := bitcoin.ParseSingleAddress(s.config.Params, script)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
@ -413,7 +413,7 @@ func (s *ConstructionAPIService) ConstructionCombine(
if err := json.Unmarshal(decodedTx, &unsigned); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal lbry transaction", err),
fmt.Errorf("%w unable to unmarshal bitcoin transaction", err),
)
}
@ -439,7 +439,7 @@ func (s *ConstructionAPIService) ConstructionCombine(
return nil, wrapErr(ErrUnableToDecodeScriptPubKey, err)
}
class, _, err := lbry.ParseSingleAddress(s.config.Params, decodedScript)
class, _, err := bitcoin.ParseSingleAddress(s.config.Params, decodedScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
@ -499,7 +499,7 @@ func (s *ConstructionAPIService) ConstructionHash(
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed lbry transaction", err),
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
@ -541,7 +541,7 @@ func (s *ConstructionAPIService) parseUnsignedTransaction(
if err := json.Unmarshal(decodedTx, &unsigned); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal lbry transaction", err),
fmt.Errorf("%w unable to unmarshal bitcoin transaction", err),
)
}
@ -569,7 +569,7 @@ func (s *ConstructionAPIService) parseUnsignedTransaction(
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: unsigned.InputAddresses[i],
},
@ -592,7 +592,7 @@ func (s *ConstructionAPIService) parseUnsignedTransaction(
for i, output := range tx.TxOut {
networkIndex := int64(i)
_, addr, err := lbry.ParseSingleAddress(s.config.Params, output.PkScript)
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, output.PkScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
@ -605,7 +605,7 @@ func (s *ConstructionAPIService) parseUnsignedTransaction(
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: addr.String(),
},
@ -637,7 +637,7 @@ func (s *ConstructionAPIService) parseSignedTransaction(
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed lbry transaction", err),
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
@ -668,7 +668,7 @@ func (s *ConstructionAPIService) parseSignedTransaction(
)
}
_, addr, err := lbry.ParseSingleAddress(s.config.Params, pkScript.Script())
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, pkScript.Script())
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
@ -685,7 +685,7 @@ func (s *ConstructionAPIService) parseSignedTransaction(
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: addr.EncodeAddress(),
},
@ -708,7 +708,7 @@ func (s *ConstructionAPIService) parseSignedTransaction(
for i, output := range tx.TxOut {
networkIndex := int64(i)
_, addr, err := lbry.ParseSingleAddress(s.config.Params, output.PkScript)
_, addr, err := bitcoin.ParseSingleAddress(s.config.Params, output.PkScript)
if err != nil {
return nil, wrapErr(
ErrUnableToDecodeAddress,
@ -721,7 +721,7 @@ func (s *ConstructionAPIService) parseSignedTransaction(
Index: int64(len(ops)),
NetworkIndex: &networkIndex,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: addr.String(),
},
@ -771,13 +771,13 @@ func (s *ConstructionAPIService) ConstructionSubmit(
if err := json.Unmarshal(decodedTx, &signed); err != nil {
return nil, wrapErr(
ErrUnableToParseIntermediateResult,
fmt.Errorf("%w unable to unmarshal signed lbry transaction", err),
fmt.Errorf("%w unable to unmarshal signed bitcoin transaction", err),
)
}
txHash, err := s.client.SendRawTransaction(ctx, signed.Transaction)
if err != nil {
return nil, wrapErr(ErrLbrycrdd, fmt.Errorf("%w unable to submit transaction", err))
return nil, wrapErr(ErrBitcoind, fmt.Errorf("%w unable to submit transaction", err))
}
return &types.TransactionIdentifierResponse{

View file

@ -19,9 +19,9 @@ import (
"encoding/hex"
"testing"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
mocks "github.com/lbryio/rosetta-lbry/mocks/services"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/services"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"
@ -47,15 +47,15 @@ func forceMarshalMap(t *testing.T, i interface{}) map[string]interface{} {
func TestConstructionService(t *testing.T) {
networkIdentifier = &types.NetworkIdentifier{
Network: lbry.TestnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.TestnetNetwork,
Blockchain: bitcoin.Blockchain,
}
cfg := &configuration.Configuration{
Mode: configuration.Online,
Network: networkIdentifier,
Params: lbry.TestnetParams,
Currency: lbry.TestnetCurrency,
Params: bitcoin.TestnetParams,
Currency: bitcoin.TestnetCurrency,
}
mockIndexer := &mocks.Indexer{}
@ -88,13 +88,13 @@ func TestConstructionService(t *testing.T) {
OperationIdentifier: &types.OperationIdentifier{
Index: 0,
},
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: "tb1qcqzmqzkswhfshzd8kedhmtvgnxax48z4fklhvm",
},
Amount: &types.Amount{
Value: "-1000000",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
CoinChange: &types.CoinChange{
CoinIdentifier: &types.CoinIdentifier{
@ -107,26 +107,26 @@ func TestConstructionService(t *testing.T) {
OperationIdentifier: &types.OperationIdentifier{
Index: 1,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: "tb1q3r8xjf0c2yazxnq9ey3wayelygfjxpfqjvj5v7",
},
Amount: &types.Amount{
Value: "954843",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
{
OperationIdentifier: &types.OperationIdentifier{
Index: 2,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: "tb1qjsrjvk2ug872pdypp33fjxke62y7awpgefr6ua",
},
Amount: &types.Amount{
Value: "44657",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
}
@ -148,7 +148,7 @@ func TestConstructionService(t *testing.T) {
},
Amount: &types.Amount{
Value: "-1000000",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
},
@ -161,7 +161,7 @@ func TestConstructionService(t *testing.T) {
// Test Metadata
metadata := &constructionMetadata{
ScriptPubKeys: []*lbry.ScriptPubKey{
ScriptPubKeys: []*bitcoin.ScriptPubKey{
{
ASM: "0 c005b00ad075d30b89a7b65b7dad8899ba6a9c55",
Hex: "0014c005b00ad075d30b89a7b65b7dad8899ba6a9c55",
@ -188,7 +188,7 @@ func TestConstructionService(t *testing.T) {
ctx,
defaultConfirmationTarget,
).Return(
lbry.MinFeeRate*10,
bitcoin.MinFeeRate*10,
nil,
).Once()
metadataResponse, err := servicer.ConstructionMetadata(ctx, &types.ConstructionMetadataRequest{
@ -201,7 +201,7 @@ func TestConstructionService(t *testing.T) {
SuggestedFee: []*types.Amount{
{
Value: "1065", // 1,420 * 0.75
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
}, metadataResponse)
@ -220,7 +220,7 @@ func TestConstructionService(t *testing.T) {
ctx,
defaultConfirmationTarget,
).Return(
lbry.MinFeeRate,
bitcoin.MinFeeRate,
nil,
).Once()
metadataResponse, err = servicer.ConstructionMetadata(ctx, &types.ConstructionMetadataRequest{
@ -233,7 +233,7 @@ func TestConstructionService(t *testing.T) {
SuggestedFee: []*types.Amount{
{
Value: "142", // we don't go below minimum fee rate
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
}, metadataResponse)
@ -253,13 +253,13 @@ func TestConstructionService(t *testing.T) {
Index: 0,
NetworkIndex: &val0,
},
Type: lbry.InputOpType,
Type: bitcoin.InputOpType,
Account: &types.AccountIdentifier{
Address: "tb1qcqzmqzkswhfshzd8kedhmtvgnxax48z4fklhvm",
},
Amount: &types.Amount{
Value: "-1000000",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
CoinChange: &types.CoinChange{
CoinIdentifier: &types.CoinIdentifier{
@ -273,13 +273,13 @@ func TestConstructionService(t *testing.T) {
Index: 1,
NetworkIndex: &val0,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: "tb1q3r8xjf0c2yazxnq9ey3wayelygfjxpfqjvj5v7",
},
Amount: &types.Amount{
Value: "954843",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
{
@ -287,13 +287,13 @@ func TestConstructionService(t *testing.T) {
Index: 2,
NetworkIndex: &val1,
},
Type: lbry.OutputOpType,
Type: bitcoin.OutputOpType,
Account: &types.AccountIdentifier{
Address: "tb1qjsrjvk2ug872pdypp33fjxke62y7awpgefr6ua",
},
Amount: &types.Amount{
Value: "44657",
Currency: lbry.TestnetCurrency,
Currency: bitcoin.TestnetCurrency,
},
},
}
@ -376,11 +376,11 @@ func TestConstructionService(t *testing.T) {
}, hashResponse)
// Test Submit
lbryTransaction := "010000000001017f9cf50b02dd5258f80cd5c3437302e027dd1336172a20cdc80305c5a55741b10100000000ffffffff02db910e000000000016001488ce6925f8513a234c05c922ee933f221323052071ae000000000000160014940726595c41fca0b4810c62991ad9d289eeb82802473044022025876ec8b9f51d343a5a56ac549c0c828005ef45ebe9da166db645c09157223f02204cd08b7278a8889a81135915bce10d1ef3bb92b217f81a0de7e79ffb3dfd6ac501210325c9a4252789b31dbb3454ec647e9516e7c596bcde2bd5da71a60fab8644e43800000000" // nolint
bitcoinTransaction := "010000000001017f9cf50b02dd5258f80cd5c3437302e027dd1336172a20cdc80305c5a55741b10100000000ffffffff02db910e000000000016001488ce6925f8513a234c05c922ee933f221323052071ae000000000000160014940726595c41fca0b4810c62991ad9d289eeb82802473044022025876ec8b9f51d343a5a56ac549c0c828005ef45ebe9da166db645c09157223f02204cd08b7278a8889a81135915bce10d1ef3bb92b217f81a0de7e79ffb3dfd6ac501210325c9a4252789b31dbb3454ec647e9516e7c596bcde2bd5da71a60fab8644e43800000000" // nolint
mockClient.On(
"SendRawTransaction",
ctx,
lbryTransaction,
bitcoinTransaction,
).Return(
transactionIdentifier.Hash,
nil,

View file

@ -25,7 +25,7 @@ var (
ErrUnimplemented,
ErrUnavailableOffline,
ErrNotReady,
ErrLbrycrdd,
ErrBitcoind,
ErrBlockNotFound,
ErrUnableToDerive,
ErrUnclearIntent,
@ -57,19 +57,19 @@ var (
Message: "Endpoint unavailable offline",
}
// ErrNotReady is returned when Lbrycrdd is not
// ErrNotReady is returned when bitcoind is not
// yet ready to serve queries.
ErrNotReady = &types.Error{
Code: 2, //nolint
Message: "Lbrycrdd is not ready",
Message: "Bitcoind is not ready",
Retriable: true,
}
// ErrLbrycrdd is returned when lbrycrdd
// ErrBitcoind is returned when bitcoind
// errors on a request.
ErrLbrycrdd = &types.Error{
ErrBitcoind = &types.Error{
Code: 3, //nolint
Message: "LBRYcrdd error",
Message: "Bitcoind error",
}
// ErrBlockNotFound is returned when a block
@ -104,7 +104,7 @@ var (
// ErrScriptPubKeysMissing is returned when
// the indexer cannot populate the required
// lbry.ScriptPubKeys to construct a transaction.
// bitcoin.ScriptPubKeys to construct a transaction.
ErrScriptPubKeysMissing = &types.Error{
Code: 8, //nolint
Message: "Missing ScriptPubKeys",
@ -125,7 +125,7 @@ var (
}
// ErrUnableToDecodeScriptPubKey is returned when a
// lbry.ScriptPubKey cannot be parsed during construction.
// bitcoin.ScriptPubKey cannot be parsed during construction.
ErrUnableToDecodeScriptPubKey = &types.Error{
Code: 11, //nolint
Message: "Unable to decode ScriptPubKey",

View file

@ -17,7 +17,7 @@ package services
import (
"context"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
@ -51,7 +51,7 @@ func (s *MempoolAPIService) Mempool(
mempoolTransactions, err := s.client.RawMempool(ctx)
if err != nil {
return nil, wrapErr(ErrLbrycrdd, err)
return nil, wrapErr(ErrBitcoind, err)
}
transactionIdentifiers := make([]*types.TransactionIdentifier, len(mempoolTransactions))

View file

@ -18,8 +18,8 @@ import (
"context"
"testing"
"github.com/lbryio/rosetta-lbry/configuration"
mocks "github.com/lbryio/rosetta-lbry/mocks/services"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/services"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"

View file

@ -17,8 +17,8 @@ package services
import (
"context"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
@ -67,7 +67,7 @@ func (s *NetworkAPIService) NetworkStatus(
peers, err := s.client.GetPeers(ctx)
if err != nil {
return nil, wrapErr(ErrLbrycrdd, err)
return nil, wrapErr(ErrBitcoind, err)
}
cachedBlockResponse, err := s.i.GetBlockLazy(ctx, nil)
@ -92,14 +92,13 @@ func (s *NetworkAPIService) NetworkOptions(
Version: &types.Version{
RosettaVersion: types.RosettaAPIVersion,
NodeVersion: NodeVersion,
MiddlewareVersion: types.String(MiddlewareVersion),
MiddlewareVersion: &MiddlewareVersion,
},
Allow: &types.Allow{
OperationStatuses: lbry.OperationStatuses,
OperationTypes: lbry.OperationTypes,
OperationStatuses: bitcoin.OperationStatuses,
OperationTypes: bitcoin.OperationTypes,
Errors: Errors,
HistoricalBalanceLookup: HistoricalBalanceLookup,
MempoolCoins: MempoolCoins,
},
}, nil
}

View file

@ -18,16 +18,16 @@ import (
"context"
"testing"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/lbryio/rosetta-lbry/lbry"
mocks "github.com/lbryio/rosetta-lbry/mocks/services"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-bitcoin/configuration"
mocks "github.com/coinbase/rosetta-bitcoin/mocks/services"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/stretchr/testify/assert"
)
var (
middlewareVersion = "0.0.8"
middlewareVersion = "0.0.5"
defaultNetworkOptions = &types.NetworkOptionsResponse{
Version: &types.Version{
RosettaVersion: types.RosettaAPIVersion,
@ -35,16 +35,16 @@ var (
MiddlewareVersion: &middlewareVersion,
},
Allow: &types.Allow{
OperationStatuses: lbry.OperationStatuses,
OperationTypes: lbry.OperationTypes,
OperationStatuses: bitcoin.OperationStatuses,
OperationTypes: bitcoin.OperationTypes,
Errors: Errors,
HistoricalBalanceLookup: HistoricalBalanceLookup,
},
}
networkIdentifier = &types.NetworkIdentifier{
Network: lbry.MainnetNetwork,
Blockchain: lbry.Blockchain,
Network: bitcoin.MainnetNetwork,
Blockchain: bitcoin.Blockchain,
}
)
@ -81,7 +81,7 @@ func TestNetworkEndpoints_Online(t *testing.T) {
cfg := &configuration.Configuration{
Mode: configuration.Online,
Network: networkIdentifier,
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
}
mockIndexer := &mocks.Indexer{}
mockClient := &mocks.Client{}
@ -104,7 +104,7 @@ func TestNetworkEndpoints_Online(t *testing.T) {
}
mockClient.On("GetPeers", ctx).Return([]*types.Peer{
{
PeerID: "34.231.101.5:9246",
PeerID: "77.93.223.9:8333",
},
}, nil)
mockIndexer.On(
@ -118,11 +118,11 @@ func TestNetworkEndpoints_Online(t *testing.T) {
networkStatus, err := servicer.NetworkStatus(ctx, nil)
assert.Nil(t, err)
assert.Equal(t, &types.NetworkStatusResponse{
GenesisBlockIdentifier: lbry.MainnetGenesisBlockIdentifier,
GenesisBlockIdentifier: bitcoin.MainnetGenesisBlockIdentifier,
CurrentBlockIdentifier: blockResponse.Block.BlockIdentifier,
Peers: []*types.Peer{
{
PeerID: "34.231.101.5:9246",
PeerID: "77.93.223.9:8333",
},
},
}, networkStatus)

View file

@ -17,7 +17,7 @@ package services
import (
"net/http"
"github.com/lbryio/rosetta-lbry/configuration"
"github.com/coinbase/rosetta-bitcoin/configuration"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/server"

View file

@ -17,35 +17,32 @@ package services
import (
"context"
"github.com/lbryio/rosetta-lbry/lbry"
"github.com/coinbase/rosetta-bitcoin/bitcoin"
"github.com/coinbase/rosetta-sdk-go/types"
)
const (
// NodeVersion is the version of
// lbry core we are using.
NodeVersion = "0.19.1.2"
// bitcoin core we are using.
NodeVersion = "0.20.1"
// HistoricalBalanceLookup indicates
// that historical balance lookup is supported.
HistoricalBalanceLookup = true
// MempoolCoins indicates that
// including mempool coins in the /account/coins
// response is not supported.
MempoolCoins = false
// inlineFetchLimit is the maximum number
// of transactions to fetch inline.
inlineFetchLimit = 100
)
var (
// MiddlewareVersion is the version
// of rosetta-lbry. We set this as a
// of rosetta-bitcoin. We set this as a
// variable instead of a constant because
// we typically need the pointer of this
// value.
MiddlewareVersion = "0.0.8"
MiddlewareVersion = "0.0.5"
)
// Client is used by the servicers to get Peer information
@ -75,7 +72,7 @@ type Indexer interface {
GetScriptPubKeys(
context.Context,
[]*types.Coin,
) ([]*lbry.ScriptPubKey, error)
) ([]*bitcoin.ScriptPubKey, error)
GetBalance(
context.Context,
*types.AccountIdentifier,
@ -85,10 +82,10 @@ type Indexer interface {
}
type unsignedTransaction struct {
Transaction string `json:"transaction"`
ScriptPubKeys []*lbry.ScriptPubKey `json:"scriptPubKeys"`
InputAmounts []string `json:"input_amounts"`
InputAddresses []string `json:"input_addresses"`
Transaction string `json:"transaction"`
ScriptPubKeys []*bitcoin.ScriptPubKey `json:"scriptPubKeys"`
InputAmounts []string `json:"input_amounts"`
InputAddresses []string `json:"input_addresses"`
}
type preprocessOptions struct {
@ -98,7 +95,7 @@ type preprocessOptions struct {
}
type constructionMetadata struct {
ScriptPubKeys []*lbry.ScriptPubKey `json:"script_pub_keys"`
ScriptPubKeys []*bitcoin.ScriptPubKey `json:"script_pub_keys"`
}
type signedTransaction struct {
@ -109,5 +106,5 @@ type signedTransaction struct {
// ParseOperationMetadata is returned from
// ConstructionParse.
type ParseOperationMetadata struct {
ScriptPubKey *lbry.ScriptPubKey `json:"scriptPubKey"`
ScriptPubKey *bitcoin.ScriptPubKey `json:"scriptPubKey"`
}