diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..2b4c3323 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @loongy @jazg diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..7d204511 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Docker Build +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v2 + with: + push: true + tags: renbot/multichain:latest + secrets: | + GIT_AUTH_TOKEN=${{ secrets.PERSONAL_ACCESS_TOKEN }} + build-args: | + GITHUB_TOKEN=${{ secrets.PERSONAL_ACCESS_TOKEN }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..f7bf5c43 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,969 @@ +name: go +on: [push] +jobs: + test-solana: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - uses: actions/setup-go@v2 + with: + go-version: "1.15.5" + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Setup environment for Solana tests + run: | + sh -c "$(curl -sSfL https://release.solana.com/v1.7.0/install)" + cd $GITHUB_WORKSPACE + export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" + echo ${{ secrets.SOLANA_KEY }} > ~/.config/solana/id.json + docker run -d -h 0.0.0.0 -p 8899:8899 -p 8900:8900 renbot/ren-solana:latest + + - name: Sleep until the node is up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests for Solana + run: | + export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" + cd $GITHUB_WORKSPACE/chain/solana + go test -timeout 100s + + test-filecoin: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker run -d -p 1234:1234 -h 0.0.0.0 \ + --name infra_filecoin_1 rohitnarurkar/multichain_filecoin:latest + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '10m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -fil=true \ + -timeout 1500s + + test-zcash: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker-compose up -d --build zcash + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -zec=true \ + -timeout 1500s + + test-terra: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker-compose up -d --build terra + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -luna=true \ + -timeout 1500s + + test-dogecoin: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker-compose up -d --build dogecoin + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -doge=true \ + -timeout 1500s + + test-btc-bch: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 + SOLANA_FFI_COMMIT: 1d5f4405dd2fb89c96cde28db33051a6e992d607 + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Configure git for Private Modules + env: + TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: git config --global url."https://roynalnaruto:${TOKEN}@github.com".insteadOf "https://github.com" + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev hwloc libhwloc-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker-compose up -d --build \ + bitcoin \ + bitcoincash + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -btc=true \ + -bch=true \ + -timeout 1500s + + test-harmony: + runs-on: ubuntu-latest + env: + FILECOIN_FFI_COMMIT: a62d00da59d1b0fb35f3a4ae854efa9441af892d + SOLANA_FFI_COMMIT: f6521b8a1af44f4d468bc8e7e67ba3766a5602ef + steps: + - name: Set up Go 1.13 + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v1 + with: + submodules: recursive + + - name: Caching modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }} + + - name: Cache extern dependencies (FFI) + id: cache-extern + uses: actions/cache@v2 + env: + cache-name: cache-externs + with: + path: .extern + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.FILECOIN_FFI_COMMIT }}-${{ env.SOLANA_FFI_COMMIT }} + + # Remove apt repos that are known to break from time to time + # See https://github.com/actions/virtual-environments/issues/323 + - name: Install dependency packages + run: | + for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done + sudo apt-get update + sudo apt-get install -y build-essential + sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config libudev-dev + sudo apt install libgmp-dev libssl-dev make gcc g++ + curl https://sh.rustup.rs -sSf | sh -s -- -y + source $HOME/.cargo/env + + - name: Get dependencies + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go get -u github.com/onsi/ginkgo/ginkgo + go get -u github.com/onsi/gomega/... + go get -u golang.org/x/lint/golint + go get -u github.com/loongy/covermerge + go get -u github.com/mattn/goveralls + go get -u github.com/xlab/c-for-go + + - name: Install dependencies (Filecoin FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE + mkdir .extern && cd .extern + git clone https://github.com/filecoin-project/filecoin-ffi.git + cd filecoin-ffi + git checkout ${{ env.FILECOIN_FFI_COMMIT }} + make + + - name: Install dependencies (Solana FFI) + if: steps.cache-extern.outputs.cache-hit != 'true' + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + cd $GITHUB_WORKSPACE/.extern + git clone https://github.com/renproject/solana-ffi.git + cd solana-ffi + git checkout ${{ env.SOLANA_FFI_COMMIT }} + make clean + make + + - name: Install dependencies (Harmony) + run: | + cd $GITHUB_WORKSPACE/chain/harmony + git clone https://github.com/harmony-one/bls.git + git clone https://github.com/harmony-one/mcl.git + cd $GITHUB_WORKSPACE/chain/harmony/bls + make + cd $GITHUB_WORKSPACE + export CGO_CFLAGS="-I$GITHUB_WORKSPACE/chain/harmony/bls/include -I$GITHUB_WORKSPACE/chain/harmony/mcl/include -I/usr/local/opt/openssl/include" + export CGO_LDFLAGS="-L$GITHUB_WORKSPACE/chain/harmony/bls/lib -L/usr/local/opt/openssl/lib" + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/chain/harmony/bls/lib:$GITHUB_WORKSPACE/chain/harmony/mcl/lib:/usr/local/opt/openssl/lib + export LIBRARY_PATH=$LD_LIBRARY_PATH + export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH + export GO111MODULE=on + + - name: Run vetting + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source $HOME/.cargo/env + go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./.extern/filecoin-ffi + go mod edit -replace=github.com/renproject/solana-ffi=./.extern/solana-ffi + go vet ./... + + - name: Run linting + run: | + cd $GITHUB_WORKSPACE + export PATH=$PATH:$(go env GOPATH)/bin + go get -u golang.org/x/lint/golint + golint $(go list ./... | grep -v filecoin-ffi) + + - name: Run multichain infrastructure + run: | + cd $GITHUB_WORKSPACE/infra + source .env + docker-compose up -d --build \ + harmony + + - name: Sleep until the nodes are up + uses: jakejarvis/wait-action@master + with: + time: '1m' + + - name: Check on docker containers + run: docker ps -a + + - name: Run tests and report test coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + export PATH=$PATH:$(go env GOPATH)/bin + source ./infra/.env + cd $GITHUB_WORKSPACE + go test \ + -one=true \ + -timeout 1500s diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..fba83b42 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "chain/filecoin/filecoin-ffi"] + path = chain/filecoin/filecoin-ffi + url = https://github.com/filecoin-project/filecoin-ffi +[submodule "chain/solana/solana-ffi"] + path = chain/solana/solana-ffi + url = https://github.com/renproject/solana-ffi diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..2c3985da --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +FROM golang + +# doing all updates and installs in a single step and removing the apt cache helps reduce the image size +RUN apt-get update && \ + apt-get install -y \ + mesa-opencl-icd \ + ocl-icd-opencl-dev \ + libssl-dev \ + libudev-dev \ + hwloc \ + libhwloc-dev \ + gcc \ + git \ + bzr \ + jq \ + pkg-config \ + curl \ + wget && \ + apt-get upgrade -y && \ + rm -rf /var/lib/apt/lists/* + +ENV GO111MODULE=on +ENV GOPROXY=https://proxy.golang.org + +ARG GITHUB_TOKEN +RUN git config --global url."https://${GITHUB_TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/" +ENV GOPRIVATE="github.com/renproject/ren-solana,github.com/renproject/solana-ffi" + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +RUN mkdir -p $(go env GOPATH) +WORKDIR $GOPATH +RUN mkdir -p src/github.com/filecoin-project +WORKDIR $GOPATH/src/github.com/filecoin-project +RUN git clone https://github.com/filecoin-project/filecoin-ffi +WORKDIR $GOPATH/src/github.com/filecoin-project/filecoin-ffi +RUN git checkout 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 +RUN make +RUN go install + +WORKDIR $GOPATH +RUN go get -u github.com/xlab/c-for-go +RUN mkdir -p src/github.com/renproject +WORKDIR $GOPATH/src/github.com/renproject +RUN git clone https://github.com/renproject/solana-ffi +WORKDIR $GOPATH/src/github.com/renproject/solana-ffi +RUN git checkout 1d5f4405dd2fb89c96cde28db33051a6e992d607 +RUN make clean && make +RUN go install ./... diff --git a/README.md b/README.md index e867eee5..f13310de 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ Adding a `Chain`: // human-readable string to this set of enumerated values. Chains must be listed // in alphabetical order. const ( - Acala = Chain("Acala") Bitcoin = Chain("Bitcoin") BitcoinCash = Chain("BitcoinCash") Dogecoin = Chain("Dogecoin") // (This is our new chain!) diff --git a/api/account/account.go b/api/account/account.go index 7d309721..82215edc 100644 --- a/api/account/account.go +++ b/api/account/account.go @@ -56,12 +56,22 @@ type Tx interface { // information, and this should be accepted during the construction of the // chain-specific transaction builder. type TxBuilder interface { - BuildTx(from, to address.Address, value, nonce pack.U256, payload pack.Bytes) (Tx, error) + BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (Tx, error) } // The Client interface defines the functionality required to interact with a // chain over RPC. type Client interface { + // LatestBlock returns the block number of the latest block. + LatestBlock(context.Context) (pack.U64, error) + + // AccountBalance returns the current balance of the given account. + AccountBalance(context.Context, address.Address) (pack.U256, error) + + // AccountNonce is the current nonce of this account, which must be used to + // build a new transaction. + AccountNonce(context.Context, address.Address) (pack.U256, error) + // Tx returns the transaction uniquely identified by the given transaction // hash. It also returns the number of confirmations for the transaction. If // the transaction cannot be found before the context is done, or the diff --git a/api/gas/gas.go b/api/gas/gas.go index 2578fc80..509fce52 100644 --- a/api/gas/gas.go +++ b/api/gas/gas.go @@ -11,15 +11,27 @@ import ( ) // The Estimator interface defines the functionality required to know the -// current recommended gas prices. +// current recommended gas price per gas unit and gas cap per gas unit. Not all +// chains have the concept of a gas cap, in which case it should be set to be +// equal to the gas price. type Estimator interface { - // EstimateGasPrice that should be used to get confirmation within a - // reasonable amount of time. The precise definition of "reasonable amount - // of time" varies from chain to chain, and so is left open to - // interpretation by the implementation. For example, in Bitcoin, it would - // be the recommended SATs-per-byte required to get a transaction into the - // next block. In Ethereum, it would be the recommended GWEI-per-gas - // required to get a transaction into one of the next few blocks (because - // blocks happen a lot faster). - EstimateGasPrice(context.Context) (pack.U256, error) + // EstimateGas base/price that should be used in order to get a transaction + // confirmed within a reasonable amount of time. The precise definition of + // "reasonable amount of time" varies from chain to chain, and so is left + // open to interpretation by the implementation. + + // For example, in Bitcoin, the gas price (and gas cap) would be the + // recommended SATs-per-byte required to get a transaction into the next + // block. + + // In Ethereum without EIP-1559, the gas price (and gas cap) would be the + // recommended GWEI-per-gas required to get a transaction into one of the + // next few blocks (because blocks happen a lot faster). In Ethereum with + // EIP1559, the gas price and gas cap would be back calculated given the gas + // cap and an estimate of the current gas base. + // + // The assumption is that the total gas cost will be gasLimit * gasPrice < + // gasLimit * gasCap. If chain nodes give back values based on different + // assumptions, then the values must be normalised as needed. + EstimateGas(context.Context) (gasPrice, gasCap pack.U256, err error) } diff --git a/api/utxo/utxo.go b/api/utxo/utxo.go index 8ae95a2d..f0c39a20 100644 --- a/api/utxo/utxo.go +++ b/api/utxo/utxo.go @@ -80,12 +80,23 @@ type TxBuilder interface { // The Client interface defines the functionality required to interact with a // chain over RPC. type Client interface { + // LatestBlock returns the the height of the longest blockchain. + LatestBlock(context.Context) (pack.U64, error) + // Output returns the transaction output identified by the given outpoint. // It also returns the number of confirmations for the output. If the output // cannot be found before the context is done, or the output is invalid, - // then an error should be returned. + // then an error should be returned. This method will not error, even if the + // output has been spent. Output(context.Context, Outpoint) (Output, pack.U64, error) + // UnspentOutput returns the unspent transaction output identified by the + // given outpoint. It also returns the number of confirmations for the + // output. If the output cannot be found before the context is done, the + // output is invalid, or the output has been spent, then an error should be + // returned. + UnspentOutput(context.Context, Outpoint) (Output, pack.U64, error) + // SubmitTx to the underlying chain. If the transaction cannot be found // before the context is done, or the transaction is invalid, then an error // should be returned. diff --git a/chain/bitcoin/address.go b/chain/bitcoin/address.go index 3547eaeb..8f875e90 100644 --- a/chain/bitcoin/address.go +++ b/chain/bitcoin/address.go @@ -1,18 +1,22 @@ package bitcoin import ( + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/base58" "github.com/renproject/multichain/api/address" - "github.com/renproject/pack" ) +// AddressEncodeDecoder implements the address.EncodeDecoder interface type AddressEncodeDecoder struct { AddressEncoder AddressDecoder } +// NewAddressEncodeDecoder constructs a new AddressEncodeDecoder with the +// chain specific configurations func NewAddressEncodeDecoder(params *chaincfg.Params) AddressEncodeDecoder { return AddressEncodeDecoder{ AddressEncoder: NewAddressEncoder(params), @@ -20,35 +24,88 @@ func NewAddressEncodeDecoder(params *chaincfg.Params) AddressEncodeDecoder { } } +// AddressEncoder encapsulates the chain specific configurations and implements +// the address.Encoder interface type AddressEncoder struct { params *chaincfg.Params } +// NewAddressEncoder constructs a new AddressEncoder with the chain specific +// configurations func NewAddressEncoder(params *chaincfg.Params) AddressEncoder { return AddressEncoder{params: params} } +// EncodeAddress implements the address.Encoder interface func (encoder AddressEncoder) EncodeAddress(rawAddr address.RawAddress) (address.Address, error) { + switch len(rawAddr) { + case 25: + return encoder.encodeBase58(rawAddr) + case 21, 33: + return encoder.encodeBech32(rawAddr) + default: + return address.Address(""), fmt.Errorf("non-exhaustive pattern: address length %v", len(rawAddr)) + } +} + +func (encoder AddressEncoder) encodeBase58(rawAddr address.RawAddress) (address.Address, error) { + // Validate that the base58 address is in fact in correct format. encodedAddr := base58.Encode([]byte(rawAddr)) if _, err := btcutil.DecodeAddress(encodedAddr, encoder.params); err != nil { - // Check that the address is valid. return address.Address(""), err } + return address.Address(encodedAddr), nil } +func (encoder AddressEncoder) encodeBech32(rawAddr address.RawAddress) (address.Address, error) { + switch len(rawAddr) { + case 21: + addr, err := btcutil.NewAddressWitnessPubKeyHash(rawAddr[1:], encoder.params) + if err != nil { + return address.Address(""), fmt.Errorf("new address witness pubkey hash: %v", err) + } + return address.Address(addr.EncodeAddress()), nil + case 33: + addr, err := btcutil.NewAddressWitnessScriptHash(rawAddr[1:], encoder.params) + if err != nil { + return address.Address(""), fmt.Errorf("new address witness script hash: %v", err) + } + return address.Address(addr.EncodeAddress()), nil + default: + return address.Address(""), fmt.Errorf("non-exhaustive pattern: bech32 address length %v", len(rawAddr)) + } +} + +// AddressDecoder encapsulates the chain specific configurations and implements +// the address.Decoder interface type AddressDecoder struct { params *chaincfg.Params } +// NewAddressDecoder constructs a new AddressDecoder with the chain specific +// configurations func NewAddressDecoder(params *chaincfg.Params) AddressDecoder { return AddressDecoder{params: params} } -func (decoder AddressDecoder) DecodeAddress(addr address.Address) (pack.Bytes, error) { - if _, err := btcutil.DecodeAddress(string(addr), decoder.params); err != nil { - // Check that the address is valid. - return nil, err +// DecodeAddress implements the address.Decoder interface +func (decoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + decodedAddr, err := btcutil.DecodeAddress(string(addr), decoder.params) + if err != nil { + return nil, fmt.Errorf("decode address: %v", err) + } + + switch a := decodedAddr.(type) { + case *btcutil.AddressPubKeyHash, *btcutil.AddressScriptHash: + return address.RawAddress(base58.Decode(string(addr))), nil + case *btcutil.AddressWitnessPubKeyHash: + rawAddr := append([]byte{a.WitnessVersion()}, a.WitnessProgram()...) + return address.RawAddress(rawAddr), nil + case *btcutil.AddressWitnessScriptHash: + rawAddr := append([]byte{a.WitnessVersion()}, a.WitnessProgram()...) + return address.RawAddress(rawAddr), nil + default: + return nil, fmt.Errorf("non-exhaustive pattern: address %T", a) } - return pack.NewBytes(base58.Decode(string(addr))), nil } diff --git a/chain/bitcoin/bitcoin.go b/chain/bitcoin/bitcoin.go index 6840651d..c51464bc 100644 --- a/chain/bitcoin/bitcoin.go +++ b/chain/bitcoin/bitcoin.go @@ -88,6 +88,10 @@ type Client interface { UnspentOutputs(ctx context.Context, minConf, maxConf int64, address address.Address) ([]utxo.Output, error) // Confirmations of a transaction in the Bitcoin network. Confirmations(ctx context.Context, txHash pack.Bytes) (int64, error) + // EstimateSmartFee + EstimateSmartFee(ctx context.Context, numBlocks int64) (float64, error) + // EstimateFeeLegacy + EstimateFeeLegacy(ctx context.Context, numBlocks int64) (float64, error) } type client struct { @@ -105,13 +109,26 @@ func NewClient(opts ClientOptions) Client { } } +// LatestBlock returns the height of the longest blockchain. +func (client *client) LatestBlock(ctx context.Context) (pack.U64, error) { + var resp int64 + if err := client.send(ctx, &resp, "getblockcount"); err != nil { + return pack.NewU64(0), fmt.Errorf("get block count: %v", err) + } + if resp < 0 { + return pack.NewU64(0), fmt.Errorf("unexpected block count, expected > 0, got: %v", resp) + } + + return pack.NewU64(uint64(resp)), nil +} + // Output associated with an outpoint, and its number of confirmations. func (client *client) Output(ctx context.Context, outpoint utxo.Outpoint) (utxo.Output, pack.U64, error) { resp := btcjson.TxRawResult{} hash := chainhash.Hash{} copy(hash[:], outpoint.Hash) if err := client.send(ctx, &resp, "getrawtransaction", hash.String(), 1); err != nil { - return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"gettxout\": %v", err) + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"getrawtransaction\": %v", err) } if outpoint.Index.Uint32() >= uint32(len(resp.Vout)) { return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad index: %v is out of range", outpoint.Index) @@ -136,6 +153,40 @@ func (client *client) Output(ctx context.Context, outpoint utxo.Outpoint) (utxo. return output, pack.NewU64(resp.Confirmations), nil } +// UnspentOutput returns the unspent transaction output identified by the +// given outpoint. It also returns the number of confirmations for the +// output. If the output cannot be found before the context is done, the +// output is invalid, or the output has been spent, then an error should be +// returned. +func (client *client) UnspentOutput(ctx context.Context, outpoint utxo.Outpoint) (utxo.Output, pack.U64, error) { + resp := btcjson.GetTxOutResult{} + hash := chainhash.Hash{} + copy(hash[:], outpoint.Hash) + if err := client.send(ctx, &resp, "gettxout", hash.String(), outpoint.Index.Uint32()); err != nil { + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad \"gettxout\": %v", err) + } + amount, err := btcutil.NewAmount(resp.Value) + if err != nil { + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad amount: %v", err) + } + if amount < 0 { + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad amount: %v", amount) + } + if resp.Confirmations < 0 { + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad confirmations: %v", resp.Confirmations) + } + pubKeyScript, err := hex.DecodeString(resp.ScriptPubKey.Hex) + if err != nil { + return utxo.Output{}, pack.NewU64(0), fmt.Errorf("bad pubkey script: %v", err) + } + output := utxo.Output{ + Outpoint: outpoint, + Value: pack.NewU256FromU64(pack.NewU64(uint64(amount))), + PubKeyScript: pack.NewBytes(pubKeyScript), + } + return output, pack.NewU64(uint64(resp.Confirmations)), nil +} + // SubmitTx to the Bitcoin network. func (client *client) SubmitTx(ctx context.Context, tx utxo.Tx) error { serial, err := tx.Serialize() @@ -205,6 +256,41 @@ func (client *client) Confirmations(ctx context.Context, txHash pack.Bytes) (int return confirmations, nil } +// EstimateSmartFee fetches the estimated bitcoin network fees to be paid (in +// BTC per kilobyte) needed for a transaction to be confirmed within `numBlocks` +// blocks. An error will be returned if the bitcoin node hasn't observed enough +// blocks to make an estimate for the provided target `numBlocks`. +func (client *client) EstimateSmartFee(ctx context.Context, numBlocks int64) (float64, error) { + resp := btcjson.EstimateSmartFeeResult{} + + if err := client.send(ctx, &resp, "estimatesmartfee", numBlocks); err != nil { + return 0.0, fmt.Errorf("estimating smart fee: %v", err) + } + + if resp.Errors != nil && len(resp.Errors) > 0 { + return 0.0, fmt.Errorf("estimating smart fee: %v", resp.Errors[0]) + } + + return *resp.FeeRate, nil +} + +func (client *client) EstimateFeeLegacy(ctx context.Context, numBlocks int64) (float64, error) { + var resp float64 + + switch numBlocks { + case int64(0): + if err := client.send(ctx, &resp, "estimatefee"); err != nil { + return 0.0, fmt.Errorf("estimating fee: %v", err) + } + default: + if err := client.send(ctx, &resp, "estimatefee", numBlocks); err != nil { + return 0.0, fmt.Errorf("estimating fee: %v", err) + } + } + + return resp, nil +} + func (client *client) send(ctx context.Context, resp interface{}, method string, params ...interface{}) error { // Encode the request. data, err := encodeRequest(method, params) diff --git a/chain/bitcoin/bitcoin_test.go b/chain/bitcoin/bitcoin_test.go index 690f70a6..a0a72bd6 100644 --- a/chain/bitcoin/bitcoin_test.go +++ b/chain/bitcoin/bitcoin_test.go @@ -59,6 +59,9 @@ var _ = Describe("Bitcoin", func() { output2, _, err := client.Output(context.Background(), output.Outpoint) Expect(err).ToNot(HaveOccurred()) Expect(reflect.DeepEqual(output, output2)).To(BeTrue()) + output2, _, err = client.UnspentOutput(context.Background(), output.Outpoint) + Expect(err).ToNot(HaveOccurred()) + Expect(reflect.DeepEqual(output, output2)).To(BeTrue()) // Build the transaction by consuming the outputs and spending // them to a set of recipients. @@ -122,11 +125,15 @@ var _ = Describe("Bitcoin", func() { confs, err := client.Confirmations(context.Background(), txHash) Expect(err).ToNot(HaveOccurred()) log.Printf(" %v/3 confirmations", confs) - if confs >= 3 { + if confs >= 1 { break } time.Sleep(10 * time.Second) } + ctxWithTimeout, cancelCtxWithTimeout := context.WithTimeout(context.Background(), time.Second) + defer cancelCtxWithTimeout() + _, _, err = client.UnspentOutput(ctxWithTimeout, output.Outpoint) + Expect(err).To(HaveOccurred()) // Check that we can load the output and that it is equal. // Otherwise, something strange is happening with the RPC diff --git a/chain/bitcoin/gas.go b/chain/bitcoin/gas.go index 40207885..d40d30bc 100644 --- a/chain/bitcoin/gas.go +++ b/chain/bitcoin/gas.go @@ -2,31 +2,56 @@ package bitcoin import ( "context" + "fmt" + "math" "github.com/renproject/pack" ) +const ( + btcToSatoshis = 1e8 + kilobyteToByte = 1024 +) + // A GasEstimator returns the SATs-per-byte that is needed in order to confirm // transactions with an estimated maximum delay of one block. In distributed // networks that collectively build, sign, and submit transactions, it is // important that all nodes in the network have reached consensus on the // SATs-per-byte. type GasEstimator struct { - satsPerByte pack.U256 + client Client + numBlocks int64 + fallbackGas pack.U256 } // NewGasEstimator returns a simple gas estimator that always returns the given // number of SATs-per-byte. -func NewGasEstimator(satsPerByte pack.U256) GasEstimator { +func NewGasEstimator(client Client, numBlocks int64, fallbackGas pack.U256) GasEstimator { return GasEstimator{ - satsPerByte: satsPerByte, + client: client, + numBlocks: numBlocks, + fallbackGas: fallbackGas, } } -// EstimateGasPrice returns the number of SATs-per-byte that is needed in order -// to confirm transactions with an estimated maximum delay of one block. It is -// the responsibility of the caller to know the number of bytes in their -// transaction. -func (gasEstimator GasEstimator) EstimateGasPrice(_ context.Context) (pack.U256, error) { - return gasEstimator.satsPerByte, nil +// EstimateGas returns the number of SATs-per-byte (for both price and cap) that +// is needed in order to confirm transactions with an estimated maximum delay of +// `numBlocks` block. It is the responsibility of the caller to know the number +// of bytes in their transaction. This method calls the `estimatesmartfee` RPC +// call to the node, which based on a conservative (considering longer history) +// strategy returns the estimated BTC per kilobyte of data in the transaction. +// An error will be returned if the bitcoin node hasn't observed enough blocks +// to make an estimate for the provided target `numBlocks`. +func (gasEstimator GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) { + feeRate, err := gasEstimator.client.EstimateSmartFee(ctx, gasEstimator.numBlocks) + if err != nil { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, err + } + + if feeRate <= 0.0 { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, fmt.Errorf("invalid fee rate: %v", feeRate) + } + + satsPerByte := uint64(math.Ceil(feeRate * btcToSatoshis / kilobyteToByte)) + return pack.NewU256FromUint64(satsPerByte), pack.NewU256FromUint64(satsPerByte), nil } diff --git a/chain/bitcoin/gas_test.go b/chain/bitcoin/gas_test.go index 7e3ae1ff..dae8dc8e 100644 --- a/chain/bitcoin/gas_test.go +++ b/chain/bitcoin/gas_test.go @@ -1 +1,52 @@ package bitcoin_test + +import ( + "context" + + "github.com/renproject/multichain/chain/bitcoin" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating bitcoin network fee", func() { + It("should work", func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client := bitcoin.NewClient(bitcoin.DefaultClientOptions()) + + // estimate fee to include tx within 1 block. + fallback1 := uint64(123) + gasEstimator1 := bitcoin.NewGasEstimator(client, 1, pack.NewU256FromUint64(fallback1)) + gasPrice1, _, err := gasEstimator1.EstimateGas(ctx) + if err != nil { + Expect(gasPrice1).To(Equal(pack.NewU256FromUint64(fallback1))) + } + + // estimate fee to include tx within 10 blocks. + fallback2 := uint64(234) + gasEstimator2 := bitcoin.NewGasEstimator(client, 10, pack.NewU256FromUint64(fallback2)) + gasPrice2, _, err := gasEstimator2.EstimateGas(ctx) + if err != nil { + Expect(gasPrice2).To(Equal(pack.NewU256FromUint64(fallback2))) + } + + // estimate fee to include tx within 100 blocks. + fallback3 := uint64(345) + gasEstimator3 := bitcoin.NewGasEstimator(client, 100, pack.NewU256FromUint64(fallback3)) + gasPrice3, _, err := gasEstimator3.EstimateGas(ctx) + if err != nil { + Expect(gasPrice3).To(Equal(pack.NewU256FromUint64(fallback3))) + } + + // expect fees in this order at the very least. + if err == nil { + Expect(gasPrice1.GreaterThanEqual(gasPrice2)).To(BeTrue()) + Expect(gasPrice2.GreaterThanEqual(gasPrice3)).To(BeTrue()) + } + }) + }) +}) diff --git a/chain/bitcoin/utxo.go b/chain/bitcoin/utxo.go index 367365e9..119e5880 100644 --- a/chain/bitcoin/utxo.go +++ b/chain/bitcoin/utxo.go @@ -81,15 +81,18 @@ type Tx struct { signed bool } +// Hash returns the transaction hash of the given underlying transaction. func (tx *Tx) Hash() (pack.Bytes, error) { txhash := tx.msgTx.TxHash() return pack.NewBytes(txhash[:]), nil } +// Inputs returns the UTXO inputs in the underlying transaction. func (tx *Tx) Inputs() ([]utxo.Input, error) { return tx.inputs, nil } +// Outputs returns the UTXO outputs in the underlying transaction. func (tx *Tx) Outputs() ([]utxo.Output, error) { hash, err := tx.Hash() if err != nil { @@ -111,7 +114,7 @@ func (tx *Tx) Outputs() ([]utxo.Output, error) { } // Sighashes returns the digests that must be signed before the transaction -// can be submitted by the client. All transactions assume that the f +// can be submitted by the client. func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { sighashes := make([]pack.Bytes32, len(tx.inputs)) @@ -150,6 +153,8 @@ func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { return sighashes, nil } +// Sign consumes a list of signatures, and adds them to the list of UTXOs in +// the underlying transactions. func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { if tx.signed { return fmt.Errorf("already signed") @@ -201,6 +206,7 @@ func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { return nil } +// Serialize serializes the UTXO transaction to bytes func (tx *Tx) Serialize() (pack.Bytes, error) { buf := new(bytes.Buffer) if err := tx.msgTx.Serialize(buf); err != nil { diff --git a/chain/bitcoincash/address.go b/chain/bitcoincash/address.go index 89722d20..f72d3a48 100644 --- a/chain/bitcoincash/address.go +++ b/chain/bitcoincash/address.go @@ -7,7 +7,10 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/base58" "github.com/btcsuite/btcutil/bech32" + "github.com/renproject/multichain/api/address" + "github.com/renproject/pack" "golang.org/x/crypto/ripemd160" ) @@ -24,6 +27,142 @@ var ( }() ) +// AddressEncodeDecoder implements the address.EncodeDecoder interface +type AddressEncodeDecoder struct { + AddressEncoder + AddressDecoder +} + +// NewAddressEncodeDecoder constructs a new AddressEncodeDecoder with the +// chain specific configurations +func NewAddressEncodeDecoder(params *chaincfg.Params) AddressEncodeDecoder { + return AddressEncodeDecoder{ + AddressEncoder: NewAddressEncoder(params), + AddressDecoder: NewAddressDecoder(params), + } +} + +// AddressEncoder encapsulates the chain specific configurations and implements +// the address.Encoder interface +type AddressEncoder struct { + params *chaincfg.Params +} + +// NewAddressEncoder constructs a new AddressEncoder with the chain specific +// configurations +func NewAddressEncoder(params *chaincfg.Params) AddressEncoder { + return AddressEncoder{params: params} +} + +// AddressDecoder encapsulates the chain specific configurations and implements +// the address.Decoder interface +type AddressDecoder struct { + params *chaincfg.Params +} + +// NewAddressDecoder constructs a new AddressDecoder with the chain specific +// configurations +func NewAddressDecoder(params *chaincfg.Params) AddressDecoder { + return AddressDecoder{params: params} +} + +// EncodeAddress implements the address.Encoder interface +func (encoder AddressEncoder) EncodeAddress(rawAddr address.RawAddress) (address.Address, error) { + rawAddrBytes := []byte(rawAddr) + var encodedAddr string + var err error + + switch len(rawAddrBytes) - 1 { + case ripemd160.Size: // P2PKH or P2SH + switch rawAddrBytes[0] { + case 0: // P2PKH + encodedAddr, err = encodeAddress(0x00, rawAddrBytes[1:21], encoder.params) + case 8: // P2SH + encodedAddr, err = encodeAddress(8, rawAddrBytes[1:21], encoder.params) + default: + return address.Address(""), btcutil.ErrUnknownAddressType + } + default: + return encodeLegacyAddress(rawAddr, encoder.params) + } + + if err != nil { + return address.Address(""), fmt.Errorf("encoding: %v", err) + } + + return address.Address(encodedAddr), nil +} + +// DecodeAddress implements the address.Decoder interface +func (decoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + // Legacy address decoding + if legacyAddr, err := btcutil.DecodeAddress(string(addr), decoder.params); err == nil { + switch legacyAddr.(type) { + case *btcutil.AddressPubKeyHash, *btcutil.AddressScriptHash, *btcutil.AddressPubKey: + return decodeLegacyAddress(addr, decoder.params) + case *btcutil.AddressWitnessPubKeyHash, *btcutil.AddressWitnessScriptHash: + return nil, fmt.Errorf("unsuported segwit bitcoin address type %T", legacyAddr) + default: + return nil, fmt.Errorf("unsuported legacy bitcoin address type %T", legacyAddr) + } + } + + if addrParts := strings.Split(string(addr), ":"); len(addrParts) != 1 { + addr = address.Address(addrParts[1]) + } + + decoded := DecodeString(string(addr)) + if !VerifyChecksum(AddressPrefix(decoder.params), decoded) { + return nil, btcutil.ErrChecksumMismatch + } + + addrBytes, err := bech32.ConvertBits(decoded[:len(decoded)-8], 5, 8, false) + if err != nil { + return nil, err + } + + switch len(addrBytes) - 1 { + case ripemd160.Size: // P2PKH or P2SH + switch addrBytes[0] { + case 0, 8: // P2PKH or P2SH + return address.RawAddress(addrBytes), nil + default: + return nil, btcutil.ErrUnknownAddressType + } + default: + return nil, errors.New("decoded address is of unknown size") + } +} + +func encodeLegacyAddress(rawAddr address.RawAddress, params *chaincfg.Params) (address.Address, error) { + // Validate that the base58 address is in fact in correct format. + encodedAddr := base58.Encode([]byte(rawAddr)) + if _, err := btcutil.DecodeAddress(encodedAddr, params); err != nil { + return address.Address(""), fmt.Errorf("address validation error: %v", err) + } + + return address.Address(encodedAddr), nil +} + +func decodeLegacyAddress(addr address.Address, params *chaincfg.Params) (address.RawAddress, error) { + // Decode the checksummed base58 format address. + decoded, ver, err := base58.CheckDecode(string(addr)) + if err != nil { + return nil, fmt.Errorf("checking: %v", err) + } + if len(decoded) != 20 { + return nil, fmt.Errorf("expected len 20, got len %v", len(decoded)) + } + + // Validate the address format. + switch ver { + case params.PubKeyHashAddrID, params.ScriptHashAddrID: + return address.RawAddress(pack.NewBytes(base58.Decode(string(addr)))), nil + default: + return nil, fmt.Errorf("unexpected address prefix") + } +} + // An Address represents a Bitcoin Cash address. type Address interface { btcutil.Address @@ -77,7 +216,7 @@ func (addr AddressPubKeyHash) String() string { // for how this method differs from String. func (addr AddressPubKeyHash) EncodeAddress() string { hash := *addr.AddressPubKeyHash.Hash160() - encoded, err := EncodeAddress(0x00, hash[:], addr.params) + encoded, err := encodeAddress(0x00, hash[:], addr.params) if err != nil { panic(fmt.Errorf("invalid address: %v", err)) } @@ -139,7 +278,7 @@ func (addr AddressScriptHash) String() string { // for how this method differs from String. func (addr AddressScriptHash) EncodeAddress() string { hash := *addr.AddressScriptHash.Hash160() - encoded, err := EncodeAddress(8, hash[:], addr.params) + encoded, err := encodeAddress(8, hash[:], addr.params) if err != nil { panic(fmt.Errorf("invalid address: %v", err)) } @@ -163,9 +302,9 @@ func (addr AddressScriptHash) BitcoinAddress() btcutil.Address { return addr.AddressScriptHash } -// EncodeAddress using Bitcoin Cash address encoding, assuming that the hash +// encodeAddress using Bitcoin Cash address encoding, assuming that the hash // data has no prefix or checksum. -func EncodeAddress(version byte, hash []byte, params *chaincfg.Params) (string, error) { +func encodeAddress(version byte, hash []byte, params *chaincfg.Params) (string, error) { if (len(hash)-20)/4 != int(version)%8 { return "", fmt.Errorf("invalid version: %d", version) } @@ -176,33 +315,9 @@ func EncodeAddress(version byte, hash []byte, params *chaincfg.Params) (string, return EncodeToString(AppendChecksum(AddressPrefix(params), data)), nil } -func DecodeAddress(addr string, params *chaincfg.Params) (Address, error) { - // Legacy address decoding - if address, err := btcutil.DecodeAddress(addr, params); err == nil { - switch address.(type) { - case *btcutil.AddressPubKeyHash, *btcutil.AddressScriptHash, *btcutil.AddressPubKey: - return AddressLegacy{Address: address}, nil - case *btcutil.AddressWitnessPubKeyHash, *btcutil.AddressWitnessScriptHash: - return nil, fmt.Errorf("unsuported segwit bitcoin address type %T", address) - default: - return nil, fmt.Errorf("unsuported legacy bitcoin address type %T", address) - } - } - - if addrParts := strings.Split(addr, ":"); len(addrParts) != 1 { - addr = addrParts[1] - } - - decoded := DecodeString(addr) - if !VerifyChecksum(AddressPrefix(params), decoded) { - return nil, btcutil.ErrChecksumMismatch - } - - addrBytes, err := bech32.ConvertBits(decoded[:len(decoded)-8], 5, 8, false) - if err != nil { - return nil, err - } - +// addressFromRawBytes consumes raw bytes representation of a bitcoincash +// address and returns a type that implements the bitcoincash.Address interface. +func addressFromRawBytes(addrBytes []byte, params *chaincfg.Params) (Address, error) { switch len(addrBytes) - 1 { case ripemd160.Size: // P2PKH or P2SH switch addrBytes[0] { @@ -214,7 +329,11 @@ func DecodeAddress(addr string, params *chaincfg.Params) (Address, error) { return nil, btcutil.ErrUnknownAddressType } default: - return nil, errors.New("decoded address is of unknown size") + addr, err := btcutil.DecodeAddress(base58.Encode(addrBytes), params) + if err != nil { + return nil, err + } + return AddressLegacy{Address: addr}, nil } } diff --git a/chain/bitcoincash/address_test.go b/chain/bitcoincash/address_test.go index a834dd27..73857928 100644 --- a/chain/bitcoincash/address_test.go +++ b/chain/bitcoincash/address_test.go @@ -1 +1,86 @@ package bitcoincash_test + +import ( + "fmt" + "math/rand" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcutil" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/renproject/id" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/bitcoincash" +) + +var _ = Describe("Bitcoin Cash", func() { + Context("Address Encode/Decode", func() { + addrEncodeDecoders := []struct { + network *chaincfg.Params + encodeDecoder bitcoincash.AddressEncodeDecoder + }{ + { + &chaincfg.MainNetParams, + bitcoincash.NewAddressEncodeDecoder(&chaincfg.MainNetParams), + }, + { + &chaincfg.TestNet3Params, + bitcoincash.NewAddressEncodeDecoder(&chaincfg.TestNet3Params), + }, + { + &chaincfg.RegressionNetParams, + bitcoincash.NewAddressEncodeDecoder(&chaincfg.RegressionNetParams), + }, + } + + for _, addrEncodeDecoder := range addrEncodeDecoders { + addrEncodeDecoder := addrEncodeDecoder + Context(fmt.Sprintf("Encode/Decode for %v network", addrEncodeDecoder.network.Name), func() { + Specify("AddressPubKeyHash", func() { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), addrEncodeDecoder.network, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := bitcoincash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), addrEncodeDecoder.network) + Expect(err).NotTo(HaveOccurred()) + addr := address.Address(addrPubKeyHash.EncodeAddress()) + + decodedRawAddr, err := addrEncodeDecoder.encodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := addrEncodeDecoder.encodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + + Specify("AddressScriptHash", func() { + script := make([]byte, rand.Intn(100)) + rand.Read(script) + addrScriptHash, err := bitcoincash.NewAddressScriptHash(script, addrEncodeDecoder.network) + Expect(err).NotTo(HaveOccurred()) + addr := address.Address(addrScriptHash.EncodeAddress()) + + decodedRawAddr, err := addrEncodeDecoder.encodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := addrEncodeDecoder.encodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + + Specify("AddressLegacy", func() { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), addrEncodeDecoder.network, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(wif.SerializePubKey()), addrEncodeDecoder.network) + Expect(err).NotTo(HaveOccurred()) + addr := address.Address(addrPubKeyHash.EncodeAddress()) + + decodedRawAddr, err := addrEncodeDecoder.encodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := addrEncodeDecoder.encodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + }) + } + }) +}) diff --git a/chain/bitcoincash/gas.go b/chain/bitcoincash/gas.go index 1658a0fe..3958e72e 100644 --- a/chain/bitcoincash/gas.go +++ b/chain/bitcoincash/gas.go @@ -1,7 +1,54 @@ package bitcoincash -import "github.com/renproject/multichain/chain/bitcoin" +import ( + "context" + "fmt" + "math" -type GasEstimator = bitcoin.GasEstimator + "github.com/renproject/pack" +) -var NewGasEstimator = bitcoin.NewGasEstimator +const ( + bchToSatoshis = 1e8 + kilobyteToByte = 1024 +) + +// A GasEstimator returns the SATs-per-byte that is needed in order to confirm +// transactions with an estimated maximum delay of one block. In distributed +// networks that collectively build, sign, and submit transactions, it is +// important that all nodes in the network have reached consensus on the +// SATs-per-byte. +type GasEstimator struct { + client Client + fallbackGas pack.U256 +} + +// NewGasEstimator returns a simple gas estimator that always returns the given +// number of SATs-per-byte. +func NewGasEstimator(client Client, fallbackGas pack.U256) GasEstimator { + return GasEstimator{ + client: client, + fallbackGas: fallbackGas, + } +} + +// EstimateGas returns the number of SATs-per-byte (for both price and cap) that +// is needed in order to confirm transactions with a minimal delay. It is the +// responsibility of the caller to know the number of bytes in their +// transaction. This method calls the `estimatefee` RPC call to the node, which +// based on a conservative (considering longer history) strategy returns the +// estimated BCH per kilobyte of data in the transaction. An error will be +// returned if the node hasn't observed enough blocks to make an estimate. +func (gasEstimator GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) { + feeRate, err := gasEstimator.client.EstimateFeeLegacy(ctx, int64(0)) + if err != nil { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, err + } + + if feeRate <= 0.0 { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, fmt.Errorf("invalid fee rate: %v", feeRate) + } + + satsPerByte := uint64(math.Ceil(feeRate * bchToSatoshis / kilobyteToByte)) + return pack.NewU256FromUint64(satsPerByte), pack.NewU256FromUint64(satsPerByte), nil +} diff --git a/chain/bitcoincash/gas_test.go b/chain/bitcoincash/gas_test.go index a834dd27..86aab014 100644 --- a/chain/bitcoincash/gas_test.go +++ b/chain/bitcoincash/gas_test.go @@ -1 +1,31 @@ package bitcoincash_test + +import ( + "context" + + "github.com/renproject/multichain/chain/bitcoincash" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating bitcoincash network fee", func() { + It("should work", func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client := bitcoincash.NewClient(bitcoincash.DefaultClientOptions()) + + fallbackGas := uint64(123) + gasEstimator := bitcoincash.NewGasEstimator(client, pack.NewU256FromUint64(fallbackGas)) + gasPrice, _, err := gasEstimator.EstimateGas(ctx) + if err != nil { + Expect(gasPrice).To(Equal(pack.NewU256FromUint64(fallbackGas))) + } else { + Expect(gasPrice.Int().Uint64()).To(BeNumerically(">", 0)) + } + }) + }) +}) diff --git a/chain/bitcoincash/utxo.go b/chain/bitcoincash/utxo.go index 6dfddc54..0cb4aac2 100644 --- a/chain/bitcoincash/utxo.go +++ b/chain/bitcoincash/utxo.go @@ -26,16 +26,25 @@ const SighashMask = txscript.SigHashType(0x1F) // Version of Bitcoin Cash transactions supported by the multichain. const Version int32 = 1 +// ClientOptions are used to parameterise the behaviour of the Client. type ClientOptions = bitcoin.ClientOptions +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the host, user, and password should be changed. func DefaultClientOptions() ClientOptions { return bitcoin.DefaultClientOptions().WithHost("http://127.0.0.1:19443") } +// A Client interacts with an instance of the Bitcoin network using the RPC +// interface exposed by a Bitcoin node. type Client = bitcoin.Client +// NewClient returns a new Client. var NewClient = bitcoin.NewClient +// The TxBuilder is an implementation of a UTXO-compatible transaction builder +// for Bitcoin. type TxBuilder struct { params *chaincfg.Params } @@ -64,6 +73,9 @@ func NewTxBuilder(params *chaincfg.Params) utxo.TxBuilder { func (txBuilder TxBuilder) BuildTx(inputs []utxo.Input, recipients []utxo.Recipient) (utxo.Tx, error) { msgTx := wire.NewMsgTx(Version) + // Address encoder-decoder + addrEncodeDecoder := NewAddressEncodeDecoder(txBuilder.params) + // Inputs for _, input := range inputs { hash := chainhash.Hash{} @@ -74,7 +86,11 @@ func (txBuilder TxBuilder) BuildTx(inputs []utxo.Input, recipients []utxo.Recipi // Outputs for _, recipient := range recipients { - addr, err := DecodeAddress(string(recipient.To), txBuilder.params) + addrBytes, err := addrEncodeDecoder.DecodeAddress(recipient.To) + if err != nil { + return &Tx{}, err + } + addr, err := addressFromRawBytes(addrBytes, txBuilder.params) if err != nil { return &Tx{}, err } @@ -103,15 +119,21 @@ type Tx struct { signed bool } +// Hash returns the transaction hash of the given underlying transaction. It +// implements the multichain.UTXOTx interface func (tx *Tx) Hash() (pack.Bytes, error) { txhash := tx.msgTx.TxHash() return pack.NewBytes(txhash[:]), nil } +// Inputs returns the UTXO inputs in the underlying transaction. It implements +// the multichain.UTXOTx interface func (tx *Tx) Inputs() ([]utxo.Input, error) { return tx.inputs, nil } +// Outputs returns the UTXO outputs in the underlying transaction. It implements +// the multichain.UTXOTx interface func (tx *Tx) Outputs() ([]utxo.Output, error) { hash, err := tx.Hash() if err != nil { @@ -132,6 +154,8 @@ func (tx *Tx) Outputs() ([]utxo.Output, error) { return outputs, nil } +// Sighashes returns the digests that must be signed before the transaction +// can be submitted by the client. func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { sighashes := make([]pack.Bytes32, len(tx.inputs)) @@ -157,6 +181,8 @@ func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { return sighashes, nil } +// Sign consumes a list of signatures, and adds them to the list of UTXOs in +// the underlying transactions. It implements the multichain.UTXOTx interface func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { if tx.signed { return fmt.Errorf("already signed") @@ -190,6 +216,7 @@ func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { return nil } +// Serialize serializes the UTXO transaction to bytes func (tx *Tx) Serialize() (pack.Bytes, error) { buf := new(bytes.Buffer) if err := tx.msgTx.Serialize(buf); err != nil { diff --git a/chain/celo/address.go b/chain/celo/address.go deleted file mode 100644 index b4a448f9..00000000 --- a/chain/celo/address.go +++ /dev/null @@ -1,23 +0,0 @@ -package celo - -import "github.com/renproject/multichain/chain/ethereum" - -// An Address on the Celo chain is functionally identical to an address on the -// Ethereum chain. -type Address = ethereum.Address - -// An AddressEncoder on the Celo chain is functionally identical to an encoder -// on the Ethereum chain. -type AddressEncoder = ethereum.AddressEncoder - -// An AddressDecoder on the Celo chain is functionally identical to a decoder on -// the Ethereum chain. -type AddressDecoder = ethereum.AddressDecoder - -// An AddressEncodeDecoder on the Celo chain is functionally identical to a -// encoder/decoder on the Ethereum chain. -type AddressEncodeDecoder = ethereum.AddressEncodeDecoder - -var ( - NewAddressEncodeDecoder = ethereum.NewAddressEncodeDecoder -) diff --git a/chain/celo/address_test.go b/chain/celo/address_test.go deleted file mode 100644 index 95d07238..00000000 --- a/chain/celo/address_test.go +++ /dev/null @@ -1 +0,0 @@ -package celo_test diff --git a/chain/cosmos/address.go b/chain/cosmos/address.go new file mode 100644 index 00000000..daffb7ed --- /dev/null +++ b/chain/cosmos/address.go @@ -0,0 +1,79 @@ +package cosmos + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/renproject/multichain/api/address" +) + +// An Address is a public address that can be encoded/decoded to/from strings. +// Addresses are usually formatted different between different network +// configurations. +type Address sdk.AccAddress + +// AccAddress convert Address to sdk.AccAddress +func (addr Address) AccAddress() sdk.AccAddress { + return sdk.AccAddress(addr) +} + +// String implements the Stringer interface +func (addr Address) String() string { + return sdk.AccAddress(addr).String() +} + +// AddressEncodeDecoder encapsulates fields that implement the +// address.EncodeDecoder interface +type AddressEncodeDecoder struct { + AddressEncoder + AddressDecoder +} + +// NewAddressEncodeDecoder creates a new address encoder-decoder +func NewAddressEncodeDecoder() AddressEncodeDecoder { + return AddressEncodeDecoder{ + AddressEncoder: NewAddressEncoder(), + AddressDecoder: NewAddressDecoder(), + } +} + +// AddressEncoder implements the address.Encoder interface +type AddressEncoder struct { +} + +// AddressDecoder implements the address.Decoder interface +type AddressDecoder struct { +} + +// NewAddressDecoder creates a new address decoder +func NewAddressDecoder() AddressDecoder { + return AddressDecoder{} +} + +// NewAddressEncoder creates a new address encoder +func NewAddressEncoder() AddressEncoder { + return AddressEncoder{} +} + +// DecodeAddress consumes a human-readable representation of a cosmos +// compatible address and decodes it to its raw bytes representation. +func (decoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + rawAddr, err := sdk.AccAddressFromBech32(string(addr)) + if err != nil { + return nil, err + } + if len(rawAddr) != sdk.AddrLen { + return nil, fmt.Errorf("unexpected address length: want=%v, got=%v", sdk.AddrLen, len(rawAddr)) + } + return address.RawAddress(rawAddr), nil +} + +// EncodeAddress consumes raw bytes and encodes them to a human-readable +// address format. +func (encoder AddressEncoder) EncodeAddress(rawAddr address.RawAddress) (address.Address, error) { + if len(rawAddr) != sdk.AddrLen { + return address.Address(""), fmt.Errorf("unexpected address length: want=%v, got=%v", sdk.AddrLen, len(rawAddr)) + } + bech32Addr := sdk.AccAddress(rawAddr) + return address.Address(bech32Addr.String()), nil +} diff --git a/chain/cosmos/address_test.go b/chain/cosmos/address_test.go new file mode 100644 index 00000000..712dd321 --- /dev/null +++ b/chain/cosmos/address_test.go @@ -0,0 +1 @@ +package cosmos_test diff --git a/chain/cosmos/client.go b/chain/cosmos/client.go new file mode 100644 index 00000000..ddeb2c86 --- /dev/null +++ b/chain/cosmos/client.go @@ -0,0 +1,289 @@ +package cosmos + +import ( + "context" + "encoding/hex" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/api/address" + "github.com/renproject/pack" + + cliContext "github.com/cosmos/cosmos-sdk/client/context" + cliRpc "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + rpchttp "github.com/tendermint/tendermint/rpc/client/http" +) + +const ( + // DefaultClientTimeout used by the Client. + DefaultClientTimeout = time.Minute + // DefaultClientTimeoutRetry used by the Client. + DefaultClientTimeoutRetry = time.Second + // DefaultClientHost used by the Client. This should only be used for local + // deployments of the multichain. + DefaultClientHost = pack.String("http://0.0.0.0:26657") + // DefaultBroadcastMode configures the behaviour of a cosmos client while it + // interacts with the cosmos node. Allowed broadcast modes can be async, sync + // and block. "async" returns immediately after broadcasting, "sync" returns + // after the transaction has been checked and "block" waits until the + // transaction is committed to the chain. + DefaultBroadcastMode = pack.String("sync") + // DefaultCoinDenom used by the Client. + DefaultCoinDenom = pack.String("uluna") +) + +// ClientOptions are used to parameterise the behaviour of the Client. +type ClientOptions struct { + Timeout time.Duration + TimeoutRetry time.Duration + Host pack.String + BroadcastMode pack.String + CoinDenom pack.String +} + +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the host, user, and password should be changed. +func DefaultClientOptions() ClientOptions { + return ClientOptions{ + Timeout: DefaultClientTimeout, + TimeoutRetry: DefaultClientTimeoutRetry, + Host: DefaultClientHost, + BroadcastMode: DefaultBroadcastMode, + CoinDenom: DefaultCoinDenom, + } +} + +// WithTimeout sets the timeout used by the Client. +func (opts ClientOptions) WithTimeout(timeout time.Duration) ClientOptions { + opts.Timeout = timeout + return opts +} + +// WithTimeoutRetry sets the timeout retry used by the Client. +func (opts ClientOptions) WithTimeoutRetry(timeoutRetry time.Duration) ClientOptions { + opts.TimeoutRetry = timeoutRetry + return opts +} + +// WithHost sets the URL of the node. +func (opts ClientOptions) WithHost(host pack.String) ClientOptions { + opts.Host = host + return opts +} + +// WithBroadcastMode sets the behaviour of the Client when interacting with the +// underlying node. +func (opts ClientOptions) WithBroadcastMode(broadcastMode pack.String) ClientOptions { + opts.BroadcastMode = broadcastMode + return opts +} + +// WithCoinDenom sets the coin denomination used by the Client. +func (opts ClientOptions) WithCoinDenom(coinDenom pack.String) ClientOptions { + opts.CoinDenom = coinDenom + return opts +} + +// Client interacts with an instance of the Cosmos based network using the REST +// interface exposed by a lightclient node. +type Client struct { + opts ClientOptions + cliCtx cliContext.CLIContext + cdc *codec.Codec + hrp string +} + +// NewClient returns a new Client. +func NewClient(opts ClientOptions, cdc *codec.Codec, hrp string) *Client { + httpClient, err := rpchttp.NewWithClient( + string(opts.Host), + "websocket", + &http.Client{ + Timeout: opts.Timeout, + + // We override the transport layer with a custom implementation as + // there is an issue with the Cosmos SDK that causes it to + // incorrectly parse URLs. + Transport: newTransport(string(opts.Host), &http.Transport{}), + }) + if err != nil { + panic(err) + } + + cliCtx := cliContext.NewCLIContext().WithCodec(cdc).WithClient(httpClient).WithTrustNode(true) + + return &Client{ + opts: opts, + cliCtx: cliCtx, + cdc: cdc, + hrp: hrp, + } +} + +// LatestBlock returns the most recent block's number. +func (client *Client) LatestBlock(ctx context.Context) (pack.U64, error) { + height, err := cliRpc.GetChainHeight(client.cliCtx) + if err != nil { + return pack.NewU64(0), fmt.Errorf("get chain height: %v", err) + } + if height < 0 { + return pack.NewU64(0), fmt.Errorf("unexpected chain height, expected > 0, got: %v", height) + } + + return pack.NewU64(uint64(height)), nil +} + +// Tx query transaction with txHash +func (client *Client) Tx(ctx context.Context, txHash pack.Bytes) (account.Tx, pack.U64, error) { + res, err := utils.QueryTx(client.cliCtx, hex.EncodeToString(txHash[:])) + if err != nil { + return &StdTx{}, pack.NewU64(0), fmt.Errorf("query fail: %v", err) + } + + authStdTx := res.Tx.(auth.StdTx) + if res.Code != 0 { + return &StdTx{}, pack.NewU64(0), fmt.Errorf("tx failed code: %v, log: %v", res.Code, res.RawLog) + } + + stdTx, err := parseStdTx(authStdTx) + if err != nil { + return &StdTx{}, pack.NewU64(0), fmt.Errorf("parse tx failed: %v", err) + } + + return &stdTx, pack.NewU64(1), nil +} + +// SubmitTx to the Cosmos based network. +func (client *Client) SubmitTx(ctx context.Context, tx account.Tx) error { + txBytes, err := tx.Serialize() + if err != nil { + return fmt.Errorf("bad \"submittx\": %v", err) + } + + res, err := client.cliCtx.WithBroadcastMode(client.opts.BroadcastMode.String()).BroadcastTx(txBytes) + if err != nil { + return err + } + + if res.Code != 0 { + return fmt.Errorf("tx failed code: %v, log: %v", res.Code, res.RawLog) + } + + return nil +} + +// AccountNonce returns the current nonce of the account. This is the nonce to +// be used while building a new transaction. +func (client *Client) AccountNonce(ctx context.Context, addr address.Address) (pack.U256, error) { + cosmosAddr, err := types.AccAddressFromBech32(string(addr)) + if err != nil { + return pack.U256{}, fmt.Errorf("bad address: '%v': %v", addr, err) + } + + for { + select { + case <-ctx.Done(): + return pack.U256{}, ctx.Err() + default: + } + + accGetter := auth.NewAccountRetriever(client.cliCtx) + acc, err := accGetter.GetAccount(Address(cosmosAddr).AccAddress()) + if err != nil { + time.Sleep(client.opts.TimeoutRetry) + continue + } + + return pack.NewU256FromU64(pack.NewU64(acc.GetSequence())), nil + } +} + +// AccountNumber returns the account number for a given address. +func (client *Client) AccountNumber(ctx context.Context, addr address.Address) (pack.U64, error) { + cosmosAddr, err := types.AccAddressFromBech32(string(addr)) + if err != nil { + return 0, fmt.Errorf("bad address: '%v': %v", addr, err) + } + + for { + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + } + + accGetter := auth.NewAccountRetriever(client.cliCtx) + acc, err := accGetter.GetAccount(Address(cosmosAddr).AccAddress()) + if err != nil { + time.Sleep(client.opts.TimeoutRetry) + continue + } + return pack.U64(acc.GetAccountNumber()), nil + } +} + +// AccountBalance returns the account balancee for a given address. +func (client *Client) AccountBalance(ctx context.Context, addr address.Address) (pack.U256, error) { + cosmosAddr, err := types.AccAddressFromBech32(string(addr)) + if err != nil { + return pack.U256{}, fmt.Errorf("bad address: '%v': %v", addr, err) + } + + for { + select { + case <-ctx.Done(): + return pack.U256{}, ctx.Err() + default: + } + + accGetter := auth.NewAccountRetriever(client.cliCtx) + acc, err := accGetter.GetAccount(Address(cosmosAddr).AccAddress()) + if err != nil { + time.Sleep(client.opts.TimeoutRetry) + continue + } + + balance := acc.GetCoins().AmountOf(string(client.opts.CoinDenom)).BigInt() + + // If the balance exceeds `MaxU256`, return an error. + if pack.MaxU256.Int().Cmp(balance) == -1 { + return pack.U256{}, fmt.Errorf("balance %v for %v exceeds MaxU256", balance.String(), addr) + } + + return pack.NewU256FromInt(balance), nil + } +} + +type transport struct { + remote string + proxy http.RoundTripper +} + +// newTransport returns a custom implementation of http.RoundTripper that +// overrides the request URL prior to sending the request. +func newTransport(remote string, proxy http.RoundTripper) *transport { + return &transport{ + remote: remote, + proxy: proxy, + } +} + +func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { + u, err := url.Parse(t.remote) + if err != nil { + return nil, err + } + req.URL = u + req.Host = u.Host + + // Proxy request. + return t.proxy.RoundTrip(req) +} diff --git a/chain/cosmos/cosmos.go b/chain/cosmos/cosmos.go new file mode 100644 index 00000000..33a99846 --- /dev/null +++ b/chain/cosmos/cosmos.go @@ -0,0 +1 @@ +package cosmos diff --git a/chain/ethereum/ethereum_suite_test.go b/chain/cosmos/cosmos_suite_test.go similarity index 55% rename from chain/ethereum/ethereum_suite_test.go rename to chain/cosmos/cosmos_suite_test.go index 1ee58840..d9717899 100644 --- a/chain/ethereum/ethereum_suite_test.go +++ b/chain/cosmos/cosmos_suite_test.go @@ -1,4 +1,4 @@ -package ethereum_test +package cosmos_test import ( "testing" @@ -7,7 +7,7 @@ import ( . "github.com/onsi/gomega" ) -func TestEthereum(t *testing.T) { +func TestCosmos(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Ethereum Suite") + RunSpecs(t, "Cosmos Suite") } diff --git a/chain/cosmos/cosmos_test.go b/chain/cosmos/cosmos_test.go new file mode 100644 index 00000000..712dd321 --- /dev/null +++ b/chain/cosmos/cosmos_test.go @@ -0,0 +1 @@ +package cosmos_test diff --git a/chain/cosmos/gas.go b/chain/cosmos/gas.go new file mode 100644 index 00000000..dbd583c3 --- /dev/null +++ b/chain/cosmos/gas.go @@ -0,0 +1,32 @@ +package cosmos + +import ( + "context" + + "github.com/renproject/multichain/api/gas" + "github.com/renproject/pack" +) + +// A GasEstimator returns the gas-per-byte that is needed in order to confirm +// transactions with an estimated maximum delay of one block. In distributed +// networks that collectively build, sign, and submit transactions, it is +// important that all nodes in the network have reached consensus on the +// gas-per-byte. +type GasEstimator struct { + gasPerByte pack.U256 +} + +// NewGasEstimator returns a simple gas estimator that always returns the same +// amount of gas-per-byte. +func NewGasEstimator(gasPerByte pack.U256) gas.Estimator { + return &GasEstimator{ + gasPerByte: gasPerByte, + } +} + +// EstimateGas returns gas required per byte for Cosmos-compatible chains. This +// value is used for both the price and cap, because Cosmos-compatible chains do +// not have a distinct concept of cap. +func (gasEstimator *GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) { + return gasEstimator.gasPerByte, gasEstimator.gasPerByte, nil +} diff --git a/chain/cosmos/gas_test.go b/chain/cosmos/gas_test.go new file mode 100644 index 00000000..f777ba2e --- /dev/null +++ b/chain/cosmos/gas_test.go @@ -0,0 +1,27 @@ +package cosmos_test + +import ( + "context" + "testing/quick" + + "github.com/renproject/multichain/chain/cosmos" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating gas parameters", func() { + It("should work", func() { + f := func(gasPerByte pack.U256) bool { + gasEstimator := cosmos.NewGasEstimator(gasPerByte) + gasPrice, _, err := gasEstimator.EstimateGas(context.Background()) + Expect(err).NotTo(HaveOccurred()) + Expect(gasPrice).To(Equal(gasPerByte)) + return true + } + Expect(quick.Check(f, nil)).To(Succeed()) + }) + }) +}) diff --git a/chain/cosmos/tx.go b/chain/cosmos/tx.go new file mode 100644 index 00000000..b96f229a --- /dev/null +++ b/chain/cosmos/tx.go @@ -0,0 +1,362 @@ +package cosmos + +import ( + "context" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/api/contract" + "github.com/renproject/pack" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/tmhash" +) + +const ( + // DefaultChainID used by the Client. + DefaultChainID = pack.String("testnet") +) + +// TxBuilderOptions only contains necessary options to build tx from tx builder +type TxBuilderOptions struct { + ChainID pack.String +} + +// DefaultTxBuilderOptions returns TxBuilderOptions with the default settings. +func DefaultTxBuilderOptions() TxBuilderOptions { + return TxBuilderOptions{ + ChainID: DefaultChainID, + } +} + +// WithChainID sets the chain ID used by the transaction builder. +func (opts TxBuilderOptions) WithChainID(chainID pack.String) TxBuilderOptions { + opts.ChainID = chainID + return opts +} + +type txBuilder struct { + client *Client + chainID pack.String +} + +// NewTxBuilder returns an implementation of the transaction builder interface +// from the Cosmos Compat API, and exposes the functionality to build simple +// Cosmos based transactions. +func NewTxBuilder(options TxBuilderOptions, client *Client) account.TxBuilder { + if client.cdc == nil { + client.cdc = simapp.MakeCodec() + } + + return txBuilder{ + client: client, + chainID: options.ChainID, + } +} + +// BuildTx consumes a list of MsgSend to build and return a cosmos transaction. +// This transaction is unsigned, and must be signed before submitting to the +// cosmos chain. +func (builder txBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (account.Tx, error) { + fromAddr, err := types.AccAddressFromBech32(string(from)) + if err != nil { + return nil, err + } + + toAddr, err := types.AccAddressFromBech32(string(to)) + if err != nil { + return nil, err + } + + sendMsg := MsgSend{ + FromAddress: Address(fromAddr), + ToAddress: Address(toAddr), + Amount: []Coin{ + { + Denom: builder.client.opts.CoinDenom, + Amount: pack.NewU64(value.Int().Uint64()), + }, + }, + } + + fees := Coins{Coin{ + Denom: builder.client.opts.CoinDenom, + Amount: pack.NewU64(gasPrice.Mul(gasLimit).Int().Uint64()), + }} + + accountNumber, err := builder.client.AccountNumber(ctx, from) + if err != nil { + return nil, err + } + + txBuilder := auth.NewTxBuilder( + utils.GetTxEncoder(builder.client.cdc), + accountNumber.Uint64(), + nonce.Int().Uint64(), + gasLimit.Int().Uint64(), + 0, + false, + builder.chainID.String(), + string(payload), + fees.Coins(), + types.DecCoins{}, + ) + + sdkMsgs := []types.Msg{sendMsg.Msg()} + + signMsg, err := txBuilder.BuildSignMsg(sdkMsgs) + if err != nil { + return nil, err + } + + return &StdTx{ + msgs: []MsgSend{sendMsg}, + fee: parseStdFee(signMsg.Fee), + memo: pack.String(payload.String()), + cdc: builder.client.cdc, + signMsg: signMsg, + }, nil +} + +// Coin copy type from types.coin +type Coin struct { + Denom pack.String `json:"denom"` + Amount pack.U64 `json:"amount"` +} + +// parseCoin parse types.Coin to Coin +func parseCoin(sdkCoin types.Coin) Coin { + return Coin{ + Denom: pack.NewString(sdkCoin.Denom), + Amount: pack.U64(uint64(sdkCoin.Amount.Int64())), + } +} + +// Coins array of Coin +type Coins []Coin + +// parseCoins parse types.Coins to Coins +func parseCoins(sdkCoins types.Coins) Coins { + coins := make(Coins, 0, len(sdkCoins)) + for _, sdkCoin := range sdkCoins { + coins = append(coins, parseCoin(sdkCoin)) + } + return coins +} + +// Coins parse pack coins to sdk coins +func (coins Coins) Coins() types.Coins { + sdkCoins := make(types.Coins, 0, len(coins)) + for _, coin := range coins { + sdkCoins = append(sdkCoins, types.Coin{ + Denom: coin.Denom.String(), + Amount: types.NewInt(int64(coin.Amount.Uint64())), + }) + } + + sdkCoins.Sort() + return sdkCoins +} + +// MsgSend - high level transaction of the coin module +type MsgSend struct { + FromAddress Address `json:"from_address" yaml:"from_address"` + ToAddress Address `json:"to_address" yaml:"to_address"` + Amount Coins `json:"amount" yaml:"amount"` +} + +// Msg convert MsgSend to types.Msg +func (msg MsgSend) Msg() types.Msg { + return bank.NewMsgSend( + msg.FromAddress.AccAddress(), + msg.ToAddress.AccAddress(), + msg.Amount.Coins(), + ) +} + +// NOTE: we only support MsgSend +// parseMsg parse types.Msg to MsgSend +func parseMsg(msg types.Msg) (MsgSend, error) { + if msg, ok := msg.(bank.MsgSend); ok { + return MsgSend{ + FromAddress: Address(msg.FromAddress), + ToAddress: Address(msg.ToAddress), + Amount: parseCoins(msg.Amount), + }, nil + } + + return MsgSend{}, fmt.Errorf("Failed to parse %v to MsgSend", msg) +} + +// StdFee auth.StdFee wrapper +type StdFee struct { + Amount Coins `json:"amount" yaml:"amount"` + Gas pack.U64 `json:"gas" yaml:"gas"` +} + +// parseStdFee parse auth.StdFee to StdFee +func parseStdFee(stdFee auth.StdFee) StdFee { + return StdFee{ + Amount: parseCoins(stdFee.Amount), + Gas: pack.U64(stdFee.Gas), + } +} + +// StdSignature auth.StdStdSignature wrapper +type StdSignature struct { + PubKey pack.Bytes `json:"pub_key" yaml:"pub_key"` + Signature pack.Bytes `json:"signature" yaml:"signature"` +} + +// parseStdSignature parse auth.StdSignature to StdSignature +func parseStdSignature(stdSig auth.StdSignature) StdSignature { + return StdSignature{ + PubKey: pack.NewBytes(stdSig.PubKey.Bytes()), + Signature: pack.NewBytes(stdSig.Signature), + } +} + +// StdTx auth.StStdTx wrapper +type StdTx struct { + msgs []MsgSend + fee StdFee + memo pack.String + signatures []auth.StdSignature + + cdc *codec.Codec + signMsg auth.StdSignMsg +} + +// From returns the sender of the transaction +func (tx StdTx) From() address.Address { + return address.Address(tx.msgs[0].FromAddress.AccAddress().String()) +} + +// To returns the recipients of the transaction. For the cosmos chain, there +// can be multiple recipients from a single transaction. +func (tx StdTx) To() address.Address { + return address.Address(tx.msgs[0].ToAddress.AccAddress().String()) +} + +// Value returns the values being transferred in a transaction. For the cosmos +// chain, there can be multiple messages (each with a different value being +// transferred) in a single transaction. +func (tx StdTx) Value() pack.U256 { + value := pack.NewU64(0) + for _, msg := range tx.msgs { + value.AddAssign(msg.Amount[0].Amount) + } + return pack.NewU256FromU64(value) +} + +// Nonce returns the transaction count of the transaction sender. +func (tx StdTx) Nonce() pack.U256 { + return pack.NewU256FromU64(pack.NewU64(tx.signMsg.Sequence)) +} + +// Payload returns the memo attached to the transaction. +func (tx StdTx) Payload() contract.CallData { + return contract.CallData(pack.NewBytes([]byte(tx.memo))) +} + +// Hash return txhash bytes. +func (tx StdTx) Hash() pack.Bytes { + if len(tx.signatures) == 0 { + return pack.Bytes{} + } + + txBytes, err := tx.Serialize() + if err != nil { + return pack.Bytes{} + } + + return pack.NewBytes(tmhash.Sum(txBytes)) +} + +// Sighashes that need to be signed before this transaction can be submitted. +func (tx StdTx) Sighashes() ([]pack.Bytes32, error) { + sighashBytes := crypto.Sha256(tx.signMsg.Bytes()) + if len(sighashBytes) != 32 { + return nil, fmt.Errorf("expected 32 bytes, got %v bytes", len(tx.signMsg.Bytes())) + } + sighash := pack.Bytes32{} + copy(sighash[:], sighashBytes) + return []pack.Bytes32{sighash}, nil +} + +// Sign the transaction by injecting signatures and the serialized pubkey of +// the signer. +func (tx *StdTx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { + var stdSignatures []auth.StdSignature + for _, sig := range signatures { + var cpPubKey secp256k1.PubKeySecp256k1 + copy(cpPubKey[:], pubKey[:secp256k1.PubKeySecp256k1Size]) + stdSignatures = append(stdSignatures, auth.StdSignature{ + // Cosmos uses 64-bytes signature + // https://github.com/tendermint/tendermint/blob/v0.33.8/crypto/secp256k1/secp256k1_nocgo.go#L60-L70 + Signature: sig[:64], + PubKey: cpPubKey, + }) + } + + signers := make(map[string]bool) + for _, msg := range tx.signMsg.Msgs { + for _, signer := range msg.GetSigners() { + signers[signer.String()] = true + } + } + + for _, sig := range stdSignatures { + signer := types.AccAddress(sig.Address()).String() + if _, ok := signers[signer]; !ok { + return fmt.Errorf("wrong signer: %s", signer) + } + } + + if len(signers) != len(stdSignatures) { + return fmt.Errorf("insufficient signers") + } + + tx.signatures = stdSignatures + return nil +} + +// Serialize the transaction. +func (tx StdTx) Serialize() (pack.Bytes, error) { + txBytes, err := tx.cdc.MarshalBinaryLengthPrefixed(auth.NewStdTx(tx.signMsg.Msgs, tx.signMsg.Fee, tx.signatures, tx.signMsg.Memo)) + if err != nil { + return pack.Bytes{}, err + } + + return txBytes, nil +} + +// parseStdTx parse auth.StdTx to StdTx +func parseStdTx(stdTx auth.StdTx) (StdTx, error) { + var msgs []MsgSend + for _, msg := range stdTx.Msgs { + msg, err := parseMsg(msg) + if err != nil { + return StdTx{}, err + } + + msgs = append(msgs, msg) + } + + fee := parseStdFee(stdTx.Fee) + memo := pack.NewString(stdTx.Memo) + + return StdTx{ + msgs: msgs, + fee: fee, + memo: memo, + signatures: stdTx.Signatures, + }, nil +} diff --git a/chain/digibyte/address.go b/chain/digibyte/address.go index 9712b843..e2f26874 100644 --- a/chain/digibyte/address.go +++ b/chain/digibyte/address.go @@ -2,6 +2,13 @@ package digibyte import "github.com/renproject/multichain/chain/bitcoin" +// AddressEncoder encapsulates the chain specific configurations and implements +// the address.Encoder interface type AddressEncoder = bitcoin.AddressEncoder + +// AddressDecoder encapsulates the chain specific configurations and implements +// the address.Decoder interface type AddressDecoder = bitcoin.AddressDecoder + +// AddressEncodeDecoder implements the address.EncodeDecoder interface type AddressEncodeDecoder = bitcoin.AddressEncodeDecoder diff --git a/chain/digibyte/digibyte.go b/chain/digibyte/digibyte.go index 7ff5c2de..70b246d5 100644 --- a/chain/digibyte/digibyte.go +++ b/chain/digibyte/digibyte.go @@ -1,6 +1,7 @@ package digibyte import ( + "math/big" "time" "github.com/btcsuite/btcd/chaincfg" @@ -14,12 +15,31 @@ func init() { } if err := chaincfg.Register(&TestnetParams); err != nil { panic(err) - } + } if err := chaincfg.Register(&RegressionNetParams); 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{ @@ -96,15 +116,15 @@ func newHashFromStr(hexStr string) *chainhash.Hash { return hash } - +// MainNetParams returns the chain configuration for mainnet var MainNetParams = chaincfg.Params{ Name: "mainnet", Net: 0xdab6c3fa, DefaultPort: "12024", // Chain parameters - GenesisBlock: &genesisBlock, - GenesisHash: &genesisHash, + GenesisBlock: &genesisBlock, + GenesisHash: &genesisHash, // Human-readable part for Bech32 encoded segwit addresses, as defined in // BIP 173. @@ -112,7 +132,7 @@ var MainNetParams = chaincfg.Params{ // Address encoding magics PubKeyHashAddrID: 0x1e, // starts with 1 - ScriptHashAddrID: 0x32, // starts with 3 + ScriptHashAddrID: 0x3f, // starts with 3 PrivateKeyID: 0x80, // starts with 5 (uncompressed) or K (compressed) WitnessPubKeyHashAddrID: 0x06, // starts with p2 WitnessScriptHashAddrID: 0x0A, // starts with 7Xh @@ -126,19 +146,20 @@ var MainNetParams = chaincfg.Params{ HDCoinType: 0x14, } +// TestnetParams returns the chain configuration for testnet var TestnetParams = chaincfg.Params{ - Name: "testnet", + Name: "testnet", // DigiByte has 0xdab5bffa as RegTest (same as Bitcoin's RegTest). // Setting it to an arbitrary value (leet_hex(digibyte)), so that we can // register the regtest network. // DigiByte Core Developers will change this soon. - Net: 0xddbdc8fd, + Net: 0xddbdc8fd, DefaultPort: "12026", // Chain parameters - GenesisBlock: &genesisBlock, - GenesisHash: &genesisHash, + GenesisBlock: &genesisBlock, + GenesisHash: &genesisHash, // Human-readable part for Bech32 encoded segwit addresses, as defined in // BIP 173. @@ -160,19 +181,20 @@ var TestnetParams = chaincfg.Params{ HDCoinType: 0x14, } +// RegressionNetParams returns the chain configuration for regression net var RegressionNetParams = chaincfg.Params{ - Name: "regtest", + Name: "regtest", // DigiByte has 0xdab5bffa as RegTest (same as Bitcoin's RegTest). // Setting it to an arbitrary value (leet_hex(digibyte)), so that we can // register the regtest network. // DigiByte Core Developers will change this soon. - Net: 0xd191841e, + Net: 0xd191841e, DefaultPort: "18444", // Chain parameters - GenesisBlock: &genesisBlock, - GenesisHash: &genesisHash, + GenesisBlock: &genesisBlock, + GenesisHash: &genesisHash, // Human-readable part for Bech32 encoded segwit addresses, as defined in // BIP 173. diff --git a/chain/digibyte/gas.go b/chain/digibyte/gas.go index 9750c922..b49ce8b3 100644 --- a/chain/digibyte/gas.go +++ b/chain/digibyte/gas.go @@ -2,4 +2,8 @@ package digibyte import "github.com/renproject/multichain/chain/bitcoin" +// GasEstimator re-exports bitcoin.GasEstimator. type GasEstimator = bitcoin.GasEstimator + +// NewGasEstimator re-exports bitcoin.NewGasEstimator. +var NewGasEstimator = bitcoin.NewGasEstimator diff --git a/chain/digibyte/utxo.go b/chain/digibyte/utxo.go index afde227d..aa80452c 100644 --- a/chain/digibyte/utxo.go +++ b/chain/digibyte/utxo.go @@ -3,14 +3,33 @@ package digibyte import "github.com/renproject/multichain/chain/bitcoin" type ( - Tx = bitcoin.Tx - TxBuilder = bitcoin.TxBuilder - Client = bitcoin.Client + // Tx represents a simple Bitcoin transaction that implements the Bitcoin Compat + // API. + Tx = bitcoin.Tx + + // The TxBuilder is an implementation of a UTXO-compatible transaction builder + // for Bitcoin. + TxBuilder = bitcoin.TxBuilder + + // A Client interacts with an instance of the Bitcoin network using the RPC + // interface exposed by a Bitcoin node. + Client = bitcoin.Client + + // ClientOptions are used to parameterise the behaviour of the Client. ClientOptions = bitcoin.ClientOptions ) var ( - NewTxBuilder = bitcoin.NewTxBuilder - NewClient = bitcoin.NewClient - DefaultClientOptions = bitcoin.DefaultClientOptions + // NewTxBuilder re-exports bitoin.NewTxBuilder + NewTxBuilder = bitcoin.NewTxBuilder + + // NewClient re-exports bitcoin.NewClient + NewClient = bitcoin.NewClient ) + +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the host, user, and password should be changed. +func DefaultClientOptions() ClientOptions { + return bitcoin.DefaultClientOptions().WithHost("http://0.0.0.0:20443") +} diff --git a/chain/dogecoin/address.go b/chain/dogecoin/address.go index e94c3a87..0e4ee882 100644 --- a/chain/dogecoin/address.go +++ b/chain/dogecoin/address.go @@ -3,7 +3,12 @@ package dogecoin import "github.com/renproject/multichain/chain/bitcoin" type ( - AddressEncoder = bitcoin.AddressEncoder - AddressDecoder = bitcoin.AddressDecoder + // AddressEncoder re-exports bitcoin.AddressEncoder. + AddressEncoder = bitcoin.AddressEncoder + + // AddressDecoder re-exports bitcoin.AddressDecoder. + AddressDecoder = bitcoin.AddressDecoder + + // AddressEncodeDecoder re-exports bitcoin.AddressEncodeDecoder. AddressEncodeDecoder = bitcoin.AddressEncodeDecoder ) diff --git a/chain/dogecoin/dogecoin.go b/chain/dogecoin/dogecoin.go index 131c96a4..d2850070 100644 --- a/chain/dogecoin/dogecoin.go +++ b/chain/dogecoin/dogecoin.go @@ -8,11 +8,15 @@ func init() { if err := chaincfg.Register(&MainNetParams); err != nil { panic(err) } + if err := chaincfg.Register(&TestNetParams); err != nil { + panic(err) + } if err := chaincfg.Register(&RegressionNetParams); err != nil { panic(err) } } +// MainNetParams returns the chain configuration for mainnet. var MainNetParams = chaincfg.Params{ Name: "mainnet", Net: 0xc0c0c0c0, @@ -32,13 +36,34 @@ var MainNetParams = chaincfg.Params{ Bech32HRPSegwit: "doge", } +// TestNetParams returns the chain configuration for testnet. +var TestNetParams = chaincfg.Params{ + Name: "testnet", + Net: 0xfcc1b7dc, + + // Address encoding magics + PubKeyHashAddrID: 113, + ScriptHashAddrID: 196, + PrivateKeyID: 241, + + // 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 + + // Human-readable part for Bech32 encoded segwit addresses, as defined in + // BIP 173. Dogecoin does not actually support this, but we do not want to + // collide with real addresses, so we specify it. + Bech32HRPSegwit: "doget", +} + +// RegressionNetParams returns the chain configuration for regression net. var RegressionNetParams = chaincfg.Params{ Name: "regtest", // Dogecoin has 0xdab5bffa as RegTest (same as Bitcoin's RegTest). // Setting it to an arbitrary value (leet_hex(dogecoin)), so that we can // register the regtest network. - Net: 0xd063c017, + Net: 0xfabfb5da, // Address encoding magics PubKeyHashAddrID: 111, diff --git a/chain/dogecoin/gas.go b/chain/dogecoin/gas.go index 07336be8..69a395fb 100644 --- a/chain/dogecoin/gas.go +++ b/chain/dogecoin/gas.go @@ -2,6 +2,8 @@ package dogecoin import "github.com/renproject/multichain/chain/bitcoin" +// GasEstimator re-exports bitcoin.GasEstimator. type GasEstimator = bitcoin.GasEstimator +// NewGasEstimator re-exports bitcoin.NewGasEstimator. var NewGasEstimator = bitcoin.NewGasEstimator diff --git a/chain/dogecoin/gas_test.go b/chain/dogecoin/gas_test.go index e03320bb..8dca3426 100644 --- a/chain/dogecoin/gas_test.go +++ b/chain/dogecoin/gas_test.go @@ -1 +1,52 @@ package dogecoin_test + +import ( + "context" + + "github.com/renproject/multichain/chain/dogecoin" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating dogecoin network fee", func() { + It("should work", func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client := dogecoin.NewClient(dogecoin.DefaultClientOptions()) + + // estimate fee to include tx within 1 block. + fallback1 := uint64(123) + gasEstimator1 := dogecoin.NewGasEstimator(client, 1, pack.NewU256FromUint64(fallback1)) + gasPrice1, _, err := gasEstimator1.EstimateGas(ctx) + if err != nil { + Expect(gasPrice1).To(Equal(pack.NewU256FromUint64(fallback1))) + } + + // estimate fee to include tx within 10 blocks. + fallback2 := uint64(234) + gasEstimator2 := dogecoin.NewGasEstimator(client, 10, pack.NewU256FromUint64(fallback2)) + gasPrice2, _, err := gasEstimator2.EstimateGas(ctx) + if err != nil { + Expect(gasPrice2).To(Equal(pack.NewU256FromUint64(fallback2))) + } + + // estimate fee to include tx within 100 blocks. + fallback3 := uint64(345) + gasEstimator3 := dogecoin.NewGasEstimator(client, 100, pack.NewU256FromUint64(fallback3)) + gasPrice3, _, err := gasEstimator3.EstimateGas(ctx) + if err != nil { + Expect(gasPrice3).To(Equal(pack.NewU256FromUint64(fallback3))) + } + + // expect fees in this order at the very least. + if err == nil { + Expect(gasPrice1.GreaterThanEqual(gasPrice2)).To(BeTrue()) + Expect(gasPrice2.GreaterThanEqual(gasPrice3)).To(BeTrue()) + } + }) + }) +}) diff --git a/chain/dogecoin/utxo.go b/chain/dogecoin/utxo.go index 5cee84d1..e998791c 100644 --- a/chain/dogecoin/utxo.go +++ b/chain/dogecoin/utxo.go @@ -3,14 +3,30 @@ package dogecoin import "github.com/renproject/multichain/chain/bitcoin" type ( - Tx = bitcoin.Tx - TxBuilder = bitcoin.TxBuilder - Client = bitcoin.Client + // Tx re-exports bitcoin.Tx. + Tx = bitcoin.Tx + + // TxBuilder re-exports bitcoin.TxBuilder. + TxBuilder = bitcoin.TxBuilder + + // Client re-exports bitcoin.Client. + Client = bitcoin.Client + + // ClientOptions re-exports bitcoin.ClientOptions. ClientOptions = bitcoin.ClientOptions ) var ( - NewTxBuilder = bitcoin.NewTxBuilder - NewClient = bitcoin.NewClient - DefaultClientOptions = bitcoin.DefaultClientOptions + // NewTxBuilder re-exports bitcoin.NewTxBuilder. + NewTxBuilder = bitcoin.NewTxBuilder + + // NewClient re-exports bitcoin.NewClient. + NewClient = bitcoin.NewClient ) + +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the host, user, and password should be changed. +func DefaultClientOptions() ClientOptions { + return bitcoin.DefaultClientOptions().WithHost("http://0.0.0.0:18332") +} diff --git a/chain/ethereum/account.go b/chain/ethereum/account.go deleted file mode 100644 index 59dd7210..00000000 --- a/chain/ethereum/account.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum diff --git a/chain/ethereum/account_test.go b/chain/ethereum/account_test.go deleted file mode 100644 index bbd71f0b..00000000 --- a/chain/ethereum/account_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum_test diff --git a/chain/ethereum/address.go b/chain/ethereum/address.go index 7a1ebb46..dd3dae5b 100644 --- a/chain/ethereum/address.go +++ b/chain/ethereum/address.go @@ -12,17 +12,20 @@ import ( "github.com/renproject/surge" ) +// AddressEncodeDecoder implements the address.EncodeDecoder interface type AddressEncodeDecoder struct { AddressEncoder AddressDecoder } +// AddressEncoder implements the address.Encoder interface. type AddressEncoder interface { EncodeAddress(address.RawAddress) (address.Address, error) } type addressEncoder struct{} +// NewAddressEncodeDecoder constructs a new AddressEncodeDecoder. func NewAddressEncodeDecoder() address.EncodeDecoder { return AddressEncodeDecoder{ AddressEncoder: NewAddressEncoder(), @@ -30,16 +33,19 @@ func NewAddressEncodeDecoder() address.EncodeDecoder { } } +// AddressDecoder implements the address.Decoder interface. type AddressDecoder interface { DecodeAddress(address.Address) (address.RawAddress, error) } type addressDecoder struct{} +// NewAddressDecoder constructs a new AddressDecoder. func NewAddressDecoder() AddressDecoder { return addressDecoder{} } +// NewAddressEncoder constructs a new AddressEncoder. func NewAddressEncoder() AddressEncoder { return addressEncoder{} } diff --git a/chain/ethereum/ethereum.go b/chain/ethereum/ethereum.go deleted file mode 100644 index 59dd7210..00000000 --- a/chain/ethereum/ethereum.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum diff --git a/chain/ethereum/ethereum_test.go b/chain/ethereum/ethereum_test.go deleted file mode 100644 index bbd71f0b..00000000 --- a/chain/ethereum/ethereum_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum_test diff --git a/chain/ethereum/gas.go b/chain/ethereum/gas.go deleted file mode 100644 index 59dd7210..00000000 --- a/chain/ethereum/gas.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum diff --git a/chain/ethereum/gas_test.go b/chain/ethereum/gas_test.go deleted file mode 100644 index bbd71f0b..00000000 --- a/chain/ethereum/gas_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethereum_test diff --git a/chain/filecoin/account.go b/chain/filecoin/account.go new file mode 100644 index 00000000..82261a42 --- /dev/null +++ b/chain/filecoin/account.go @@ -0,0 +1,142 @@ +package filecoin + +import ( + "bytes" + "context" + "fmt" + + filaddress "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/chain/types" + "github.com/minio/blake2b-simd" + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/api/contract" + "github.com/renproject/pack" +) + +// TxBuilder represents a transaction builder that builds transactions to be +// broadcasted to the filecoin network. The TxBuilder is configured using a +// gas price and gas limit. +type TxBuilder struct { +} + +// NewTxBuilder creates a new transaction builder. +func NewTxBuilder() TxBuilder { + return TxBuilder{} +} + +// BuildTx receives transaction fields and constructs a new transaction. +func (txBuilder TxBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (account.Tx, error) { + filfrom, err := filaddress.NewFromString(string(from)) + if err != nil { + return nil, fmt.Errorf("bad from address '%v': %v", from, err) + } + filto, err := filaddress.NewFromString(string(to)) + if err != nil { + return nil, fmt.Errorf("bad to address '%v': %v", to, err) + } + methodNum := abi.MethodNum(0) + return &Tx{ + msg: types.Message{ + Version: types.MessageVersion, + From: filfrom, + To: filto, + Value: big.Int{Int: value.Int()}, + Nonce: nonce.Int().Uint64(), + GasFeeCap: big.Int{Int: gasCap.Int()}, + GasLimit: gasLimit.Int().Int64(), + GasPremium: big.Int{Int: gasPrice.Int()}, + Method: methodNum, + Params: payload, + }, + signature: pack.Bytes65{}, + }, nil +} + +// Tx represents a filecoin transaction, encapsulating a message and its +// signature. +type Tx struct { + msg types.Message + signature pack.Bytes65 +} + +// Hash returns the hash that uniquely identifies the transaction. +// Generally, hashes are irreversible hash functions that consume the +// content of the transaction. +func (tx Tx) Hash() pack.Bytes { + if !tx.signature.Equal(&pack.Bytes65{}) { + // construct crypto.Signature + signature := crypto.Signature{ + Type: crypto.SigTypeSecp256k1, + Data: tx.signature.Bytes(), + } + // construct types.SignedMessage + signedMessage := types.SignedMessage{ + Message: tx.msg, + Signature: signature, + } + return pack.NewBytes(signedMessage.Cid().Bytes()) + } + return pack.NewBytes(tx.msg.Cid().Bytes()) +} + +// From returns the address that is sending the transaction. Generally, +// this is also the address that must sign the transaction. +func (tx Tx) From() address.Address { + return address.Address(tx.msg.From.String()) +} + +// To returns the address that is receiving the transaction. This can be the +// address of an external account, controlled by a private key, or it can be +// the address of a contract. +func (tx Tx) To() address.Address { + return address.Address(tx.msg.To.String()) +} + +// Value being sent from the sender to the receiver. +func (tx Tx) Value() pack.U256 { + return pack.NewU256FromInt(tx.msg.Value.Int) +} + +// Nonce returns the nonce used to order the transaction with respect to all +// other transactions signed and submitted by the sender. +func (tx Tx) Nonce() pack.U256 { + return pack.NewU256FromU64(pack.NewU64(tx.msg.Nonce)) +} + +// Payload returns arbitrary data that is associated with the transaction. +// Generally, this payload is used to send notes between external accounts, +// or invoke business logic on a contract. +func (tx Tx) Payload() contract.CallData { + return contract.CallData(tx.msg.Params) +} + +// Sighashes returns the digests that must be signed before the transaction +// can be submitted by the client. +func (tx Tx) Sighashes() ([]pack.Bytes32, error) { + return []pack.Bytes32{pack.Bytes32(blake2b.Sum256(tx.Hash()))}, nil +} + +// Sign the transaction by injecting signatures for the required sighashes. +// The serialized public key used to sign the sighashes must also be +// specified. +func (tx *Tx) Sign(signatures []pack.Bytes65, pubkey pack.Bytes) error { + if len(signatures) != 1 { + return fmt.Errorf("expected 1 signature, got %v signatures", len(signatures)) + } + tx.signature = signatures[0] + return nil +} + +// Serialize the transaction into bytes. Generally, this is the format in +// which the transaction will be submitted by the client. +func (tx Tx) Serialize() (pack.Bytes, error) { + buf := new(bytes.Buffer) + if err := tx.msg.MarshalCBOR(buf); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/chain/filecoin/account_test.go b/chain/filecoin/account_test.go new file mode 100644 index 00000000..0d419baa --- /dev/null +++ b/chain/filecoin/account_test.go @@ -0,0 +1 @@ +package filecoin_test diff --git a/chain/filecoin/address.go b/chain/filecoin/address.go new file mode 100644 index 00000000..cb34c5a6 --- /dev/null +++ b/chain/filecoin/address.go @@ -0,0 +1,46 @@ +package filecoin + +import ( + filaddress "github.com/filecoin-project/go-address" + "github.com/renproject/multichain/api/address" +) + +// AddressEncodeDecoder implements the address.EncodeDecoder interface +type AddressEncodeDecoder struct { + AddressEncoder + AddressDecoder +} + +// AddressEncoder implements the address.Encoder interface. +type AddressEncoder struct{} + +// AddressDecoder implements the address.Decoder interface. +type AddressDecoder struct{} + +// NewAddressEncodeDecoder constructs a new AddressEncodeDecoder. +func NewAddressEncodeDecoder() AddressEncodeDecoder { + return AddressEncodeDecoder{ + AddressEncoder: AddressEncoder{}, + AddressDecoder: AddressDecoder{}, + } +} + +// EncodeAddress implements the address.Encoder interface. It receives a raw +// address and encodes it to a human-readable stringified address. +func (encoder AddressEncoder) EncodeAddress(raw address.RawAddress) (address.Address, error) { + addr, err := filaddress.NewFromBytes([]byte(raw)) + if err != nil { + return address.Address(""), err + } + return address.Address(addr.String()), nil +} + +// DecodeAddress implements the address.Decoder interface. It receives a human +// readable address and decodes it to an address represented by raw bytes. +func (addrDecoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + rawAddr, err := filaddress.NewFromString(string(addr)) + if err != nil { + return nil, err + } + return address.RawAddress(rawAddr.Bytes()), nil +} diff --git a/chain/filecoin/address_test.go b/chain/filecoin/address_test.go new file mode 100644 index 00000000..670419ef --- /dev/null +++ b/chain/filecoin/address_test.go @@ -0,0 +1,97 @@ +package filecoin_test + +import ( + "math/rand" + "testing/quick" + "time" + + filaddress "github.com/filecoin-project/go-address" + "github.com/multiformats/go-varint" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/filecoin" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Address", func() { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + encoderDecoder := filecoin.NewAddressEncodeDecoder() + + Context("when encoding and decoding", func() { + Context("for ID protocol", func() { + It("should behave correctly without errors", func() { + f := func() bool { + x := varint.ToUvarint(uint64(r.Int63())) + x = append([]byte{byte(filaddress.ID)}, x...) + + rawAddr := address.RawAddress(pack.NewBytes(x[:])) + addr, err := encoderDecoder.AddressEncoder.EncodeAddress(rawAddr) + Expect(err).ToNot(HaveOccurred()) + + decodedAddr, err := encoderDecoder.AddressDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + Expect(decodedAddr).To(Equal(rawAddr)) + return true + } + Expect(quick.Check(f, nil)).To(Succeed()) + }) + }) + + Context("for Sepc protocol", func() { + It("should behave correctly without errors", func() { + f := func(x [filaddress.PayloadHashLength]byte) bool { + y := append([]byte{byte(filaddress.SECP256K1)}, x[:]...) + + rawAddr := address.RawAddress(pack.NewBytes(y[:])) + addr, err := encoderDecoder.AddressEncoder.EncodeAddress(rawAddr) + Expect(err).ToNot(HaveOccurred()) + + decodedAddr, err := encoderDecoder.AddressDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + Expect(decodedAddr).To(Equal(rawAddr)) + return true + } + Expect(quick.Check(f, nil)).To(Succeed()) + }) + }) + + Context("for Actor protocol", func() { + It("should behave correctly without errors", func() { + f := func(x [filaddress.PayloadHashLength]byte) bool { + y := append([]byte{byte(filaddress.Actor)}, x[:]...) + + rawAddr := address.RawAddress(pack.NewBytes(y[:])) + addr, err := encoderDecoder.AddressEncoder.EncodeAddress(rawAddr) + Expect(err).ToNot(HaveOccurred()) + + decodedAddr, err := encoderDecoder.AddressDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + Expect(decodedAddr).To(Equal(rawAddr)) + return true + } + Expect(quick.Check(f, nil)).To(Succeed()) + }) + }) + + Context("for BLS protocol", func() { + It("should behave correctly without errors", func() { + f := func(x [filaddress.BlsPublicKeyBytes]byte) bool { + y := append([]byte{byte(filaddress.BLS)}, x[:]...) + + rawAddr := address.RawAddress(pack.NewBytes(y[:])) + addr, err := encoderDecoder.AddressEncoder.EncodeAddress(rawAddr) + Expect(err).ToNot(HaveOccurred()) + + decodedAddr, err := encoderDecoder.AddressDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + Expect(decodedAddr).To(Equal(rawAddr)) + return true + } + Expect(quick.Check(f, nil)).To(Succeed()) + }) + }) + }) +}) diff --git a/chain/filecoin/client.go b/chain/filecoin/client.go new file mode 100644 index 00000000..b783e465 --- /dev/null +++ b/chain/filecoin/client.go @@ -0,0 +1,207 @@ +package filecoin + +import ( + "context" + "fmt" + "net/http" + + filaddress "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/api/v0api" + filclient "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/api/address" + "github.com/renproject/pack" +) + +const ( + // AuthorizationKey is the header key used for authorization + AuthorizationKey = "Authorization" + + // DefaultClientRPCURL is the RPC URL used by default, to interact with the + // filecoin lotus node. + DefaultClientRPCURL = "http://127.0.0.1:1234/rpc/v0" + + // DefaultClientAuthToken is the auth token used to instantiate the lotus + // client. A valid lotus auth token is required to write messages to the + // filecoin storage. To do read-only queries, auth token is not required. + DefaultClientAuthToken = "" +) + +// ClientOptions are used to parameterise the behaviour of the Client. +type ClientOptions struct { + RPCURL string + AuthToken string +} + +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the rpc-url and authentication token should be +// changed. +func DefaultClientOptions() ClientOptions { + return ClientOptions{ + RPCURL: DefaultClientRPCURL, + AuthToken: DefaultClientAuthToken, + } +} + +// WithRPCURL returns a modified version of the options with the given API +// rpc-url +func (opts ClientOptions) WithRPCURL(rpcURL pack.String) ClientOptions { + opts.RPCURL = string(rpcURL) + return opts +} + +// WithAuthToken returns a modified version of the options with the given +// authentication token. +func (opts ClientOptions) WithAuthToken(authToken pack.String) ClientOptions { + opts.AuthToken = string(authToken) + return opts +} + +// Client holds options to connect to a filecoin lotus node, and the underlying +// RPC client instance. +type Client struct { + opts ClientOptions + node v0api.FullNode + closer jsonrpc.ClientCloser +} + +// NewClient creates and returns a new JSON-RPC client to the Filecoin node +func NewClient(opts ClientOptions) (*Client, error) { + requestHeaders := make(http.Header) + if opts.AuthToken != DefaultClientAuthToken { + requestHeaders.Add(AuthorizationKey, opts.AuthToken) + } + + node, closer, err := filclient.NewFullNodeRPCV0(context.Background(), opts.RPCURL, requestHeaders) + if err != nil { + return nil, err + } + + return &Client{opts, node, closer}, nil +} + +// LatestBlock returns the block number at the current chain head. +func (client *Client) LatestBlock(ctx context.Context) (pack.U64, error) { + headTipset, err := client.node.ChainHead(ctx) + if err != nil { + return pack.NewU64(0), fmt.Errorf("get chain head: %v", err) + } + if headTipset.Height() < 0 { + return pack.NewU64(0), fmt.Errorf("unexpected chain head, expected > 0, got: %v", headTipset.Height()) + } + + return pack.NewU64(uint64(headTipset.Height())), nil +} + +// Tx returns the transaction uniquely identified by the given transaction +// hash. It also returns the number of confirmations for the transaction. +func (client *Client) Tx(ctx context.Context, txID pack.Bytes) (account.Tx, pack.U64, error) { + // parse the transaction ID to a message ID + msgID, err := cid.Parse([]byte(txID)) + if err != nil { + return nil, pack.NewU64(0), fmt.Errorf("parsing txid: %v", err) + } + + // lookup message receipt to get its height + messageLookup, err := client.node.StateSearchMsg(ctx, msgID) + if err != nil { + return nil, pack.NewU64(0), fmt.Errorf("searching state for txid: %v", err) + } + if messageLookup == nil { + return nil, pack.NewU64(0), fmt.Errorf("searching state for txid %v: not found", msgID) + } + if messageLookup.Receipt.ExitCode.IsError() { + return nil, pack.NewU64(0), fmt.Errorf("executing transaction: %v", messageLookup.Receipt.ExitCode.String()) + } + if !messageLookup.Message.Equals(msgID) { + return nil, pack.U64(0), fmt.Errorf("searching state for txid: expected %v, got %v", msgID, messageLookup.Message) + } + + // get the most recent tipset and its height + chainHead, err := client.LatestBlock(ctx) + if err != nil { + return nil, pack.NewU64(0), err + } + confs := uint64(chainHead) - uint64(messageLookup.Height) + 1 + if confs < 0 { + return nil, pack.NewU64(0), fmt.Errorf("get chain head: negative confirmations") + } + + // get the message + msg, err := client.node.ChainGetMessage(ctx, msgID) + if err != nil { + return nil, pack.NewU64(0), fmt.Errorf("getting txid %v from chain: %v", msgID, err) + } + + return &Tx{msg: *msg}, pack.NewU64(confs), nil +} + +// SubmitTx to the underlying blockchain network. +func (client *Client) SubmitTx(ctx context.Context, tx account.Tx) error { + switch tx := tx.(type) { + case *Tx: + // construct crypto.Signature + signature := crypto.Signature{ + Type: crypto.SigTypeSecp256k1, + Data: tx.signature.Bytes(), + } + + // construct types.SignedMessage + signedMessage := types.SignedMessage{ + Message: tx.msg, + Signature: signature, + } + + // submit transaction to mempool + msgID, err := client.node.MpoolPush(ctx, &signedMessage) + if err != nil { + return fmt.Errorf("pushing txid %v to mpool: %v", msgID, err) + } + return nil + default: + return fmt.Errorf("expected type %T, got type %T", new(Tx), tx) + } +} + +// AccountNonce returns the current nonce of the account. This is the nonce to +// be used while building a new transaction. +func (client *Client) AccountNonce(ctx context.Context, addr address.Address) (pack.U256, error) { + filAddr, err := filaddress.NewFromString(string(addr)) + if err != nil { + return pack.U256{}, fmt.Errorf("bad address '%v': %v", addr, err) + } + + actor, err := client.node.StateGetActor(ctx, filAddr, types.NewTipSetKey(cid.Undef)) + if err != nil { + return pack.U256{}, fmt.Errorf("searching state for addr %v: %v", addr, err) + } + + return pack.NewU256FromU64(pack.NewU64(actor.Nonce)), nil +} + +// AccountBalance returns the account balancee for a given address. +func (client *Client) AccountBalance(ctx context.Context, addr address.Address) (pack.U256, error) { + filAddr, err := filaddress.NewFromString(string(addr)) + if err != nil { + return pack.U256{}, fmt.Errorf("bad address '%v': %v", addr, err) + } + + actor, err := client.node.StateGetActor(ctx, filAddr, types.NewTipSetKey(cid.Undef)) + if err != nil { + return pack.U256{}, fmt.Errorf("searching state for addr %v: %v", addr, err) + } + + balance := actor.Balance.Int + + // If the balance exceeds `MaxU256`, return an error. + if pack.MaxU256.Int().Cmp(balance) == -1 { + return pack.U256{}, fmt.Errorf("balance %v for %v exceeds MaxU256", balance.String(), addr) + } + + return pack.NewU256FromInt(balance), nil +} diff --git a/chain/filecoin/client_test.go b/chain/filecoin/client_test.go new file mode 100644 index 00000000..0d419baa --- /dev/null +++ b/chain/filecoin/client_test.go @@ -0,0 +1 @@ +package filecoin_test diff --git a/chain/filecoin/filecoin-ffi b/chain/filecoin/filecoin-ffi new file mode 160000 index 00000000..8b97bd82 --- /dev/null +++ b/chain/filecoin/filecoin-ffi @@ -0,0 +1 @@ +Subproject commit 8b97bd8230b77bd32f4f27e4766a6d8a03b4e801 diff --git a/chain/filecoin/filecoin.go b/chain/filecoin/filecoin.go new file mode 100644 index 00000000..e0985944 --- /dev/null +++ b/chain/filecoin/filecoin.go @@ -0,0 +1 @@ +package filecoin diff --git a/chain/filecoin/filecoin_suite_test.go b/chain/filecoin/filecoin_suite_test.go new file mode 100644 index 00000000..db0159ad --- /dev/null +++ b/chain/filecoin/filecoin_suite_test.go @@ -0,0 +1,13 @@ +package filecoin_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestFilecoin(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Filecoin Suite") +} diff --git a/chain/filecoin/filecoin_test.go b/chain/filecoin/filecoin_test.go new file mode 100644 index 00000000..0bf67fef --- /dev/null +++ b/chain/filecoin/filecoin_test.go @@ -0,0 +1,138 @@ +package filecoin_test + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + filaddress "github.com/filecoin-project/go-address" + filtypes "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" + "github.com/renproject/id" + "github.com/renproject/multichain" + "github.com/renproject/multichain/chain/filecoin" + "github.com/renproject/pack" + "github.com/renproject/surge" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Filecoin", func() { + Context("when broadcasting a tx", func() { + It("should work", func() { + // create context for the test + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // instantiate the client + client, err := filecoin.NewClient( + filecoin.DefaultClientOptions(). + WithAuthToken(fetchAuthToken()), + ) + Expect(err).ToNot(HaveOccurred()) + + // read the private key that we will send transactions from + senderPrivKeyStr := os.Getenv("FILECOIN_PK") + if senderPrivKeyStr == "" { + panic("FILECOIN_PK is undefined") + } + var ki filtypes.KeyInfo + data, err := hex.DecodeString(senderPrivKeyStr) + Expect(err).NotTo(HaveOccurred()) + err = json.Unmarshal(data, &ki) + Expect(err).NotTo(HaveOccurred()) + senderPrivKey := id.PrivKey{} + err = surge.FromBinary(&senderPrivKey, ki.PrivateKey) + Expect(err).NotTo(HaveOccurred()) + + // read sender's address into the filecoin-compatible format + senderAddr := os.Getenv("FILECOIN_ADDRESS") + if senderAddr == "" { + panic("FILECOIN_ADDRESS is undefined") + } + senderFilAddr, err := filaddress.NewFromString(string(senderAddr)) + Expect(err).NotTo(HaveOccurred()) + + // random recipient + recipientPK := id.NewPrivKey() + recipientPubKey := recipientPK.PubKey() + recipientPubKeyCompressed, err := surge.ToBinary(recipientPubKey) + Expect(err).NotTo(HaveOccurred()) + recipientFilAddr, err := filaddress.NewSecp256k1Address(recipientPubKeyCompressed) + Expect(err).NotTo(HaveOccurred()) + + // get good gas estimates + gasLimit := uint64(2200000) + gasEstimator := filecoin.NewGasEstimator(client, int64(gasLimit)) + gasPremium, gasFeeCap, err := gasEstimator.EstimateGas(ctx) + Expect(err).ToNot(HaveOccurred()) + + // construct the transaction builder + filTxBuilder := filecoin.NewTxBuilder() + + // build the transaction + sender := multichain.Address(pack.String(senderFilAddr.String())) + amount := pack.NewU256FromU64(pack.NewU64(100000000)) + nonce, err := client.AccountNonce(ctx, sender) + Expect(err).ToNot(HaveOccurred()) + + tx, err := filTxBuilder.BuildTx( + ctx, + sender, + multichain.Address(pack.String(recipientFilAddr.String())), + amount, // amount + nonce, // nonce + pack.NewU256FromU64(pack.NewU64(gasLimit)), // gasLimit + gasPremium, + gasFeeCap, + pack.Bytes(nil), // payload + ) + Expect(err).ToNot(HaveOccurred()) + + // Sign the filecoin-side lock transaction + txSighashes, err := tx.Sighashes() + Expect(err).ToNot(HaveOccurred()) + Expect(len(txSighashes)).To(Equal(1)) + Expect(len(txSighashes[0])).To(Equal(32)) + sighash32 := txSighashes[0] + hash := id.Hash(sighash32) + sig, err := senderPrivKey.Sign(&hash) + Expect(err).NotTo(HaveOccurred()) + sigBytes, err := surge.ToBinary(sig) + Expect(err).NotTo(HaveOccurred()) + txSignature := pack.Bytes65{} + copy(txSignature[:], sigBytes) + Expect(tx.Sign([]pack.Bytes65{txSignature}, []byte{})).To(Succeed()) + + // submit the transaction + txHash := tx.Hash() + txID, err := cid.Parse([]byte(txHash)) + Expect(err).NotTo(HaveOccurred()) + fmt.Printf("msgID = %v\n", txID) + err = client.SubmitTx(ctx, tx) + Expect(err).ToNot(HaveOccurred()) + + // Wait slightly before we query the chain's node. + time.Sleep(time.Second) + + // wait for the transaction to be included in a block + for { + // Loop until the transaction has at least a few confirmations. + tx, confs, err := client.Tx(ctx, txHash) + if err == nil { + Expect(confs.Uint64()).To(BeNumerically(">", 0)) + Expect(tx.From()).To(Equal(sender)) + Expect(tx.Value()).To(Equal(amount)) + break + } + + // wait and retry querying for the transaction + time.Sleep(5 * time.Second) + } + }) + }) +}) diff --git a/chain/filecoin/gas.go b/chain/filecoin/gas.go new file mode 100644 index 00000000..2b86c3de --- /dev/null +++ b/chain/filecoin/gas.go @@ -0,0 +1,70 @@ +package filecoin + +import ( + "context" + "fmt" + "math/big" + + filaddress "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/types" + "github.com/renproject/pack" +) + +// A GasEstimator returns the gas fee cap and gas premium that is needed in +// order to confirm transactions with an estimated maximum delay of one block. +// In distributed networks that collectively build, sign, and submit +// transactions, it is important that all nodes in the network have reached +// consensus on these values. +type GasEstimator struct { + client *Client + gasLimit int64 +} + +// NewGasEstimator returns a simple gas estimator that fetches the ideal gas +// fee cap and gas premium for a filecoin transaction to be included in a block +// with minimal delay. +func NewGasEstimator(client *Client, gasLimit int64) *GasEstimator { + return &GasEstimator{ + client: client, + gasLimit: gasLimit, + } +} + +// EstimateGas returns an estimate of the current gas price (also known as gas +// premium) and gas cap. These numbers change with congestion. These estimates +// are often a little bit off, and this should be considered when using them. +func (gasEstimator *GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) { + // Create a dummy "Send" message. + msgIn := types.Message{ + Version: types.MessageVersion, + From: filaddress.TestAddress, + To: filaddress.TestAddress2, + Value: types.EmptyInt, + Nonce: 0, + GasLimit: gasEstimator.gasLimit, + GasFeeCap: types.EmptyInt, + GasPremium: types.EmptyInt, + Method: abi.MethodNum(0), + Params: []byte{}, + } + + // Estimate the gas fee cap and gas premium fields for this dummy message. + msgOut, err := gasEstimator.client.node.GasEstimateMessageGas(ctx, &msgIn, nil, types.EmptyTSK) + if err != nil { + return pack.NewU256([32]byte{}), pack.NewU256([32]byte{}), fmt.Errorf("estimating gas price: %v", err) + } + + gasFeeCapBytes, err := msgOut.GasFeeCap.Bytes() + if err != nil { + return pack.NewU256([32]byte{}), pack.NewU256([32]byte{}), fmt.Errorf("getting abi/big bytes for %v: %v", msgOut.GasFeeCap, err) + } + gasPremiumBytes, err := msgOut.GasPremium.Bytes() + if err != nil { + return pack.NewU256([32]byte{}), pack.NewU256([32]byte{}), fmt.Errorf("getting abi/big bytes for %v: %v", msgOut.GasPremium, err) + } + gasFeeCap := big.NewInt(0).SetBytes(gasFeeCapBytes) + gasPremium := big.NewInt(0).SetBytes(gasPremiumBytes) + + return pack.NewU256FromInt(gasPremium), pack.NewU256FromInt(gasFeeCap), nil +} diff --git a/chain/filecoin/gas_test.go b/chain/filecoin/gas_test.go new file mode 100644 index 00000000..6c2a1df4 --- /dev/null +++ b/chain/filecoin/gas_test.go @@ -0,0 +1,56 @@ +package filecoin_test + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "strings" + + "github.com/renproject/multichain/chain/filecoin" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating gas parameters", func() { + It("should work", func() { + // create context for the test + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // instantiate the client + client, err := filecoin.NewClient( + filecoin.DefaultClientOptions(). + WithAuthToken(fetchAuthToken()), + ) + Expect(err).ToNot(HaveOccurred()) + + // instantiate the gas estimator + gasEstimator := filecoin.NewGasEstimator(client, 2000000) + + // estimate gas price + _, _, err = gasEstimator.EstimateGas(ctx) + Expect(err).ToNot(HaveOccurred()) + }) + }) +}) + +func fetchAuthToken() pack.String { + // fetch the auth token from filecoin's running docker container + cmd := exec.Command("docker", "exec", "infra_filecoin_1", "/bin/bash", "-c", "/app/lotus auth api-info --perm admin") + var out bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stderr + err := cmd.Run() + if err != nil { + fmt.Println(fmt.Sprint(err) + ": " + stderr.String()) + panic(fmt.Sprintf("could not run command: %v", err)) + } + tokenWithSuffix := strings.TrimPrefix(out.String(), "FULLNODE_API_INFO=") + authToken := strings.Split(tokenWithSuffix, ":/") + return pack.NewString(fmt.Sprintf("Bearer %s", authToken[0])) +} diff --git a/chain/harmony/account.go b/chain/harmony/account.go index 66d37d46..87aef0f1 100644 --- a/chain/harmony/account.go +++ b/chain/harmony/account.go @@ -1 +1,334 @@ -package harmony \ No newline at end of file +package harmony + +import ( + "context" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rlp" + "github.com/harmony-one/harmony/core/types" + common2 "github.com/harmony-one/harmony/rpc/common" + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/api/contract" + "github.com/renproject/pack" + "math/big" +) + +const ( + DefaultShardID = 1 + DefaultHost = "http://127.0.0.1:9598" +) + +type TxBuilder struct { + chainID *big.Int +} + +func NewTxBuilder(chainId *big.Int) account.TxBuilder { + return &TxBuilder{ + chainID: chainId, + } +} + +func (txBuilder *TxBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (account.Tx, error) { + toAddr, err := NewEncoderDecoder().DecodeAddress(to) + if err != nil { + return nil, err + } + tx := types.NewTransaction( + nonce.Int().Uint64(), + common.BytesToAddress(toAddr), + DefaultShardID, + value.Int(), + gasLimit.Int().Uint64(), + gasPrice.Int(), + payload) + return &Tx{ + harmonyTx: *tx, + chainId: txBuilder.chainID, + sender: from, + signed: false, + }, nil +} + +type TxData struct { + Blockhash string `json:"blockHash"` + Blocknumber uint64 `json:"blockNumber"` + From string `json:"from"` + Gas uint64 `json:"gas"` + Gasprice *big.Int `json:"gasPrice"` + Hash string `json:"hash"` + Input string `json:"input"` + Nonce uint64 `json:"nonce"` + R string `json:"r"` + S string `json:"s"` + Shardid uint32 `json:"shardID"` + Timestamp uint64 `json:"timestamp"` + To string `json:"to"` + Toshardid uint32 `json:"toShardID"` + Transactionindex uint64 `json:"transactionIndex"` + V string `json:"v"` + Value *big.Int `json:"value"` +} + +type Tx struct { + harmonyTx types.Transaction + chainId *big.Int + sender address.Address + signed bool +} + +func (tx *Tx) Hash() pack.Bytes { + return pack.NewBytes(tx.harmonyTx.Hash().Bytes()) +} + +func (tx *Tx) From() address.Address { + from, err := tx.harmonyTx.SenderAddress() + if err == nil { + addr, err := NewEncoderDecoder().EncodeAddress(from.Bytes()) + if err == nil { + return addr + } + } + return tx.sender +} + +func (tx *Tx) To() address.Address { + to := tx.harmonyTx.To() + if to != nil { + addr, err := NewEncoderDecoder().EncodeAddress(to.Bytes()) + if err == nil { + return addr + } + } + return "" +} + +func (tx *Tx) Value() pack.U256 { + return pack.NewU256FromInt(tx.harmonyTx.Value()) +} + +func (tx *Tx) Nonce() pack.U256 { + return pack.NewU256FromU64(pack.NewU64(tx.harmonyTx.Nonce())) +} + +func (tx *Tx) Payload() contract.CallData { + return tx.harmonyTx.Data() +} + +func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { + const digestLength = 32 + var ( + digestHash [32]byte + sighashes []pack.Bytes32 + ) + h := types.NewEIP155Signer(tx.chainId).Hash(&tx.harmonyTx).Bytes() + if len(h) != digestLength { + return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", digestLength, len(h)) + } + copy(digestHash[:], h[:32]) + sighashes = append(sighashes, digestHash) + return sighashes, nil +} + +func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { + if len(signatures) != 1 { + return fmt.Errorf("expected 1 signature, got %v signatures", len(signatures)) + } + signedTx, err := tx.harmonyTx.WithSignature(types.NewEIP155Signer(tx.chainId), signatures[0].Bytes()) + if err != nil { + return err + } + tx.harmonyTx = *signedTx + tx.signed = true + return nil +} + +func (tx *Tx) Serialize() (pack.Bytes, error) { + serializedTx, err := rlp.EncodeToBytes(&tx.harmonyTx) + if err != nil { + return pack.Bytes{}, err + } + return pack.NewBytes(serializedTx), nil +} + +type ClientOptions struct { + Host string +} + +type Client struct { + opts ClientOptions +} + +func (opts ClientOptions) WithHost(host string) ClientOptions { + opts.Host = host + return opts +} + +func DefaultClientOptions() ClientOptions { + return ClientOptions{ + Host: DefaultHost, + } +} + +func NewClient(opts ClientOptions) *Client { + return &Client{opts: opts} +} + +func (c *Client) LatestBlock(ctx context.Context) (pack.U64, error) { + for { + select { + case <-ctx.Done(): + return pack.NewU64(0), ctx.Err() + default: + } + const method = "hmyv2_blockNumber" + response, err := SendData(method, []byte{}, c.opts.Host) + if err != nil { + fmt.Println(err) + return pack.NewU64(0), err + } + var latestBlock uint64 + if err := json.Unmarshal(*response.Result, &latestBlock); err != nil { + return pack.NewU64(0), fmt.Errorf("decoding result: %v", err) + } + return pack.NewU64(latestBlock), nil + } +} + +func (c *Client) AccountBalance(ctx context.Context, addr address.Address) (pack.U256, error) { + for { + select { + case <-ctx.Done(): + return pack.U256{}, ctx.Err() + default: + } + data := []byte(fmt.Sprintf("[\"%s\"]", addr)) + const method = "hmyv2_getBalance" + response, err := SendData(method, data, c.opts.Host) + if err != nil { + fmt.Println(err) + return pack.U256{}, err + } + var balance uint64 + if err := json.Unmarshal(*response.Result, &balance); err != nil { + return pack.U256{}, fmt.Errorf("decoding result: %v", err) + } + return pack.NewU256FromU64(pack.NewU64(balance)), nil + } +} + +func (c *Client) AccountNonce(ctx context.Context, addr address.Address) (pack.U256, error) { + for { + select { + case <-ctx.Done(): + return pack.U256{}, ctx.Err() + default: + } + data := []byte(fmt.Sprintf("[\"%s\", \"%s\"]", addr, "SENT")) + const method = "hmyv2_getTransactionsCount" + response, err := SendData(method, data, c.opts.Host) + if err != nil { + fmt.Println(err) + return pack.U256{}, err + } + var nonce uint64 + if err := json.Unmarshal(*response.Result, &nonce); err != nil { + return pack.U256{}, fmt.Errorf("decoding result: %v", err) + } + return pack.NewU256FromU64(pack.NewU64(nonce)), nil + } +} + +func (c *Client) Tx(ctx context.Context, hash pack.Bytes) (account.Tx, pack.U64, error) { + for { + select { + case <-ctx.Done(): + return nil, pack.NewU64(0), ctx.Err() + default: + } + data := []byte(fmt.Sprintf("[\"%s\"]", hexutil.Encode(hash))) + const method = "hmyv2_getTransactionByHash" + response, err := SendData(method, data, c.opts.Host) + if err != nil { + return nil, pack.NewU64(0), err + } + var txData TxData + if response.Result == nil { + return nil, pack.NewU64(0), fmt.Errorf("decoding result: %v", err) + } + if err := json.Unmarshal(*response.Result, &txData); err != nil { + return nil, pack.NewU64(0), fmt.Errorf("decoding result: %v", err) + } + + tx, err := buildTxFromTxData(txData) + return tx, pack.NewU64(1), err + } +} + +func (c *Client) SubmitTx(ctx context.Context, tx account.Tx) error { + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + txSerilized, err := tx.Serialize() + if err != nil { + return err + } + hexSignature := hexutil.Encode(txSerilized) + data := []byte(fmt.Sprintf("[\"%s\"]", hexSignature)) + const method = "hmyv2_sendRawTransaction" + tx1 := new(types.Transaction) + err = rlp.DecodeBytes(txSerilized, tx1) + _, err = SendData(method, data, c.opts.Host) + if err != nil { + return err + } + return nil + } +} + +func (c *Client) ChainId(ctx context.Context) (*big.Int, error) { + for { + select { + case <-ctx.Done(): + return big.NewInt(0), ctx.Err() + default: + } + const method = "hmyv2_getNodeMetadata" + response, err := SendData(method, []byte{}, c.opts.Host) + if err != nil { + fmt.Println(err) + return big.NewInt(0), err + } + var nodeMetadata common2.NodeMetadata + if err := json.Unmarshal(*response.Result, &nodeMetadata); err != nil { + return big.NewInt(0), fmt.Errorf("decoding result: %v", err) + } + return nodeMetadata.ChainConfig.ChainID, nil + } +} + +func buildTxFromTxData(data TxData) (account.Tx, error) { + toAddr, err := NewEncoderDecoder().DecodeAddress(address.Address(data.To)) + if err != nil { + return nil, err + } + tx := types.NewTransaction( + data.Nonce, + common.BytesToAddress(toAddr), + data.Shardid, + data.Value, + data.Gas, + data.Gasprice, + pack.Bytes(nil), + ) + return &Tx{ + harmonyTx: *tx, + sender: address.Address(data.From), + signed: true, + }, nil +} \ No newline at end of file diff --git a/chain/harmony/account_test.go b/chain/harmony/account_test.go index b86b6ac2..8fb97af2 100644 --- a/chain/harmony/account_test.go +++ b/chain/harmony/account_test.go @@ -1 +1,83 @@ -package harmony_test \ No newline at end of file +package harmony_test + +import ( + "context" + "github.com/btcsuite/btcutil/bech32" + "github.com/ethereum/go-ethereum/crypto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/harmony" + "github.com/renproject/pack" + "time" +) + +var _ = Describe("Harmony", func() { + Context("when broadcasting a tx", func() { + It("should work", func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + c := harmony.NewClient(harmony.DefaultClientOptions()) + chainId, err := c.ChainId(ctx) + Expect(err).NotTo(HaveOccurred()) + + x := "1f84c95ac16e6a50f08d44c7bde7aff8742212fda6e4321fde48bf83bef266dc" + senderKey, err := crypto.HexToECDSA(x) + Expect(err).NotTo(HaveOccurred()) + addrBytes, err := bech32.ConvertBits(crypto.PubkeyToAddress(senderKey.PublicKey).Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + senderAddr, err := bech32.Encode(harmony.Bech32AddressHRP, addrBytes) + Expect(err).NotTo(HaveOccurred()) + + toKey, _ := crypto.GenerateKey() + toAddrBytes, err := bech32.ConvertBits(crypto.PubkeyToAddress(toKey.PublicKey).Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + toAddr, err := bech32.Encode(harmony.Bech32AddressHRP, toAddrBytes) + Expect(err).NotTo(HaveOccurred()) + + nonce, err := c.AccountNonce(ctx, address.Address(senderAddr)) + Expect(err).NotTo(HaveOccurred()) + + gasLimit := uint64(80000000) + gas, err := harmony.Estimator{}.EstimateGasPrice(ctx) + Expect(err).NotTo(HaveOccurred()) + + amount := pack.NewU256FromU64(pack.NewU64(100000000)) + + txBuilder := harmony.NewTxBuilder(chainId) + tx, err := txBuilder.BuildTx(ctx, address.Address(senderAddr), address.Address(toAddr), amount, nonce, pack.NewU256FromU64(pack.NewU64(gasLimit)), gas, gas, pack.Bytes(nil)) + Expect(err).NotTo(HaveOccurred()) + + sigHash, err := tx.Sighashes() + Expect(err).ToNot(HaveOccurred()) + Expect(len(sigHash)).To(Equal(1)) + + sig, err := crypto.Sign(sigHash[0][:], senderKey) + Expect(err).ToNot(HaveOccurred()) + Expect(len(sig)).To(Equal(65)) + + var signature [65]byte + copy(signature[:], sig) + err = tx.Sign([]pack.Bytes65{pack.NewBytes65(signature)}, pack.Bytes(nil)) + Expect(err).ToNot(HaveOccurred()) + + err = c.SubmitTx(ctx, tx) + Expect(err).ToNot(HaveOccurred()) + + time.Sleep(time.Second) + for { + txResp, _, err := c.Tx(ctx, tx.Hash()) + if err == nil && txResp != nil { + break + } + // wait and retry querying for the transaction + time.Sleep(5 * time.Second) + } + + updatedBalance, err := c.AccountBalance(ctx, address.Address(toAddr)) + Expect(err).NotTo(HaveOccurred()) + Expect(updatedBalance).To(Equal(amount)) + + }) + }) +}) diff --git a/chain/harmony/address.go b/chain/harmony/address.go index 66d37d46..28e50e1e 100644 --- a/chain/harmony/address.go +++ b/chain/harmony/address.go @@ -1 +1,56 @@ -package harmony \ No newline at end of file +package harmony + +import ( + "github.com/btcsuite/btcutil/bech32" + "github.com/renproject/multichain/api/address" +) + +const Bech32AddressHRP = "one" + +type EncoderDecoder struct { + address.Encoder + address.Decoder +} + +func NewEncoderDecoder() address.EncodeDecoder { + return EncoderDecoder{ + Encoder: NewEncoder(), + Decoder: NewDecoder(), + } +} + +type Encoder struct{} + +func (Encoder) EncodeAddress(addr address.RawAddress) (address.Address, error) { + converted, err := bech32.ConvertBits(addr, 8, 5, true) + if err != nil { + return "", err + } + encodedAddr, err := bech32.Encode(Bech32AddressHRP, converted) + if err != nil { + return "", err + } + return address.Address(encodedAddr), nil +} + +type Decoder struct{} + +func (Decoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + _, decodedAddr, err := bech32.Decode(string(addr)) + if err != nil { + return nil, err + } + converted, err := bech32.ConvertBits(decodedAddr, 5, 8, false) + if err != nil { + return nil, err + } + return converted, nil +} + +func NewEncoder() address.Encoder { + return Encoder{} +} + +func NewDecoder() address.Decoder { + return Decoder{} +} \ No newline at end of file diff --git a/chain/harmony/address_test.go b/chain/harmony/address_test.go index b86b6ac2..284db70d 100644 --- a/chain/harmony/address_test.go +++ b/chain/harmony/address_test.go @@ -1 +1,76 @@ -package harmony_test \ No newline at end of file +package harmony_test + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/harmony" +) + +var _ = Describe("Address", func() { + Context("when decoding a valid address", func() { + It("should work without errors", func() { + addrs := []string{ + "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", + "A12UEL5L", + "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", + "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + } + encoderDecoder := harmony.NewEncoderDecoder() + for _, addr := range addrs { + _, err := encoderDecoder.DecodeAddress(address.Address(addr)) + Expect(err).ToNot(HaveOccurred()) + } + }) + }) + + Context("when decoding an invalid address", func() { + It("should work without errors", func() { + addrs := []string{ + "split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", + "s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", + "spl" + string(rune(127)) + "t1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + "split1cheo2y9e2w", + "split1a2y9w", + "1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", + } + for _, addr := range addrs { + _, err := harmony.NewEncoderDecoder().DecodeAddress(address.Address(addr)) + Expect(err).To(HaveOccurred()) + } + }) + }) + + Context("when encoding a valid address", func() { + It("should work without errors", func() { + key, _ := crypto.GenerateKey() + ethAddr := crypto.PubkeyToAddress(key.PublicKey).String() + encoderDecoder := harmony.NewEncoderDecoder() + addr, err := encoderDecoder.EncodeAddress(common.HexToAddress(ethAddr).Bytes()) + Expect(err).ToNot(HaveOccurred()) + + rawAddr, err := encoderDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + for i, b := range rawAddr { + Expect(b).To(Equal(common.HexToAddress(ethAddr).Bytes()[i])) + } + }) + }) + + Context("when encoding/decoding a valid address", func() { + It("should work without errors", func() { + addr := address.Address("one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur") + encoderDecoder := harmony.NewEncoderDecoder() + rawAddr, err := encoderDecoder.DecodeAddress(addr) + Expect(err).ToNot(HaveOccurred()) + + conv, err := encoderDecoder.EncodeAddress(rawAddr) + Expect(err).ToNot(HaveOccurred()) + Expect(conv).To(Equal(addr)) + }) + }) +}) \ No newline at end of file diff --git a/chain/harmony/contract.go b/chain/harmony/contract.go index 66d37d46..0e7b086c 100644 --- a/chain/harmony/contract.go +++ b/chain/harmony/contract.go @@ -1 +1,45 @@ -package harmony \ No newline at end of file +package harmony + +import ( + "context" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/api/contract" + "github.com/renproject/pack" +) + +type CallArgs struct { + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Value *hexutil.Big `json:"value"` + Data *hexutil.Bytes `json:"data"` +} +type Params struct { + CallArgs CallArgs + Block uint64 +} + +func (c *Client) CallContract(ctx context.Context, addr address.Address, callData contract.CallData) (pack.Bytes, error) { + const method = "hmyv2_call" + // Unmarshal required to get the block number parameter for the call + var callParams Params + err := json.Unmarshal(callData, &callParams) + if err != nil { + return nil, err + } + args, err := json.Marshal(callParams.CallArgs) + if err != nil { + return nil, err + } + data := []byte(fmt.Sprintf("[%s, %d]", string(args), callParams.Block)) + response, err := SendData(method, data, c.opts.Host) + if err != nil { + return nil, err + } + return pack.NewBytes(*response.Result), nil +} \ No newline at end of file diff --git a/chain/harmony/contract_test.go b/chain/harmony/contract_test.go index b86b6ac2..2902492a 100644 --- a/chain/harmony/contract_test.go +++ b/chain/harmony/contract_test.go @@ -1 +1,34 @@ -package harmony_test \ No newline at end of file +package harmony_test + +import ( + "context" + "encoding/json" + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/harmony" +) + +var _ = Describe("Harmony", func() { + Context("when calling a contract", func() { + It("should work", func() { + contractAddr := address.Address("one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3") + rawAddr, err := harmony.NewEncoderDecoder().DecodeAddress(contractAddr) + bech32Addr := common.BytesToAddress(rawAddr) + callData := harmony.CallArgs{ + To: &bech32Addr, + } + params := harmony.Params{ + CallArgs: callData, + Block: 37000, + } + marshalledData, err := json.Marshal(params) + Expect(err).NotTo(HaveOccurred()) + + c := harmony.NewClient(harmony.DefaultClientOptions()) + _, err = c.CallContract(context.TODO(), contractAddr, marshalledData) + Expect(err).NotTo(HaveOccurred()) + }) + }) +}) \ No newline at end of file diff --git a/chain/harmony/gas.go b/chain/harmony/gas.go index 66d37d46..8b229592 100644 --- a/chain/harmony/gas.go +++ b/chain/harmony/gas.go @@ -1 +1,21 @@ -package harmony \ No newline at end of file +package harmony + +import( + "context" + "math/big" + + "github.com/renproject/pack" +) + +var ( + defaultGas = big.NewInt(1) +) + +type Estimator struct {} + +// The average block time on Harmony is 5 seconds & each block has a max +// gas limit of 80 million. There is currently no need to estimate gas for +// regular transactions & we do not have the RPC for it. +func (Estimator) EstimateGasPrice(ctx context.Context) (pack.U256, error) { + return pack.NewU256FromInt(defaultGas), nil +} diff --git a/chain/harmony/gas_test.go b/chain/harmony/gas_test.go index b86b6ac2..1c1ee60e 100644 --- a/chain/harmony/gas_test.go +++ b/chain/harmony/gas_test.go @@ -1 +1,20 @@ -package harmony_test \ No newline at end of file +package harmony_test + +import ( + "context" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/renproject/multichain/chain/harmony" + "github.com/renproject/pack" +) + +var _ = Describe("Gas", func() { + Context("when estimating gas", func() { + It("should work without errors", func() { + e := harmony.Estimator{} + gas, err := e.EstimateGasPrice(context.TODO()) + Expect(err).NotTo(HaveOccurred()) + Expect(gas).To(Equal(pack.NewU256FromU64(pack.NewU64(1)))) + }) + }) +}) diff --git a/chain/harmony/harmony_suite_test.go b/chain/harmony/harmony_suite_test.go new file mode 100644 index 00000000..2578be39 --- /dev/null +++ b/chain/harmony/harmony_suite_test.go @@ -0,0 +1,12 @@ +package harmony + +import "testing" +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestHarmony(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Harmony Suite") +} \ No newline at end of file diff --git a/chain/harmony/rpc.go b/chain/harmony/rpc.go new file mode 100644 index 00000000..88333e57 --- /dev/null +++ b/chain/harmony/rpc.go @@ -0,0 +1,154 @@ +package harmony + +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "net/http" + "strings" + "time" +) + +// Request defines a JSON-RPC 2.0 request object. See +// https://www.jsonrpc.org/specification for more information. A Request should +// not be explicitly created, but instead unmarshaled from JSON. +type Request struct { + Version string `json:"jsonrpc"` + ID interface{} `json:"id"` + Method string `json:"method"` + Params json.RawMessage `json:"params,omitempty"` +} + +// Response defines a JSON-RPC 2.0 response object. See +// https://www.jsonrpc.org/specification for more information. A Response is +// usually marshaled into bytes and returned in response to a Request. +type Response struct { + Version string `json:"jsonrpc"` + ID interface{} `json:"id"` + Result *json.RawMessage `json:"result,omitempty"` + Error *Error `json:"error,omitempty"` +} + +// Error defines a JSON-RPC 2.0 error object. See +// https://www.jsonrpc.org/specification for more information. +type Error struct { + Code int `json:"code"` + Message string `json:"message"` + Data *json.RawMessage `json:"data"` +} + +// SendData sends data to method via jsonrpc +func SendData(method string, data []byte, url string) (Response, error) { + request := Request{ + Version: "2.0", + ID: 1, + Method: method, + Params: data, + } + // Send request to lightnode + response, err := SendRequest(request, url) + if err != nil { + return Response{}, err + } + + var resp Response + buf := new(bytes.Buffer) + buf.ReadFrom(response.Body) + if err := json.Unmarshal(buf.Bytes(), &resp); err != nil { + return Response{}, fmt.Errorf("cannot decode %v response body = %s, err = %v", method, buf.String(), err) + } + if resp.Error != nil { + return Response{}, fmt.Errorf("got err back from %v request, err = %v", method, resp.Error) + } + return resp, nil +} + +// SendDataWithRetry is the same as SendData but will retry if sending the request failed +func SendDataWithRetry(method string, data []byte, url string) (Response, error) { + request := Request{ + Version: "2.0", + ID: 1, + Method: method, + Params: data, + } + // Send request to lightnode with retry (max 10 times) + response, err := SendRequestWithRetry(request, url, 10, 10) + if err != nil { + return Response{}, fmt.Errorf("failed to send request, err = %v", err) + } + + var resp Response + buf := new(bytes.Buffer) + buf.ReadFrom(response.Body) + if err := json.Unmarshal(buf.Bytes(), &resp); err != nil { + return Response{}, fmt.Errorf("cannot decode %v response body = %s, err = %v", method, buf.String(), err) + } + if resp.Error != nil { + return Response{}, fmt.Errorf("got err back from %v request, err = %v", method, resp.Error) + } + return resp, nil +} + +// SendRequest sends the JSON-2.0 request to the target url and returns the response and any error. +func SendRequest(request Request, url string) (*http.Response, error) { + data, err := json.Marshal(request) + if err != nil { + return nil, err + } + resp, err := SendRawPost(data, url) + if err != nil { + fmt.Printf("Sending %s to %s resulted in an error: %v\n", string(data), url, err) + return nil, err + } + return resp, nil +} + +// SendRawPost sends a raw bytes as a POST request to the URL specified +func SendRawPost(data []byte, url string) (*http.Response, error) { + if !strings.HasPrefix(url, "http") { + url = "http://" + url + } + client := newClient(10 * time.Second) + buff := bytes.NewBuffer(data) + req, err := http.NewRequest("POST", url, buff) + req.Header.Set("Content-Type", "application/json") + if err != nil { + return nil, err + } + return client.Do(req) +} + +// SendRequestWithRetry calls SendRequest but with configurable retry logic +func SendRequestWithRetry(request Request, url string, timeoutInSecs int, retries int) (response *http.Response, err error) { + failures := 0 + for failures < retries { + response, err = SendRequest(request, url) + if err != nil { + failures++ + if failures >= retries { + return nil, err + } + fmt.Printf("%s errored: %v. Retrying after %d seconds\n", url, err, timeoutInSecs) + time.Sleep(time.Duration(timeoutInSecs) * time.Second) + continue + } + break + } + return +} + +func newClient(timeout time.Duration) *http.Client { + return &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 10 * time.Second, + }).DialContext, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 4 * time.Second, + ResponseHeaderTimeout: 3 * time.Second, + }, + Timeout: timeout, + } +} \ No newline at end of file diff --git a/chain/solana/address.go b/chain/solana/address.go index 26de0b05..3dff6412 100644 --- a/chain/solana/address.go +++ b/chain/solana/address.go @@ -4,19 +4,44 @@ import ( "fmt" "github.com/btcsuite/btcutil/base58" - "github.com/renproject/pack" + "github.com/renproject/multichain/api/address" ) +// AddressDecoder implements the address.Decoder interface. type AddressDecoder struct{} -func NewAddressDecoder() AddressDecoder { - return AddressDecoder{} +// AddressEncoder implements the address.Encoder interface. +type AddressEncoder struct{} + +// AddressEncodeDecoder implements the address.EncodeDecoder interface. +type AddressEncodeDecoder struct { + AddressEncoder + AddressDecoder +} + +// NewAddressEncodeDecoder constructs and returns a new AddressEncodeDecoder. +func NewAddressEncodeDecoder() AddressEncodeDecoder { + return AddressEncodeDecoder{ + AddressEncoder: AddressEncoder{}, + AddressDecoder: AddressDecoder{}, + } +} + +// EncodeAddress consumes a raw byte-representation of an address and encodes it +// to the human-readable Base58 format. +func (AddressEncoder) EncodeAddress(rawAddress address.RawAddress) (address.Address, error) { + if len(rawAddress) != 32 { + return address.Address(""), fmt.Errorf("expected address length 32, got address length %v", len(rawAddress)) + } + return address.Address(base58.Encode(rawAddress)), nil } -func (AddressDecoder) DecodeAddress(encoded pack.String) (pack.Bytes, error) { +// DecodeAddress consumes a human-readable Base58 format and decodes it into a +// raw byte-representation. +func (AddressDecoder) DecodeAddress(encoded address.Address) (address.RawAddress, error) { decoded := base58.Decode(string(encoded)) if len(decoded) != 32 { return nil, fmt.Errorf("expected address length 32, got address length %v", len(decoded)) } - return pack.Bytes(decoded), nil + return address.RawAddress(decoded), nil } diff --git a/chain/solana/solana-ffi b/chain/solana/solana-ffi new file mode 160000 index 00000000..1d5f4405 --- /dev/null +++ b/chain/solana/solana-ffi @@ -0,0 +1 @@ +Subproject commit 1d5f4405dd2fb89c96cde28db33051a6e992d607 diff --git a/chain/solana/solana.go b/chain/solana/solana.go index 110b7365..27a74a1f 100644 --- a/chain/solana/solana.go +++ b/chain/solana/solana.go @@ -2,22 +2,28 @@ package solana import ( "context" + "encoding/base64" "encoding/json" "fmt" "github.com/btcsuite/btcutil/base58" "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/api/contract" "github.com/renproject/pack" "go.uber.org/zap" ) +// DefaultClientRPCURL is the default RPC URL for the Solana cluster. const DefaultClientRPCURL = "http://localhost:8899" +// ClientOptions define the options to instantiate a new Solana client. type ClientOptions struct { Logger *zap.Logger RPCURL string } +// DefaultClientOptions return the client options used to instantiate a Solana +// client by default. func DefaultClientOptions() ClientOptions { logger, err := zap.NewDevelopment() if err != nil { @@ -29,25 +35,87 @@ func DefaultClientOptions() ClientOptions { } } +// WithRPCURL returns a modified version of the options with the given API +// rpc-url +func (opts ClientOptions) WithRPCURL(rpcURL pack.String) ClientOptions { + opts.RPCURL = string(rpcURL) + return opts +} + +// Client represents a Solana client that implements the multichain Contract API. type Client struct { opts ClientOptions } +// NewClient returns a new solana.Client interface that implements the +// multichain Contract API. func NewClient(opts ClientOptions) *Client { return &Client{opts: opts} } -func (client *Client) CallContract(ctx context.Context, contract address.Address, input pack.Bytes) (output pack.Bytes, err error) { - if input != nil && len(input) != 0 { - return nil, fmt.Errorf("expected nil input, got %v input", input) +// FindProgramAddress is a wrapper function that calls the Solana FFI to find +// the deterministic program-derived address using the program and seeds. +func FindProgramAddress(seeds []byte, program address.RawAddress) (address.Address, error) { + addrEncodeDecoder := NewAddressEncodeDecoder() + encoded, err := addrEncodeDecoder.EncodeAddress(program) + if err != nil { + return address.Address(""), err } - // Make an RPC call to "getAccountInfo" to get the data associated with the - // account (we interpret the contract address as the account identifier). - params, err := json.Marshal(string(pack.String(contract))) + return ProgramDerivedAddress(seeds, encoded), nil +} + +// GetAccountData fetches and returns the account data. +func (client *Client) GetAccountData(account address.Address) (pack.Bytes, error) { + // Fetch account info with base64 encoding. The default base58 encoding does + // not support account data that is larger than 128 bytes, hence base64. + params := json.RawMessage(fmt.Sprintf(`["%v", {"encoding":"base64"}]`, string(account))) + res, err := SendDataWithRetry("getAccountInfo", params, client.opts.RPCURL) if err != nil { - return pack.Bytes(nil), fmt.Errorf("encoding params: %v", err) + return nil, fmt.Errorf("calling rpc method \"getAccountInfo\": %v", err) } + if res.Result == nil { + return nil, fmt.Errorf("decoding result: empty") + } + + // Deserialise the account's info into the appropriate struct. + info := ResponseGetAccountInfo{} + if err := json.Unmarshal(*res.Result, &info); err != nil { + return nil, fmt.Errorf("decoding result: %v", err) + } + + // Decode the Base58 encoded account data into raw byte-representation. Since + // this holds the burn log's data. + data, err := base64.RawStdEncoding.DecodeString(info.Value.Data[0]) + if err != nil { + return nil, fmt.Errorf("decoding base64 value: %v", err) + } + + return pack.Bytes(data), nil +} + +// CallContract implements the multichain Contract API. In the case of Solana, +// it is used to fetch burn logs associated with a particular burn nonce. +func (client *Client) CallContract( + ctx context.Context, + program address.Address, + calldata contract.CallData, +) (pack.Bytes, error) { + addrEncodeDecoder := NewAddressEncodeDecoder() + decodedProgram, err := addrEncodeDecoder.DecodeAddress(program) + if err != nil { + return pack.Bytes(nil), fmt.Errorf("decode address: %v", err) + } + + // Find the program-derived address that will have persisted the burn log. + burnLogAccount, err := FindProgramAddress([]byte(calldata), decodedProgram) + if err != nil { + return pack.Bytes(nil), fmt.Errorf("find program-derived address: %v", err) + } + + // Make an RPC call to "getAccountInfo" to get the data associated with the + // account (we interpret the contract address as the account identifier). + params := json.RawMessage(fmt.Sprintf(`["%v", {"encoding":"base58"}]`, string(burnLogAccount))) res, err := SendDataWithRetry("getAccountInfo", params, client.opts.RPCURL) if err != nil { return pack.Bytes(nil), fmt.Errorf("calling rpc method \"getAccountInfo\": %v", err) @@ -56,17 +124,18 @@ func (client *Client) CallContract(ctx context.Context, contract address.Address return pack.Bytes(nil), fmt.Errorf("decoding result: empty") } - // Decode the data associated with the account into pack-encoded bytes. + // Deserialise the account's info into the appropriate struct. info := ResponseGetAccountInfo{} if err := json.Unmarshal(*res.Result, &info); err != nil { return pack.Bytes(nil), fmt.Errorf("decoding result: %v", err) } - fmt.Printf("account data: %v", info.Value.Data) - data := base58.Decode(info.Value.Data) - // data, err := base64.StdEncoding.DecodeString() + // Decode the Base58 encoded account data into raw byte-representation. Since + // this holds the burn log's data. + data := base58.Decode(info.Value.Data[0]) if err != nil { return pack.Bytes(nil), fmt.Errorf("decoding result from base58: %v", err) } + return pack.NewBytes(data), nil } diff --git a/chain/solana/solana_ffi.go b/chain/solana/solana_ffi.go new file mode 100644 index 00000000..dcffa4a5 --- /dev/null +++ b/chain/solana/solana_ffi.go @@ -0,0 +1,24 @@ +package solana + +import ( + "github.com/renproject/multichain/api/address" + "github.com/renproject/pack" + "github.com/renproject/solana-ffi/cgo" +) + +// UniquePubkey creates an atomically incrementing pubkey used for tests and +// benchmarking purposes. +func UniquePubkey() address.Address { + pubkey := cgo.UniquePubkey() + return address.Address(pubkey) +} + +// ProgramDerivedAddress derives an address for an account that only the given +// program has the authority to sign. The address is of the same form as a +// Solana pubkey, except they are ensured to not be on the es25519 curve and +// thus have no associated private key. This address is deterministic, based +// upon the program and the seeds slice. +func ProgramDerivedAddress(seeds pack.Bytes, program address.Address) address.Address { + programDerivedAddressEncoded := cgo.ProgramDerivedAddress(seeds, uint32(len(seeds)), string(program)) + return address.Address(programDerivedAddressEncoded) +} diff --git a/chain/solana/solana_ffi_test.go b/chain/solana/solana_ffi_test.go new file mode 100644 index 00000000..f61548a1 --- /dev/null +++ b/chain/solana/solana_ffi_test.go @@ -0,0 +1,51 @@ +package solana_test + +import ( + "github.com/ethereum/go-ethereum/crypto" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/solana" + "github.com/renproject/pack" + "github.com/renproject/solana-ffi/cgo" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Solana FFI", func() { + Context("FFI", func() { + It("should create a unique pubkey", func() { + key1 := solana.UniquePubkey() + key2 := solana.UniquePubkey() + Expect(key1).NotTo(Equal(key2)) + }) + }) + + Context("Program Derived Address", func() { + It("should correctly compute 1", func() { + program := address.Address("6kAHanNCT1LKFoMn3fBdyvJuvHLcWhLpJbTpbHpqRiG4") + seeds := []byte("GatewayState") + programDerivedAddress := solana.ProgramDerivedAddress(pack.Bytes(seeds), program) + expectedDerivedAddress := address.Address("APthNc29MGRJRkKahDRNrSNA2o1e8p6aFAJNRV8ZdJaV") + Expect(programDerivedAddress[:]).To(Equal(expectedDerivedAddress)) + }) + + It("should correctly compute 2", func() { + program := address.Address("6kAHanNCT1LKFoMn3fBdyvJuvHLcWhLpJbTpbHpqRiG4") + selector := "BTC/toSolana" + selectorHash := crypto.Keccak256([]byte(selector)) + programDerivedAddress := solana.ProgramDerivedAddress(pack.Bytes(selectorHash), program) + expectedDerivedAddress := address.Address("6SPY5x3tmjLZ9SWcZFKhwpANrhYJagNNF4Sa4LAwtbCn") + Expect(programDerivedAddress[:]).To(Equal(expectedDerivedAddress)) + }) + }) + + Context("Associated Token Account", func() { + It("should correctly calculate", func() { + walletAddress := "fYq3qkHoVogcPnkxFWAwiJGJs29Xtg4FZ6xcAHWd51w" + selector := "BTC/toSolana" + assTokenAccount := cgo.AssociatedTokenAccount(walletAddress, selector) + expectedAssTokenAccount := "GxMKqib75YSD5RegZP8A7ZkSv8uBFmfNsNXzGptBdqdo" + Expect(assTokenAccount).To(Equal(expectedAssTokenAccount)) + }) + }) +}) diff --git a/chain/solana/solana_test.go b/chain/solana/solana_test.go index 8286dcc4..e769291f 100644 --- a/chain/solana/solana_test.go +++ b/chain/solana/solana_test.go @@ -2,26 +2,128 @@ package solana_test import ( "context" + "encoding/binary" + "os" + "time" - "github.com/renproject/multichain/api/address" + "github.com/btcsuite/btcd/chaincfg" + "github.com/ethereum/go-ethereum/crypto" + "github.com/near/borsh-go" + "github.com/renproject/multichain" + "github.com/renproject/multichain/chain/bitcoin" "github.com/renproject/multichain/chain/solana" "github.com/renproject/pack" + "github.com/renproject/solana-ffi/cgo" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) +// Bytes32 is an alias for [32]byte +type Bytes32 = [32]byte + +// GatewayRegistry defines the state of gateway registry, serialized and +// deserialized by the borsh schema. +type GatewayRegistry struct { + IsInitialised uint8 + Owner Bytes32 + Count uint64 + Selectors []Bytes32 + Gateways []Bytes32 +} + var _ = Describe("Solana", func() { - Context("...", func() { - It("...", func() { + // Setup logger. + loggerConfig := zap.NewDevelopmentConfig() + loggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + logger, err := loggerConfig.Build() + Expect(err).ToNot(HaveOccurred()) + + Context("When minting and burning", func() { + It("should succeed", func() { + // Base58 address of the Gateway program that is deployed to Solana. + program := multichain.Address("FDdKRjbBeFtyu5c66cZghJsTTjDTT1aD3zsgTWMTpaif") + + // Construct user's keypair path (~/.config/solana/id.json). + userHomeDir, err := os.UserHomeDir() + Expect(err).NotTo(HaveOccurred()) + keypairPath := userHomeDir + "/.config/solana/id.json" + + // RenVM secret and the selector for this gateway. + renVmSecret := "0000000000000000000000000000000000000000000000000000000000000001" + selector := "BTC/toSolana" + + // Mint some tokens. + time.Sleep(10 * time.Second) + mintAmount := uint64(1000000000) // 10 tokens. + mintSig := cgo.GatewayMint(keypairPath, solana.DefaultClientRPCURL, renVmSecret, selector, mintAmount) + logger.Debug("Mint", zap.String("tx signature", string(mintSig))) + + // Burn some tokens. + time.Sleep(10 * time.Second) + recipient := multichain.Address("mwjUmhAW68zCtgZpW5b1xD5g7MZew6xPV4") + bitcoinAddrEncodeDecoder := bitcoin.NewAddressEncodeDecoder(&chaincfg.RegressionNetParams) + recipientRawAddr, err := bitcoinAddrEncodeDecoder.DecodeAddress(recipient) + Expect(err).NotTo(HaveOccurred()) + burnCount := cgo.GatewayGetBurnCount(solana.DefaultClientRPCURL) + burnAmount := uint64(500000000) // 5 tokens. + burnSig := cgo.GatewayBurn(keypairPath, solana.DefaultClientRPCURL, selector, burnCount, burnAmount, uint32(len(recipientRawAddr)), []byte(recipientRawAddr)) + logger.Debug("Burn", zap.String("tx signature", string(burnSig))) + + // Fetch burn log. + time.Sleep(20 * time.Second) client := solana.NewClient(solana.DefaultClientOptions()) - _, err := client.CallContract( - context.Background(), - address.Address(pack.NewString("JBUjNGPApBQ3gw6w2UQPYr1978rkFEGqH1Zs3PZBrHec")), - pack.NewBytes([]byte{}), - ) - Expect(err).ToNot(HaveOccurred()) - // Expect(value).To(Equal()) + calldata := make([]byte, 8) + binary.LittleEndian.PutUint64(calldata, burnCount) + data, err := client.CallContract(context.Background(), program, multichain.ContractCallData(calldata)) + Expect(err).NotTo(HaveOccurred()) + Expect(len(data)).To(Equal(41)) + + fetchedAmount := binary.LittleEndian.Uint64(data[:8]) + recipientLen := uint8(data[8:9][0]) + fetchedRecipient := pack.Bytes(data[9 : 9+int(recipientLen)]) + Expect(fetchedAmount).To(Equal(burnAmount)) + Expect([]byte(fetchedRecipient)).To(Equal([]byte(recipientRawAddr))) + }) + }) + + Context("When getting Gateways from Registry", func() { + It("should deserialize successfully", func() { + // Solana client using default client options. + client := solana.NewClient(solana.DefaultClientOptions()) + + // Base58 address of the Gateway registry program deployed to Solana. + registryProgram := multichain.Address("DHpzwsdvAzq61PN9ZwQWg2hzwX8gYNfKAdsNKKtdKDux") + seeds := []byte("GatewayRegistryState") + registryState := solana.ProgramDerivedAddress(pack.Bytes(seeds), registryProgram) + + // Fetch account data at gateway registry's state + accountData, err := client.GetAccountData(registryState) + Expect(err).NotTo(HaveOccurred()) + + // Deserialize the account data into registry state's structure. + registry := GatewayRegistry{} + err = borsh.Deserialize(®istry, []byte(accountData)) + Expect(err).NotTo(HaveOccurred()) + + // The registry (in the CI test environment) is pre-populated with gateway + // addresses for BTC/toSolana selector. + btcSelectorHash := [32]byte{} + copy(btcSelectorHash[:], crypto.Keccak256([]byte("BTC/toSolana"))) + zero := pack.NewU256FromU8(pack.U8(0)).Bytes32() + + addrEncodeDecoder := solana.NewAddressEncodeDecoder() + expectedBtcGateway, _ := addrEncodeDecoder.DecodeAddress(multichain.Address("FDdKRjbBeFtyu5c66cZghJsTTjDTT1aD3zsgTWMTpaif")) + + Expect(registry.Count).To(Equal(uint64(1))) + Expect(registry.Selectors[0]).To(Equal(btcSelectorHash)) + Expect(registry.Selectors[1]).To(Equal(zero)) + Expect(len(registry.Selectors)).To(Equal(32)) + Expect(registry.Gateways[0][:]).To(Equal([]byte(expectedBtcGateway))) + Expect(registry.Gateways[1]).To(Equal(zero)) + Expect(len(registry.Gateways)).To(Equal(32)) }) }) }) diff --git a/chain/solana/solanarpc.go b/chain/solana/solanarpc.go index bab18c95..a69c2803 100644 --- a/chain/solana/solanarpc.go +++ b/chain/solana/solanarpc.go @@ -1,17 +1,22 @@ package solana +// AccountContext is the JSON-interface of the account's context representing +// what slot the account's value has been returned for. type AccountContext struct { Slot int `json:"slot"` } +// AccountValue is the JSON-interface of the account's information. type AccountValue struct { - Data string `json:"data"` - Executable bool `json:"executable"` - Lamports int `json:"lamports"` - Owner string `json:"owner"` - RentEpoch int `json:"rentEpoch"` + Data [2]string `json:"data"` + Executable bool `json:"executable"` + Lamports int `json:"lamports"` + Owner string `json:"owner"` + RentEpoch int `json:"rentEpoch"` } +// ResponseGetAccountInfo is the JSON-interface of the response for the +// getAccountInfo query. type ResponseGetAccountInfo struct { Context AccountContext `json:"context"` Value AccountValue `json:"value"` diff --git a/chain/terra/address.go b/chain/terra/address.go new file mode 100644 index 00000000..1d4a59ec --- /dev/null +++ b/chain/terra/address.go @@ -0,0 +1,28 @@ +package terra + +import "github.com/renproject/multichain/chain/cosmos" + +type ( + // Address re-exports cosmos-compatible address + Address = cosmos.Address + + // AddressDecoder re-exports cosmos.AddressDecoder + AddressDecoder = cosmos.AddressDecoder + + // AddressEncoder re-exports cosmos.AddressEncoder + AddressEncoder = cosmos.AddressEncoder + + // AddressEncodeDecoder re-exports cosmos.AddressEncodeDecoder + AddressEncodeDecoder = cosmos.AddressEncodeDecoder +) + +var ( + // NewAddressDecoder re-exports cosmos.NewAddressDecoder + NewAddressDecoder = cosmos.NewAddressDecoder + + // NewAddressEncoder re-exports cosmos.NewAddressEncoder + NewAddressEncoder = cosmos.NewAddressEncoder + + // NewAddressEncodeDecoder re-exports cosmos.NewAddressEnodeDecoder + NewAddressEncodeDecoder = cosmos.NewAddressEncodeDecoder +) diff --git a/chain/terra/address_test.go b/chain/terra/address_test.go new file mode 100644 index 00000000..37288b64 --- /dev/null +++ b/chain/terra/address_test.go @@ -0,0 +1,46 @@ +package terra_test + +import ( + "fmt" + + "github.com/renproject/multichain" + "github.com/renproject/multichain/chain/terra" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Terra", func() { + Context("when decoding address", func() { + decoder := terra.NewAddressDecoder() + Context("when decoding a valid address", func() { + It("should work", func() { + addrStr := "terra1ztez03dp94y2x55fkhmrvj37ck204geq33msma" + _, err := decoder.DecodeAddress(multichain.Address(pack.NewString(addrStr))) + Expect(err).ToNot(HaveOccurred()) + }) + }) + Context("when decoding an address with invalid prefix", func() { + It("should fail", func() { + addrStr := "cosmosztez03dp94y2x55fkhmrvj37ck204geq33msma" + _, err := decoder.DecodeAddress(multichain.Address(pack.NewString(addrStr))) + Expect(err).To(HaveOccurred()) + }) + }) + Context("when decoding an invalid address", func() { + It("should fail", func() { + addrStr := "terra1ztez03dp94y2x55fkhmrvj37ck204geq33msm" + _, err := decoder.DecodeAddress(multichain.Address(pack.NewString(addrStr))) + Expect(err).To(HaveOccurred()) + }) + }) + Context("when decoding an empty address", func() { + It("should fail", func() { + addrStr := "" + _, err := decoder.DecodeAddress(multichain.Address(pack.NewString(addrStr))) + Expect(err).Should(MatchError(fmt.Errorf("unexpected address length: want=20, got=0"))) + }) + }) + }) +}) diff --git a/chain/terra/terra.go b/chain/terra/terra.go new file mode 100644 index 00000000..4d6137e0 --- /dev/null +++ b/chain/terra/terra.go @@ -0,0 +1,55 @@ +package terra + +import ( + "github.com/cosmos/cosmos-sdk/types" + "github.com/renproject/multichain/api/account" + "github.com/renproject/multichain/chain/cosmos" + "github.com/terra-project/core/app" +) + +type ( + // Client re-exports cosmos.Client + Client = cosmos.Client + + // ClientOptions re-exports cosmos.ClientOptions + ClientOptions = cosmos.ClientOptions + + // TxBuilderOptions re-exports cosmos.TxBuilderOptions + TxBuilderOptions = cosmos.TxBuilderOptions +) + +var ( + // DefaultClientOptions re-exports cosmos.DefaultClientOptions + DefaultClientOptions = cosmos.DefaultClientOptions + + // DefaultTxBuilderOptions re-exports cosmos.DefaultTxBuilderOptions + DefaultTxBuilderOptions = cosmos.DefaultTxBuilderOptions + + // NewGasEstimator re-exports cosmos.NewGasEstimator + NewGasEstimator = cosmos.NewGasEstimator +) + +// Set the Bech32 address prefix for the globally-defined config variable inside +// Cosmos SDK. This is required as there are a number of functions inside the +// SDK that make use of this global config directly, instead of allowing us to +// provide a custom config. +func init() { + // TODO: This will prevent us from being able to support multiple + // Cosmos-compatible chains in the Multichain. This is expected to be + // resolved before v1.0 of the Cosmos SDK (issue being tracked here: + // https://github.com/cosmos/cosmos-sdk/issues/7448). + types.GetConfig().SetBech32PrefixForAccount("terra", "terrapub") + types.GetConfig().Seal() +} + +// NewClient returns returns a new Client with Terra codec. +func NewClient(opts ClientOptions) *Client { + return cosmos.NewClient(opts, app.MakeCodec(), "terra") +} + +// NewTxBuilder returns an implementation of the transaction builder interface +// from the Cosmos Compat API, and exposes the functionality to build simple +// Terra transactions. +func NewTxBuilder(opts TxBuilderOptions, client *Client) account.TxBuilder { + return cosmos.NewTxBuilder(opts, client) +} diff --git a/chain/terra/terra_suite_test.go b/chain/terra/terra_suite_test.go new file mode 100644 index 00000000..11f9c854 --- /dev/null +++ b/chain/terra/terra_suite_test.go @@ -0,0 +1,13 @@ +package terra_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestTerra(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Terra Suite") +} diff --git a/chain/terra/terra_test.go b/chain/terra/terra_test.go new file mode 100644 index 00000000..c462c68c --- /dev/null +++ b/chain/terra/terra_test.go @@ -0,0 +1,134 @@ +package terra_test + +import ( + "context" + "encoding/hex" + "os" + "time" + + "github.com/renproject/id" + "github.com/renproject/multichain" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/terra" + "github.com/renproject/pack" + "github.com/renproject/surge" + "github.com/tendermint/tendermint/crypto/secp256k1" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Terra", func() { + Context("when submitting transactions", func() { + Context("when sending LUNA", func() { + It("should work", func() { + // create context for the test + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Load private key, and assume that the associated address has + // funds to spend. You can do this by setting TERRA_PK to the + // value specified in the `./multichaindeploy/.env` file. + pkEnv := os.Getenv("TERRA_PK") + if pkEnv == "" { + panic("TERRA_PK is undefined") + } + + pkBz, err := hex.DecodeString(pkEnv) + Expect(err).ToNot(HaveOccurred()) + + var pk secp256k1.PrivKeySecp256k1 + copy(pk[:], pkBz) + + var privKey id.PrivKey + err = surge.FromBinary(&privKey, pkBz) + Expect(err).NotTo(HaveOccurred()) + + addr := terra.Address(pk.PubKey().Address()) + + // random recipient + pkRecipient := secp256k1.GenPrivKey() + addrEncoder := terra.NewAddressEncoder() + recipient, err := addrEncoder.EncodeAddress(address.RawAddress(pack.Bytes(pkRecipient.PubKey().Address()))) + Expect(err).NotTo(HaveOccurred()) + + // instantiate a new client + client := terra.NewClient( + terra.DefaultClientOptions(). + WithCoinDenom("uluna"), + ) + nonce, err := client.AccountNonce(ctx, multichain.Address(addr.String())) + Expect(err).NotTo(HaveOccurred()) + + // create a new cosmos-compatible transaction builder + txBuilder := terra.NewTxBuilder( + terra.DefaultTxBuilderOptions(). + WithChainID("testnet"), + client, + ) + + // build the transaction + payload := pack.NewBytes([]byte("multichain")) + amount := pack.NewU256FromU64(pack.U64(2000000)) + tx, err := txBuilder.BuildTx( + ctx, + multichain.Address(addr.String()), // from + recipient, // to + amount, // amount + nonce, // nonce + pack.NewU256FromU64(pack.U64(200000)), // gas limit + pack.NewU256FromU64(pack.U64(1)), // gas price + pack.NewU256FromU64(pack.U64(1)), // gas cap + payload, // memo + ) + Expect(err).NotTo(HaveOccurred()) + + // get the transaction bytes and sign it + sighashes, err := tx.Sighashes() + Expect(err).NotTo(HaveOccurred()) + Expect(len(sighashes)).To(Equal(1)) + hash := id.Hash(sighashes[0]) + sig, err := privKey.Sign(&hash) + Expect(err).NotTo(HaveOccurred()) + sigBytes, err := surge.ToBinary(sig) + Expect(err).NotTo(HaveOccurred()) + sig65 := pack.Bytes65{} + copy(sig65[:], sigBytes) + + // attach the signature to the transaction + pubKey := pk.PubKey().(secp256k1.PubKeySecp256k1) + err = tx.Sign( + []pack.Bytes65{sig65}, + pack.NewBytes(pubKey[:]), + ) + Expect(err).NotTo(HaveOccurred()) + + // submit the transaction to the chain + txHash := tx.Hash() + err = client.SubmitTx(ctx, tx) + Expect(err).NotTo(HaveOccurred()) + + for { + // Loop until the transaction has at least a few + // confirmations. This implies that the transaction is + // definitely valid, and the test has passed. We were + // successfully able to use the multichain to construct and + // submit a Bitcoin transaction! + foundTx, confs, err := client.Tx(ctx, txHash) + if err == nil { + Expect(confs.Uint64()).To(Equal(uint64(1))) + Expect(foundTx.Payload()).To(Equal(multichain.ContractCallData([]byte(payload.String())))) + Expect(foundTx.Nonce()).To(Equal(nonce)) + Expect(foundTx.From()).To(Equal(multichain.Address(addr.String()))) + Expect(foundTx.To()).To(Equal(recipient)) + Expect(foundTx.Value()).To(Equal(amount)) + break + } + + // wait and retry querying for the transaction + time.Sleep(2 * time.Second) + } + }) + }) + }) +}) diff --git a/chain/zcash/address.go b/chain/zcash/address.go index 794b0be6..10c90b7d 100644 --- a/chain/zcash/address.go +++ b/chain/zcash/address.go @@ -3,14 +3,133 @@ package zcash import ( "bytes" "crypto/sha256" - "errors" + "fmt" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/base58" + "github.com/renproject/multichain/api/address" + "github.com/renproject/pack" "golang.org/x/crypto/ripemd160" ) +// AddressEncodeDecoder implements the address.EncodeDecoder interface +type AddressEncodeDecoder struct { + AddressEncoder + AddressDecoder +} + +// AddressEncoder encapsulates the chain specific configurations and implements +// the address.Encoder interface +type AddressEncoder struct { + params *Params +} + +// AddressDecoder encapsulates the chain specific configurations and implements +// the address.Decoder interface +type AddressDecoder struct { + params *Params +} + +// NewAddressEncoder constructs a new AddressEncoder with the chain specific +// configurations +func NewAddressEncoder(params *Params) AddressEncoder { + return AddressEncoder{params: params} +} + +// NewAddressDecoder constructs a new AddressDecoder with the chain specific +// configurations +func NewAddressDecoder(params *Params) AddressDecoder { + return AddressDecoder{params: params} +} + +// NewAddressEncodeDecoder constructs a new AddressEncodeDecoder with the +// chain specific configurations +func NewAddressEncodeDecoder(params *Params) AddressEncodeDecoder { + return AddressEncodeDecoder{ + AddressEncoder: NewAddressEncoder(params), + AddressDecoder: NewAddressDecoder(params), + } +} + +// EncodeAddress implements the address.Encoder interface +func (encoder AddressEncoder) EncodeAddress(rawAddr address.RawAddress) (address.Address, error) { + var addrType uint8 + var err error + var hash [20]byte + var prefix []byte + + switch len(rawAddr) { + case ripemd160.Size + 5: + prefix = rawAddr[:1] + addrType, err = addressType(prefix, encoder.params) + copy(hash[:], rawAddr[1:21]) + case ripemd160.Size + 6: + prefix = rawAddr[:2] + addrType, err = addressType(prefix, encoder.params) + copy(hash[:], rawAddr[2:22]) + default: + return address.Address(""), fmt.Errorf("validating address length: expected %v or %v, got %v", ripemd160.Size+5, ripemd160.Size+6, len(rawAddr)) + } + + if err != nil { + return address.Address(""), fmt.Errorf("parsing address type: %v", err) + } + + switch addrType { + case 0, 1: // P2PKH or P2SH + return address.Address(pack.String(encodeAddress(hash[:], prefix))), nil + default: + return address.Address(""), fmt.Errorf("unexpected address type: %v", addrType) + } +} + +// DecodeAddress implements the address.Decoder interface +func (decoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { + var decoded = base58.Decode(string(addr)) + var addrType uint8 + var err error + var hash [20]byte + + switch len(decoded) { + case ripemd160.Size + 5: + addrType, err = addressType(decoded[:1], decoder.params) + copy(hash[:], decoded[1:21]) + case ripemd160.Size + 6: + addrType, err = addressType(decoded[:2], decoder.params) + copy(hash[:], decoded[2:22]) + default: + return nil, fmt.Errorf("validating address length: expected %v or %v, got %v", ripemd160.Size+5, ripemd160.Size+6, len(decoded)) + } + + if err != nil { + return nil, fmt.Errorf("parsing address type: %v", err) + } + + var cksum [4]byte + copy(cksum[:], decoded[len(decoded)-4:]) + if checksum(decoded[:len(decoded)-4]) != cksum { + return nil, fmt.Errorf("validating checksum: %v", base58.ErrChecksum) + } + + switch addrType { + case 0, 1: // P2PKH or P2SH + return address.RawAddress(pack.Bytes(decoded)), nil + default: + return nil, fmt.Errorf("unexpected address type: %v", addrType) + } +} + +func addressType(prefix []byte, params *Params) (uint8, error) { + if bytes.Equal(prefix, params.P2PKHPrefix) { + return 0, nil + } + if bytes.Equal(prefix, params.P2SHPrefix) { + return 1, nil + } + return 0, btcutil.ErrUnknownAddressType +} + // An Address represents a Zcash address. type Address interface { btcutil.Address @@ -122,35 +241,26 @@ func (addr AddressScriptHash) IsForNet(params *chaincfg.Params) bool { return addr.AddressScriptHash.IsForNet(params) } -func DecodeAddress(addr string) (Address, error) { - var decoded = base58.Decode(addr) - if len(decoded) != 26 && len(decoded) != 25 { - return nil, base58.ErrInvalidFormat - } - - var cksum [4]byte - copy(cksum[:], decoded[len(decoded)-4:]) - if checksum(decoded[:len(decoded)-4]) != cksum { - return nil, base58.ErrChecksum - } - - if len(decoded)-6 != ripemd160.Size && len(decoded)-5 != ripemd160.Size { - return nil, errors.New("incorrect payload len") - } - +// addressFromRawBytes decodes a string-representation of an address to an address +// type that implements the zcash.Address interface +func addressFromRawBytes(addrBytes []byte, params *Params) (Address, error) { var addrType uint8 - var params *Params var err error var hash [20]byte - if len(decoded) == 26 { - addrType, params, err = parsePrefix(decoded[:2]) - copy(hash[:], decoded[2:22]) - } else { - addrType, params, err = parsePrefix(decoded[:1]) - copy(hash[:], decoded[1:21]) + + switch len(addrBytes) { + case ripemd160.Size + 5: + addrType, err = addressType(addrBytes[:1], params) + copy(hash[:], addrBytes[1:21]) + case ripemd160.Size + 6: + addrType, err = addressType(addrBytes[:2], params) + copy(hash[:], addrBytes[2:22]) + default: + return nil, fmt.Errorf("validating address length: expected %v or %v, got %v", ripemd160.Size+5, ripemd160.Size+6, len(addrBytes)) } + if err != nil { - return nil, err + return nil, fmt.Errorf("parsing address type: %v", err) } switch addrType { @@ -158,9 +268,9 @@ func DecodeAddress(addr string) (Address, error) { return NewAddressPubKeyHash(hash[:], params) case 1: // P2SH return NewAddressScriptHashFromHash(hash[:], params) + default: + return nil, fmt.Errorf("unexpected address type: %v", addrType) } - - return nil, errors.New("unknown address") } func encodeAddress(hash, prefix []byte) string { @@ -181,25 +291,3 @@ func checksum(input []byte) (cksum [4]byte) { copy(cksum[:], h2[:4]) return } - -func parsePrefix(prefix []byte) (uint8, *Params, error) { - if bytes.Equal(prefix, MainNetParams.P2PKHPrefix) { - return 0, &MainNetParams, nil - } - if bytes.Equal(prefix, MainNetParams.P2SHPrefix) { - return 1, &MainNetParams, nil - } - if bytes.Equal(prefix, TestNet3Params.P2PKHPrefix) { - return 0, &TestNet3Params, nil - } - if bytes.Equal(prefix, TestNet3Params.P2SHPrefix) { - return 1, &TestNet3Params, nil - } - if bytes.Equal(prefix, RegressionNetParams.P2PKHPrefix) { - return 0, &RegressionNetParams, nil - } - if bytes.Equal(prefix, RegressionNetParams.P2SHPrefix) { - return 1, &RegressionNetParams, nil - } - return 0, nil, btcutil.ErrUnknownAddressType -} diff --git a/chain/zcash/address_test.go b/chain/zcash/address_test.go index 38e5b45b..49129591 100644 --- a/chain/zcash/address_test.go +++ b/chain/zcash/address_test.go @@ -1 +1,97 @@ package zcash_test + +import ( + "bytes" + "math/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" + "github.com/renproject/id" + "github.com/renproject/multichain/api/address" + "github.com/renproject/multichain/chain/zcash" +) + +var _ = Describe("Zcash Address", func() { + Context("address", func() { + addrEncodeDecoder := zcash.NewAddressEncodeDecoder(&zcash.RegressionNetParams) + + It("addr pub key hash", func() { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), zcash.RegressionNetParams.Params, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := zcash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + addr := address.Address(addrPubKeyHash.EncodeAddress()) + + decodedRawAddr, err := addrEncodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := addrEncodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + + It("addr script hash", func() { + script := make([]byte, rand.Intn(100)) + rand.Read(script) + addrScriptHash, err := zcash.NewAddressScriptHash(script, &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + addr := address.Address(addrScriptHash.EncodeAddress()) + + decodedRawAddr, err := addrEncodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := addrEncodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + }) + + Context("AddressEncodeDecoder", func() { + It("should give an error when decoding address on different network", func() { + params := []zcash.Params{ + zcash.MainNetParams, + zcash.TestNet3Params, + zcash.RegressionNetParams, + } + + for i, param := range params { + // Generate a P2PKH address with the params + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), param.Params, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := zcash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), ¶m) + Expect(err).NotTo(HaveOccurred()) + p2pkhAddr := address.Address(addrPubKeyHash.EncodeAddress()) + + // Generate a P2SH address with the params + script := make([]byte, rand.Intn(100)) + rand.Read(script) + addrScriptHash, err := zcash.NewAddressScriptHash(script, ¶m) + Expect(err).NotTo(HaveOccurred()) + p2shAddr := address.Address(addrScriptHash.EncodeAddress()) + + // Try decode the address using decoders with different network params + for j := range params { + addrEncodeDecoder := zcash.NewAddressEncodeDecoder(¶ms[j]) + _, err := addrEncodeDecoder.DecodeAddress(p2pkhAddr) + // Check the prefix in the params instead of comparing the network directly + // because testnet and regression network has the same prefix. + if bytes.Equal(params[i].P2PKHPrefix, params[j].P2PKHPrefix) { + Expect(err).NotTo(HaveOccurred()) + } else { + Expect(err).To(HaveOccurred()) + } + + _, err = addrEncodeDecoder.DecodeAddress(p2shAddr) + if bytes.Equal(params[i].P2PKHPrefix, params[j].P2PKHPrefix) { + Expect(err).NotTo(HaveOccurred()) + } else { + Expect(err).To(HaveOccurred()) + } + } + } + }) + }) +}) diff --git a/chain/zcash/gas.go b/chain/zcash/gas.go index 6b864739..d10b37e7 100644 --- a/chain/zcash/gas.go +++ b/chain/zcash/gas.go @@ -1,7 +1,57 @@ package zcash -import "github.com/renproject/multichain/chain/bitcoin" +import ( + "context" + "fmt" + "math" -type GasEstimator = bitcoin.GasEstimator + "github.com/renproject/pack" +) -var NewGasEstimator = bitcoin.NewGasEstimator +const ( + multiplier = 1e8 + kilobyteToByte = 1024 +) + +// A GasEstimator returns the SATs-per-byte that is needed in order to confirm +// transactions with an estimated maximum delay of one block. In distributed +// networks that collectively build, sign, and submit transactions, it is +// important that all nodes in the network have reached consensus on the +// SATs-per-byte. +type GasEstimator struct { + client Client + numBlocks int64 + fallbackGas pack.U256 +} + +// NewGasEstimator returns a simple gas estimator that always returns the given +// number of SATs-per-byte. +func NewGasEstimator(client Client, numBlocks int64, fallbackGas pack.U256) GasEstimator { + return GasEstimator{ + client: client, + numBlocks: numBlocks, + fallbackGas: fallbackGas, + } +} + +// EstimateGas returns the number of SATs-per-byte (for both price and cap) that +// is needed in order to confirm transactions with an estimated maximum delay of +// `numBlocks` block. It is the responsibility of the caller to know the number +// of bytes in their transaction. This method calls the `estimatesmartfee` RPC +// call to the node, which based on a conservative (considering longer history) +// strategy returns the estimated BTC per kilobyte of data in the transaction. +// An error will be returned if the bitcoin node hasn't observed enough blocks +// to make an estimate for the provided target `numBlocks`. +func (gasEstimator GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) { + feeRate, err := gasEstimator.client.EstimateFeeLegacy(ctx, gasEstimator.numBlocks) + if err != nil { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, err + } + + if feeRate <= 0.0 { + return gasEstimator.fallbackGas, gasEstimator.fallbackGas, fmt.Errorf("invalid fee rate: %v", feeRate) + } + + satsPerByte := uint64(math.Ceil(feeRate * multiplier / kilobyteToByte)) + return pack.NewU256FromUint64(satsPerByte), pack.NewU256FromUint64(satsPerByte), nil +} diff --git a/chain/zcash/gas_test.go b/chain/zcash/gas_test.go index 38e5b45b..2b95033d 100644 --- a/chain/zcash/gas_test.go +++ b/chain/zcash/gas_test.go @@ -1 +1,52 @@ package zcash_test + +import ( + "context" + + "github.com/renproject/multichain/chain/zcash" + "github.com/renproject/pack" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Gas", func() { + Context("when estimating zcash network fee", func() { + It("should work", func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client := zcash.NewClient(zcash.DefaultClientOptions()) + + // estimate fee to include tx within 1 block. + fallback1 := uint64(123) + gasEstimator1 := zcash.NewGasEstimator(client, 1, pack.NewU256FromUint64(fallback1)) + gasPrice1, _, err := gasEstimator1.EstimateGas(ctx) + if err != nil { + Expect(gasPrice1).To(Equal(pack.NewU256FromUint64(fallback1))) + } + + // estimate fee to include tx within 10 blocks. + fallback2 := uint64(234) + gasEstimator2 := zcash.NewGasEstimator(client, 10, pack.NewU256FromUint64(fallback2)) + gasPrice2, _, err := gasEstimator2.EstimateGas(ctx) + if err != nil { + Expect(gasPrice2).To(Equal(pack.NewU256FromUint64(fallback2))) + } + + // estimate fee to include tx within 100 blocks. + fallback3 := uint64(345) + gasEstimator3 := zcash.NewGasEstimator(client, 100, pack.NewU256FromUint64(fallback3)) + gasPrice3, _, err := gasEstimator3.EstimateGas(ctx) + if err != nil { + Expect(gasPrice3).To(Equal(pack.NewU256FromUint64(fallback3))) + } + + // expect fees in this order at the very least. + if err == nil { + Expect(gasPrice1.GreaterThanEqual(gasPrice2)).To(BeTrue()) + Expect(gasPrice2.GreaterThanEqual(gasPrice3)).To(BeTrue()) + } + }) + }) +}) diff --git a/chain/zcash/utxo.go b/chain/zcash/utxo.go index aa4dee7b..46e09d20 100644 --- a/chain/zcash/utxo.go +++ b/chain/zcash/utxo.go @@ -21,16 +21,24 @@ import ( // Version of Zcash transactions supported by the multichain. const Version int32 = 4 +// ClientOptions are used to parameterise the behaviour of the Client. type ClientOptions = bitcoin.ClientOptions +// DefaultClientOptions returns ClientOptions with the default settings. These +// settings are valid for use with the default local deployment of the +// multichain. In production, the host, user, and password should be changed. func DefaultClientOptions() ClientOptions { return bitcoin.DefaultClientOptions().WithHost("http://127.0.0.1:18232") } +// Client re-exports bitcoin.Client. type Client = bitcoin.Client +// NewClient re-exports bitcoin.Client var NewClient = bitcoin.NewClient +// The TxBuilder is an implementation of a UTXO-compatible transaction builder +// for Bitcoin. type TxBuilder struct { params *Params expiryHeight uint32 @@ -60,6 +68,9 @@ func NewTxBuilder(params *Params, expiryHeight uint32) utxo.TxBuilder { func (txBuilder TxBuilder) BuildTx(inputs []utxo.Input, recipients []utxo.Recipient) (utxo.Tx, error) { msgTx := wire.NewMsgTx(Version) + // Address encoder-decoder + addrEncodeDecoder := NewAddressEncodeDecoder(txBuilder.params) + // Inputs for _, input := range inputs { hash := chainhash.Hash{} @@ -70,7 +81,11 @@ func (txBuilder TxBuilder) BuildTx(inputs []utxo.Input, recipients []utxo.Recipi // Outputs for _, recipient := range recipients { - addr, err := DecodeAddress(string(recipient.To)) + addrBytes, err := addrEncodeDecoder.DecodeAddress(recipient.To) + if err != nil { + return &Tx{}, err + } + addr, err := addressFromRawBytes(addrBytes, txBuilder.params) if err != nil { return &Tx{}, err } @@ -100,6 +115,7 @@ type Tx struct { signed bool } +// Hash returns the transaction hash of the given underlying transaction. func (tx *Tx) Hash() (pack.Bytes, error) { serial, err := tx.Serialize() if err != nil { @@ -109,9 +125,12 @@ func (tx *Tx) Hash() (pack.Bytes, error) { return pack.NewBytes(txhash[:]), nil } +// Inputs returns the UTXO inputs in the underlying transaction. func (tx *Tx) Inputs() ([]utxo.Input, error) { return tx.inputs, nil } + +// Outputs returns the UTXO outputs in the underlying transaction. func (tx *Tx) Outputs() ([]utxo.Output, error) { hash, err := tx.Hash() if err != nil { @@ -132,6 +151,8 @@ func (tx *Tx) Outputs() ([]utxo.Output, error) { return outputs, nil } +// Sighashes returns the digests that must be signed before the transaction +// can be submitted by the client. func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { sighashes := make([]pack.Bytes32, len(tx.inputs)) for i, txin := range tx.inputs { @@ -160,6 +181,8 @@ func (tx *Tx) Sighashes() ([]pack.Bytes32, error) { return sighashes, nil } +// Sign consumes a list of signatures, and adds them to the list of UTXOs in +// the underlying transactions. func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { if tx.signed { return fmt.Errorf("already signed") @@ -192,6 +215,7 @@ func (tx *Tx) Sign(signatures []pack.Bytes65, pubKey pack.Bytes) error { return nil } +// Serialize serializes the UTXO transaction to bytes. func (tx *Tx) Serialize() (pack.Bytes, error) { w := new(bytes.Buffer) pver := uint32(0) diff --git a/chain/zcash/zcash.go b/chain/zcash/zcash.go index f76d1081..03043ec3 100644 --- a/chain/zcash/zcash.go +++ b/chain/zcash/zcash.go @@ -17,6 +17,7 @@ const ( versionSaplingGroupID = 0x892f2085 ) +// Params signifies the chain specific parameters of the Zcash network. type Params struct { // TODO: We do not actually need to embed the entire chaincfg params object. *chaincfg.Params @@ -26,6 +27,7 @@ type Params struct { Upgrades []ParamsUpgrade } +// ParamsUpgrade ... type ParamsUpgrade struct { ActivationHeight uint32 BranchID []byte @@ -34,6 +36,7 @@ type ParamsUpgrade struct { var ( witnessMarkerBytes = []byte{0x00, 0x01} + // MainNetParams defines the mainnet configuration. MainNetParams = Params{ Params: &chaincfg.MainNetParams, @@ -44,8 +47,12 @@ var ( {347500, []byte{0x19, 0x1B, 0xA8, 0x5B}}, {419200, []byte{0xBB, 0x09, 0xB8, 0x76}}, {653600, []byte{0x60, 0x0E, 0xB4, 0x2B}}, + {903000, []byte{0x0B, 0x23, 0xB9, 0xF5}}, + {1046400, []byte{0xA6, 0x75, 0xff, 0xe9}}, }, } + + // TestNet3Params defines the testnet configuration. TestNet3Params = Params{ Params: &chaincfg.TestNet3Params, @@ -56,8 +63,12 @@ var ( {207500, []byte{0x19, 0x1B, 0xA8, 0x5B}}, {280000, []byte{0xBB, 0x09, 0xB8, 0x76}}, {584000, []byte{0x60, 0x0E, 0xB4, 0x2B}}, + {903800, []byte{0x0B, 0x23, 0xB9, 0xF5}}, + {1028500, []byte{0xA6, 0x75, 0xff, 0xe9}}, }, } + + // RegressionNetParams defines a devet/regnet configuration. RegressionNetParams = Params{ Params: &chaincfg.RegressionNetParams, @@ -65,9 +76,11 @@ var ( P2SHPrefix: []byte{0x1C, 0xBA}, Upgrades: []ParamsUpgrade{ {0, []byte{0x00, 0x00, 0x00, 0x00}}, - {60, []byte{0x19, 0x1B, 0xA8, 0x5B}}, - {80, []byte{0xBB, 0x09, 0xB8, 0x76}}, - {100, []byte{0x60, 0x0E, 0xB4, 0x2B}}, + {10, []byte{0x19, 0x1B, 0xA8, 0x5B}}, + {20, []byte{0xBB, 0x09, 0xB8, 0x76}}, + {30, []byte{0x60, 0x0E, 0xB4, 0x2B}}, + {40, []byte{0x0B, 0x23, 0xB9, 0xF5}}, + {50, []byte{0xA6, 0x75, 0xff, 0xe9}}, }, } ) diff --git a/go.mod b/go.mod index 9d1029f0..317d4015 100644 --- a/go.mod +++ b/go.mod @@ -3,35 +3,39 @@ module github.com/renproject/multichain go 1.14 require ( - github.com/btcsuite/btcd v0.20.1-beta + github.com/btcsuite/btcd v0.21.0-beta github.com/btcsuite/btcutil v1.0.2 github.com/codahale/blake2 v0.0.0-20150924215134-8d10d0420cbf github.com/cosmos/cosmos-sdk v0.39.1 - github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 // indirect - github.com/ethereum/go-ethereum v1.9.19 - github.com/filecoin-project/go-address v0.0.3 - github.com/filecoin-project/go-amt-ipld v0.0.0-20191205011053-79efc22d6cdc // indirect - github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect - github.com/filecoin-project/go-bitfield v0.1.0 // indirect - github.com/filecoin-project/go-data-transfer v0.5.0 // indirect - github.com/filecoin-project/go-fil-markets v0.3.2 // indirect - github.com/filecoin-project/lotus v0.4.1 - github.com/filecoin-project/sector-storage v0.0.0-20200723200950-ed2e57dde6df // indirect - github.com/filecoin-project/specs-actors v0.6.2-0.20200724193152-534b25bdca30 - github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a // indirect - github.com/ipfs/go-ds-badger2 v0.1.1-0.20200708190120-187fc06f714e // indirect - github.com/ipfs/go-hamt-ipld v0.1.1 // indirect - github.com/lib/pq v1.7.0 // indirect + github.com/ethereum/go-ethereum v1.9.20 + github.com/filecoin-project/go-address v0.0.5 + github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec + github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48 + github.com/filecoin-project/lotus v1.9.0 + github.com/harmony-one/harmony v1.10.2 + github.com/ipfs/go-cid v0.0.7 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/multiformats/go-varint v0.0.6 + github.com/near/borsh-go v0.3.0 github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 - github.com/raulk/clock v1.1.0 // indirect github.com/renproject/id v0.4.2 - github.com/renproject/pack v0.2.3 - github.com/renproject/surge v1.2.5 + github.com/renproject/pack v0.2.5 + github.com/renproject/solana-ffi v0.1.2 + github.com/renproject/surge v1.2.6 github.com/tendermint/tendermint v0.33.8 - github.com/terra-project/core v0.3.7 - github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 // indirect - go.uber.org/zap v1.15.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + github.com/terra-project/core v0.4.0-rc.4 + go.uber.org/zap v1.16.0 + golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a ) + +replace github.com/cosmos/ledger-cosmos-go => github.com/terra-project/ledger-terra-go v0.11.1-terra + +replace github.com/CosmWasm/go-cosmwasm => github.com/terra-project/go-cosmwasm v0.10.1-terra + +replace github.com/filecoin-project/filecoin-ffi => ./chain/filecoin/filecoin-ffi + +replace github.com/renproject/solana-ffi => ./chain/solana/solana-ffi + +replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 + diff --git a/go.sum b/go.sum index 690ddb94..086ad27b 100644 --- a/go.sum +++ b/go.sum @@ -9,21 +9,16 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= +contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -31,6 +26,9 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY= github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= @@ -49,14 +47,21 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 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/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -65,11 +70,12 @@ github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3o github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -92,13 +98,17 @@ github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.32.11/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= @@ -108,8 +118,9 @@ github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dm github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -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-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -119,71 +130,93 @@ github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2ut github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/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/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20200916222308-4e219a90ba5b/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ= +github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ= +github.com/cockroachdb/redact v0.0.0-20200622112456-cd282804bbd3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codahale/blake2 v0.0.0-20150924215134-8d10d0420cbf h1:5ZeQB3mThuz5C2MSER6T5GdtXTF9CMMk42F9BOyRsEQ= github.com/codahale/blake2 v0.0.0-20150924215134-8d10d0420cbf/go.mod h1:BO2rLUAZMrpgh6GBVKi0Gjdqw2MgCtJrtmUdDeZRKjY= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+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= github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/cosmos-sdk v0.37.14/go.mod h1:qKU3AzVJ0GGWARqImZj24CIX35Q4nJEE+WrXVU/CzFo= +github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= +github.com/cosmos/cosmos-sdk v0.39.1 h1:vhjf9PZh9ph8btAj9aBpHoVITgVVjNBpM3x5Gl/Vwac= github.com/cosmos/cosmos-sdk v0.39.1/go.mod h1:ry2ROl5n+f2/QXpKJo3rdWNJwll00z7KhIVcxNcl16M= -github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= -github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= -github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -193,34 +226,36 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= -github.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4/go.mod h1:Bu8QYdU0YdB2ZQZezHxabmOIciddiwLRnyV4nuZ2HQE= -github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4/go.mod h1:SnqWL9jksIMK63UKkfmWI6f9PDN8ROoCgg+Z4zWk7hg= +github.com/drand/drand v1.2.1/go.mod h1:j0P7RGmVaY7E/OuO2yQOcQj7OgeZCuhgu2gdv0JAm+g= github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw= github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= -github.com/drand/kyber v1.1.0/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= -github.com/drand/kyber v1.1.1/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= -github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk= +github.com/drand/kyber v1.1.4/go.mod h1:9+IgTq7kadePhZg7eRwSD7+bA+bmvqRK+8DtmoV5a3U= +github.com/drand/kyber-bls12381 v0.2.0/go.mod h1:zQip/bHdeEB6HFZSU3v+d3cQE0GaBVQw9aR2E7AdoeI= +github.com/drand/kyber-bls12381 v0.2.1/go.mod h1:JwWn4nHO9Mp4F5qCie5sVIPQZ0X6cw8XAeMRvc/GXBE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/etclabscore/go-jsonschema-walk v0.0.6/go.mod h1:VdfDY72AFAiUhy0ZXEaWSpveGjMT5JcDIm903NGqFwQ= +github.com/etclabscore/go-openrpc-reflect v0.0.36/go.mod h1:0404Ky3igAasAOpyj1eESjstTyneBAIk5PgJFbK4s5E= github.com/ethereum/go-ethereum v1.9.5/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= -github.com/ethereum/go-ethereum v1.9.19 h1:c9IrhzqPKY+ZkS/YhXCO3rgNzlxsVrCYIRvrIAFmIWM= -github.com/ethereum/go-ethereum v1.9.19/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg= +github.com/ethereum/go-ethereum v1.9.20 h1:kk/J5OIoaoz3DRrCXznz3RGi212mHHXwzXlY/ZQxcj0= +github.com/ethereum/go-ethereum v1.9.20/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= @@ -228,63 +263,106 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= -github.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09/go.mod h1:HEJn6kOXMNhCNBYNTO/lrEI7wSgqCOR6hN5ecfYUnC8= -github.com/filecoin-project/filecoin-ffi v0.0.0-20200326153646-e899cc1dd072/go.mod h1:PtH9YP0rURHUKHrKeEBeWg/BqIBMQOz8wtlXlVGREBE= -github.com/filecoin-project/filecoin-ffi v0.26.1-0.20200508175440-05b30afeb00d/go.mod h1:vlQ7sDkbrtM70QMJFDvEyTDywY5SvIjadRCUB+76l90= -github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d/go.mod h1:XE4rWG1P7zWPaC11Pkn1CVR20stqN52MnMkIrF4q6ZU= -github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= -github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= -github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef/go.mod h1:SrA+pWVoUivqKOfC+ckVYbx41hWz++HxJcrlmHNnebU= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= -github.com/filecoin-project/go-amt-ipld v0.0.0-20191205011053-79efc22d6cdc/go.mod h1:KsFPWjF+UUYl6n9A+qbg4bjFgAOneicFZtDH/LQEX2U= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-address v0.0.4 h1:gSNMv0qWwH16fGQs7ycOUrDjY6YCSsgLUl0I0KLjo8w= +github.com/filecoin-project/go-address v0.0.4/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= +github.com/filecoin-project/go-address v0.0.5 h1:SSaFT/5aLfPXycUlFyemoHYhRgdyXClXCyDdNJKPlDM= +github.com/filecoin-project/go-address v0.0.5/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= -github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.2-0.20200629135455-587b27927d38/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.1.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20201006184820-924ee87a1349 h1:pIuR0dnMD0i+as8wNnjjHyQrnhP5O5bmba/lmgQeRgU= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20201006184820-924ee87a1349/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= +github.com/filecoin-project/go-amt-ipld/v3 v3.0.0 h1:Ou/q82QeHGOhpkedvaxxzpBYuqTxLCcj5OChkDNx4qc= +github.com/filecoin-project/go-amt-ipld/v3 v3.0.0/go.mod h1:Qa95YNAbtoVCTSVtX38aAC1ptBnJfPma1R/zZsKmx4o= +github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-bitfield v0.2.1 h1:S6Uuqcspqu81sWJ0He4OAfFLm1tSwPdVjtKTkl5m/xQ= +github.com/filecoin-project/go-bitfield v0.2.1/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-bitfield v0.2.3 h1:pedK/7maYF06Z+BYJf2OeFFqIDEh6SP6mIOlLFpYXGs= +github.com/filecoin-project/go-bitfield v0.2.3/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW8p9au0C68JPgk= +github.com/filecoin-project/go-bitfield v0.2.4/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-commp-utils v0.0.0-20201119054358-b88f7a96a434/go.mod h1:6s95K91mCyHY51RPWECZieD3SGWTqIFLf1mPOes9l5U= +github.com/filecoin-project/go-commp-utils v0.1.0 h1:PaDxoXYh1TXnnz5kA/xSObpAQwcJSUs4Szb72nuaNdk= +github.com/filecoin-project/go-commp-utils v0.1.0/go.mod h1:6s95K91mCyHY51RPWECZieD3SGWTqIFLf1mPOes9l5U= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-data-transfer v0.3.0/go.mod h1:cONglGP4s/d+IUQw5mWZrQK+FQATQxr3AXzi4dRh0l4= -github.com/filecoin-project/go-data-transfer v0.5.0/go.mod h1:7yckbsPPMGuN3O1+SYNE/lowwheaUn5woGILpjN52UI= -github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= +github.com/filecoin-project/go-data-transfer v0.9.0 h1:nTT8j7Hu3TM0wRWrGy83/ctawG7sleJGdFWtIsUsKgY= +github.com/filecoin-project/go-data-transfer v0.9.0/go.mod h1:i2CqUy7TMQGKukj9BgqIxiP8nDHDXU2VLd771KVaCaQ= +github.com/filecoin-project/go-data-transfer v1.0.1/go.mod h1:UxvfUAY9v3ub0a21BSK9u3pB2aq30Y0KMsG+w9/ysyo= +github.com/filecoin-project/go-data-transfer v1.4.3 h1:ECEw69NOfmEZ7XN1NSBvj3KTbbH2mIczQs+Z2w4bD7c= +github.com/filecoin-project/go-data-transfer v1.4.3/go.mod h1:n8kbDQXWrY1c4UgfMa9KERxNCWbOTDwdNhf2MpN9dpo= +github.com/filecoin-project/go-ds-versioning v0.1.0/go.mod h1:mp16rb4i2QPmxBnmanUx8i/XANp+PFCCJWiAb+VW4/s= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.3.2-0.20200702145639-4034a18364e4/go.mod h1:UY+/zwNXHN73HcrN6HxNDpv6KKM6ehqfCuE9vK9khF8= -github.com/filecoin-project/go-fil-markets v0.3.2/go.mod h1:e/IofcotbwH7ftgeK+TjjdjFsrCDWrh5vvnr7k1OSH8= -github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM= -github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-fil-commcid v0.0.0-20201016201715-d41df56b4f6a h1:hyJ+pUm/4U4RdEZBlg6k8Ma4rDiuvqyGpoICXAxwsTg= +github.com/filecoin-project/go-fil-commcid v0.0.0-20201016201715-d41df56b4f6a/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= +github.com/filecoin-project/go-fil-markets v1.0.0 h1:np9+tlnWXh9xYG4oZfha6HZFLYOaAZoMGR3V4w6DM48= +github.com/filecoin-project/go-fil-markets v1.0.0/go.mod h1:lXExJyYHwpMMddCqhEdNrc7euYJKNkp04K76NZqJLGg= +github.com/filecoin-project/go-fil-markets v1.0.5-0.20201113164554-c5eba40d5335/go.mod h1:AJySOJC00JRWEZzRG2KsfUnqEf5ITXxeX09BE9N4f9c= +github.com/filecoin-project/go-fil-markets v1.2.5 h1:bQgtXbwxKyPxSEQoUI5EaTHJ0qfzyd5NosspuADCm6Y= +github.com/filecoin-project/go-fil-markets v1.2.5/go.mod h1:7JIqNBmFvOyBzk/EiPYnweVdQnWhshixb5B9b1653Ag= +github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= +github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= +github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1 h1:zbzs46G7bOctkZ+JUX3xirrj0RaEsi+27dtlsgrTNBg= +github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI= +github.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49 h1:FSY245KeXFCUgyfFEu+bhrZNk8BGGJyfpSmQl2aiPU8= +github.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec h1:rGI5I7fdU4viManxmDdbk5deZO7afe6L1Wc04dAmlOM= +github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= +github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= -github.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= -github.com/filecoin-project/go-statemachine v0.0.0-20200619205156-c7bf525c06ef/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= -github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.0.0-20201013222834-41ea465f274f h1:TZDTu4MtBKSFLXWGKLy+cvC3nHfMFIrVgWLAz/+GgZQ= +github.com/filecoin-project/go-state-types v0.0.0-20201013222834-41ea465f274f/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48 h1:Jc4OprDp3bRDxbsrXNHPwJabZJM3iDy+ri8/1e0ZnX4= +github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe h1:dF8u+LEWeIcTcfUcCf3WFVlc81Fr2JKg8zPzIbBDKDw= +github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIiWBRilQjQ+5IiwdQ= github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= +github.com/filecoin-project/go-statestore v0.1.1 h1:ufMFq00VqnT2CAuDpcGnwLnCX1I/c3OROw/kXVNSTZk= +github.com/filecoin-project/go-statestore v0.1.1/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/lotus v0.4.1/go.mod h1:uo3yDPhPlpHwdCKr0k41/a205WwlSclQamx+sQDKRMI= -github.com/filecoin-project/sector-storage v0.0.0-20200615154852-728a47ab99d6/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM= -github.com/filecoin-project/sector-storage v0.0.0-20200625154333-98ef8e4ef246/go.mod h1:8f0hWDzzIi1hKs4IVKH9RnDsO4LEHVz8BNat0okDOuY= -github.com/filecoin-project/sector-storage v0.0.0-20200630180318-4c1968f62a8f/go.mod h1:r12d7tsmJKz8QDGoCvl65Ay2al6mOgDqxAGUxbyrgMs= -github.com/filecoin-project/sector-storage v0.0.0-20200723200950-ed2e57dde6df/go.mod h1:7EE+f7jM4kCy2MKHoiiwNDQGJSb+QQzZ+y+/17ugq4w= -github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= -github.com/filecoin-project/specs-actors v0.0.0-20200226200336-94c9b92b2775/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU= -github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= -github.com/filecoin-project/specs-actors v0.6.0/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.6.2-0.20200702170846-2cd72643a5cf/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.6.2-0.20200724193152-534b25bdca30/go.mod h1:ppIYDlWQvcfzDW0zxar53Z1Ag69er4BmFvJAtV1uDMI= -github.com/filecoin-project/specs-storage v0.1.0/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/storage-fsm v0.0.0-20200625160832-379a4655b044/go.mod h1:JD7fmV1BYADDcy4EYQnqFH/rUzXsh0Je0jXarCjZqSk= +github.com/filecoin-project/lotus v1.1.2 h1:cs74C5oNVoIIFmjovpSuJR3qXzXcqS9cpOT+oSmNRiE= +github.com/filecoin-project/lotus v1.1.2/go.mod h1:jSlQv+/+WGox3TdEzBEfmXzvbot4OOsBiIh98t7AnAA= +github.com/filecoin-project/lotus v1.9.0 h1:TDKDLbmgYTL8M0mlfd9HmJVEYRlSSOQnakg4+9rfyWM= +github.com/filecoin-project/lotus v1.9.0/go.mod h1:4YC/8rizrrp2wKOYvHQEjCxZbziXi68BhrzvI+FCye0= +github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= +github.com/filecoin-project/specs-actors v0.9.12 h1:iIvk58tuMtmloFNHhAOQHG+4Gci6Lui0n7DYQGi3cJk= +github.com/filecoin-project/specs-actors v0.9.12/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= +github.com/filecoin-project/specs-actors v0.9.13 h1:rUEOQouefi9fuVY/2HOroROJlZbOzWYXXeIh41KF2M4= +github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= +github.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY= +github.com/filecoin-project/specs-actors/v2 v2.2.0 h1:IyCICb0NHYeD0sdSqjVGwWydn/7r7xXuxdpvGAcRCGY= +github.com/filecoin-project/specs-actors/v2 v2.2.0/go.mod h1:rlv5Mx9wUhV8Qsz+vUezZNm+zL4tK08O0HreKKPB2Wc= +github.com/filecoin-project/specs-actors/v2 v2.3.2/go.mod h1:UuJQLoTx/HPvvWeqlIFmC/ywlOLHNe8SNQ3OunFbu2Y= +github.com/filecoin-project/specs-actors/v2 v2.3.5-0.20210114162132-5b58b773f4fb h1:orr/sMzrDZUPAveRE+paBdu1kScIUO5zm+HYeh+VlhA= +github.com/filecoin-project/specs-actors/v2 v2.3.5-0.20210114162132-5b58b773f4fb/go.mod h1:LljnY2Mn2homxZsmokJZCpRuhOPxfXhvcek5gWkmqAc= +github.com/filecoin-project/specs-actors/v3 v3.1.0 h1:s4qiPw8pgypqBGAy853u/zdZJ7K9cTZdM1rTiSonHrg= +github.com/filecoin-project/specs-actors/v3 v3.1.0/go.mod h1:mpynccOLlIRy0QnR008BwYBwT9fen+sPR13MA1VmMww= +github.com/filecoin-project/specs-actors/v4 v4.0.0 h1:vMALksY5G3J5rj3q9rbcyB+f4Tk1xrLqSgdB3jOok4s= +github.com/filecoin-project/specs-actors/v4 v4.0.0/go.mod h1:TkHXf/l7Wyw4ZejyXIPS2rK8bBO0rdwhTZyQQgaglng= +github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57 h1:N6IBsnGXfAMXd677G6EiOKewFwQ7Ulcuupi4U6wYmXE= +github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57/go.mod h1:283yBMMUSDB2abcjP/hhrwTkhb9h3sfM6KGrep/ZlBI= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= +github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= -github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -293,7 +371,10 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -301,20 +382,33 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/spec v0.19.7/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.11/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.8/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -324,6 +418,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= @@ -331,7 +426,9 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -340,43 +437,51 @@ github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5+85/pbdkiYcBqM1JWmhpAXLmy0fw= github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -387,16 +492,14 @@ github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORR github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 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/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -410,24 +513,30 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= -github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= -github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -439,7 +548,9 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -452,25 +563,36 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/iancoleman/orderedmap v0.1.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg= github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= -github.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug= +github.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo= +github.com/ipfs/go-bitswap v0.3.2/go.mod h1:AyWWfN3moBzQX0banEtfKOfbXb3ZeoOeXnZGNPV9S6w= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= +github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= github.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI= github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834 h1:hFJoI1D2a3MqiNkSb4nKwrdkhCngUxUTFNwVwovZX2s= github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-blockservice v0.1.4 h1:Vq+MlsH8000KbbUciRyYMEw/NNP8UAGmcqKi4uWmFGA= +github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -479,6 +601,8 @@ github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= @@ -488,7 +612,10 @@ github.com/ipfs/go-datastore v0.3.0/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRV github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.2/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= +github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= @@ -502,53 +629,72 @@ github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZ github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= +github.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459/go.mod h1:oh4liWHulKcDKVhCska5NLelE3MatWl+1FwSz3tY91g= +github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0= github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= -github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= -github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= -github.com/ipfs/go-graphsync v0.0.6-0.20200715204712-ef06b3d32e83/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= -github.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e/go.mod h1:giiPqWYCnRBYpNTsJ/EX1ojldX5kTXrXYckSJQ7ko9M= -github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f/go.mod h1:phOFBB7W73N9dg1glcb1fQ9HtQFDUpeyJgatW8ns0bw= +github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM= +github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-graphsync v0.3.0/go.mod h1:gEBvJUNelzMkaRPJTpg/jaKN4AQW/7wDWu0K92D8o10= +github.com/ipfs/go-graphsync v0.3.1 h1:dJLYrck4oyJDfMVhGEKiWHxaY8oYMWko4m2Fi+4bofo= +github.com/ipfs/go-graphsync v0.3.1/go.mod h1:bw4LiLM5Oq/uLdzEtih9LK8GrwSijv+XqYiWCTxHMqs= +github.com/ipfs/go-graphsync v0.4.2/go.mod h1:/VmbZTUdUMTbNkgzAiCEucIIAU3BkLE2cZrDCVUhyi0= +github.com/ipfs/go-graphsync v0.4.3/go.mod h1:mPOwDYv128gf8gxPFgXnz4fNrSYPsWyqisJ7ych+XDY= +github.com/ipfs/go-graphsync v0.6.0 h1:x6UvDUGA7wjaKNqx5Vbo7FGT8aJ5ryYA0dMQ5jN3dF0= +github.com/ipfs/go-graphsync v0.6.0/go.mod h1:e2ZxnClqBBYAtd901g9vXMJzS47labjAtOzsWtOzKNk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= +github.com/ipfs/go-ipfs-blockstore v1.0.1 h1:fnuVj4XdZp4yExhd0CnUwAiMNJHiPnfInhiuwz4lW1w= +github.com/ipfs/go-ipfs-blockstore v1.0.1/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= +github.com/ipfs/go-ipfs-blockstore v1.0.3 h1:RDhK6fdg5YsonkpMuMpdvk/pRtOQlrIRIybuQfkvB2M= +github.com/ipfs/go-ipfs-blockstore v1.0.3/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-cmds v0.1.0 h1:0CEde9EcxByej8+L6d1PST57J4ambRPyCTjLG5Ymou8= github.com/ipfs/go-ipfs-cmds v0.1.0/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8= github.com/ipfs/go-ipfs-config v0.0.11/go.mod h1:wveA8UT5ywN26oKStByzmz1CO6cXwLKKM6Jn/Hfw08I= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= -github.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= +github.com/ipfs/go-ipfs-http-client v0.0.5 h1:niW5M0qqa0O/VRCAzr3f5Y7i3MjTpf0lhpkisjRtHR8= github.com/ipfs/go-ipfs-http-client v0.0.5/go.mod h1:8EKP9RGUrUex4Ff86WhnKU7seEBOtjdgXlY9XHYvYMw= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8= github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-cbor v0.0.5-0.20200204214505-252690b78669/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf h1:PRCy+w3GocY77CBEwTprp6hn7PLiEU1YToKe7B+1FVk= github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5G8= +github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= @@ -556,19 +702,27 @@ github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSI github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 h1:3bijxqzQ1O9yg7gd7Aqk80oaEvsJ+uXw0zSvi2qR3Jw= github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-merkledag v0.3.2 h1:MRqj40QkrWkvPswXs4EfSslhZ4RVPRbxwX11js0t1xY= +github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks= github.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo= +github.com/ipfs/go-path v0.0.7 h1:H06hKMquQ0aYtHiHryOMLpQC1qC3QwXwkahcEVD51Ho= github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= @@ -577,15 +731,24 @@ github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUn github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= github.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8= github.com/ipfs/go-unixfs v0.2.1/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= +github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipfs/interface-go-ipfs-core v0.2.3 h1:E6uQ+1fJjkxJWlL9lAE72a5FWeyeeNL3GitLy8+jq3Y= github.com/ipfs/interface-go-ipfs-core v0.2.3/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s= github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg= github.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs= -github.com/ipld/go-car v0.1.1-0.20200429200904-c222d793c339/go.mod h1:eajxljm6I8o3LitnFeVEmucwZmz7+yLSiKce9yYMefg= -github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c= +github.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4/go.mod h1:xrMEcuSq+D1vEwl+YAXsg/JfA98XGpXDwnkIL4Aimqw= +github.com/ipld/go-car v0.1.1-0.20201119040415-11b6074b6d4d/go.mod h1:2Gys8L8MJ6zkh1gktTSXreY63t4UbyvNp5JaudTyxHQ= github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f h1:XpOuNQ5GbXxUcSukbQcW9jkE7REpaFGJU2/T00fo9kA= +github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM= +github.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018 h1:RbRHv8epkmvBYA5cGfz68GUSbOgx5j/7ObLIl4Rsif0= +github.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM= github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200922192210-9a2bfd4440a6/go.mod h1:3pHYooM9Ea65jewRwrb2u5uHZCNkNTe9ABsVB+SrkH0= +github.com/ipld/go-ipld-prime-proto v0.1.0/go.mod h1:11zp8f3sHVgIqtb/c9Kr5ZGqpnCLF1IVTNOez9TopzE= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= @@ -599,6 +762,7 @@ github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -606,9 +770,13 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -627,8 +795,9 @@ github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4 github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= +github.com/kilic/bls12-381 v0.0.0-20200731194930-64c428e1bff5/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= +github.com/kilic/bls12-381 v0.0.0-20200820230200-6b2c19996391/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -640,16 +809,18 @@ github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfo github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= @@ -660,6 +831,7 @@ github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UG github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE= github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= @@ -672,10 +844,12 @@ github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZk github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA= github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8= +github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE= +github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= +github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= @@ -684,12 +858,15 @@ github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQ github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= github.com/libp2p/go-libp2p-autonat v0.2.3/go.mod h1:2U6bNWCNsAG9LEbwccBDQbjzQ8Krdjge1jLTE9rdoMM= +github.com/libp2p/go-libp2p-autonat v0.3.2/go.mod h1:0OzOi1/cVc7UcxfOddemYD5vzEqi4fwRbnZcJGLi68U= +github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= github.com/libp2p/go-libp2p-autonat-svc v0.1.0/go.mod h1:fqi8Obl/z3R4PFVLm8xFtZ6PBL9MlV/xumymRFkKq5A= github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.3/go.mod h1:KML1//wiKR8vuuJO0y3LUd1uLv+tlkGTAr3jC0S5cLg= github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ= +github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE= github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= @@ -699,6 +876,8 @@ github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3 github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= github.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4= +github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= github.com/libp2p/go-libp2p-connmgr v0.1.1/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk= github.com/libp2p/go-libp2p-connmgr v0.2.3/go.mod h1:Gqjg29zI8CwXX21zRxy6gOg8VYu3zVerJRt2KyktzH4= github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= @@ -724,6 +903,10 @@ github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqe github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskWE7pvqs= +github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.7.0 h1:4a0TMjrWNTZlNvcqxZmrMRDi/NQWrhwO2pkTuLSQ/IQ= +github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= @@ -734,6 +917,8 @@ github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFT github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= +github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= +github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= @@ -741,9 +926,11 @@ github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= github.com/libp2p/go-libp2p-kad-dht v0.2.1/go.mod h1:k7ONOlup7HKzQ68dE6lSnp07cdxdkmnRa+6B4Fh9/w0= -github.com/libp2p/go-libp2p-kad-dht v0.8.1/go.mod h1:u3rbYbp3CSraAHD5s81CJ3hHozKTud/UOXfAgh93Gek= +github.com/libp2p/go-libp2p-kad-dht v0.8.3/go.mod h1:HnYYy8taJWESkqiESd1ngb9XX/XGGsMA5G0Vj2HoSh4= +github.com/libp2p/go-libp2p-kad-dht v0.11.0/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= github.com/libp2p/go-libp2p-kbucket v0.2.1/go.mod h1:/Rtu8tqbJ4WQ2KTCOMJhggMukOLNLNPY1EtEWWLxUvc= github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY= +github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= @@ -752,6 +939,8 @@ github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3 github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE= +github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= @@ -761,6 +950,7 @@ github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8 github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= +github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= @@ -774,19 +964,26 @@ github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U= github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk= +github.com/libp2p/go-libp2p-pubsub v0.3.6 h1:9oO8W7qIWCYQYyz5z8nUsPcb3rrFehBlkbqvbSVjBxY= +github.com/libp2p/go-libp2p-pubsub v0.3.6/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb h1:HExLcdXn8fgtXPciUw97O5NNhBn31dt6d9fVUD4cngo= +github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= +github.com/libp2p/go-libp2p-quic-transport v0.8.2/go.mod h1:L+e0q15ZNaYm3seHgbsXjWP8kXLEqz+elLWKk9l8DhM= +github.com/libp2p/go-libp2p-quic-transport v0.9.0/go.mod h1:xyY+IgxL0qsW7Kiutab0+NlxM0/p9yRtrGTYsuMWf70= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= +github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= @@ -804,12 +1001,17 @@ github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaT github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h/GGZes8Wku/M5Y= github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA= +github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= +github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= +github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= @@ -827,6 +1029,8 @@ github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9R github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= +github.com/libp2p/go-libp2p-yamux v0.4.1/go.mod h1:FA/NjRYRVNjqOzpGuGqcruH7jAU2mYIjtKBicVOL3dc= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= @@ -837,22 +1041,29 @@ github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTW github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= +github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= @@ -865,6 +1076,7 @@ github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19 github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= @@ -882,40 +1094,53 @@ github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZ github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.3.6/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= +github.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.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.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= @@ -929,21 +1154,27 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -953,7 +1184,11 @@ github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVq github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -963,12 +1198,17 @@ github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= +github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I= +github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= @@ -977,8 +1217,11 @@ github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQ github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= +github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= @@ -987,14 +1230,21 @@ github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-multistream v0.1.2 h1:knyamLYMPFPngQjGQ0lhnlys3jtVR/3xV6TREUJr+fE= +github.com/multiformats/go-multistream v0.1.2/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU= +github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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= @@ -1005,8 +1255,12 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/near/borsh-go v0.3.0 h1:+DvG7eApOD3KrHIh7TwZvYzhXUF/OzMTC6aRTUEtW+8= +github.com/near/borsh-go v0.3.0/go.mod h1:NeMochZp7jN/pYFuxLkrZtmLqbADmnp/y1+/dL+AsyQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= @@ -1026,6 +1280,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -1034,6 +1289,8 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333/go.mod h1:Ag6rSXkHIckQmjFBCweJEEt1mrTPBv8b9W4aU/NQWfI= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= @@ -1042,6 +1299,8 @@ github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NH github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= @@ -1057,6 +1316,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -1064,12 +1324,15 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1082,15 +1345,16 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1099,6 +1363,7 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1111,32 +1376,38 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.0 h1:jhMy6QXfi3y2HEzFoyuCj40z4OZIIHHPtFyCMftmvKA= github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rakyll/statik v0.1.5/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= +github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= -github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/raulk/go-watchdog v1.0.1/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/renproject/id v0.4.2 h1:XseNDPPCJtsZjIWR7Qgf+zxy0Gt5xsLrfwpQxJt5wFQ= github.com/renproject/id v0.4.2/go.mod h1:bCzV4zZkyWetf0GvhJxMT9HQNnGUwzQpImtXOUXqq0k= -github.com/renproject/pack v0.2.3 h1:6zHFyz45ow52iLNLG19eyA/UphJE8b2LsYEcLC3HqQQ= -github.com/renproject/pack v0.2.3/go.mod h1:pzX3Hc04RoPft89LaZJVp0xgngVGi90V7GvyC3mOGg4= +github.com/renproject/pack v0.2.5 h1:BNfam8PCb5qJuIX36IqOkcRgaZLOZsM1lZZSakbOxb4= +github.com/renproject/pack v0.2.5/go.mod h1:pzX3Hc04RoPft89LaZJVp0xgngVGi90V7GvyC3mOGg4= github.com/renproject/surge v1.2.2/go.mod h1:jNVsKCM3/2PAllkc2cx7g2saG9NrHRX5x20I/TDMXOs= -github.com/renproject/surge v1.2.5 h1:P2qKZxWiKrC8hw7in/hXVtic+dGkhd1M0H/1Lj+fJnw= github.com/renproject/surge v1.2.5/go.mod h1:jNVsKCM3/2PAllkc2cx7g2saG9NrHRX5x20I/TDMXOs= +github.com/renproject/surge v1.2.6 h1:4EV2jbBPvQM8Wnv5zL1N1X/UbaH6AZiRUv7r4xZ8ncA= +github.com/renproject/surge v1.2.6/go.mod h1:jNVsKCM3/2PAllkc2cx7g2saG9NrHRX5x20I/TDMXOs= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/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/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -1172,6 +1443,7 @@ github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81a github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -1189,24 +1461,27 @@ github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= 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/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= -github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= @@ -1220,35 +1495,47 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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.3.1-0.20190311161405-34c6fa2dc709/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.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/supranational/blst v0.1.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= -github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= -github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= +github.com/tendermint/iavl v0.14.0 h1:Jkff+IFrXxRWtH9Jn/ga/2cxNnzMTv58xEKgCJsKUBg= github.com/tendermint/iavl v0.14.0/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE= -github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= -github.com/tendermint/tendermint v0.32.13/go.mod h1:5/B1XZjNYtVBso8o1l/Eg4A0Mhu42lDcmftoQl95j/E= github.com/tendermint/tendermint v0.33.5/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= github.com/tendermint/tendermint v0.33.7/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= +github.com/tendermint/tendermint v0.33.8 h1:Xxu4QhpqcomSE0iQDw1MqLgfsa8fqtPtWFJK6zZOVso= github.com/tendermint/tendermint v0.33.8/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= -github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= -github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= +github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= -github.com/terra-project/core v0.3.7/go.mod h1:YAzVMRCDjmgFlAgLF3h1CAHZjtWuK4CmmsjWkqSg5s0= +github.com/terra-project/core v0.4.0-rc.4 h1:6ZK9KyUCRWw5kQmcBmTbKy6RZ8UU2ew9T3NrlH4jS1U= +github.com/terra-project/core v0.4.0-rc.4/go.mod h1:QoddSVukyuI5qM0rFp7xvKjTn/aoK3D177MUt1V7YXM= +github.com/terra-project/go-cosmwasm v0.10.1-terra h1:3yvESyqndOoJKmmFyGKfQy7rLg2Gz4ULwwoCi4fDqAw= +github.com/terra-project/go-cosmwasm v0.10.1-terra/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc= +github.com/terra-project/ledger-terra-go v0.11.1-terra/go.mod h1:5fdyEuDNvsymbqag/EaaAeWAgyAebQe2VH38H+DnXnA= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= @@ -1260,6 +1547,7 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -1274,19 +1562,23 @@ github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM= -github.com/whyrusleeping/cbor-gen v0.0.0-20190917003517-d78d67427694/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= -github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163 h1:TtcUeY2XZSriVWR1pXyfCBWIf/NGC2iUdNw1lofUjUU= +github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2 h1:7HzUKl5d/dELS9lLeT4W6YvliZx+s9k/eOOIdHKrA/w= +github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4= +github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= @@ -1297,20 +1589,29 @@ github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDb github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ= github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= +github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4/go.mod h1:K+EVq8d5QcQ2At5VECsA+SNZvWefyBXh8TnIsxo1OvQ= github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A= +github.com/whyrusleeping/pubsub v0.0.0-20190708150250-92bcb0691325/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A= +github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/c-for-go v0.0.0-20201002084316-c134bfab968f/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= +github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb/go.mod h1:pbNsDSxn1ICiNn9Ct4ZGNrwzfkkwYbx/lw8VuyutFIg= +github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk= +github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.12.1/go.mod h1:KatxXrVDzgWwbssUWsF5+cOJHXPvzQ09YSlzGNuhOEo= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= @@ -1329,13 +1630,19 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1343,15 +1650,18 @@ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+ go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 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/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1379,15 +1689,16 @@ golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1395,9 +1706,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1410,7 +1720,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1418,7 +1727,9 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1453,16 +1764,19 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/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-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201022231255-08b38378de70 h1:Z6x4N9mAi4oF0TbHweCsH618MO6OI6UFgV0FP5n0wBY= +golang.org/x/net v0.0.0-20201022231255-08b38378de70/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1478,7 +1792,11 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ 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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1514,7 +1832,6 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1525,13 +1842,12 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1539,20 +1855,25 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c h1:38q6VNPWR010vN82/SB121GujZNIfAUb4YttE2rhGuc= +golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1591,17 +1912,13 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201112185108-eeaa07dd7696/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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1620,9 +1937,6 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1648,17 +1962,12 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1667,7 +1976,6 @@ google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLD google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1678,8 +1986,10 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1689,16 +1999,20 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= @@ -1715,10 +2029,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= @@ -1729,8 +2043,18 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254= +modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk= +modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk= +modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/infra/.env b/infra/.env index ee8b3a16..75dd3d0e 100644 --- a/infra/.env +++ b/infra/.env @@ -1,3 +1,10 @@ +# +# Binance Smart Chain +# + +export BINANCE_MNEMONIC="clutch captain shoe salt awake harvest setup primary inmate ugly among become" +export BINANCE_ADDRESS=0xa0df350d2637096571F7A701CBc1C5fdE30dF76A + # # Bitcoin # @@ -45,6 +52,12 @@ export DOGECOIN_ADDRESS=n3PSSpR4zqUKWH4tcRjP9aTwJ4GmixQXmt export ETHEREUM_MNEMONIC="clutch captain shoe salt awake harvest setup primary inmate ugly among become" export ETHEREUM_ADDRESS=0xa0df350d2637096571F7A701CBc1C5fdE30dF76A +# +# Fantom +# +export FANTOM_PK=163f5f0f9a621d72fedd85ffca3d08d131ab4e812181e0d30ffd1c885d20aac7 +export FANTOM_ADDRESS=0x239fA7623354eC26520dE878B52f13Fe84b06971 + # # Harmony # @@ -55,8 +68,8 @@ export HARMONY_ADDRESS=one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3 # # Filecoin # -export FILECOIN_PK=7b2254797065223a22736563703235366b31222c22507269766174654b6579223a223168436f364f617442746f58636d304f6565665849473873374e505573576472372f6666735a58755964493d227d -export FILECOIN_ADDRESS=t17lz42vyixtlfs4a3j76cw53w32qb57w7g4g6qua +export FILECOIN_PK=7b2254797065223a22736563703235366b31222c22507269766174654b6579223a22756d6a634e436a487a5438455757485849754a4c4b58745035437153323435666238626c656c756e5448493d227d +export FILECOIN_ADDRESS=f1ej2tountzqwnu6uswhqdzvw6yy5xvcig6rxl2qa # # Terra @@ -77,3 +90,14 @@ export TERRA_ADDRESS=terra10s4mg25tu6termrk8egltfyme4q7sg3hl8s38u # access to plenty of testing funds. export ZCASH_PK=cNSVbbsAcBQ6BAmMr6yH6DLWr7QTDptHwdzpy4GYxGDkNZeKnczK export ZCASH_ADDRESS=tmCTReBSJEDMWfFCkXXPMSB3EfuPg6SE9dw + +# +# Avalanche +# +export AVAX_USERNAME="Username" +export AVAX_PASSWORD="Few43!r389hfweu32" +export AVAX_PK="PrivateKey-ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN" +export AVAX_ADDRESS="X-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u" +export C_AVAX_PK="0xb8c1b5c1d81f9475fdf2e334517d29f733bdfa40682207571b12fc1142cbf329" +export C_AVAX_HEX_ADDRESS="0xa0df350d2637096571F7A701CBc1C5fdE30dF76A" +export C_AVAX_BECH32_ADDRESS="C-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u" diff --git a/infra/acala/Dockerfile b/infra/acala/Dockerfile new file mode 100644 index 00000000..a988fb74 --- /dev/null +++ b/infra/acala/Dockerfile @@ -0,0 +1,38 @@ +FROM ubuntu:xenial + +RUN apt-get update && apt-get install --yes --fix-missing software-properties-common curl git clang +RUN apt-get install --yes --fix-missing --no-install-recommends build-essential + +# Install Rust +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Clone repository +RUN git clone https://github.com/AcalaNetwork/Acala.git + +RUN mv Acala /app +WORKDIR /app + +# TEMPORARY: use the branch that has a good reference to the submodules +# TODO: remove when the `master` branch of Acala is updated +RUN git fetch +RUN git checkout update-orml +RUN git pull + +# Make sure submodule.recurse is set to true to make life with submodule easier. +RUN git config --global submodule.recurse true + +# Build +RUN make init +RUN make build + +WORKDIR / +COPY run.sh /root/ +RUN chmod +x /root/run.sh + +# rpc port +EXPOSE 9933 +# ws port +EXPOSE 9944 + +ENTRYPOINT ["./root/run.sh"] diff --git a/infra/acala/run.sh b/infra/acala/run.sh new file mode 100644 index 00000000..a48318f1 --- /dev/null +++ b/infra/acala/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash +ADDRESS=$1 + +# Start +cd /app +make run +sleep 10 + +# Print setup +echo "ACALA_ADDRESS=$ADDRESS" diff --git a/infra/avalanche/Dockerfile b/infra/avalanche/Dockerfile new file mode 100644 index 00000000..5b077ae0 --- /dev/null +++ b/infra/avalanche/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:groovy + +RUN apt update -y +RUN apt-get install -y wget curl build-essential + +# INSTALL GO AND RUST +RUN wget -c https://golang.org/dl/go1.15.5.linux-amd64.tar.gz +RUN tar -C /usr/local -xzf go1.15.5.linux-amd64.tar.gz +ENV PATH=$PATH:/usr/local/go/bin + +# Fetch avalanchego +WORKDIR /app +RUN wget https://github.com/ava-labs/avalanchego/releases/download/v1.4.5/avalanchego-linux-amd64-v1.4.5.tar.gz +RUN tar -xzf avalanchego-linux-amd64-v1.4.5.tar.gz +RUN rm avalanchego-linux-amd64-v1.4.5.tar.gz +ENV PATH=$PATH:/app/avalanchego-v1.4.5 + +# COPY run script +COPY run.sh run.sh +RUN chmod +x run.sh + +# RPC SERVER PORT +EXPOSE 9650 + +# RUN +ENTRYPOINT [ "./run.sh" ] diff --git a/infra/avalanche/run.sh b/infra/avalanche/run.sh new file mode 100644 index 00000000..925c57c3 --- /dev/null +++ b/infra/avalanche/run.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +AVAX_USERNAME=$1 +AVAX_PASSWORD=$2 +AVAX_PK=$3 +AVAX_ADDRESS=$4 +C_AVAX_PK=$5 +C_AVAX_HEX_ADDRESS=$6 +C_AVAX_BECH32_ADDRESS=$7 + +avalanchego \ + --assertions-enabled=true \ + --tx-fee=1000000 \ + --public-ip=0.0.0.0 \ + --network-id=local \ + --signature-verification-enabled=true \ + --api-admin-enabled=true \ + --api-ipcs-enabled=true \ + --api-keystore-enabled=true \ + --api-metrics-enabled=true \ + --http-host=0.0.0.0 \ + --http-port=9650 \ + --http-tls-enabled=false \ + --plugin-dir=/app/avalanchego-v1.4.5/avalanchego-latest/plugins \ + --log-level=info \ + --snow-avalanche-batch-size=30 \ + --snow-avalanche-num-parents=5 \ + --snow-sample-size=1 \ + --snow-quorum-size=1 \ + --snow-virtuous-commit-threshold=1 \ + --snow-rogue-commit-threshold=4 \ + --staking-enabled=false \ + --staking-port=9651 \ + --api-auth-required=false & + +# create a new user +sleep 10 +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" :1, + "method" :"keystore.createUser", + "params" :{ + "username":"'"$AVAX_USERNAME"'", + "password":"'"$AVAX_PASSWORD"'" + } +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore + +# import private key that contains AVAX into X-chain +sleep 1 +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" :1, + "method" :"avm.importKey", + "params" :{ + "username":"'"$AVAX_USERNAME"'", + "password":"'"$AVAX_PASSWORD"'", + "privateKey":"'"$AVAX_PK"'" + } +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X + +# import private key into C-chain +sleep 1 +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" :1, + "method" :"avax.importKey", + "params" :{ + "username" :"'"$AVAX_USERNAME"'", + "password":"'"$AVAX_PASSWORD"'", + "privateKey":"'"$AVAX_PK"'" + } +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/C/avax + +# export the AVAX to C-chain +sleep 1 +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" :1, + "method" :"avm.exportAVAX", + "params" :{ + "to":"'"$C_AVAX_BECH32_ADDRESS"'", + "destinationChain": "C", + "amount": 5000000000000, + "username":"'"$AVAX_USERNAME"'", + "password":"'"$AVAX_PASSWORD"'" + } +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X + +# import AVAX to the hex address +sleep 1 +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" :1, + "method" :"avax.importAVAX", + "params" :{ + "to":"'"$C_AVAX_HEX_ADDRESS"'", + "sourceChain":"X", + "username":"'"$AVAX_USERNAME"'", + "password":"'"$AVAX_PASSWORD"'" + } +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/C/avax + +wait %1 diff --git a/infra/binance/Dockerfile b/infra/binance/Dockerfile new file mode 100644 index 00000000..f8646aa1 --- /dev/null +++ b/infra/binance/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:xenial + +RUN apt-get update --fix-missing +RUN apt-get install --yes curl + +RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - +RUN apt-get install --yes nodejs +RUN npm install -g ganache-cli + +COPY run.sh /root/run.sh +RUN chmod +x /root/run.sh + +EXPOSE 8575 + +ENTRYPOINT ["./root/run.sh"] diff --git a/infra/binance/Dockerfile-riolta b/infra/binance/Dockerfile-riolta new file mode 100644 index 00000000..a63ce80c --- /dev/null +++ b/infra/binance/Dockerfile-riolta @@ -0,0 +1,23 @@ +# Build Geth in a stock Go builder container +FROM golang:1.14-alpine as builder + +RUN apk add --no-cache make gcc musl-dev linux-headers git + +WORKDIR /app +RUN git clone -b 1.0.1.beta.2 https://github.com/binance-chain/bsc +WORKDIR /app/bsc + +RUN make geth + +RUN touch genesis.json +RUN touch config.yaml +RUN wget -q -O genesis.json https://github.com/binance-chain/bsc/releases/download/v1.0.0-beta.1/genesis.json +RUN wget -q -O config.yaml https://github.com/binance-chain/bsc/releases/download/v1.0.0-beta.1/config.toml + +# RPC port +EXPOSE 8575 + +# init the node with genesis file +RUN ./build/bin/geth --datadir node init genesis.json + +ENTRYPOINT ["./build/bin/geth", "--config", "./config.yaml", "--datadir", "./node", "--rpc", "--rpcport", "8575"] diff --git a/infra/fantom/run.sh b/infra/binance/run.sh similarity index 71% rename from infra/fantom/run.sh rename to infra/binance/run.sh index 5880da45..6355dadf 100644 --- a/infra/fantom/run.sh +++ b/infra/binance/run.sh @@ -4,7 +4,9 @@ ADDRESS=$2 ganache-cli \ -h 0.0.0.0 \ + -a 105 \ -k muirGlacier \ -i 420 \ -m "$MNEMONIC" \ - -u $ADDRESS \ No newline at end of file + -p 8575 \ + -u $ADDRESS diff --git a/infra/bitcoin/Dockerfile b/infra/bitcoin/Dockerfile index 24688872..bb1688ca 100644 --- a/infra/bitcoin/Dockerfile +++ b/infra/bitcoin/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:xenial +FROM ubuntu:bionic RUN apt-get update && apt-get install --yes software-properties-common RUN apt-get install --yes curl diff --git a/infra/bitcoin/run.sh b/infra/bitcoin/run.sh index 5176e272..0a00cdef 100644 --- a/infra/bitcoin/run.sh +++ b/infra/bitcoin/run.sh @@ -1,5 +1,6 @@ #!/bin/bash ADDRESS=$1 +PRIV_KEY=$2 # Start /app/bin/bitcoind @@ -11,12 +12,19 @@ echo "BITCOIN_ADDRESS=$ADDRESS" # Import the address /app/bin/bitcoin-cli importaddress $ADDRESS +# Import the private key to spend UTXOs +/app/bin/bitcoin-cli importprivkey $PRIV_KEY + # Generate enough block to pass the maturation time /app/bin/bitcoin-cli generatetoaddress 101 $ADDRESS # Simulate mining while : do + # generate new btc to the address /app/bin/bitcoin-cli generatetoaddress 1 $ADDRESS - sleep 10 -done \ No newline at end of file + sleep 5 + # send tx to own address while paying fee to the miner + /app/bin/bitcoin-cli sendtoaddress $ADDRESS 0.5 "" "" true + sleep 5 +done diff --git a/infra/bitcoincash/Dockerfile b/infra/bitcoincash/Dockerfile index fd3765a8..085e635a 100644 --- a/infra/bitcoincash/Dockerfile +++ b/infra/bitcoincash/Dockerfile @@ -1,14 +1,16 @@ -FROM ubuntu:xenial +FROM ubuntu:bionic # Install bitcoind-abc. RUN apt-get update && apt-get install --yes software-properties-common && \ -add-apt-repository --yes ppa:bitcoin-abc/ppa && apt-get update && \ +add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update && \ +apt-get install --yes g++-7 && \ +add-apt-repository ppa:bitcoin-cash-node/ppa && apt-get update && \ apt-get install --yes bitcoind COPY bitcoin.conf /root/.bitcoin/ COPY run.sh /root/ RUN chmod +x /root/run.sh -EXPOSE 18443 +EXPOSE 19443 -ENTRYPOINT ["./root/run.sh"] \ No newline at end of file +ENTRYPOINT ["./root/run.sh"] diff --git a/infra/docker-compose.yaml b/infra/docker-compose.yaml index 9ee382af..9c5dc344 100644 --- a/infra/docker-compose.yaml +++ b/infra/docker-compose.yaml @@ -1,5 +1,31 @@ version: "2" services: + # + # Acala + # + acala: + build: + context: ./acala + ports: + - "0.0.0.0:9933:9933" + - "0.0.0.0:9944:9944" + entrypoint: + - "./root/run.sh" + - "${ACALA_ADDRESS}" + + # + # Binance Smart Chain + # + binance: + build: + context: ./binance + ports: + - "0.0.0.0:8575:8575" + entrypoint: + - "./root/run.sh" + - "${BINANCE_MNEMONIC}" + - "${BINANCE_ADDRESS}" + # # Bitcoin # @@ -11,6 +37,7 @@ services: entrypoint: - "./root/run.sh" - "${BITCOIN_ADDRESS}" + - "${BITCOIN_PK}" # # Bitcoin Cash @@ -83,10 +110,6 @@ services: context: ./fantom ports: - "0.0.0.0:18545:18545" - entrypoint: - - "./root/run.sh" - - "${FANTOM_MNEMONIC}" - - "${FANTOM_ADDRESS}" # # Filecoin @@ -99,19 +122,6 @@ services: entrypoint: - "/root/run.sh" - # - # Solana - # - solana: - build: - context: ./solana - ports: - - "0.0.0.0:8899:8899" - - "0.0.0.0:8900:8900" - - "0.0.0.0:9900:9900" - entrypoint: - - "./root/run.sh" - # # Zcash # @@ -135,3 +145,50 @@ services: entrypoint: - "./root/run.sh" - "${TERRA_ADDRESS}" + + ## + ## Polygon + ## + polygon: + build: + context: ./polygon + ports: + - "0.0.0.0:28545:8545" + entrypoint: + - "./root/run.sh" + + ## + ## Solana + ## + solana: + image: renbot/ren-solana:latest + ports: + - "0.0.0.0:8899-8900:8899-8900" + + ## + ## Moonbeam + ## + moonbeam: + image: purestake/moonbeam:tutorial-v7 + ports: + - "0.0.0.0:9944:9944" + - "0.0.0.0:9933:9933" + command: --dev --ws-external --rpc-external + + # + # Avalanche + # + avalanche: + build: + context: ./avalanche + ports: + - "0.0.0.0:9650:9650" + entrypoint: + - "./run.sh" + - "${AVAX_USERNAME}" + - "${AVAX_PASSWORD}" + - "${AVAX_PK}" + - "${AVAX_ADDRESS}" + - "${C_AVAX_PK}" + - "${C_AVAX_HEX_ADDRESS}" + - "${C_AVAX_BECH32_ADDRESS}" diff --git a/infra/ethereum/run.sh b/infra/ethereum/run.sh index 5880da45..4b283e7b 100644 --- a/infra/ethereum/run.sh +++ b/infra/ethereum/run.sh @@ -2,9 +2,11 @@ MNEMONIC=$1 ADDRESS=$2 -ganache-cli \ - -h 0.0.0.0 \ - -k muirGlacier \ - -i 420 \ - -m "$MNEMONIC" \ - -u $ADDRESS \ No newline at end of file +ganache-cli \ + -h 0.0.0.0 \ + -a 105 \ + -k muirGlacier \ + -l 14969745 \ + -i 420 \ + -m "$MNEMONIC" \ + -u $ADDRESS diff --git a/infra/fantom/Dockerfile b/infra/fantom/Dockerfile index 8438e3b4..2c2118e1 100644 --- a/infra/fantom/Dockerfile +++ b/infra/fantom/Dockerfile @@ -1,15 +1,23 @@ -FROM ubuntu:xenial +FROM ubuntu:groovy -RUN apt-get update --fix-missing -RUN apt-get install --yes curl +# Install dependencies +RUN apt-get update -y +RUN apt-get install -y build-essential git wget -RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - -RUN apt-get install --yes nodejs -RUN npm install -g ganache-cli +# Install Go +RUN wget -c https://golang.org/dl/go1.15.5.linux-amd64.tar.gz +RUN tar -C /usr/local -xzf go1.15.5.linux-amd64.tar.gz +ENV PATH=$PATH:/usr/local/go/bin -COPY run.sh /root/run.sh -RUN chmod +x /root/run.sh +# Build Opera +WORKDIR /app +RUN git clone https://github.com/Fantom-foundation/go-opera.git +WORKDIR /app/go-opera +RUN git checkout release/1.0.0-rc.4 +RUN make +ENV PATH=$PATH:/app/go-opera/build -EXPOSE 8545 +# Expose the default port of the JSON-RPC server +EXPOSE 18545 -ENTRYPOINT ["./root/run.sh"] \ No newline at end of file +ENTRYPOINT [ "opera", "--fakenet", "1/1", "--http", "--http.api=eth,net", "--http.vhosts", "*", "--http.addr", "0.0.0.0" ] diff --git a/infra/filecoin/Dockerfile b/infra/filecoin/Dockerfile index aa8c623b..db653b4d 100644 --- a/infra/filecoin/Dockerfile +++ b/infra/filecoin/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:xenial +FROM ubuntu:bionic RUN apt update -y RUN apt install -y mesa-opencl-icd ocl-icd-opencl-dev gcc git bzr jq pkg-config curl wget nano @@ -8,20 +8,23 @@ RUN wget -c https://golang.org/dl/go1.14.6.linux-amd64.tar.gz RUN tar -C /usr/local -xzf go1.14.6.linux-amd64.tar.gz ENV PATH=$PATH:/usr/local/go/bin -COPY run.sh /root/run.sh -COPY miner.key /root/miner.key -RUN chmod +x /root/run.sh -RUN chmod +x /root/miner.key - WORKDIR /app RUN git clone https://github.com/filecoin-project/lotus . +RUN git checkout d4cdc6d3340b8496c9f98e2d0daed8d1bd9b271e RUN make 2k RUN ./lotus fetch-params 2048 RUN ./lotus-seed pre-seal --sector-size 2KiB --num-sectors 2 RUN ./lotus-seed genesis new localnet.json RUN ./lotus-seed genesis add-miner localnet.json ~/.genesis-sectors/pre-seal-t01000.json +COPY run.sh /root/run.sh +COPY miner.key /root/miner.key +COPY user.key /root/user.key +RUN chmod +x /root/run.sh +RUN chmod +x /root/miner.key +RUN chmod +x /root/user.key + EXPOSE 1234 CMD /root/run.sh diff --git a/infra/filecoin/miner.key b/infra/filecoin/miner.key index e4d811cd..2c0c1e21 100644 --- a/infra/filecoin/miner.key +++ b/infra/filecoin/miner.key @@ -1 +1 @@ -7b2254797065223a22736563703235366b31222c22507269766174654b6579223a223168436f364f617442746f58636d304f6565665849473873374e505573576472372f6666735a58755964493d227d \ No newline at end of file +7b2254797065223a22736563703235366b31222c22507269766174654b6579223a223168436f364f617442746f58636d304f6565665849473873374e505573576472372f6666735a58755964493d227d diff --git a/infra/filecoin/run.sh b/infra/filecoin/run.sh index 1e2ec3e3..e7bb1213 100644 --- a/infra/filecoin/run.sh +++ b/infra/filecoin/run.sh @@ -1,5 +1,9 @@ #!/bin/bash +cd /app/ + +export LOTUS_SKIP_GENESIS_CHECK=_yes_ + ./lotus daemon --lotus-make-genesis=dev.gen --genesis-template=localnet.json --bootstrap=false & PID=$! @@ -10,6 +14,10 @@ sleep 10 ./lotus wallet import /root/miner.key +./lotus wallet import /root/user.key + +./lotus auth create-token --perm admin + kill $PID echo ' @@ -41,19 +49,19 @@ Timeout = "30s" # HeadNotifs = false #' > ~/.lotus/config.toml -./lotus daemon --lotus-make-genesis=/root/dev.gen --genesis-template=/root/localnet.json --bootstrap=false & +./lotus daemon --lotus-make-genesis=/root/dev.gen --genesis-template=/app/localnet.json --bootstrap=false & sleep 5 -./lotus-storage-miner init --genesis-miner --actor=t01000 --sector-size=2KiB --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json --nosync +./lotus-miner init --genesis-miner --actor=t01000 --sector-size=2KiB --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json --nosync -./lotus-storage-miner run --nosync & +./lotus-miner run --nosync & sleep 15 MAIN_WALLET="$(jq -r '.t01000.Owner' ~/.genesis-sectors/pre-seal-t01000.json)" -./lotus send --from $MAIN_WALLET t17lz42vyixtlfs4a3j76cw53w32qb57w7g4g6qua 1000000 +./lotus send --from $MAIN_WALLET t1ej2tountzqwnu6uswhqdzvw6yy5xvcig6rxl2qa 1000000 while : do diff --git a/infra/filecoin/user.key b/infra/filecoin/user.key new file mode 100644 index 00000000..cd4bb900 --- /dev/null +++ b/infra/filecoin/user.key @@ -0,0 +1 @@ +7b2254797065223a22736563703235366b31222c22507269766174654b6579223a22756d6a634e436a487a5438455757485849754a4c4b58745035437153323435666238626c656c756e5448493d227d diff --git a/infra/polygon/Dockerfile b/infra/polygon/Dockerfile new file mode 100644 index 00000000..e7dbb040 --- /dev/null +++ b/infra/polygon/Dockerfile @@ -0,0 +1,13 @@ +FROM maticnetwork/bor:master + +COPY run.sh /root/run.sh +RUN chmod +x /root/run.sh + +RUN mkdir -p /root/.bor/keystore +COPY genesis.json /root/.bor/genesis.json +COPY nodekey /root/.bor/nodekey +COPY static-nodes.json /root/.bor/static-nodes.json +COPY json-keystore /root/.bor/keystore/UTC--2021-05-11T14-27-08.753Z--0xbf7A416377ed8f1F745A739C8ff59094EB2FEFD2 +COPY password.txt /root/.bor/password.txt + +ENTRYPOINT [ "./root/run.sh" ] diff --git a/infra/polygon/genesis.json b/infra/polygon/genesis.json new file mode 100644 index 00000000..acf7b977 --- /dev/null +++ b/infra/polygon/genesis.json @@ -0,0 +1,50 @@ +{ + "config": { + "chainId": 15001, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "bor": { + "period": 1, + "producerDelay": 4, + "sprint": 64, + "backupMultiplier": 1, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001" + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612944565b610706565b60405161021e93929190613283565b60405180910390f35b610241600480360361023c9190810190612944565b61075d565b60405161024f9291906130a4565b60405180910390f35b610272600480360361026d919081019061296d565b610939565b60405161027f91906130db565b60405180910390f35b6102a2600480360361029d9190810190612a4c565b610a91565b005b6102be60048036036102b9919081019061296d565b61112a565b6040516102cb91906130db565b60405180910390f35b6102dc611281565b6040516102e99190613231565b60405180910390f35b61030c600480360361030791908101906128a1565b611286565b60405161031991906130f6565b60405180910390f35b61033c60048036036103379190810190612944565b611307565b6040516103499190613231565b60405180910390f35b61035a611437565b6040516103679190613089565b60405180910390f35b61038a600480360361038591908101906128dd565b61144f565b60405161039791906130db565b60405180910390f35b6103a861151a565b6040516103b591906130f6565b60405180910390f35b6103d860048036036103d391908101906129a9565b611531565b6040516103e59190613231565b60405180910390f35b6104086004803603610403919081019061296d565b611619565b6040516104159190613216565b60405180910390f35b610426611781565b6040516104339190613231565b60405180910390f35b61045660048036036104519190810190612826565b611791565b60405161046391906130db565b60405180910390f35b6104866004803603610481919081019061284f565b6117ab565b60405161049391906130f6565b60405180910390f35b6104a4611829565b6040516104b393929190613283565b60405180910390f35b6104c461189d565b6040516104d29291906130a4565b60405180910390f35b6104e361198e565b6040516104f09190613231565b60405180910390f35b610513600480360361050e9190810190612a10565b611993565b6040516105229392919061324c565b60405180910390f35b61054560048036036105409190810190612826565b6119f7565b60405161055291906130db565b60405180910390f35b610563611a11565b60405161057091906130f6565b60405180910390f35b610593600480360361058e9190810190612944565b611a28565b6040516105a09190613231565b60405180910390f35b6105b1611b59565b6040516105be91906130f6565b60405180910390f35b6105cf611b70565b6040516105de93929190613283565b60405180910390f35b61060160048036036105fc9190810190612944565b611bd1565b60405161060e9190613231565b60405180910390f35b61061f611cd1565b60405161062d9291906130a4565b60405180910390f35b610650600480360361064b9190810190612944565b611ce5565b60405161065d9190613231565b60405180910390f35b61066e611d06565b60405161067b91906132ba565b60405180910390f35b61069e60048036036106999190810190612a10565b611d0b565b6040516106ad9392919061324c565b60405180910390f35b6106be611d6f565b6040516106cb9190613231565b60405180910390f35b6106ee60048036036106e99190810190612944565b611d81565b6040516106fd93929190613283565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611bd1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906131f6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611dab565b5b610b456001826120cc90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613176565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906131d6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c11906131b6565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613156565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613196565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612620565b506000600160008a815260200190815260200160002081610d879190612620565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120eb565b612119565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b6020026020010151612119565b90506000808c81526020019081526020016000208054809190600101610e349190612620565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516121f6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516121f6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612267565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120eb565b612119565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b6020026020010151612119565b9050600160008d81526020019081526020016000208054809190600101610fff9190612620565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516121f6565b815260200161104a8360018151811061103d57fe5b60200260200101516121f6565b815260200161106c8360028151811061105f57fe5b6020026020010151612267565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a393929190612ff6565b6040516020818303038152906040526040516112bf9190613033565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612878565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b602002602001015160200151836120cc90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b6040516115269061305f565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161228a565b90506000611585828961231690919063ffffffff16565b905061158f612652565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb8160200151876120cc90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612652565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611bd1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c6929190612fca565b6040516020818303038152906040526040516117e29190613033565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612878565b9050919050565b60008060008061184a600161183c611781565b6120cc90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060016040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073bf7a416377ed8f1f745a739c8ff59094eb2fefd2816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606060016040519080825280602002602001820160405280156119635781602001602082028038833980820191505090505b5090506127108160008151811061197657fe5b60200260200101818152505081819350935050509091565b60ff81565b600160205281600052604060002081815481106119ac57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611a0a611a04611781565b83610939565b9050919050565b604051611a1d9061304a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611afb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611a5f565b505050509050600080905060008090505b8251811015611b4e57611b3f838281518110611b2457fe5b602002602001015160200151836120cc90919063ffffffff16565b91508080600101915050611b0c565b508092505050919050565b604051611b6590613074565b604051809103902081565b600080600080611b7e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611c9157611bee612689565b6002600060036001850381548110611c0257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611c5f57506000816040015114155b8015611c6f575080604001518411155b15611c8257806000015192505050611ccc565b50808060019003915050611bdd565b5060006003805490501115611cc757600360016003805490500381548110611cb557fe5b90600052602060002001549050611ccc565b600090505b919050565b606080611cdd4361075d565b915091509091565b60038181548110611cf257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611d2457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611d7b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611db661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600260008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506003819080600181540180825580915050906001820390600052602060002001600090919290919091505550600080600083815260200190815260200160002081611e5f9190612620565b5060006001600083815260200190815260200160002081611e809190612620565b5060008090505b8351811015611fa2576000808381526020019081526020016000208054809190600101611eb49190612620565b506040518060600160405280828152602001848381518110611ed257fe5b60200260200101518152602001858381518110611eeb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506000808481526020019081526020016000208281548110611f2957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611e87565b5060008090505b83518110156120c657600160008381526020019081526020016000208054809190600101611fd79190612620565b506040518060600160405280828152602001848381518110611ff557fe5b6020026020010151815260200185838151811061200e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061204d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611fa9565b50505050565b6000808284019050838110156120e157600080fd5b8091505092915050565b6120f36126aa565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061212482612420565b61212d57600080fd5b60006121388361246e565b905060608160405190808252806020026020018201604052801561217657816020015b6121636126c4565b81526020019060019003908161215b5790505b509050600061218885602001516124df565b8560200151019050600080600090505b848110156121e9576121a983612568565b91506040518060400160405280838152602001848152508482815181106121cc57fe5b602002602001018190525081830192508080600101915050612198565b5082945050505050919050565b600080826000015111801561221057506021826000015111155b61221957600080fd5b600061222883602001516124df565b9050600081846000015103905060008083866020015101905080519150602083101561225b57826020036101000a820491505b81945050505050919050565b6000601582600001511461227a57600080fd5b612283826121f6565b9050919050565b60608183018451101561229c57600080fd5b60608215600081146122b95760405191506020820160405261230a565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156122f757805183526020830192506020810190506122da565b50868552601f19601f8301166040525050505b50809150509392505050565b6000806000806041855114612331576000935050505061241a565b602085015192506040850151915060ff6041860151169050601b8160ff16101561235c57601b810190505b601b8160ff16141580156123745750601c8160ff1614155b15612385576000935050505061241a565b6000600187838686604051600081526020016040526040516123aa9493929190613111565b6020604051602081039080840390855afa1580156123cc573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561241257600080fd5b809450505050505b92915050565b600080826000015114156124375760009050612469565b60008083602001519050805160001a915060c060ff168260ff16101561246257600092505050612469565b6001925050505b919050565b6000808260000151141561248557600090506124da565b6000809050600061249984602001516124df565b84602001510190506000846000015185602001510190505b808210156124d3576124c282612568565b8201915082806001019350506124b1565b8293505050505b919050565b600080825160001a9050608060ff168110156124ff576000915050612563565b60b860ff16811080612524575060c060ff168110158015612523575060f860ff1681105b5b15612533576001915050612563565b60c060ff168110156125535760018060b80360ff16820301915050612563565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156125895760019150612616565b60b860ff168110156125a6576001608060ff168203019150612615565b60c060ff168110156125d65760b78103600185019450806020036101000a85510460018201810193505050612614565b60f860ff168110156125f357600160c060ff168203019150612613565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561264d5760030281600302836000526020600020918201910161264c91906126de565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61273191905b8082111561272d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016126e4565b5090565b90565b600081359050612743816134b3565b92915050565b600081359050612758816134ca565b92915050565b60008151905061276d816134ca565b92915050565b60008083601f84011261278557600080fd5b8235905067ffffffffffffffff81111561279e57600080fd5b6020830191508360018202830111156127b657600080fd5b9250929050565b600082601f8301126127ce57600080fd5b81356127e16127dc82613302565b6132d5565b915080825260208301602083018583830111156127fd57600080fd5b61280883828461345d565b50505092915050565b600081359050612820816134e1565b92915050565b60006020828403121561283857600080fd5b600061284684828501612734565b91505092915050565b60006020828403121561286157600080fd5b600061286f84828501612749565b91505092915050565b60006020828403121561288a57600080fd5b60006128988482850161275e565b91505092915050565b600080604083850312156128b457600080fd5b60006128c285828601612749565b92505060206128d385828601612749565b9150509250929050565b6000806000606084860312156128f257600080fd5b600061290086828701612749565b935050602061291186828701612749565b925050604084013567ffffffffffffffff81111561292e57600080fd5b61293a868287016127bd565b9150509250925092565b60006020828403121561295657600080fd5b600061296484828501612811565b91505092915050565b6000806040838503121561298057600080fd5b600061298e85828601612811565b925050602061299f85828601612734565b9150509250929050565b6000806000606084860312156129be57600080fd5b60006129cc86828701612811565b93505060206129dd86828701612749565b925050604084013567ffffffffffffffff8111156129fa57600080fd5b612a06868287016127bd565b9150509250925092565b60008060408385031215612a2357600080fd5b6000612a3185828601612811565b9250506020612a4285828601612811565b9150509250929050565b600080600080600080600060a0888a031215612a6757600080fd5b6000612a758a828b01612811565b9750506020612a868a828b01612811565b9650506040612a978a828b01612811565b955050606088013567ffffffffffffffff811115612ab457600080fd5b612ac08a828b01612773565b9450945050608088013567ffffffffffffffff811115612adf57600080fd5b612aeb8a828b01612773565b925092505092959891949750929550565b6000612b088383612b2c565b60208301905092915050565b6000612b208383612f9d565b60208301905092915050565b612b35816133d2565b82525050565b612b44816133d2565b82525050565b6000612b558261334e565b612b5f8185613389565b9350612b6a8361332e565b8060005b83811015612b9b578151612b828882612afc565b9750612b8d8361336f565b925050600181019050612b6e565b5085935050505092915050565b6000612bb382613359565b612bbd818561339a565b9350612bc88361333e565b8060005b83811015612bf9578151612be08882612b14565b9750612beb8361337c565b925050600181019050612bcc565b5085935050505092915050565b612c0f816133e4565b82525050565b612c26612c21826133f0565b61349f565b82525050565b612c358161341c565b82525050565b612c4c612c478261341c565b6134a9565b82525050565b6000612c5d82613364565b612c6781856133ab565b9350612c7781856020860161346c565b80840191505092915050565b6000612c906004836133c7565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612cd0602d836133b6565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612d36600f836133b6565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612d766013836133b6565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612db66045836133b6565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000612e42602a836133b6565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000612ea8600e836133c7565b91507f6865696d64616c6c2d31353030310000000000000000000000000000000000006000830152600e82019050919050565b6000612ee86005836133c7565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000612f286012836133b6565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b606082016000820151612f716000850182612f9d565b506020820151612f846020850182612f9d565b506040820151612f976040850182612b2c565b50505050565b612fa681613446565b82525050565b612fb581613446565b82525050565b612fc481613450565b82525050565b6000612fd68285612c15565b600182019150612fe68284612c3b565b6020820191508190509392505050565b60006130028286612c15565b6001820191506130128285612c3b565b6020820191506130228284612c3b565b602082019150819050949350505050565b600061303f8284612c52565b915081905092915050565b600061305582612c83565b9150819050919050565b600061306a82612e9b565b9150819050919050565b600061307f82612edb565b9150819050919050565b600060208201905061309e6000830184612b3b565b92915050565b600060408201905081810360008301526130be8185612b4a565b905081810360208301526130d28184612ba8565b90509392505050565b60006020820190506130f06000830184612c06565b92915050565b600060208201905061310b6000830184612c2c565b92915050565b60006080820190506131266000830187612c2c565b6131336020830186612fbb565b6131406040830185612c2c565b61314d6060830184612c2c565b95945050505050565b6000602082019050818103600083015261316f81612cc3565b9050919050565b6000602082019050818103600083015261318f81612d29565b9050919050565b600060208201905081810360008301526131af81612d69565b9050919050565b600060208201905081810360008301526131cf81612da9565b9050919050565b600060208201905081810360008301526131ef81612e35565b9050919050565b6000602082019050818103600083015261320f81612f1b565b9050919050565b600060608201905061322b6000830184612f5b565b92915050565b60006020820190506132466000830184612fac565b92915050565b60006060820190506132616000830186612fac565b61326e6020830185612fac565b61327b6040830184612b3b565b949350505050565b60006060820190506132986000830186612fac565b6132a56020830185612fac565b6132b26040830184612fac565b949350505050565b60006020820190506132cf6000830184612fbb565b92915050565b6000604051905081810181811067ffffffffffffffff821117156132f857600080fd5b8060405250919050565b600067ffffffffffffffff82111561331957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006133dd82613426565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561348a57808201518184015260208101905061346f565b83811115613499576000848401525b50505050565b6000819050919050565b6000819050919050565b6134bc816133d2565b81146134c757600080fd5b50565b6134d38161341c565b81146134de57600080fd5b50565b6134ea81613446565b81146134f557600080fd5b5056fea365627a7a72315820421f0e2879cc0d2332ed8ec9bd7d2e5227bba908a312849a3318dfaf3b5bd3106c6578706572696d656e74616cf564736f6c634300050b0040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fce28085b549b31600000", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611f046023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611ee16023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f3a9900000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b613a9981565b60015481565b604051806080016040528060528152602001611f27605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611e75573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820bb602c3c6bcd412ef9bc4b050494e16a2ec21725618669ec9857d8853ab3333a64736f6c634300050b0032" + }, + "bf7A416377ed8f1F745A739C8ff59094EB2FEFD2": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/infra/polygon/json-keystore b/infra/polygon/json-keystore new file mode 100644 index 00000000..b4cd5507 --- /dev/null +++ b/infra/polygon/json-keystore @@ -0,0 +1,21 @@ +{ + "version": 3, + "id": "6f3e9ee2-0db1-464b-8977-3d6dab963efa", + "address": "bf7a416377ed8f1f745a739c8ff59094eb2fefd2", + "crypto": { + "ciphertext": "8bce0b16e5b34d3cf5f9090e49253450e39f8c56a2e7344514e9d81b1db51c0b", + "cipherparams": { + "iv": "df9eaeaedbf9ee8c29c1416db77abaff" + }, + "cipher": "aes-128-ctr", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "salt": "b30d9d712a504e7c96d4331b351b38ce5e121b6d4d33290345ab2def479fb408", + "n": 8192, + "r": 8, + "p": 1 + }, + "mac": "b5465c6825699d4e441454cba0e8cc508c07438077c359ab0ca516ace51f0218" + } +} diff --git a/infra/polygon/nodekey b/infra/polygon/nodekey new file mode 100644 index 00000000..483a11fe --- /dev/null +++ b/infra/polygon/nodekey @@ -0,0 +1 @@ +bf7f3c94e16d94784358f555c2ac58ea9f77f009816af471a0aab815d5578848 diff --git a/infra/polygon/password.txt b/infra/polygon/password.txt new file mode 100644 index 00000000..50cb46d0 --- /dev/null +++ b/infra/polygon/password.txt @@ -0,0 +1 @@ +password0 diff --git a/infra/polygon/run.sh b/infra/polygon/run.sh new file mode 100644 index 00000000..2827b558 --- /dev/null +++ b/infra/polygon/run.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +NODE_DIR=/root/.bor +DATA_DIR=/root/.bor/data +ADDRESS="bf7A416377ed8f1F745A739C8ff59094EB2FEFD2" + +bor --datadir $DATA_DIR init $NODE_DIR/genesis.json +cp $NODE_DIR/nodekey $DATA_DIR/bor/ +cp $NODE_DIR/static-nodes.json $DATA_DIR/bor/ + +bor --nousb \ + --datadir $DATA_DIR \ + --port 30303 \ + --bor.withoutheimdall \ + --http --http.addr '0.0.0.0' \ + --http.vhosts '*' \ + --http.corsdomain '*' \ + --http.port 8545 \ + --http.api 'personal,eth,net,web3,txpool,miner,admin,bor' \ + --syncmode 'full' \ + --networkid '15001' \ + --miner.gaslimit '2000000000' \ + --txpool.nolocals \ + --txpool.accountslots '128' \ + --txpool.globalslots '20000' \ + --txpool.lifetime '0h16m0s' \ + --unlock $ADDRESS \ + --keystore $NODE_DIR/keystore \ + --password $NODE_DIR/password.txt \ + --allow-insecure-unlock \ + --mine diff --git a/infra/polygon/static-nodes.json b/infra/polygon/static-nodes.json new file mode 100644 index 00000000..8bc7c7d7 --- /dev/null +++ b/infra/polygon/static-nodes.json @@ -0,0 +1,3 @@ +[ + "enode://344282ecde713de509be84a6aa0e65d2b36c9a8475373ef0b62dc3e086eacf4b58083c65eaf039f1097d80048699643a05aeea215afe97c27170346501f16fac@172.20.1.100:30303" +] diff --git a/infra/solana/Dockerfile b/infra/solana/Dockerfile deleted file mode 100644 index 43633d56..00000000 --- a/infra/solana/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM debian:buster - -RUN apt-get update --fix-missing -RUN apt-get install --yes curl bzip2 libssl-dev - -RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - -RUN apt-get install --yes nodejs - -RUN curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v1.2.13/install/solana-install-init.sh | sh -s - v1.2.13 - -COPY run.sh /root/run.sh -RUN chmod +x /root/run.sh - -EXPOSE 8899/tcp -EXPOSE 8900 -EXPOSE 9900 - -ENTRYPOINT ["./root/run.sh"] -CMD [""] \ No newline at end of file diff --git a/infra/solana/run.sh b/infra/solana/run.sh deleted file mode 100644 index f40bd4aa..00000000 --- a/infra/solana/run.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash -# -# Run a minimal Solana cluster. Ctrl-C to exit. -# -# Before running this script ensure standard Solana programs are available -# in the PATH, or that `cargo build` ran successfully -# -set -e - -# Update path -PATH="/root/.local/share/solana/install/active_release/bin:$PATH" - -# Prefer possible `cargo build` binaries over PATH binaries -cd "$(dirname "$0")/" - -profile=debug -if [[ -n $NDEBUG ]]; then - profile=release -fi -PATH=$PWD/target/$profile:$PATH - -ok=true -for program in solana-{faucet,genesis,keygen,validator}; do - $program -V || ok=false -done -$ok || { - echo - echo "Unable to locate required programs. Try building them first with:" - echo - echo " $ cargo build --all" - echo - exit 1 -} - -export RUST_LOG=${RUST_LOG:-solana=info} # if RUST_LOG is unset, default to info -export RUST_BACKTRACE=1 -dataDir=$PWD/config/"$(basename "$0" .sh)" -ledgerDir=$PWD/config/ledger - -set -x -validator_identity="$dataDir/validator-identity.json" -if [[ -e $validator_identity ]]; then - echo "Use existing validator keypair" -else - solana-keygen new --no-passphrase -so "$validator_identity" -fi -validator_vote_account="$dataDir/validator-vote-account.json" -if [[ -e $validator_vote_account ]]; then - echo "Use existing validator vote account keypair" -else - solana-keygen new --no-passphrase -so "$validator_vote_account" -fi -validator_stake_account="$dataDir/validator-stake-account.json" -if [[ -e $validator_stake_account ]]; then - echo "Use existing validator stake account keypair" -else - solana-keygen new --no-passphrase -so "$validator_stake_account" -fi -faucet="$dataDir"/faucet.json -if [[ -e $faucet ]]; then - echo "Use existing faucet keypair" -else - solana-keygen new --no-passphrase -fso "$faucet" -fi - -if [[ -e "$ledgerDir"/genesis.bin || -e "$ledgerDir"/genesis.tar.bz2 ]]; then - echo "Use existing genesis" -else - # shellcheck disable=SC2086 - solana-genesis \ - --hashes-per-tick sleep \ - --faucet-pubkey "$dataDir"/faucet.json \ - --faucet-lamports 500000000000000000 \ - --bootstrap-validator \ - "$dataDir"/validator-identity.json \ - "$dataDir"/validator-vote-account.json \ - "$dataDir"/validator-stake-account.json \ - --ledger "$ledgerDir" \ - --operating-mode development \ - $SOLANA_RUN_SH_GENESIS_ARGS -fi - -abort() { - set +e - kill "$faucet" "$validator" - wait "$validator" -} -trap abort INT TERM EXIT - -solana-faucet --keypair "$dataDir"/faucet.json & -faucet=$! - -args=( - --identity "$dataDir"/validator-identity.json - --vote-account "$dataDir"/validator-vote-account.json - --ledger "$ledgerDir" - --gossip-port 8001 - --rpc-port 8899 - --rpc-faucet-address 127.0.0.1:9900 - --log - - --enable-rpc-exit - --enable-rpc-transaction-history - --init-complete-file "$dataDir"/init-completed -) -solana-validator "${args[@]}" & -validator=$! - -wait "$validator" \ No newline at end of file diff --git a/infra/terra/Dockerfile b/infra/terra/Dockerfile index d307f8bf..9602daf0 100644 --- a/infra/terra/Dockerfile +++ b/infra/terra/Dockerfile @@ -1,17 +1,25 @@ FROM ubuntu:xenial -RUN apt-get update --fix-missing && apt-get install --yes software-properties-common wget -RUN wget -c https://github.com/terra-project/core/releases/download/v0.4.0-rc.2/terra_0.4.0_rc.2_Linux_x86_64.tar.gz -O - | tar xz -RUN mkdir -p /app/bin -RUN mv ./terrad ./terracli /app/bin -RUN chmod +x /app/bin/terrad -RUN chmod +x /app/bin/terracli -RUN ln -s /app/bin/terrad /usr/bin/terrad -RUN ln -s /app/bin/terracli /usr/bin/terracli +RUN apt-get update --fix-missing && apt-get install --yes software-properties-common build-essential wget curl git + +RUN wget -c https://golang.org/dl/go1.15.5.linux-amd64.tar.gz +RUN tar -C /usr/local -xzf go1.15.5.linux-amd64.tar.gz +ENV PATH=$PATH:/usr/local/go/bin + +WORKDIR /app +RUN git clone https://github.com/terra-project/core.git +WORKDIR /app/core +RUN git fetch --all -p +RUN git checkout v0.4.6 +RUN make install COPY run.sh /root/run.sh RUN chmod +x /root/run.sh EXPOSE 26657 +ENV PATH=$PATH:/root/go/bin + +WORKDIR / + ENTRYPOINT ["./root/run.sh"] diff --git a/infra/zcash/Dockerfile b/infra/zcash/Dockerfile index e976dcab..8d14df3b 100644 --- a/infra/zcash/Dockerfile +++ b/infra/zcash/Dockerfile @@ -1,11 +1,11 @@ -FROM ubuntu:xenial +FROM ubuntu:bionic # Install zcashd. -RUN apt-get update && \ - apt-get install -y --no-install-recommends apt-transport-https gnupg2 ca-certificates wget && \ - wget -qO - https://apt.z.cash/zcash.asc | apt-key add - && \ - echo "deb https://apt.z.cash/ jessie main" | tee /etc/apt/sources.list.d/zcash.list && \ - apt-get update && apt-get install -y --no-install-recommends zcash && \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends apt-transport-https gnupg2 ca-certificates wget && \ + wget -qO - https://apt.z.cash/zcash.asc | apt-key add - && \ + echo "deb [arch=amd64] https://apt.z.cash/ stretch main" | tee /etc/apt/sources.list.d/zcash.list && \ + apt-get update && apt-get install -y --no-install-recommends zcash && \ mkdir -p /root/.zcash-params && zcash-fetch-params COPY zcash.conf /root/.zcash/zcash.conf @@ -14,4 +14,4 @@ RUN chmod +x /root/run.sh EXPOSE 18232 -ENTRYPOINT ["./root/run.sh"] \ No newline at end of file +ENTRYPOINT ["./root/run.sh"] diff --git a/infra/zcash/run.sh b/infra/zcash/run.sh index dc66a07d..7bd0e0c3 100644 --- a/infra/zcash/run.sh +++ b/infra/zcash/run.sh @@ -2,7 +2,13 @@ ADDRESS=$1 # Start -zcashd -mineraddress=$ADDRESS +zcashd \ + -mineraddress=$ADDRESS \ + -nuparams=5ba81b19:10 \ + -nuparams=76b809bb:20 \ + -nuparams=2bb40e60:30 \ + -nuparams=f5b9230b:40 \ + -nuparams=e9ff75a6:50 sleep 10 echo "ZCASH_ADDRESS=$ADDRESS" @@ -18,4 +24,4 @@ while : do zcash-cli generate 1 sleep 10 -done \ No newline at end of file +done diff --git a/infra/zcash/zcash.conf b/infra/zcash/zcash.conf index 87e21705..5b8aab13 100644 --- a/infra/zcash/zcash.conf +++ b/infra/zcash/zcash.conf @@ -8,6 +8,3 @@ server=1 txindex=1 gen=1 minetolocalwallet=0 -nuparams=5ba81b19:40 -nuparams=76b809bb:60 -nuparams=2bb40e60:80 \ No newline at end of file diff --git a/multichain.go b/multichain.go index e27b45f6..b9732ead 100644 --- a/multichain.go +++ b/multichain.go @@ -8,39 +8,87 @@ import ( "github.com/renproject/multichain/api/contract" "github.com/renproject/multichain/api/gas" "github.com/renproject/multichain/api/utxo" - "github.com/renproject/multichain/chain/ethereum" "github.com/renproject/surge" ) type ( - Address = address.Address - AddressEncodeDecoder = address.EncodeDecoder - EthereumCompatAddress = ethereum.Address - RawAddress = address.RawAddress + // An Address is a human-readable representation of a public identity. It can + // be the address of an external account, contract, or script. + Address = address.Address + + // The AddressEncodeDecoder interfaces combines encoding and decoding + // functionality into one interface. + AddressEncodeDecoder = address.EncodeDecoder + + // RawAddress is an address that has been decoded into its binary form. + RawAddress = address.RawAddress ) type ( - AccountTx = account.Tx + // The AccountTx interface defines the functionality that must be exposed by + // account-based transactions. + AccountTx = account.Tx + + // The AccountTxBuilder interface defines the functionality required to build + // account-based transactions. Most chain implementations require additional + // information, and this should be accepted during the construction of the + // chain-specific transaction builder. AccountTxBuilder = account.TxBuilder - AccountClient = account.Client + + // The AccountClient interface defines the functionality required to interact + // with a chain over RPC. + AccountClient = account.Client ) type ( - UTXOutpoint = utxo.Outpoint - UTXOutput = utxo.Output - UTXOInput = utxo.Input + // A UTXOutpoint identifies a specific output produced by a transaction. + UTXOutpoint = utxo.Outpoint + + // A UTXOutput is produced by a transaction. It includes the conditions + // required to spend the output (called the pubkey script, based on Bitcoin). + UTXOutput = utxo.Output + + // A UTXOInput specifies an existing output, produced by a previous + // transaction, to be consumed by another transaction. It includes the script + // that meets the conditions specified by the consumed output (called the sig + // script, based on Bitcoin). + UTXOInput = utxo.Input + + // A UTXORecipient specifies an address, and an amount, for which a + // transaction will produce an output. Depending on the output, the address + // can take on different formats (e.g. in Bitcoin, addresses can be P2PK, + // P2PKH, or P2SH). UTXORecipient = utxo.Recipient - UTXOTx = utxo.Tx + + // A UTXOTx interfaces defines the functionality that must be exposed by + // utxo-based transactions. + UTXOTx = utxo.Tx + + // A UTXOTxBuilder interface defines the functionality required to build + // account-based transactions. Most chain implementations require additional + // information, and this should be accepted during the construction of the + // chain-specific transaction builder. UTXOTxBuilder = utxo.TxBuilder - UTXOClient = utxo.Client + + // A UTXOClient interface defines the functionality required to interact with + // a chain over RPC. + UTXOClient = utxo.Client ) type ( + // ContractCallData is used to specify a function and its parameters when + // invoking business logic on a contract. ContractCallData = contract.CallData - ContractCaller = contract.Caller + + // The ContractCaller interface defines the functionality required to call + // readonly functions on a contract. Calling functions that mutate contract + // state should be done using the Account API. + ContractCaller = contract.Caller ) type ( + // The GasEstimator interface defines the functionality required to know the + // current recommended gas prices. GasEstimator = gas.Estimator ) @@ -51,33 +99,42 @@ type Asset string // from an existing chain, you must add a human-readable string to this set of // enumerated values. Assets must be listed in alphabetical order. const ( - BCH = Asset("BCH") // Bitcoin Cash - BNB = Asset("BNB") // Binance Coin - BTC = Asset("BTC") // Bitcoin - CELO = Asset("CELO") // Celo - DGB = Asset("DGB") // DigiByte - DOGE = Asset("DOGE") // Dogecoin - ETH = Asset("ETH") // Ether - FIL = Asset("FIL") // Filecoin - FTM = Asset("FTM") // Fantom - SOL = Asset("SOL") // Solana - LUNA = Asset("LUNA") // Luna + AVAX = Asset("AVAX") // Avalanche + BCH = Asset("BCH") // Bitcoin Cash + BNB = Asset("BNB") // Binance Coin + BTC = Asset("BTC") // Bitcoin + DGB = Asset("DGB") // DigiByte + DOGE = Asset("DOGE") // Dogecoin + ETH = Asset("ETH") // Ether + FIL = Asset("FIL") // Filecoin + FTM = Asset("FTM") // Fantom + GLMR = Asset("GLMR") // Glimmer + LUNA = Asset("LUNA") // Luna + MATIC = Asset("MATIC") // Matic PoS (Polygon) + SOL = Asset("SOL") // Solana ONE = Asset("ONE") // Harmony - ZEC = Asset("ZEC") // Zcash + ZEC = Asset("ZEC") // Zcash + + // These assets are defined separately because they are mock assets. These + // assets should only be used for testing. + + AMOCK1 = Asset("AMOCK1") // Account-based mock asset + AMOCK2 = Asset("AMOCK2") // Account-based mock asset + UMOCK = Asset("UMOCK") // UTXO-based mock asset ) // OriginChain returns the chain upon which the asset originates. For example, // the origin chain of BTC is Bitcoin. func (asset Asset) OriginChain() Chain { switch asset { + case AVAX: + return Avalanche case BCH: return BitcoinCash case BNB: return BinanceSmartChain case BTC: return Bitcoin - case CELO: - return Celo case DGB: return DigiByte case DOGE: @@ -86,21 +143,57 @@ func (asset Asset) OriginChain() Chain { return Ethereum case FIL: return Filecoin + case GLMR: + return Moonbeam case FTM: return Fantom case LUNA: return Terra + case MATIC: + return Polygon case SOL: return Solana case ONE: return Harmony case ZEC: return Zcash + + // These assets are handled separately because they are mock assets. These + // assets should only be used for testing. + + case AMOCK1: + return AccountMocker1 + case AMOCK2: + return AccountMocker2 + case UMOCK: + return UTXOMocker + default: return Chain("") } } +// ChainType returns the chain-type (Account or UTXO) for the given asset +func (asset Asset) ChainType() ChainType { + switch asset { + case BCH, BTC, DGB, DOGE, ZEC: + return ChainTypeUTXOBased + case AVAX, BNB, ETH, FIL, GLMR, LUNA, MATIC, ONE: + return ChainTypeAccountBased + + // These assets are handled separately because they are mock assets. These + // assets should only be used for testing. + + case AMOCK1, AMOCK2: + return ChainTypeAccountBased + case UMOCK: + return ChainTypeUTXOBased + + default: + return ChainType("") + } +} + // SizeHint returns the number of bytes required to represent the asset in // binary. func (asset Asset) SizeHint() int { @@ -124,20 +217,28 @@ type Chain string // human-readable string to this set of enumerated values. Chains must be listed // in alphabetical order. const ( - Acala = Chain("Acala") + Avalanche = Chain("Avalanche") BinanceSmartChain = Chain("BinanceSmartChain") Bitcoin = Chain("Bitcoin") BitcoinCash = Chain("BitcoinCash") - Celo = Chain("Celo") DigiByte = Chain("DigiByte") Dogecoin = Chain("Dogecoin") Ethereum = Chain("Ethereum") Fantom = Chain("Fantom") Filecoin = Chain("Filecoin") Harmony = Chain("Harmony") + Moonbeam = Chain("Moonbeam") + Polygon = Chain("Polygon") Solana = Chain("Solana") Terra = Chain("Terra") Zcash = Chain("Zcash") + + // These chains are defined separately because they are mock chains. These + // chains should only be used for testing. + + AccountMocker1 = Chain("AccountMocker1") + AccountMocker2 = Chain("AccountMocker2") + UTXOMocker = Chain("UTXOMocker") ) // SizeHint returns the number of bytes required to represent the chain in @@ -158,30 +259,101 @@ func (chain *Chain) Unmarshal(buf []byte, rem int) ([]byte, int, error) { return surge.UnmarshalString((*string)(chain), buf, rem) } +// ChainType returns the chain type (whether account-based or utxo-based chain) +// for the chain. func (chain Chain) ChainType() ChainType { switch chain { case Bitcoin, BitcoinCash, DigiByte, Dogecoin, Zcash: return ChainTypeUTXOBased - case BinanceSmartChain, Ethereum: + case Avalanche, BinanceSmartChain, Ethereum, Fantom, Filecoin, Moonbeam, Polygon, Solana, Harmony, Terra: + return ChainTypeAccountBased + + // These chains are handled separately because they are mock chains. These + // chains should only be used for testing. + + case AccountMocker1, AccountMocker2: return ChainTypeAccountBased + case UTXOMocker: + return ChainTypeUTXOBased + default: return ChainType("") } } +// IsAccountBased returns true when invoked on an account-based chain, otherwise +// returns false. func (chain Chain) IsAccountBased() bool { return chain.ChainType() == ChainTypeAccountBased } +// IsUTXOBased returns true when invoked on a utxo-based chain, otherwise +// returns false. func (chain Chain) IsUTXOBased() bool { return chain.ChainType() == ChainTypeUTXOBased } +// NativeAsset returns the underlying native asset for a chain. For example, the +// root asset of Bitcoin chain is BTC. +func (chain Chain) NativeAsset() Asset { + switch chain { + case Avalanche: + return AVAX + case BinanceSmartChain: + return BNB + case BitcoinCash: + return BCH + case Bitcoin: + return BTC + case DigiByte: + return DGB + case Dogecoin: + return DOGE + case Ethereum: + return ETH + case Fantom: + return FTM + case Filecoin: + return FIL + case Moonbeam: + return GLMR + case Polygon: + return MATIC + case Harmony: + return ONE + case Solana: + return SOL + case Terra: + return LUNA + case Zcash: + return ZEC + + // These chains are handled separately because they are mock chains. These + // chains should only be used for testing. + + case AccountMocker1: + return AMOCK1 + case AccountMocker2: + return AMOCK2 + case UTXOMocker: + return UMOCK + + default: + return Asset("") + } +} + +// ChainType represents the type of chain (whether account-based or utxo-based) type ChainType string const ( + // ChainTypeAccountBased is an identifier for all account-based chains, + // namely, BinanceSmartChain, Ethereum, Filecoin, and so on. ChainTypeAccountBased = ChainType("Account") - ChainTypeUTXOBased = ChainType("UTXO") + + // ChainTypeUTXOBased is an identifier for all utxo-based chains, namely, + // Bitcoin, BitcoinCash, DigiByte, and so on. + ChainTypeUTXOBased = ChainType("UTXO") ) // SizeHint returns the number of bytes required to represent the chain type in @@ -202,12 +374,32 @@ func (chainType *ChainType) Unmarshal(buf []byte, rem int) ([]byte, int, error) return surge.UnmarshalString((*string)(chainType), buf, rem) } +// Network identifies the network type for the multichain deployment type Network string const ( + // NetworkLocalnet represents a local network for chains. It is usually only + // accessible from the device running the network, and is not accessible + // over the Internet. Chain rules are often slightly different to allow for + // faster block times and easier access to testing funds. This is also + // sometimes referred to as "regnet" or "regression network". It should only + // be used for local testing. NetworkLocalnet = Network("localnet") - NetworkTestnet = Network("testnet") - NetworkMainnet = Network("mainnet") + + // NetworkDevnet represents the development network for chains. This network + // is typically a deployed version of the localnet. Chain rules are often + // slightly different to allow for faster block times and easier access to + // testing funds. + NetworkDevnet = Network("devnet") + + // NetworkTestnet represents the test network for chains. This network is + // typically a publicly accessible network that has the same, or very + // similar, chain rules compared to mainnet. Assets on this type of network + // are usually not considered to have value. + NetworkTestnet = Network("testnet") + + // NetworkMainnet represents the main network for chains. + NetworkMainnet = Network("mainnet") ) // SizeHint returns the number of bytes required to represent the network in diff --git a/multichain_test.go b/multichain_test.go index c9dfef38..8148d35b 100644 --- a/multichain_test.go +++ b/multichain_test.go @@ -1,4 +1,1308 @@ package multichain_test -// TODO: Run test suite of simple tests for all supported chains. The idea is to -// use the common APIs to run these tests. +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "flag" + "fmt" + "math/rand" + "os" + "os/exec" + "reflect" + "strings" + "testing/quick" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/base58" + cosmossdk "github.com/cosmos/cosmos-sdk/types" + filaddress "github.com/filecoin-project/go-address" + filtypes "github.com/filecoin-project/lotus/chain/types" + "github.com/renproject/id" + "github.com/renproject/multichain" + "github.com/renproject/multichain/chain/bitcoin" + "github.com/renproject/multichain/chain/bitcoincash" + + "github.com/btcsuite/btcutil/bech32" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + // "github.com/renproject/multichain/chain/digibyte" + "github.com/renproject/multichain/chain/dogecoin" + "github.com/renproject/multichain/chain/filecoin" + "github.com/renproject/multichain/chain/harmony" + "github.com/renproject/multichain/chain/terra" + "github.com/renproject/multichain/chain/zcash" + "github.com/renproject/pack" + "github.com/renproject/surge" + "github.com/tendermint/tendermint/crypto/secp256k1" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var ( + testBTC = flag.Bool("btc", false, "Pass this flag to test Bitcoin") + testBCH = flag.Bool("bch", false, "Pass this flag to test Bitcoincash") + testDOGE = flag.Bool("doge", false, "Pass this flag to test Dogecoin") + testFIL = flag.Bool("fil", false, "Pass this flag to test Filecoin") + testONE = flag.Bool("one", false, "Pass this flag to test Harmony") + testLUNA = flag.Bool("luna", false, "Pass this flag to test Terra") + testZEC = flag.Bool("zec", false, "Pass this flag to test Zcash") +) + +var _ = Describe("Multichain", func() { + // new randomness + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + // Create context to work within. + ctx := context.Background() + + // Initialise the logger. + loggerConfig := zap.NewDevelopmentConfig() + loggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + logger, err := loggerConfig.Build() + Expect(err).ToNot(HaveOccurred()) + + // Populate the test flags by underlying asset chain. + testFlags := map[multichain.Chain]bool{} + testFlags[multichain.Bitcoin] = *testBTC + testFlags[multichain.BitcoinCash] = *testBCH + testFlags[multichain.Dogecoin] = *testDOGE + testFlags[multichain.Filecoin] = *testFIL + testFlags[multichain.Harmony] = *testONE + testFlags[multichain.Terra] = *testLUNA + testFlags[multichain.Zcash] = *testZEC + + // + // Multichain Configs + // + Context("Multichain Declarations", func() { + Context("All supporting chains/assets are declared", func() { + accountChains := []struct { + chain multichain.Chain + asset multichain.Asset + }{ + { + multichain.Avalanche, + multichain.AVAX, + }, + { + multichain.Fantom, + multichain.FTM, + }, + { + multichain.Filecoin, + multichain.FIL, + }, + { + multichain.Moonbeam, + multichain.GLMR, + }, + { + multichain.Polygon, + multichain.MATIC, + }, + { + multichain.Harmony, + multichain.ONE, + }, + { + multichain.Solana, + multichain.SOL, + }, + { + multichain.Terra, + multichain.LUNA, + }, + } + utxoChains := []struct { + chain multichain.Chain + asset multichain.Asset + }{ + { + multichain.Bitcoin, + multichain.BTC, + }, + { + multichain.BitcoinCash, + multichain.BCH, + }, + { + multichain.DigiByte, + multichain.DGB, + }, + { + multichain.Dogecoin, + multichain.DOGE, + }, + { + multichain.Zcash, + multichain.ZEC, + }, + } + + for _, accountChain := range accountChains { + accountChain := accountChain + Specify(fmt.Sprintf("Chain=%v, Asset=%v should be supported", accountChain.chain, accountChain.asset), func() { + Expect(accountChain.chain.IsAccountBased()).To(BeTrue()) + Expect(accountChain.chain.NativeAsset()).To(Equal(accountChain.asset)) + Expect(accountChain.asset.OriginChain()).To(Equal(accountChain.chain)) + }) + } + for _, utxoChain := range utxoChains { + utxoChain := utxoChain + Specify(fmt.Sprintf("Chain=%v, Asset=%v should be supported", utxoChain.chain, utxoChain.asset), func() { + Expect(utxoChain.chain.IsUTXOBased()).To(BeTrue()) + Expect(utxoChain.chain.NativeAsset()).To(Equal(utxoChain.asset)) + Expect(utxoChain.asset.OriginChain()).To(Equal(utxoChain.chain)) + }) + } + }) + }) + + // + // ADDRESS API + // + Context("Address API", func() { + chainTable := []struct { + chain multichain.Chain + newEncodeDecoder func() multichain.AddressEncodeDecoder + newAddress func() multichain.Address + newRawAddress func() multichain.RawAddress + newSHAddress func() multichain.Address + newSHRawAddress func() multichain.RawAddress + }{ + { + multichain.Bitcoin, + func() multichain.AddressEncodeDecoder { + addrEncodeDecoder := bitcoin.NewAddressEncodeDecoder(&chaincfg.RegressionNetParams) + return addrEncodeDecoder + }, + func() multichain.Address { + // Generate a random SECP256K1 private key. + pk := id.NewPrivKey() + // Get bitcoin WIF private key with the pub key configured to be in + // the compressed form. + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), &chaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(wif.SerializePubKey()), &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Return the human-readable encoded bitcoin address in base58 format. + return multichain.Address(addrPubKeyHash.EncodeAddress()) + }, + func() multichain.RawAddress { + // Generate a random SECP256K1 private key. + pk := id.NewPrivKey() + // Get bitcoin WIF private key with the pub key configured to be in + // the compressed form. + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), &chaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + // Get the address pubKey hash. This is the most commonly used format + // for a bitcoin address. + addrPubKeyHash, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(wif.SerializePubKey()), &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Encode into the checksummed base58 format. + encoded := addrPubKeyHash.EncodeAddress() + return multichain.RawAddress(pack.Bytes(base58.Decode(encoded))) + }, + func() multichain.Address { + // Random bytes of script. + script := make([]byte, r.Intn(100)) + r.Read(script) + // Create address script hash from the random script bytes. + addrScriptHash, err := btcutil.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Return in human-readable encoded form. + return multichain.Address(addrScriptHash.EncodeAddress()) + }, + func() multichain.RawAddress { + // Random bytes of script. + script := make([]byte, r.Intn(100)) + r.Read(script) + // Create address script hash from the random script bytes. + addrScriptHash, err := btcutil.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + // Encode to the checksummed base58 format. + encoded := addrScriptHash.EncodeAddress() + return multichain.RawAddress(pack.Bytes(base58.Decode(encoded))) + }, + }, + { + multichain.Filecoin, + func() multichain.AddressEncodeDecoder { + return filecoin.NewAddressEncodeDecoder() + }, + func() multichain.Address { + pubKey := make([]byte, 64) + r.Read(pubKey) + addr, err := filaddress.NewSecp256k1Address(pubKey) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addr.String()) + }, + func() multichain.RawAddress { + rawAddr := make([]byte, 20) + r.Read(rawAddr) + formattedRawAddr := append([]byte{byte(filaddress.SECP256K1)}, rawAddr[:]...) + return multichain.RawAddress(pack.NewBytes(formattedRawAddr[:])) + }, + func() multichain.Address { + return multichain.Address("") + }, + func() multichain.RawAddress { + return multichain.RawAddress([]byte{}) + }, + }, + { + multichain.Terra, + func() multichain.AddressEncodeDecoder { + return terra.NewAddressEncodeDecoder() + }, + func() multichain.Address { + pk := secp256k1.GenPrivKey() + addr := cosmossdk.AccAddress(pk.PubKey().Address()) + return multichain.Address(addr.String()) + }, + func() multichain.RawAddress { + pk := secp256k1.GenPrivKey() + rawAddr := pk.PubKey().Address() + return multichain.RawAddress(pack.Bytes(rawAddr)) + }, + func() multichain.Address { + return multichain.Address("") + }, + func() multichain.RawAddress { + return multichain.RawAddress([]byte{}) + }, + }, + { + multichain.BitcoinCash, + func() multichain.AddressEncodeDecoder { + addrEncodeDecoder := bitcoincash.NewAddressEncodeDecoder(&chaincfg.RegressionNetParams) + return addrEncodeDecoder + }, + func() multichain.Address { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), &chaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := bitcoincash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addrPubKeyHash.EncodeAddress()) + }, + func() multichain.RawAddress { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), &chaincfg.RegressionNetParams, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := bitcoincash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + + addrBytes := addrPubKeyHash.ScriptAddress() + addrBytes = append([]byte{0x00}, addrBytes...) + return multichain.RawAddress(pack.Bytes(addrBytes)) + }, + func() multichain.Address { + script := make([]byte, r.Intn(100)) + r.Read(script) + addrScriptHash, err := bitcoincash.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addrScriptHash.EncodeAddress()) + }, + func() multichain.RawAddress { + script := make([]byte, r.Intn(100)) + r.Read(script) + addrScriptHash, err := bitcoincash.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + + addrBytes := addrScriptHash.ScriptAddress() + addrBytes = append([]byte{8}, addrBytes...) + return multichain.RawAddress(pack.Bytes(addrBytes)) + }, + }, + { + multichain.Zcash, + func() multichain.AddressEncodeDecoder { + addrEncodeDecoder := zcash.NewAddressEncodeDecoder(&zcash.RegressionNetParams) + return addrEncodeDecoder + }, + func() multichain.Address { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), zcash.RegressionNetParams.Params, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := zcash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addrPubKeyHash.EncodeAddress()) + }, + func() multichain.RawAddress { + pk := id.NewPrivKey() + wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), zcash.RegressionNetParams.Params, true) + Expect(err).NotTo(HaveOccurred()) + addrPubKeyHash, err := zcash.NewAddressPubKeyHash(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed()), &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.RawAddress(pack.Bytes(base58.Decode(addrPubKeyHash.EncodeAddress()))) + }, + func() multichain.Address { + script := make([]byte, r.Intn(100)) + r.Read(script) + addrScriptHash, err := zcash.NewAddressScriptHash(script, &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addrScriptHash.EncodeAddress()) + }, + func() multichain.RawAddress { + script := make([]byte, r.Intn(100)) + r.Read(script) + addrScriptHash, err := zcash.NewAddressScriptHash(script, &zcash.RegressionNetParams) + Expect(err).NotTo(HaveOccurred()) + return multichain.RawAddress(pack.Bytes(base58.Decode(addrScriptHash.EncodeAddress()))) + }, + }, + { + multichain.Harmony, + func() multichain.AddressEncodeDecoder { + return harmony.NewEncoderDecoder() + }, + func() multichain.Address { + key, _ := crypto.GenerateKey() + addrBytes := crypto.PubkeyToAddress(key.PublicKey) + conv, err := bech32.ConvertBits(addrBytes.Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + addr, err := bech32.Encode(harmony.Bech32AddressHRP, conv) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addr) + }, + func() multichain.RawAddress { + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey).String() + Expect(err).NotTo(HaveOccurred()) + return common.HexToAddress(addr).Bytes() + }, + func() multichain.Address { + return multichain.Address("") + }, + func() multichain.RawAddress { + return multichain.RawAddress([]byte{}) + }, + }, + } + + for _, chain := range chainTable { + chain := chain + Context(fmt.Sprintf("%v", chain.chain), func() { + encodeDecoder := chain.newEncodeDecoder() + + It("should encode a raw address correctly", func() { + rawAddr := chain.newRawAddress() + encodedAddr, err := encodeDecoder.EncodeAddress(rawAddr) + Expect(err).NotTo(HaveOccurred()) + decodedRawAddr, err := encodeDecoder.DecodeAddress(encodedAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(decodedRawAddr).To(Equal(rawAddr)) + }) + + It("should decode an address correctly", func() { + addr := chain.newAddress() + decodedRawAddr, err := encodeDecoder.DecodeAddress(addr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := encodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(addr)) + }) + + if chain.chain.IsUTXOBased() { + It("should encoded a raw script address correctly", func() { + rawScriptAddr := chain.newSHRawAddress() + encodedAddr, err := encodeDecoder.EncodeAddress(rawScriptAddr) + Expect(err).NotTo(HaveOccurred()) + decodedRawAddr, err := encodeDecoder.DecodeAddress(encodedAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(decodedRawAddr).To(Equal(rawScriptAddr)) + }) + + It("should decode a script address correctly", func() { + scriptAddr := chain.newSHAddress() + decodedRawAddr, err := encodeDecoder.DecodeAddress(scriptAddr) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := encodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(encodedAddr).To(Equal(scriptAddr)) + }) + } + + if chain.chain == multichain.Bitcoin { + mainnetEncodeDecoder := bitcoin.NewAddressEncodeDecoder(&chaincfg.MainNetParams) + + It("should decode a Bech32 address correctly", func() { + segwitAddrs := []string{ + "bc1qp3gcp95e85rupv9zgj57j0lvsqnzcehawzaax3", + "bc1qh6fjfx39ae4ahvusc4eggyrwjm65zyu83mzwlx", + "bc1q3zqxadsagdwjp2fpddn8dk5ge8lf0nn0p750ar", + "bc1q2lthuszmh0mynte4nzsfqtjjseu6fdrmeffr62", + "bc1qdqkfrt2hpgncqwut88809he6wxysfw8w3cgsh4", + "bc1qna5zwwuqcst3dqqx8rmwa66jpa45w28tlypg54", + "bc1qjk2ytl6uctuxfsyf8dn6ptwfsthfat4hd78l0m", + "bc1qyg6zhg9dhmkj0wz4svsdz6g0ujll225v0wc5hx", + "bc1quvtmmjccre6plqslujw7qcy820fycg2q2a73an", + "bc1qztxl2qc3k90uud846qfeawqzz3aedhq48vv3lu", + "bc1qvkknfkfhfr0axql478klvjs6sanwj6njym5wf2", + "bc1qya5t2pj7hqpezcnwh72k69h4cgg3srqwtd0e6w", + } + for _, segwitAddr := range segwitAddrs { + decodedRawAddr, err := mainnetEncodeDecoder.DecodeAddress(multichain.Address(segwitAddr)) + Expect(err).NotTo(HaveOccurred()) + encodedAddr, err := mainnetEncodeDecoder.EncodeAddress(decodedRawAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(string(encodedAddr)).To(Equal(segwitAddr)) + } + }) + + It("should encode a Bech32 address correctly", func() { + loop := func() bool { + l := 21 + if r.Intn(2) == 1 { + l = 33 + } + randBytes := make([]byte, l) + r.Read(randBytes) + randBytes[0] = byte(0) + rawAddr := multichain.RawAddress(randBytes) + encodedAddr, err := mainnetEncodeDecoder.EncodeAddress(rawAddr) + Expect(err).NotTo(HaveOccurred()) + decodedRawAddr, err := mainnetEncodeDecoder.DecodeAddress(encodedAddr) + Expect(err).NotTo(HaveOccurred()) + Expect(decodedRawAddr).To(Equal(rawAddr)) + return true + } + Expect(quick.Check(loop, nil)).To(Succeed()) + }) + } + }) + } + }) + + // + // ACCOUNT API + // + Context("Account API", func() { + accountChainTable := []struct { + senderEnv func() (id.PrivKey, *id.PubKey, multichain.Address) + privKeyToAddr func(pk id.PrivKey) multichain.Address + rpcURL pack.String + randomRecipientAddr func() multichain.Address + initialise func(pack.String) (multichain.AccountClient, multichain.AccountTxBuilder) + txParams func(multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) + chain multichain.Chain + }{ + { + func() (id.PrivKey, *id.PubKey, multichain.Address) { + pkEnv := os.Getenv("TERRA_PK") + if pkEnv == "" { + panic("TERRA_PK is undefined") + } + pkBytes, err := hex.DecodeString(pkEnv) + Expect(err).NotTo(HaveOccurred()) + var pk secp256k1.PrivKeySecp256k1 + copy(pk[:], pkBytes) + addrEncoder := terra.NewAddressEncoder() + senderAddr, err := addrEncoder.EncodeAddress(multichain.RawAddress(pack.Bytes(pk.PubKey().Address()))) + Expect(err).NotTo(HaveOccurred()) + senderPrivKey := id.PrivKey{} + err = surge.FromBinary(&senderPrivKey, pkBytes) + Expect(err).NotTo(HaveOccurred()) + return senderPrivKey, senderPrivKey.PubKey(), senderAddr + }, + func(privKey id.PrivKey) multichain.Address { + pkBytes, err := surge.ToBinary(privKey) + Expect(err).NotTo(HaveOccurred()) + var pk secp256k1.PrivKeySecp256k1 + copy(pk[:], pkBytes) + addrEncoder := terra.NewAddressEncoder() + addr, err := addrEncoder.EncodeAddress(multichain.RawAddress(pack.Bytes(pk.PubKey().Address()))) + Expect(err).NotTo(HaveOccurred()) + return addr + }, + "http://127.0.0.1:26657", + func() multichain.Address { + recipientKey := secp256k1.GenPrivKey() + addrEncoder := terra.NewAddressEncoder() + recipient, err := addrEncoder.EncodeAddress(multichain.RawAddress(pack.Bytes(recipientKey.PubKey().Address()))) + Expect(err).NotTo(HaveOccurred()) + return recipient + }, + func(rpcURL pack.String) (multichain.AccountClient, multichain.AccountTxBuilder) { + client := terra.NewClient( + terra.DefaultClientOptions(). + WithHost(rpcURL). + WithCoinDenom("uluna"), + ) + txBuilder := terra.NewTxBuilder( + terra.DefaultTxBuilderOptions(). + WithChainID("testnet"), + client, + ) + + return client, txBuilder + }, + func(_ multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) { + amount := pack.NewU256FromU64(pack.U64(2000000)) + gasLimit := pack.NewU256FromU64(pack.U64(100000)) + gasPrice := pack.NewU256FromU64(pack.U64(1)) + gasCap := pack.NewU256FromInt(gasPrice.Int()) + payload := pack.NewBytes([]byte("multichain")) + return amount, gasLimit, gasPrice, gasCap, payload + }, + multichain.Terra, + }, + { + func() (id.PrivKey, *id.PubKey, multichain.Address) { + pkEnv := os.Getenv("FILECOIN_PK") + if pkEnv == "" { + panic("FILECOIN_PK is undefined") + } + var ki filtypes.KeyInfo + data, err := hex.DecodeString(pkEnv) + Expect(err).NotTo(HaveOccurred()) + err = json.Unmarshal(data, &ki) + Expect(err).NotTo(HaveOccurred()) + privKey := id.PrivKey{} + err = surge.FromBinary(&privKey, ki.PrivateKey) + Expect(err).NotTo(HaveOccurred()) + pubKey := privKey.PubKey() + + // FIXME: add method in renproject/id to get uncompressed pubkey bytes + pubKeyCompressed, err := surge.ToBinary(pubKey) + Expect(err).NotTo(HaveOccurred()) + /*addr*/ _, err = filaddress.NewSecp256k1Address(pubKeyCompressed) + Expect(err).NotTo(HaveOccurred()) + addrStr := os.Getenv("FILECOIN_ADDRESS") + if addrStr == "" { + panic("FILECOIN_ADDRESS is undefined") + } + + return privKey, pubKey, multichain.Address(pack.String(addrStr)) + }, + func(privKey id.PrivKey) multichain.Address { + pubKey := privKey.PubKey() + pubKeyCompressed, err := surge.ToBinary(pubKey) + Expect(err).NotTo(HaveOccurred()) + addr, err := filaddress.NewSecp256k1Address(pubKeyCompressed) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(pack.String(addr.String())) + }, + "http://127.0.0.1:1234/rpc/v0", + func() multichain.Address { + pk := id.NewPrivKey() + pubKey := pk.PubKey() + pubKeyCompressed, err := surge.ToBinary(pubKey) + Expect(err).NotTo(HaveOccurred()) + addr, err := filaddress.NewSecp256k1Address(pubKeyCompressed) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(pack.String(addr.String())) + }, + func(rpcURL pack.String) (multichain.AccountClient, multichain.AccountTxBuilder) { + // dirty hack to fetch auth token + client, err := filecoin.NewClient( + filecoin.DefaultClientOptions(). + WithRPCURL(rpcURL). + WithAuthToken(fetchAuthToken()), + ) + Expect(err).NotTo(HaveOccurred()) + + txBuilder := filecoin.NewTxBuilder() + + return client, txBuilder + }, + func(client multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) { + amount := pack.NewU256FromU64(pack.NewU64(100000000)) + gasLimit := pack.NewU256FromU64(pack.NewU64(2189560)) + + // Fetch gas price and gas cap using the gas estimator. + filecoinClient := client.(*filecoin.Client) + gasPrice, gasCap, err := filecoin.NewGasEstimator(filecoinClient, gasLimit.Int().Int64()). + EstimateGas(context.Background()) + Expect(err).NotTo(HaveOccurred()) + + payload := pack.Bytes(nil) + return amount, gasLimit, gasPrice, gasCap, payload + }, + multichain.Filecoin, + }, + { + func() (id.PrivKey, *id.PubKey, multichain.Address) { + pkEnv := os.Getenv("HARMONY_PK") + if pkEnv == "" { + panic("HARMONY_PK is undefined") + } + senderKey, err := crypto.HexToECDSA(pkEnv) + Expect(err).NotTo(HaveOccurred()) + addrBytes, err := bech32.ConvertBits(crypto.PubkeyToAddress(senderKey.PublicKey).Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + addr, err := bech32.Encode(harmony.Bech32AddressHRP, addrBytes) + Expect(err).NotTo(HaveOccurred()) + return id.PrivKey(*senderKey), (*id.PubKey)(&senderKey.PublicKey), multichain.Address(addr) + }, + func(privKey id.PrivKey) multichain.Address { + addrBytes, err := bech32.ConvertBits(crypto.PubkeyToAddress(privKey.PublicKey).Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + addr, err := bech32.Encode(harmony.Bech32AddressHRP, addrBytes) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(addr) + }, + "http://127.0.0.1:9598", + func() multichain.Address { + toKey, _ := crypto.GenerateKey() + toAddrBytes, err := bech32.ConvertBits(crypto.PubkeyToAddress(toKey.PublicKey).Bytes(), 8, 5, true) + Expect(err).NotTo(HaveOccurred()) + toAddr, err := bech32.Encode(harmony.Bech32AddressHRP, toAddrBytes) + Expect(err).NotTo(HaveOccurred()) + return multichain.Address(toAddr) + }, + func(rpcURL pack.String) (multichain.AccountClient, multichain.AccountTxBuilder) { + client := harmony.NewClient(harmony.DefaultClientOptions()) + chainId, err := client.ChainId(ctx) + Expect(err).NotTo(HaveOccurred()) + txBuilder := harmony.NewTxBuilder(chainId) + return client, txBuilder + }, + func(client multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) { + gasLimit := uint64(80000000) + gas, err := harmony.Estimator{}.EstimateGasPrice(ctx) + Expect(err).NotTo(HaveOccurred()) + + amount := pack.NewU256FromU64(pack.NewU64(100000000)) + return amount, pack.NewU256FromU64(pack.NewU64(gasLimit)), gas, gas, pack.Bytes(nil) + }, + multichain.Harmony, + }, + } + + for _, accountChain := range accountChainTable { + accountChain := accountChain + if !testFlags[accountChain.chain] { + continue + } + + Context(fmt.Sprintf("%v", accountChain.chain), func() { + Specify("build, broadcast and fetch tx", func() { + // Load private key and the associated address. + senderPrivKey, senderPubKey, senderAddr := accountChain.senderEnv() + + // Get a random recipient address. + recipientAddr := accountChain.randomRecipientAddr() + + // Initialise the account chain's client, and possibly get a nonce for + // the sender. + accountClient, txBuilder := accountChain.initialise(accountChain.rpcURL) + + // Get the appropriate nonce for sender. + nonce, err := accountClient.AccountNonce(ctx, senderAddr) + Expect(err).NotTo(HaveOccurred()) + + // Build a transaction. + amount, gasLimit, gasPrice, gasCap, payload := accountChain.txParams(accountClient) + + accountTx, err := txBuilder.BuildTx( + ctx, + multichain.Address(senderAddr), + recipientAddr, + amount, nonce, gasLimit, gasPrice, gasCap, + payload, + ) + Expect(err).NotTo(HaveOccurred()) + + // Get the transaction bytes and sign them. + sighashes, err := accountTx.Sighashes() + Expect(err).NotTo(HaveOccurred()) + hash := id.Hash(sighashes[0]) + sig, err := senderPrivKey.Sign(&hash) + Expect(err).NotTo(HaveOccurred()) + sigBytes, err := surge.ToBinary(sig) + Expect(err).NotTo(HaveOccurred()) + txSignature := pack.Bytes65{} + copy(txSignature[:], sigBytes) + senderPubKeyBytes, err := surge.ToBinary(senderPubKey) + Expect(err).NotTo(HaveOccurred()) + err = accountTx.Sign( + []pack.Bytes65{txSignature}, + pack.NewBytes(senderPubKeyBytes), + ) + Expect(err).NotTo(HaveOccurred()) + + // Submit the transaction to the account chain. + txHash := accountTx.Hash() + err = accountClient.SubmitTx(ctx, accountTx) + Expect(err).NotTo(HaveOccurred()) + logger.Debug("submit tx", zap.String("from", string(senderAddr)), zap.String("to", string(recipientAddr)), zap.Any("txHash", txHash)) + + // Wait slightly before we query the chain's node. + time.Sleep(time.Second) + + for { + // Loop until the transaction has at least a few confirmations. + tx, confs, err := accountClient.Tx(ctx, txHash) + if err == nil { + Expect(confs.Uint64()).To(BeNumerically(">", 0)) + Expect(tx.Value()).To(Equal(amount)) + Expect(tx.From()).To(Equal(senderAddr)) + Expect(tx.To()).To(Equal(recipientAddr)) + Expect(tx.Value()).To(Equal(amount)) + break + } + + // wait and retry querying for the transaction + time.Sleep(5 * time.Second) + } + }) + + It("should be able to fetch the latest block", func() { + // Initialise client + accountClient, _ := accountChain.initialise(accountChain.rpcURL) + + latestBlock, err := accountClient.LatestBlock(ctx) + Expect(err).NotTo(HaveOccurred()) + Expect(uint64(latestBlock)).To(BeNumerically(">", 1)) + }) + }) + } + }) + + // + // UTXO API + // + Context("UTXO API", func() { + utxoChainTable := []struct { + privKeyEnv string + newAddressPKH func([]byte) (btcutil.Address, error) + newAddressSH func([]byte) (btcutil.Address, error) + rpcURL pack.String + initialise func(pack.String, btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) + txBuilder multichain.UTXOTxBuilder + chain multichain.Chain + }{ + { + "BITCOIN_PK", + func(pkh []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressPubKeyHash(pkh, &chaincfg.RegressionNetParams) + return addr, err + }, + func(script []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + return addr, err + }, + pack.NewString("http://0.0.0.0:18443"), + func(rpcURL pack.String, pkhAddr btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) { + client := bitcoin.NewClient(bitcoin.DefaultClientOptions()) + outputs, err := client.UnspentOutputs(ctx, 0, 999999999, multichain.Address(pkhAddr.EncodeAddress())) + Expect(err).NotTo(HaveOccurred()) + return client, outputs, client.Confirmations + }, + bitcoin.NewTxBuilder(&chaincfg.RegressionNetParams), + multichain.Bitcoin, + }, + { + "BITCOINCASH_PK", + func(pkh []byte) (btcutil.Address, error) { + addr, err := bitcoincash.NewAddressPubKeyHash(pkh, &chaincfg.RegressionNetParams) + return addr, err + }, + func(script []byte) (btcutil.Address, error) { + addr, err := bitcoincash.NewAddressScriptHash(script, &chaincfg.RegressionNetParams) + return addr, err + }, + pack.NewString("http://0.0.0.0:19443"), + func(rpcURL pack.String, pkhAddr btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) { + client := bitcoincash.NewClient(bitcoincash.DefaultClientOptions()) + outputs, err := client.UnspentOutputs(ctx, 0, 999999999, multichain.Address(pkhAddr.EncodeAddress())) + Expect(err).NotTo(HaveOccurred()) + return client, outputs, client.Confirmations + }, + bitcoincash.NewTxBuilder(&chaincfg.RegressionNetParams), + multichain.BitcoinCash, + }, + { + "DOGECOIN_PK", + func(pkh []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressPubKeyHash(pkh, &dogecoin.RegressionNetParams) + return addr, err + }, + func(script []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressScriptHash(script, &dogecoin.RegressionNetParams) + return addr, err + }, + pack.NewString("http://0.0.0.0:18332"), + func(rpcURL pack.String, pkhAddr btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) { + client := dogecoin.NewClient(dogecoin.DefaultClientOptions()) + outputs, err := client.UnspentOutputs(ctx, 0, 999999999, multichain.Address(pkhAddr.EncodeAddress())) + Expect(err).NotTo(HaveOccurred()) + return client, outputs, client.Confirmations + }, + dogecoin.NewTxBuilder(&dogecoin.RegressionNetParams), + multichain.Dogecoin, + }, + { + "ZCASH_PK", + func(pkh []byte) (btcutil.Address, error) { + addr, err := zcash.NewAddressPubKeyHash(pkh, &zcash.RegressionNetParams) + return addr, err + }, + func(script []byte) (btcutil.Address, error) { + addr, err := zcash.NewAddressScriptHash(script, &zcash.RegressionNetParams) + return addr, err + }, + pack.String("http://0.0.0.0:18232"), + func(rpcURL pack.String, pkhAddr btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) { + client := zcash.NewClient(zcash.DefaultClientOptions()) + outputs, err := client.UnspentOutputs(ctx, 0, 999999999, multichain.Address(pkhAddr.EncodeAddress())) + Expect(err).NotTo(HaveOccurred()) + return client, outputs, client.Confirmations + }, + zcash.NewTxBuilder(&zcash.RegressionNetParams, 1000000), + multichain.Zcash, + }, + /* + { + "DIGIBYTE_PK", + func(pkh []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressPubKeyHash(pkh, &digibyte.RegressionNetParams) + return addr, err + }, + func(script []byte) (btcutil.Address, error) { + addr, err := btcutil.NewAddressScriptHash(script, &digibyte.RegressionNetParams) + return addr, err + }, + pack.NewString("http://0.0.0.0:20443"), + func(rpcURL pack.String, pkhAddr btcutil.Address) (multichain.UTXOClient, []multichain.UTXOutput, func(context.Context, pack.Bytes) (int64, error)) { + client := digibyte.NewClient(digibyte.DefaultClientOptions()) + outputs, err := client.UnspentOutputs(ctx, 0, 999999999, multichain.Address(pkhAddr.EncodeAddress())) + Expect(err).NotTo(HaveOccurred()) + return client, outputs, client.Confirmations + }, + digibyte.NewTxBuilder(&digibyte.RegressionNetParams), + multichain.DigiByte, + }, + */ + } + + for _, utxoChain := range utxoChainTable { + utxoChain := utxoChain + if !testFlags[utxoChain.chain] { + continue + } + + Context(fmt.Sprintf("%v", utxoChain.chain), func() { + Specify("(P2PKH) build, broadcast and fetch tx", func() { + // Load private key. + pkEnv := os.Getenv(utxoChain.privKeyEnv) + if pkEnv == "" { + panic(fmt.Sprintf("%v is undefined", utxoChain.privKeyEnv)) + } + wif, err := btcutil.DecodeWIF(pkEnv) + Expect(err).NotTo(HaveOccurred()) + + // Get the PKH address from the loaded private key. + pkhAddr, err := utxoChain.newAddressPKH(btcutil.Hash160(wif.PrivKey.PubKey().SerializeCompressed())) + Expect(err).NotTo(HaveOccurred()) + + // Recipient 1 + pkhAddrUncompressed, err := utxoChain.newAddressPKH(btcutil.Hash160(wif.PrivKey.PubKey().SerializeUncompressed())) + Expect(err).ToNot(HaveOccurred()) + + // Recipient 2 + recipientPrivKey := id.NewPrivKey() + recipientPubKey := recipientPrivKey.PubKey() + recipientPubKeyCompressed, err := surge.ToBinary(recipientPubKey) + Expect(err).NotTo(HaveOccurred()) + recipientPkhAddr, err := utxoChain.newAddressPKH(btcutil.Hash160(((*btcec.PublicKey)(recipientPubKey)).SerializeCompressed())) + Expect(err).NotTo(HaveOccurred()) + + // Initialise the UTXO client and fetch the unspent outputs. Also get a + // function to query the number of block confirmations for a transaction. + utxoClient, unspentOutputs, confsFn := utxoChain.initialise(utxoChain.rpcURL, pkhAddr) + Expect(len(unspentOutputs)).To(BeNumerically(">", 0)) + var output multichain.UTXOutput + thresholdValue := pack.NewU256FromU64(pack.NewU64(2500)) + for _, unspentOutput := range unspentOutputs { + if unspentOutput.Value.GreaterThan(thresholdValue) { + output = unspentOutput + break + } + } + + // Build a transaction + inputs := []multichain.UTXOInput{ + {Output: multichain.UTXOutput{ + Outpoint: multichain.UTXOutpoint{ + Hash: output.Outpoint.Hash[:], + Index: output.Outpoint.Index, + }, + PubKeyScript: output.PubKeyScript, + Value: output.Value, + }}, + } + utxoValue1 := pack.NewU256FromU64(pack.NewU64((output.Value.Int().Uint64() - 1000) / 4)) + utxoValue2 := pack.NewU256FromU64(pack.NewU64((output.Value.Int().Uint64() - 1000) * 3 / 4)) + recipients := []multichain.UTXORecipient{ + { + To: multichain.Address(pkhAddrUncompressed.EncodeAddress()), + Value: utxoValue1, + }, + { + To: multichain.Address(recipientPkhAddr.EncodeAddress()), + Value: utxoValue2, + }, + } + utxoTx, err := utxoChain.txBuilder.BuildTx(inputs, recipients) + Expect(err).NotTo(HaveOccurred()) + + // Get the sighashes that need to be signed, and sign them. + sighashes, err := utxoTx.Sighashes() + signatures := make([]pack.Bytes65, len(sighashes)) + Expect(err).ToNot(HaveOccurred()) + for i := range sighashes { + hash := id.Hash(sighashes[i]) + privKey := (*id.PrivKey)(wif.PrivKey) + signature, err := privKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures[i] = pack.NewBytes65(signature) + } + Expect(utxoTx.Sign(signatures, pack.NewBytes(wif.SerializePubKey()))).To(Succeed()) + + // Submit the signed transaction to the UTXO chain's node. + txHash, err := utxoTx.Hash() + Expect(err).ToNot(HaveOccurred()) + err = utxoClient.SubmitTx(ctx, utxoTx) + Expect(err).ToNot(HaveOccurred()) + + // Check confirmations after waiting for the transaction to be in the + // mempool. + time.Sleep(time.Second) + + for { + // Loop until the transaction has at least a few + // confirmations. + confs, err := confsFn(ctx, txHash) + Expect(err).ToNot(HaveOccurred()) + logger.Debug(fmt.Sprintf("[%v] confirming", utxoChain.chain), zap.Uint64("current", uint64(confs))) + if confs >= 1 { + break + } + time.Sleep(10 * time.Second) + } + + // Load the output and verify that it is equal to the original output. + output2, _, err := utxoClient.Output(ctx, output.Outpoint) + Expect(err).ToNot(HaveOccurred()) + Expect(reflect.DeepEqual(output, output2)).To(BeTrue()) + + // Load the first output and verify the value. + output3, _, err := utxoClient.Output(ctx, multichain.UTXOutpoint{ + Hash: txHash, + Index: pack.NewU32(0), + }) + Expect(err).ToNot(HaveOccurred()) + Expect(output3.Value).To(Equal(utxoValue1)) + + // Load the second output and verify the value. + output4, _, err := utxoClient.Output(ctx, multichain.UTXOutpoint{ + Hash: txHash, + Index: pack.NewU32(1), + }) + Expect(err).ToNot(HaveOccurred()) + Expect(output4.Value).To(Equal(utxoValue2)) + + // Construct UTXO to be signed by invalid key. This UTXO should fail + // when submitted to the network, since the signer doesn't have the + // right to spend it. + // We submit the invalid signed UTXO (which should fail), and wait + // for a maximum of 5 seconds. + inputs2 := []multichain.UTXOInput{{ + Output: output4, + }} + recipients2 := []multichain.UTXORecipient{{ + To: multichain.Address(pkhAddr.EncodeAddress()), + Value: output4.Value.Sub(pack.NewU256FromU64(pack.U64(500))), + }} + utxoTx2, err := utxoChain.txBuilder.BuildTx(inputs2, recipients2) + Expect(err).NotTo(HaveOccurred()) + sighashes2, err := utxoTx2.Sighashes() + signatures2 := make([]pack.Bytes65, len(sighashes2)) + for i := range sighashes2 { + hash := id.Hash(sighashes2[i]) + privKey := (*id.PrivKey)(wif.PrivKey) + signature, err := privKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures2[i] = pack.NewBytes65(signature) + } + Expect(utxoTx2.Sign(signatures2, pack.NewBytes(wif.SerializePubKey()))).To(Succeed()) + failingCtx, failingCancelFn := context.WithTimeout(ctx, 5*time.Second) + Expect(utxoClient.SubmitTx(failingCtx, utxoTx2)).To(HaveOccurred()) + failingCancelFn() + + // Try to spend UTXO from valid key. We should be able to successfully + // submit the signed UTXO to the network. + utxoTx3, err := utxoChain.txBuilder.BuildTx(inputs2, recipients2) + Expect(err).NotTo(HaveOccurred()) + sighashes3, err := utxoTx3.Sighashes() + signatures3 := make([]pack.Bytes65, len(sighashes3)) + for i := range sighashes3 { + hash := id.Hash(sighashes3[i]) + signature, err := recipientPrivKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures3[i] = pack.NewBytes65(signature) + } + Expect(utxoTx3.Sign(signatures3, pack.NewBytes(recipientPubKeyCompressed))).To(Succeed()) + Expect(utxoClient.SubmitTx(ctx, utxoTx3)).NotTo(HaveOccurred()) + }) + + Specify("(P2SH) build, broadcast and fetch tx", func() { + // Load private key. + pkEnv := os.Getenv(utxoChain.privKeyEnv) + if pkEnv == "" { + panic(fmt.Sprintf("%v is undefined", utxoChain.privKeyEnv)) + } + wif, err := btcutil.DecodeWIF(pkEnv) + Expect(err).NotTo(HaveOccurred()) + + // Get the PKH address from the loaded private key. + pkhAddr, err := utxoChain.newAddressPKH(btcutil.Hash160(wif.PrivKey.PubKey().SerializeCompressed())) + Expect(err).NotTo(HaveOccurred()) + + // Recipient + recipientPrivKey := id.NewPrivKey() + recipientPubKey := recipientPrivKey.PubKey() + recipientPubKeyCompressed, err := surge.ToBinary(recipientPubKey) + Expect(err).NotTo(HaveOccurred()) + pubKey := pack.Bytes(((*btcec.PublicKey)(recipientPubKey)).SerializeCompressed()) + script, err := getScript(pubKey) + Expect(err).NotTo(HaveOccurred()) + pubKeyScript, err := getPubKeyScript(pubKey) + Expect(err).NotTo(HaveOccurred()) + recipientP2SH, err := utxoChain.newAddressSH(script) + Expect(err).NotTo(HaveOccurred()) + + // Initialise the UTXO client and fetch the unspent outputs. Also get a + // function to query the number of block confirmations for a transaction. + utxoClient, unspentOutputs, confsFn := utxoChain.initialise(utxoChain.rpcURL, pkhAddr) + Expect(len(unspentOutputs)).To(BeNumerically(">", 0)) + var output multichain.UTXOutput + thresholdValue := pack.NewU256FromU64(pack.NewU64(2500)) + for _, unspentOutput := range unspentOutputs { + if unspentOutput.Value.GreaterThan(thresholdValue) { + output = unspentOutput + break + } + } + + // Build a transaction + inputs := []multichain.UTXOInput{ + {Output: multichain.UTXOutput{ + Outpoint: multichain.UTXOutpoint{ + Hash: output.Outpoint.Hash[:], + Index: output.Outpoint.Index, + }, + PubKeyScript: output.PubKeyScript, + Value: output.Value, + }}, + } + recipients := []multichain.UTXORecipient{ + { + To: multichain.Address(recipientP2SH.EncodeAddress()), + Value: output.Value.Sub(pack.NewU256FromU64(pack.U64(500))), + }, + } + utxoTx, err := utxoChain.txBuilder.BuildTx(inputs, recipients) + Expect(err).NotTo(HaveOccurred()) + + // Get the sighashes that need to be signed, and sign them. + sighashes, err := utxoTx.Sighashes() + signatures := make([]pack.Bytes65, len(sighashes)) + Expect(err).ToNot(HaveOccurred()) + for i := range sighashes { + hash := id.Hash(sighashes[i]) + privKey := (*id.PrivKey)(wif.PrivKey) + signature, err := privKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures[i] = pack.NewBytes65(signature) + } + Expect(utxoTx.Sign(signatures, pack.NewBytes(wif.SerializePubKey()))).To(Succeed()) + + // Submit the signed transaction to the UTXO chain's node. + txHash, err := utxoTx.Hash() + Expect(err).ToNot(HaveOccurred()) + err = utxoClient.SubmitTx(ctx, utxoTx) + Expect(err).ToNot(HaveOccurred()) + logger.Debug("[P2KH -> P2SH] submit tx", zap.String("from", pkhAddr.EncodeAddress()), zap.String("to", recipientP2SH.EncodeAddress()), zap.String("txHash", string(txHashToHex(txHash)))) + + // Check confirmations after waiting for the transaction to be in the + // mempool. + time.Sleep(time.Second) + + for { + // Loop until the transaction has at least a few + // confirmations. + confs, err := confsFn(ctx, txHash) + Expect(err).ToNot(HaveOccurred()) + logger.Debug(fmt.Sprintf("[%v] confirming", utxoChain.chain), zap.Uint64("current", uint64(confs))) + if confs >= 1 { + break + } + time.Sleep(10 * time.Second) + } + + // Load the output and verify that the pub key script is as calculated + // initially. + output2, _, err := utxoClient.Output(ctx, multichain.UTXOutpoint{ + Hash: txHash, + Index: pack.NewU32(0), + }) + Expect(err).ToNot(HaveOccurred()) + Expect(output2.PubKeyScript.Equal(pubKeyScript)).To(BeTrue()) + + // Validate that the output2 is spendable + sigScript, err := getScript(pubKey) + Expect(err).NotTo(HaveOccurred()) + inputs2 := []multichain.UTXOInput{{ + Output: output2, + SigScript: sigScript, + }} + recipients2 := []multichain.UTXORecipient{{ + To: multichain.Address(pkhAddr.EncodeAddress()), + Value: output2.Value.Sub(pack.NewU256FromU64(pack.U64(500))), + }} + utxoTx2, err := utxoChain.txBuilder.BuildTx(inputs2, recipients2) + Expect(err).NotTo(HaveOccurred()) + + // Create another transaction using the same inputs, which we will + // sign with the original user's address. Validate that none other + // than the recipient's signature can spend this UTXO. + utxoTx3, err := utxoChain.txBuilder.BuildTx(inputs2, recipients2) + Expect(err).NotTo(HaveOccurred()) + + // Get the sighashes that need to be signed, and sign them. + sighashes2, err := utxoTx2.Sighashes() + signatures2 := make([]pack.Bytes65, len(sighashes2)) + signatures3 := make([]pack.Bytes65, len(sighashes2)) + Expect(err).ToNot(HaveOccurred()) + for i := range sighashes2 { + hash := id.Hash(sighashes2[i]) + signature, err := recipientPrivKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures2[i] = pack.NewBytes65(signature) + } + for i := range sighashes2 { + hash := id.Hash(sighashes2[i]) + privKey := (*id.PrivKey)(wif.PrivKey) + signature, err := privKey.Sign(&hash) + Expect(err).ToNot(HaveOccurred()) + signatures3[i] = pack.NewBytes65(signature) + } + Expect(utxoTx2.Sign(signatures2, pack.NewBytes(recipientPubKeyCompressed))).To(Succeed()) + Expect(utxoTx3.Sign(signatures3, pack.NewBytes(wif.SerializePubKey()))).To(Succeed()) + + // Try to submit tx signed by invalid spender. This should fail since + failingCtx, failingCancelFn := context.WithTimeout(ctx, 5*time.Second) + Expect(utxoClient.SubmitTx(failingCtx, utxoTx3)).To(HaveOccurred()) + failingCancelFn() + + // Submit the signed transaction to the UTXO chain's node. + txHash2, err := utxoTx2.Hash() + Expect(err).ToNot(HaveOccurred()) + err = utxoClient.SubmitTx(ctx, utxoTx2) + Expect(err).ToNot(HaveOccurred()) + logger.Debug("[P2SH -> P2KH] submit tx", zap.String("from", recipientP2SH.EncodeAddress()), zap.String("to", pkhAddr.EncodeAddress()), zap.String("txHash", string(txHashToHex(txHash2)))) + + // Check confirmations after waiting for the transaction to be in the + // mempool. + time.Sleep(time.Second) + + for { + // Loop until the transaction has at least a few + // confirmations. + confs, err := confsFn(ctx, txHash2) + Expect(err).ToNot(HaveOccurred()) + logger.Debug(fmt.Sprintf("[%v] confirming", utxoChain.chain), zap.Uint64("current", uint64(confs))) + if confs >= 1 { + break + } + time.Sleep(10 * time.Second) + } + }) + + It("should be able to fetch the latest block", func() { + // get a random address + randAddr := make([]byte, 20) + r.Read(randAddr) + pkhAddr, err := utxoChain.newAddressPKH(randAddr) + Expect(err).NotTo(HaveOccurred()) + + // initialise client + utxoClient, _, _ := utxoChain.initialise(utxoChain.rpcURL, pkhAddr) + + latestBlock, err := utxoClient.LatestBlock(ctx) + Expect(err).NotTo(HaveOccurred()) + Expect(uint64(latestBlock)).To(BeNumerically(">", 1)) + }) + }) + } + }) +}) + +func txHashToHex(txHash pack.Bytes) pack.String { + // bitcoin's msgTx is a byte-reversed hash + // https://github.com/btcsuite/btcd/blob/master/chaincfg/chainhash/hash.go#L27-L28 + txHashCopy := make([]byte, len(txHash)) + copy(txHashCopy[:], txHash) + hashSize := len(txHashCopy) + for i := 0; i < hashSize/2; i++ { + txHashCopy[i], txHashCopy[hashSize-1-i] = txHashCopy[hashSize-1-i], txHashCopy[i] + } + return pack.String(hex.EncodeToString(txHashCopy)) +} + +func fetchAuthToken() pack.String { + // fetch the auth token from filecoin's running docker container + cmd := exec.Command("docker", "exec", "infra_filecoin_1", "/bin/bash", "-c", "/app/lotus auth api-info --perm admin") + var out bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stderr + err := cmd.Run() + if err != nil { + fmt.Println(fmt.Sprint(err) + ": " + stderr.String()) + panic(fmt.Sprintf("could not run command: %v", err)) + } + tokenWithSuffix := strings.TrimPrefix(out.String(), "FULLNODE_API_INFO=") + authToken := strings.Split(tokenWithSuffix, ":/") + return pack.NewString(fmt.Sprintf("Bearer %s", authToken[0])) +} + +func getScript(pubKey pack.Bytes) (pack.Bytes, error) { + pubKeyHash160 := btcutil.Hash160(pubKey) + return txscript.NewScriptBuilder(). + AddOp(txscript.OP_DUP). + AddOp(txscript.OP_HASH160). + AddData(pubKeyHash160). + AddOp(txscript.OP_EQUALVERIFY). + AddOp(txscript.OP_CHECKSIG). + Script() +} + +func getPubKeyScript(pubKey pack.Bytes) (pack.Bytes, error) { + script, err := getScript(pubKey) + if err != nil { + return nil, fmt.Errorf("invalid script: %v", err) + } + pubKeyScript, err := txscript.NewScriptBuilder(). + AddOp(txscript.OP_HASH160). + AddData(btcutil.Hash160(script)). + AddOp(txscript.OP_EQUAL). + Script() + if err != nil { + return nil, fmt.Errorf("invalid pubkeyscript: %v", err) + } + return pubKeyScript, nil +}